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" <cocoaha...@googlemail.com > 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 (Cocoa-dev@lists.apple.com)

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:
http://lists.apple.com/mailman/options/cocoa-dev/cocoaharry%40googlemail.com

This email sent to cocoaha...@googlemail.com





_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to