4

I use different keyboard layouts and switched between them using a simple script

on changeKeyboardLayout(layoutName)
    tell application "System Events" to tell process "SystemUIServer"
        tell (1st menu bar item of menu bar 1 whose description is "text input") to {click, click (menu 1's menu item layoutName)}
    end tell
end changeKeyboardLayout
changeKeyboardLayout("German LaTeX2")

That worked well until the latest update. I don't really speak AppleScript, but a bit of testing indicates that SystemUIServer no longer has access to a menu item with name "text input". Trying

tell application "System Events" to tell process "SystemUIServer" to get value of attribute "AXDescription" of every menu bar item of menu bar 1

gives me Siri, blutooth, time machine, clock and a few others. So somehow the input source menu is managed differently now, but I have now clue how or how to find out (all searches pointed me to scripts similar to mine)

Update 2019/12/10

The suggested solutions so far both have defects, in one case you always get a delay of 5 seconds which is rather long and the trick with killing "System Events" as taken from the other posting doesn't always seem to work, sometimes it results in the script getting a timeout (which is even worse then have the 5 seconds delay all the time), so it looks as if this is still in need for a better solution

2

Unfortunately things have changed in macOS Catalina and you''ll have to activate that menu in a different manner.

The following example AppleScript code, shown further below, works for me in macOS Catalina, however as I was testing in a virtual machine I do not know if the time lag in the running of the code, between clicking the target menu and the subsequent code, is inherent of an issue in the virtual machine or it will be the same on a physical machine.

I do not have German LaTeX2 so I used German instead, although for convenience I have replaced it in the code after testing.

The usual caveats apply for the use of this in: System Preferences > Security & Privacy > Privacy > Accessibility

Example AppleScript code:

tell application "System Events" to ¬
    tell application process "TextInputMenuAgent" to ¬
        tell menu bar item 1 of menu bar 2
            click
            click menu item "German LaTeX2" of menu 1
        end tell

This does the same thing in a different manner, and one of these ways may be faster.

tell application "System Events" to ¬
    tell application process "TextInputMenuAgent" to ¬
        click menu bar item 1 of menu bar 2

tell application "System Events"
    keystroke "g"
    key code 36
end tell

To use the example AppleScript code in a handler:

changeKeyboardLayout("German LaTeX2")

on changeKeyboardLayout(layoutName)
    tell application "System Events" to ¬
        tell application process "TextInputMenuAgent" to ¬
            tell menu bar item 1 of menu bar 2
                click
                click menu item layoutName of menu 1
            end tell
end changeKeyboardLayout

Or the second version of the code:

changeKeyboardLayout("German LaTeX2")

on changeKeyboardLayout(layoutName)
    tell application "System Events" to ¬
        tell application process "TextInputMenuAgent" to ¬
            click menu bar item 1 of menu bar 2
    tell application "System Events"
        keystroke (first text item of layoutName)
        key code 36
    end tell
end changeKeyboardLayout

Note: The example AppleScript code is just that and does not contain any error handling as may be appropriate. The onus is upon the user to add any error handling as may be appropriate, needed or wanted. Have a look at the try statement and error statement in the AppleScript Language Guide. See also, Working with Errors.

| improve this answer | |
  • thanks. the first version works for me, the second doesn't work for me as I have several items in the list starting with "g". The delay happens on a physical machine too. and it is long (5 seconds?) But I found this answer here apple.stackexchange.com/a/92386 which helps if I combine it with yours ie then it works without hanging. – Frank Mittelbach Dec 7 '19 at 8:43
  • 1
    @Frank Mittelbach, While at the moment I do not have a need for this, as all the current scripts I use are not prone to this bug, nonetheless, I've saved a copy of the linked web page for future reference it needed. BTW It made it near instantaneous in the virtual machine too. Thanks! – user3439894 Dec 7 '19 at 13:25
3

For the record, combing the answer how to get to the input source menu in Catalina with an answer that deals with the bug (?) generating a delay give a version that work as nicely as the old one did:

on changeKeyboardLayout(layoutName)
    launch application "System Events"
    delay 0.2
    ignoring application responses
        tell application "System Events" to tell process "TextInputMenuAgent"
            click menu bar item 1 of menu bar 2
        end tell
    end ignoring
    do shell script "killall System\\ Events"
    delay 0.1
    tell application "System Events" to tell process "TextInputMenuAgent"
        tell menu bar item 1 of menu bar 2
            click menu item layoutName of menu 1
        end tell
    end tell
end changeKeyboardLayout

changeKeyboardLayout("German LaTeX2")

Update 2019/12/10

The trick with killing "System Events" as taken from the other posting doesn't always seem to work, sometimes it results in the script getting a timeout (which is even worse then have the 5 seconds delay all the time), so it looks as if the solution to my question is still somewhat open

| improve this answer | |
1

I wrote this script a while ago that uses a carbon API to change the keyboard input source through low-level system calls, which would ordinarily be ideal and obviously preferable to manipulating the UI. That said, it is a couple of years old, and so I couldn't say whether or not it will still be viable in Catalina, not least because carbon is being (or is) deprecated, but the script is written in JavaScript for Automation, which, like AppleScript, is basically falling to bits.

But, I'll post it anyway, just in case it does have value in the newer OS setting:

ObjC.import('Carbon');

nil = $();

unwrap = ObjC.deepUnwrap.bind(ObjC);
bind = ObjC.bindFunction.bind(ObjC);
bind('CFMakeCollectable', [ 'id', [ 'void *' ] ]);
Ref.prototype.nsObject = function() {
    return unwrap($.CFMakeCollectable(this));
}


function run() {
    const lang = 'German';

    const currentSource = $.TISCopyCurrentKeyboardInputSource();
    const sources   = unwrap($.TISCreateInputSourceList(nil, false)),
          sourceIDs = sources.map(src => $.TISGetInputSourceProperty(
                                      src,'TISPropertyInputSourceID')
                             .nsObject()),
          sourceID  = sourceIDs.filter(src=>src.indexOf(lang)!==-1)[0],
          source    = unwrap($.TISCreateInputSourceList(
                            { 'TISPropertyInputSourceID' : sourceID },
                      false))[0];
    const status    = $.TISSelectInputSource(source);
    return (status==0);
}
| improve this answer | |
  • It crashes Script Editor set to JavaScript on macOS Catalina 10.15.1, without changing the input language. – user3439894 Dec 7 '19 at 22:30
  • @user3439894 That's a shame, but not at all surprising. The JavaScriptOSA core has simply been left to decay, although it's the objective-C bridge that's crumbling I think, as the crashes started in Mojave whenever the OSA engine was trying to bridge to/from C-style references. I've written it in Swift too, which I have somewhere, unless I left it on my MacBook before it went in for repair. – CJK Dec 7 '19 at 23:05
1

I have found an alternative solution that guarantees no delay, using the system-wide keyboard shortcut ^F8 (predefined in "System Preferences > Keyboard > Shortcuts > Keyboard > Move focus to status menus")

combined with the desired amount of down-arrow key-strokes and a Return, works like a charm

I wish the above looks like AppleScript for you, the fact is I still can't write the simplest AppleScript after years of using it.

So I defined the above series of key-strokes in BetterTouchTool, it does the job :)

BetterTouchTool ScreenShot

| improve this answer | |

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .