macosapplescript

Determine OS X keyboard layout ("input source") in the terminal/a script?


I would like to determine the OS X keyboard layout (or "input source" as OS X calls it) from the terminal so that I can show it in places like the tmux status bar.

So I want to know if the current layout is "U.S." or "Swedish - Pro" for example.

Googling turns up nothing for me. Is this possible?


Solution

  • Note: @MarkSetchell deserves credit for coming up with the fundamental approach - where to [start to] look and what tools to use. After further investigation and back and forth in the comments I thought I'd summarize the solution (as of OS X 10.9.1):

    do shell script "defaults read ~/Library/Preferences/com.apple.HIToolbox.plist \\
     AppleSelectedInputSources | \\
     egrep -w 'KeyboardLayout Name' | sed -E 's/^.+ = \"?([^\"]+)\"?;$/\\1/'"
    

    Note how \ is escaped as \\ for the benefit of AppleScript, which ensures that just \ reaches the shell. If you want to execute the same command directly from the shell (as one line), it would be:
    defaults read ~/Library/Preferences/com.apple.HIToolbox.plist AppleSelectedInputSources | egrep -w 'KeyboardLayout Name' |sed -E 's/^.+ = \"?([^\"]+)\"?;$/\1/'

    Update:

    Turns out that AppleScript itself can parse property lists, but it's a bit like pulling teeth. Also, incredibly, the potentially-not-fully-current-values problem also affects AppleScript's parsing.

    Below is an AppleScript handler that gets the current keyboard layout; it uses a do shell script-based workaround to ensure that the plist file is current, but otherwise uses AppleScript's property-list features, via the Property List Suite of application System Events.

    Note: Obviously, the above shell-based approach is much shorter in this case, but the code below demonstrates general techniques for working with property lists.

    # Example call.
    set activeKbdLayout to my getActiveKeyboardLayout() # ->, e.g., "U.S."
    
    on getActiveKeyboardLayout()
      
      # Surprisingly, using POSIX-style paths (even with '~') works with 
      # the `property list file` type.
      set plistPath to "~/Library/Preferences/com.apple.HIToolbox.plist"
      
      # !! First, ensure that the plist cache is flushed and that the
      # !! *.plist file contains the current value; simply executing
      # !! `default read` against the file - even with a dummy
      # !! key - does that.
      try
        do shell script "defaults read " & plistPath & " dummy"
      end try
      
      tell application "System Events"
        
        repeat with pli in property list items of ¬
          property list item "AppleSelectedInputSources" of ¬
          property list file plistPath
          # Look for (first) entry with key "KeyboardLayout Name" and return
          # its value.
          # Note: Not all entries may have a 'KeyboardLayout Name' key, 
          # so we must ignore errors.
          try
            return value of property list item "KeyboardLayout Name" of pli
          end try
        end repeat
        
      end tell
    end getActiveKeyboardLayout