19

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?

Henrik N
  • 15,786
  • 5
  • 82
  • 131

6 Answers6

23

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/'

  • The currently selected keyboard layout is stored in the user-level file ~/Library/Preferences/com.apple.HIToolbox.plist, top-level key AppleSelectedInputSources, subkey KeyboardLayout Name.
  • defaults read ensures that the current settings are read (sadly, as of OSX 10.9, the otherwise superior /usr/libexec/PlistBuddy sees only a cached version, which may be out of sync).
  • Since defaults read cannot return an individual key's value, the value of interest must be extracted via egrep and sed - one caveat there is that defaults read conditionally uses double quotes around key names and string values, depending on whether they are a single word (without punctuation) or not.

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
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • Shell one-liner (needs ripgrep installed): `defaults read ~/Library/Preferences/com.apple.HIToolbox.plist AppleSelectedInputSources | command rg -e '"KeyboardLayout Name" = "([^"]*)"' --replace '$1' --only-matching --color never` – HappyFace Oct 07 '20 at 15:54
  • Thanks, @HappyFace, but a shell one-liner is already part of the answer (below the first code snippet), and it uses standard utilities (not everyone has `rg`). – mklement0 Oct 07 '20 at 15:56
12

Recently I had written a small console utility (https://github.com/myshov/xkbswitch-macosx) on Objective-C to do this. It's a lot faster than a script based solutions. It can to get the current input layout but also it can to set the given input layout.

To get a current layout:

$xkbswitch -ge
> US

To set a given layout:

$xkbswith -se Russian
Alexander Myshov
  • 2,881
  • 2
  • 20
  • 31
  • Why there was a `% ` at the end of the output when `xkbswitch -ge` executed, i.e, `US%`. `env.: Apple Chip M1Pro OSX 12.0.` – Jerry Oct 07 '22 at 14:33
7

I am not sure of this answer, but it may be worth checking out. If you look in file:

/Library/Preferences/com.apple.HIToolbox.plist

there is a variable called

AppleCurrentKeyboardLayoutSourceID

and mine is set to "British" and I am in Britain...

You can read the file in a script with:

defaults read /Library/Preferences/com.apple.HIToolbox.plist  AppleEnabledInputSources

sample output below:

(
    {
    InputSourceKind = "Keyboard Layout";
    "KeyboardLayout ID" = 2;
    "KeyboardLayout Name" = British;
}
)

So, I guess your question can be simply answered using this:

#!/bin/bash
defaults read /Library/Preferences/com.apple.HIToolbox.plist  AppleEnabledInputSources | grep -sq Swedish
[[ $? -eq 0 ]] && echo Swedish
Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • 1
    +1 for sleuthing. Since `default read` can apparently only target _top-level_ keys, here's an alternative using `PlistBuddy` that specifically extracts the value of the "KeyboardLayout Name" key: `/usr/libexec/PlistBuddy -c 'print "AppleSelectedInputSources:0:KeyboardLayout Name"' /Library/Preferences/com.apple.HIToolbox.plist` – mklement0 Feb 06 '14 at 15:13
  • Oh, excellent, thank you! Mine includes `"KeyboardLayout Name" = "Swedish - Pro";` Though if I change the keyboard layout, the `defaults read` command keeps saying "Swedish - Pro". The file contents also appear unchanged. So I guess it's sadly not updated immediately. – Henrik N Feb 06 '14 at 17:38
  • Maybe try "kullall finder" to restart the GUI and see if that updates the file... – Mark Setchell Feb 06 '14 at 18:17
  • If this answers your question, could you accept it so I get a lovely big green tick please? If not, please say what is still missing so that I, and cleverer people than me, can assist you further! – Mark Setchell Feb 06 '14 at 18:52
  • 3
    @MarkSetchell, @HenrikN: The answer lies in (a) targeting the _user-level_ plist file: `~/Library/Preferences/com.apple.HIToolbox.plist` - not the initial `~` - and (b) targeting the `AppleSelectedInputSources` key (instead of `AppleEnabledInputSources`). To put it all together: `defaults read ~/Library/Preferences/com.apple.HIToolbox.plist AppleSelectedInputSources | egrep -w 'KeyboardLayout Name' | sed -E 's/.+ = "?([^"]+)"?;/\1/'`. Note: The reason I used `defaults read` after all is that it - unlike `PlistBuddy` - ensures that the _current_ value is read. – mklement0 Feb 06 '14 at 20:26
  • (cont'd) The `sed` gymnastics are required, because `defaults read` only _sometimes_ uses double quotes, namely only when the value happens need it (when it's not a single word without punctuation). – mklement0 Feb 06 '14 at 20:28
  • Mark, I set @mklement0's answer as the accepted one because it summarizes things most clearly and has something runnable at the top that seems to work and be up to date for me. But you came up with the basic idea – thank you so much! – Henrik N Feb 08 '14 at 09:41
  • No problems. Thank you for saying. Glad it worked out for you :-) – Mark Setchell Feb 08 '14 at 09:53
  • @MarkSetchell: Thanks for being OK with it, and thanks for helping me a learn a few things. – mklement0 Feb 08 '14 at 16:22
  • @MarkSetchell, why can't we use AppleCurrentKeyboardLayoutSourceID variable to read the keyboard layout value? – sarabdeep singh Sep 26 '16 at 19:23
5

This question led to the creation of the keyboardSwitcher CLI Tool: https://github.com/Lutzifer/keyboardSwitcher

Though similar to the already mentioned https://github.com/myshov/xkbswitch-macosx this has additional features, e.g. the list of Layouts is not hardcoded and thus can also support third party layouts (e.g. Logitech) and supports installation via homebrew.

Lutzifer
  • 755
  • 1
  • 6
  • 11
2

Figured out how to do it with AppleScript, assuming you have the menu bar input menu.

Run this in a terminal:

osascript -e 'tell application "System Events" to tell process "SystemUIServer" to get the value of the first menu bar item of menu bar 1 whose description is "text input"'

Works fine even if you only show the input menu as flag icons, without the input source name.

Mavericks will probably prompt you to allow access, the first time. In earlier versions of OS X I suspect you'll need to turn on support for assistive devices in your accessibility preferences.

techraf
  • 64,883
  • 27
  • 193
  • 198
Henrik N
  • 15,786
  • 5
  • 82
  • 131
  • 1
    I get the error `73:157: execution error: System Events got an error: osascript is not allowed assistive access. (-1719)` – Alex Jul 27 '17 at 17:26
  • @Alex I believe this is due to the thing described in the last paragraph of the answer. It might be more complicated in newer versions of macOS, though. Maybe if you google the error message? That turned up this, for example: http://techqa.info/programming/question/21913504/Accessibility-settings-for-non-GUI-apps-using-AppleScript-in-OSX-Mavericks- Let us know what you find. – Henrik N Jul 31 '17 at 12:09
0

I was searching for an answer to an issue I was having with the keyboard layout that lead me to this post. I found the solution for my problem here.

Resolved Issues You might experience difficulty logging into your account because the keyboard layout may change unexpectedly at the Login window. (40821875)

Workaround: Log in to your account, launch Terminal, and execute the following command:

sudo rm -rf /var/db/securityagent/Library/Preferences/com.apple.HIToolbox.plist

This is an Apple official release note for Mojave

rickrvo
  • 543
  • 3
  • 17