Re: Detect Keyboard Layout for CGKeyCodes
Re: Detect Keyboard Layout for CGKeyCodes
- Subject: Re: Detect Keyboard Layout for CGKeyCodes
- From: Joe Turner <email@hidden>
- Date: Thu, 20 Aug 2009 15:33:08 -0500
Hey,
Thanks for the tip. I started writing my own method, but then when
searching for how to get the data from the UCKeyboardLayout, I found
some code that I modified to work perfectly. I will share it here for
those that need it.
- (CGKeyCode)keyCodeForKeyboard:(const UCKeyboardLayout *)uchrHeader
character:(NSString *)character {
if ([character isEqualToString:@"RETURN"]) return kVK_Return;
if ([character isEqualToString:@"TAB"]) return kVK_Tab;
if ([character isEqualToString:@"SPACE"]) return kVK_Space;
if ([character isEqualToString:@"DELETE"]) return kVK_Delete;
if ([character isEqualToString:@"ESCAPE"]) return kVK_Escape;
if ([character isEqualToString:@"F5"]) return kVK_F5;
if ([character isEqualToString:@"F6"]) return kVK_F6;
if ([character isEqualToString:@"F7"]) return kVK_F7;
if ([character isEqualToString:@"F3"]) return kVK_F3;
if ([character isEqualToString:@"F8"]) return kVK_F8;
if ([character isEqualToString:@"F9"]) return kVK_F9;
if ([character isEqualToString:@"F11"]) return kVK_F11;
if ([character isEqualToString:@"F13"]) return kVK_F13;
if ([character isEqualToString:@"F16"]) return kVK_F16;
if ([character isEqualToString:@"F14"]) return kVK_F14;
if ([character isEqualToString:@"F10"]) return kVK_F10;
if ([character isEqualToString:@"F12"]) return kVK_F12;
if ([character isEqualToString:@"F15"]) return kVK_F15;
if ([character isEqualToString:@"HELP"]) return kVK_Help;
if ([character isEqualToString:@"HOME"]) return kVK_Home;
if ([character isEqualToString:@"PAGE UP"]) return kVK_PageUp;
if ([character isEqualToString:@"FORWARD DELETE"]) return
kVK_ForwardDelete;
if ([character isEqualToString:@"F4"]) return kVK_F4;
if ([character isEqualToString:@"END"]) return kVK_End;
if ([character isEqualToString:@"F2"]) return kVK_F2;
if ([character isEqualToString:@"PAGE DOWN"]) return kVK_PageDown;
if ([character isEqualToString:@"F1"]) return kVK_F1;
if ([character isEqualToString:@"LEFT"]) return kVK_LeftArrow;
if ([character isEqualToString:@"RIGHT"]) return kVK_RightArrow;
if ([character isEqualToString:@"DOWN"]) return kVK_DownArrow;
if ([character isEqualToString:@"UP"]) return kVK_UpArrow;
UTF16Char theCharacter = [character characterAtIndex:0];
long i, j, k;
unsigned char *uchrData = (unsigned char *)uchrHeader;
UCKeyboardTypeHeader *uchrTable = uchrHeader->keyboardTypeList;
Boolean found = false;
UInt16 virtualKeyCode;
for (i = 0; i < (uchrHeader->keyboardTypeCount) && !found; i++) {
UCKeyToCharTableIndex *uchrKeyIX;
UCKeyStateRecordsIndex *stateRecordsIndex;
if (uchrTable[i].keyStateRecordsIndexOffset != 0 ) {
stateRecordsIndex = (UCKeyStateRecordsIndex *) (((unsigned char*)
uchrData) + (uchrTable[i].keyStateRecordsIndexOffset));
if ((stateRecordsIndex->keyStateRecordsIndexFormat) !=
kUCKeyStateRecordsIndexFormat) {
stateRecordsIndex = NULL;
}
} else {
stateRecordsIndex = NULL;
}
uchrKeyIX = (UCKeyToCharTableIndex *)(((unsigned char *)uchrData) +
(uchrTable[i].keyToCharTableIndexOffset));
if (kUCKeyToCharTableIndexFormat == (uchrKeyIX-
>keyToCharTableIndexFormat)) {
for (j = 0; j < (uchrKeyIX->keyToCharTableCount) && !found; j++) {
UCKeyOutput *keyToCharData = (UCKeyOutput *) ( ((unsigned char*)
uchrData) + (uchrKeyIX->keyToCharTableOffsets[j]) );
for (k = 0; k < (uchrKeyIX->keyToCharTableSize) && !found; k++) {
if (((keyToCharData[k]) & kUCKeyOutputTestForIndexMask) ==
kUCKeyOutputStateIndexMask) {
long theIndex = (kUCKeyOutputGetIndexMask & keyToCharData[k]);
if (stateRecordsIndex != NULL && theIndex <= stateRecordsIndex-
>keyStateRecordCount) {
UCKeyStateRecord *theStateRecord = (UCKeyStateRecord *)
(((unsigned char *) uchrData) + (stateRecordsIndex-
>keyStateRecordOffsets[theIndex]));
if ((theStateRecord->stateZeroCharData) == theCharacter) {
virtualKeyCode = k;
found = true;
}
} else {
if ((keyToCharData[k]) == theCharacter) {
virtualKeyCode = k;
found = true;
}
}
} else if (((keyToCharData[k]) & kUCKeyOutputTestForIndexMask) ==
kUCKeyOutputSequenceIndexMask) {
} else if ( (keyToCharData[k]) == 0xFFFE || (keyToCharData[k])
== 0xFFFF ) {
} else {
if ((keyToCharData[k]) == theCharacter) {
virtualKeyCode = k;
found = true;
}
}
}
}
}
}
return (CGKeyCode)virtualKeyCode;
}
Cheers,
Joe Turner
On Aug 20, 2009, at 4:47 AM, Harry Jordan wrote:
Hi Joe,
Sorry to misunderstand your intentions. I had an inkling I might be
reading your question wrong. I'm intrigued now as to how you might
do it. This low level c code makes my head spin, but if I read the
docs correctly it should be possible to decode the keyCodes to
Unicode character tables from UCKeyboardLayout.
First get the current UCKeyboardLayout:
TISInputSourceRef currentKeyboard =
TISCopyCurrentKeyboardInputSource();
CFDataRef uchr =
(CFDataRef)TISGetInputSourceProperty(currentKeyboard,
kTISPropertyUnicodeKeyLayoutData);
const UCKeyboardLayout *keyboardLayout = (const
UCKeyboardLayout*)CFDataGetBytePtr(uchr);
Then use a combination of the "Unicode Utilities Reference", and the
"Specification for 'uchr'" pages in the documentation to work out
how to read the current layout as a series of structs which
reference each other by telling you the pointer offset from
*keyboardLayout.
I think the tree of structs that you'd need to follow looks
something like this:
UCKeyboardLayout > array of UCKeyboardTypeHeader > array of
UCKeyToCharTableIndex > array of UCKeyOutput
Although I couldn't find an explicit reference to this in the
documentation, I think the position in the array of each UCKeyOutput
is equivalent to it's keyCode. Then you need to read UCKeyOutput's
bytes (14 and 15) to find out how to decode it's Unicode character.
Hope that's more what you were looking for. Sorry I can't seem to
find a friendlier solution.
Harry
On 20 Awst 2009, at 03:02, Joe Turner wrote:
Hey,
This is not *exactly* what I would like to achieve. Basically, what
I would like to do is the reverse: I would like to convert a string
into a CGKeyCode. Like on a US keyboard, I would input the string
"a" and get returned the CGKeyCode 0. This would be extremely
straight-forward (just a matter of including Events.h from
HIUtilites), except that all the constants only stand true for US
keyboards. So, I would like to be able to convert based on the
keyboard they have, so the right key gets a simulation of a click.
Or, maybe there's a better way to do this than CGEvents? I just
need it to be universal–This app is a background app, so the
keystroke needs to be able to be inserted anywhere.
Cheers,
Joe Turner
On Wednesday, August 19, 2009, at 07:30PM, "Harry Jordan" <email@hidden
> wrote:
I've not used CGEvents much.. (Once upon a time, hopefully never
again) but if I remember rightly CGKeyCodes are equivalent to
NSEvent
keyCodes*. If not you can easily convert between the two using: +
(NSEvent *)eventWithCGEvent:(CGEventRef)cgEvent.
Have a look at this: http://inquisitivecocoa.com/2009/04/05/key-code-translator/
for my version of what I think your trying to achieve. Be warned,
there are a few gaps in my implementation (like F numbers for
instance), but that shouldn't be that hard to add.
Harry Jordan
http://inquisitivesoftware.com/
On 19 Awst 2009, at 18:40, Joe Turner wrote:
Hey,
I've got an application that basically simulates a keyboard using
CGEvents with CGKeyCodes. However, because CGKeyCodes only map the
position of the key on a keyboard, and not the actual key, I've run
into some issues. Is there an easy way to detect the type of
keyboard they have, and convert a CGKeyCode from a standard US
keyboard to whatever keyboard they have?
Any help would be much appreciated! :)
Joe
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the
list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden