Login

Changing Keyboard Input - Command Line Utility

If you have the need to programmatically change between languages on the Macintosh, this may be what you are looking for. This code kindly provided by Stefan Klieme


There are two examples. One is an AppleScript example and the other is a command line tool. The command line tool is very useful and easy to use. Example Tool Usage

 

changeInput                           //prints current input language 

changeInput name //changes input language to name

changeInput toggle name1 name2 //toggles input language between name1 and name2

AppleScript Example

changeInputLanguage("Hebrew")
changeInputLanguage("U.S.")

on changeInputLanguage(L)
 tell application "System Events" to tell process "SystemUIServer"
 tell (1st menu bar item of menu bar 1 whose value of attribute "AXDescription" is "text input")
 return {its value, click, click menu 1's menu item L}
 end tell
 end tell
end changeInputLanguage


Download a Pre-compiled Version icon ChangeInput (3.86 kB)

Instructions for Compiling Yourself Make a folder on your desktop and name it 'input' Create a text file with with the code below and save it in this folder. Name it 'changeInput.m' Be sure to make this file "plain text." Do not use Word or the Rich Text format in TextEdit. It might be wise to download the free TextWranger for this purpose.

Open up the Terminal from /Applications/Utilities/Terminal.app and type the following ALL ON ONE LINE.

name=~/desktop/input/changeInput; gcc "$name".m -o "$name" -l objc
-framework foundation -framework carbon</pre>


What the above code does:

This sets a variable named "name" to a full path -> "/Users/USER_NAME/Desktop/input/changeInput"


This keeps us from typing the path twice in the code.

It ends in a semi-colon to inform the terminal that this is the end of one statement and it can move on to the next statement.

name=~/desktop/input/changeInput;


gcc is the GNU Objective-C compiler we are using to compile this code.


"$name".m is the variable name, which contains the path as shown above with the ".m" appending to the end. This gives us a full path to the "inputChange.m" file in the input folder.


-o is the output option and it specifies the full path to where you want this executable to be created. Here we are using the variable "$name" which is the same name as the ".m" file without the extension.

gcc "$name".m -o "$name"


-l objc is telling the compiler to link this code with the Objective-C runtime library called objc.

-l objc


This is linking each framework included in this code. If we had other frameworks, we would add then in the same way.

-framework foundation -framework carbon



#import <Foundation/Foundation.h>
#import <Carbon/Carbon.h>
/*###############################################################################
#                                                                                #
#     changeInput                                                                #
#                                                                                #
#     author:   Stefan Klieme (based on an idea by Craig Williams)                #
#     created:  2009-11-05                                                        #
#       Changes input language                                                    #
#     Usage:    changeInput                        prints current input language    #
#                changeInput    name                changes input language to name    #
#                changeInput    toggle name1 name2    toggles input language between    #
#                                                name1 and name2                    #
#                                                                                #
#################################################################################
#                                                                                #
#     This program is free software: you can redistribute it and/or modify        #
#     it under the terms of the GNU General Public License as published by        #
#     the Free Software Foundation, either version 3 of the License, or            #
#     (at your option) any later version.                                        #
#                                                                                #
#     This program is distributed in the hope that it will be useful,            #
#     but WITHOUT ANY WARRANTY; without even the implied warranty of            #
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                #
#     GNU General Public License for more details.                                #
#                                                                                #
#     You should have received a copy of the GNU General Public License            #
#     along with this program.  If not, see <http://www.gnu.org/licenses/>.        #
#                                                                                #
################################################################################*/
 
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
    NSArray *args = [[NSProcessInfo processInfo] arguments];
    TISInputSourceRef current = TISCopyCurrentKeyboardLayoutInputSource();
    NSString *currentName = (NSString *)TISGetInputSourceProperty(current, kTISPropertyLocalizedName);
    if (argc == 1) {
        printf("%s\n", [currentName UTF8String]);
    }
    else {
        NSString *chosenInput, *language1, *language2;
        NSArray  *inputArray = (NSArray *)TISCreateInputSourceList ( NULL, false);
        NSMutableDictionary *availableLanguages = [NSMutableDictionary dictionaryWithCapacity:[inputArray count]];
        NSUInteger i;
        TISInputSourceRef chosen, languageRef1, languageRef2;
        for (i = 0; i < [inputArray count]; ++i) {
            [availableLanguages setObject:[inputArray objectAtIndex:i] forKey:TISGetInputSourceProperty((TISInputSourceRef)[inputArray objectAtIndex:i], kTISPropertyLocalizedName)];
        }
        [inputArray release];
        
        if (argc == 4 && [[args objectAtIndex:1] isEqualTo:@"toggle"]) {
            language1 = [args objectAtIndex:2];
            language2 = [args objectAtIndex:3];
            languageRef1 = (TISInputSourceRef)[availableLanguages objectForKey:language1];
            languageRef2 = (TISInputSourceRef)[availableLanguages objectForKey:language2];
            if (languageRef1 != nil && languageRef2 != nil) {
                chosenInput = ([language1 isEqualTo:currentName]) ? language2 : language1; 
                chosen = (TISInputSourceRef)[availableLanguages objectForKey:chosenInput];
            }
            else {
                chosenInput = (languageRef1 == nil) ? language1 : language2;
                chosen = nil;
            }
        }
        else {
            chosenInput = [args objectAtIndex:1];
            chosen = (TISInputSourceRef)[availableLanguages objectForKey:chosenInput];
        }
        if (chosen) {
            OSStatus err = TISSelectInputSource (chosen);
            if (err)
                printf("Could not change input language (error %i)\n", (int)err);
            else
                printf("Changed input language to %s\n", [chosenInput UTF8String]);
        } 
        else {
            printf("%s not available\n", [chosenInput UTF8String]);
        }
    }
    CFRelease(current);
    [pool release];
    return 0;
}

Comments  

 
+2 # 2010-10-01 04:32
Thanks, this really helped me out! I use a Japanese macbook with a customized US-style keyboard layout. OSX likes to switch to the builtin layouts at inopportune times, and your script gave me an easy way to swap to my layout without having to scroll through the list of input methods.

Note that for my environment I had to use

TISCopyCurrentK eyboardInputSou rce

instead of

TISCopyCurrentK eyboardLayoutIn putSource

Thanks again!
Reply | Reply with quote | Quote
 
 
0 # 2012-05-18 14:16
This is super-helpful: I compiled it today to support automatic environment switching in a pair-programming shop. Now I can use Dvorak without too much pair-partner conflict :). (I didn't need the previous commenter's change, btw.)
Reply | Reply with quote | Quote
 
 
0 # 2012-10-17 10:19
Thank you for this! I used it in conjunction with Keyboard Maestro to workaround an issue with SublimeText2 where text wrapping would fail using the "U.S. International - PC" input source.
Reply | Reply with quote | Quote
 

Add comment


Security code
Refresh

 

Product Categories