Detecting keyboard layout through AS ObjC interface?

Short of defaults read on com.apple.HIToolbox.plist, what seems the best way to detect active keyboard layout from AppleScript ?

Is there some analogy of this JavaScript for Automation snippet ?

(() => {

    ObjC.import('Carbon');
    ObjC.bindFunction('CFMakeCollectable', ['id', ['void *']]);

    return ObjC.unwrap(
        $.CFMakeCollectable(
            $.TISGetInputSourceProperty(
                $.TISCopyCurrentKeyboardInputSource(),
                $.kTISPropertyInputSourceID
            )
        )
    );

})();

Do you mean something like this:

I changed the variable name from “InputContext” to “CurrentTextInput” because the new name is more descriptive (Bill Kopp 2/16/2018).

use framework "Foundation"

set CurrentTextInput to current application's NSTextInputContext's currentInputContext() --> <NSTextInputContext: 0x6000012b92c0>
class of CurrentTextInput --> (Class) NSTextInputContext

set KeyboardInputSource to CurrentTextInput's selectedKeyboardInputSource() --> (NSString) "com.apple.keylayout.US"
set KeyboardInputSourceName to KeyboardInputSource as text --> "com.apple.keylayout.US"
set LocalizedKeyboardInputSourceName to (current application's NSTextInputContext's localizedNameForInputSource:KeyboardInputSource) as text --> "U.S."

set TheResult to "Keyboard input source name: " & KeyboardInputSourceName & return & "Localized keyboard inputSource name: " & LocalizedKeyboardInputSourceName

The script outputs:

Keyboard input source name: com.apple.keylayout.US
Localized keyboard inputSource name: U.S.

If I change to the British keyboard it outputs:

Keyboard input source name: com.apple.keylayout.British
Localized keyboard inputSource name: British

2 Likes

That’s good – thank you !

(and in addition to an AS function (lower down) it also suggests an improvement to the JS for Automation version, which wasn’t obtaining a localised name)

Updated JS

(() => {

    ObjC.import('Carbon');
    ObjC.bindFunction('CFMakeCollectable', ['id', ['void *']]);

    // keyboardLayout :: IO () -> {source :: String, localName :: String}
    const keyboardLayout = () => {
        const source = $.TISCopyCurrentKeyboardInputSource();
        return [
                ['source', $.kTISPropertyInputSourceID],
                ['localized', $.kTISPropertyLocalizedName]
            ]
            .reduce((a, [k, p]) => Object.assign(a, {
                [k]: ObjC.unwrap($.CFMakeCollectable(
                    $.TISGetInputSourceProperty(source, p)
                ))
            }), {});
    };

    return keyboardLayout();
})();

An Applescript wrapping

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

-- keyboardLayout :: IO () -> {source :: String, localName :: String}
on keyboardLayout()
    set context to current application's NSTextInputContext
    set source to (context's currentInputContext())'s ¬
        selectedKeyboardInputSource()
    {source:source as text, localName:¬
        (context's localizedNameForInputSource:source) as text}
end keyboardLayout

keyboardLayout()