Hello
I have confirmed the odd behaviour under 10.5.8. It seems to me the required accessibility is defective under 10.5.8. The GUI scripting code works fine under 10.6.8 but the row index of the enabled input source will change to some smaller number when you reopen the System Preferences.app.
Anyway, I've written a simple command line utility in C, which lets you manipulate the text input source. Here's the recipe for you.
# Recipe.
A) To compile and test the C programme.
A1) Copy the code listed below as main.c into new document of text editor (e.g. TextEdit) and save it as plain text named "main.c" on desktop.
A2) In Terminal.app, run the following (type each line followed by return) to create an executable file named "textinputsource" on desktop:
cd ~/Desktop
gcc -framework Carbon -o textinputsource main.c
A3) In Terminal.app, type the following and return to toggle the enabled/disabled state of the specified input source:
./textinputsource -t 'Greek Polytonic'
B) To create an AppleScript wrapper to call this utility.
B1) Create a new AppleScript script with the following contents and save it as a script bundle or an application bundle:
set p to (path to resource "textinputsource")'s POSIX path
do shell script p's quoted form & " -t 'Greek Polytonic'"
B2) Show package contents (via contextual menu) of the saved bundle and put the executable file "textinputsource" loose in its Contents/Resources directory. Now you can run the script bundle or the application bundle to toggle the input source.
# Notes.
• The utility programme has some other options. E.g., you can select the specified source by -s option. See comments in source code for details.
• You need to have Developer Tools installed to build the programme.
• Tested under 10.5.8 and 10.6.8 but no warranties of any kind.
• I noticed that System Preferences.app won't update the check box live when the enabled/disabled state is changed by this utility. You'd need to rerun the System Preferences to reflect the change in its GUI.
• This is freeware you may use and modify as you like. 🙂
# File
main.c
-----------------------------------------------------------
/*
file
main.c
function
to manipulate text input source, i.e.,
- print currently selected source,
- select specified source (enable it as needed)
- enable specified source,
- disable specified source,
- toggle enabled/disabled state of specified source.
compile
gcc -framework Carbon -o textinputsource main.c
usage e.g.
./textinputsource [-s|e|d|t name]
given no arguments, it will print the current source name.
options:
-s : select source name (enable it as needed)
-e : enable source name
-d : disable source name
-t : toggle enabled/disabled on source name
*/
#include <Carbon/Carbon.h>
#include <libgen.h> // basename
TISInputSourceRef getInputSourceByName(char *);
int
main (int argc, char * argv[])
{
int ret = -1;
int c;
TISInputSourceRef tis;
CFStringRef name;
OSStatus err = 0;
while ((c = getopt(argc, argv, "s:e:d:t:h")) != -1)
{
switch (c)
{
case 's':
tis = getInputSourceByName(optarg);
if (tis)
{
CFBooleanRef enabled = TISGetInputSourceProperty(tis, kTISPropertyInputSourceIsEnabled);
if (enabled == kCFBooleanFalse)
TISEnableInputSource(tis);
err = TISSelectInputSource(tis);
CFRelease(tis);
}
ret = tis ? (int) err : 1;
break;
case 'e':
tis = getInputSourceByName(optarg);
if (tis)
{
err = TISEnableInputSource(tis);
CFRelease(tis);
}
ret = tis ? (int) err : 1;
break;
case 'd':
tis = getInputSourceByName(optarg);
if (tis)
{
err = TISDisableInputSource(tis);
CFRelease(tis);
}
ret = tis ? (int) err : 1;
break;
case 't':
tis = getInputSourceByName(optarg);
if (tis)
{
CFBooleanRef enabled = TISGetInputSourceProperty(tis, kTISPropertyInputSourceIsEnabled);
if (enabled == kCFBooleanTrue)
err = TISDisableInputSource(tis);
else
err = TISEnableInputSource(tis);
CFRelease(tis);
}
ret = tis ? (int) err : 1;
break;
case 'h':
case '?':
default:
fprintf(stderr, "Usage: %s %s\n\t\%s\n\t%s\n\t%s\n\t%s\n\t%s\n",
basename(argv[0]),
"[-s|e|d|t name]",
"-s : select source name (enable it as needed)",
"-e : enable source name",
"-d : disable source name",
"-t : toggle enabled/disabled of source name",
"no arguments : print current source name"
);
ret = 1;
break;
}
}
if (ret == -1) // no args: print current keyboard input source
{
tis = TISCopyCurrentKeyboardInputSource();
name = TISGetInputSourceProperty(tis, kTISPropertyLocalizedName);
int len = CFStringGetLength(name) * 4 + 1;
char cname[len];
bool b = CFStringGetCString(name, cname, len, kCFStringEncodingUTF8);
printf("%s\n", b ? cname : "");
ret = b ? 0 : 1;
}
if (err != noErr)
fprintf(stderr, "Text Input Source Services error: %d\n", (int) err);
return ret;
}
TISInputSourceRef
getInputSourceByName(char *cname)
{
// char *cname : input source name in UTF-8 terminated by null character
// return TISInputSourceRef or NULL : text input source reference (retained)
CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, cname, kCFStringEncodingUTF8);
CFStringRef keys[] = { kTISPropertyLocalizedName };
CFStringRef values[] = { name };
CFDictionaryRef dict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 1, NULL, NULL);
CFArrayRef array = TISCreateInputSourceList(dict, true);
CFRelease(dict);
CFRelease(name);
if (!array)
{
fprintf(stderr, "No such text input source: %s\n", optarg);
return NULL;
}
TISInputSourceRef tis = (TISInputSourceRef) CFArrayGetValueAtIndex(array, 0);
CFRetain(tis);
CFRelease(array);
return tis;
}
-----------------------------------------------------------
Hope this may help,
H