I need a function that, given a character, returns the CGKeyCode
associated with the position of that character on the current keyboard layout. E.g., given "b", it should return kVK_ANSI_B
if using U.S. QWERTY, or kVK_ANSI_N
if using Dvorak.
我需要一个函数,给定一个字符,返回与当前键盘布局上该字符的位置相关联的CGKeyCode。例如,给定“b”,如果使用美国QWERTY则应返回kVK_ANSI_B,如果使用Dvorak则应返回kVK_ANSI_N。
The Win32 API has the function VkKeyScan()
for this purpose; X11 has the function XStringToKeySym()
. Is there such a function in the CG API?
Win32 API具有用于此目的的函数VkKeyScan(); X11具有XStringToKeySym()函数。 CG API中有这样的功能吗?
I need this in order to pass a parameter to CGEventCreateKeyboardEvent()
. I've tried using CGEventKeyboardSetUnicodeString()
instead, but that apparently does not support modifier flags (which I need).
我需要这个以便将参数传递给CGEventCreateKeyboardEvent()。我尝试使用CGEventKeyboardSetUnicodeString(),但显然不支持修饰符标志(我需要)。
I have searched extensively for this but cannot find a decent answer. Currently I am using the following code (found online), which works, but is not exactly elegant (and rather difficult to decipher how to simplify) and I would prefer not to use it in production code:
我已经广泛搜索了这个但是找不到合适的答案。目前我正在使用以下代码(在线发现),它有效,但并不完全优雅(而且很难解释如何简化),我宁愿不在生产代码中使用它:
#include <stdint.h>
#include <stdio.h>
#include <ApplicationServices/ApplicationServices.h>
CGKeyCode keyCodeForCharWithLayout(const char c,
const UCKeyboardLayout *uchrHeader);
CGKeyCode keyCodeForChar(const char c)
{
CFDataRef currentLayoutData;
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
if (currentKeyboard == NULL) {
fputs("Could not find keyboard layout\n", stderr);
return UINT16_MAX;
}
currentLayoutData = TISGetInputSourceProperty(currentKeyboard,
kTISPropertyUnicodeKeyLayoutData);
CFRelease(currentKeyboard);
if (currentLayoutData == NULL) {
fputs("Could not find layout data\n", stderr);
return UINT16_MAX;
}
return keyCodeForCharWithLayout(c,
(const UCKeyboardLayout *)CFDataGetBytePtr(currentLayoutData));
}
/* Beware! Messy, incomprehensible code ahead!
* TODO: XXX: FIXME! Please! */
CGKeyCode keyCodeForCharWithLayout(const char c,
const UCKeyboardLayout *uchrHeader)
{
uint8_t *uchrData = (uint8_t *)uchrHeader;
UCKeyboardTypeHeader *uchrKeyboardList = uchrHeader->keyboardTypeList;
/* Loop through the keyboard type list. */
ItemCount i, j;
for (i = 0; i < uchrHeader->keyboardTypeCount; ++i) {
/* Get a pointer to the keyToCharTable structure. */
UCKeyToCharTableIndex *uchrKeyIX = (UCKeyToCharTableIndex *)
(uchrData + (uchrKeyboardList[i].keyToCharTableIndexOffset));
/* Not sure what this is for but it appears to be a safeguard... */
UCKeyStateRecordsIndex *stateRecordsIndex;
if (uchrKeyboardList[i].keyStateRecordsIndexOffset != 0) {
stateRecordsIndex = (UCKeyStateRecordsIndex *)
(uchrData + (uchrKeyboardList[i].keyStateRecordsIndexOffset));
if ((stateRecordsIndex->keyStateRecordsIndexFormat) !=
kUCKeyStateRecordsIndexFormat) {
stateRecordsIndex = NULL;
}
} else {
stateRecordsIndex = NULL;
}
/* Make sure structure is a table that can be searched. */
if ((uchrKeyIX->keyToCharTableIndexFormat) != kUCKeyToCharTableIndexFormat) {
continue;
}
/* Check the table of each keyboard for character */
for (j = 0; j < uchrKeyIX->keyToCharTableCount; ++j) {
UCKeyOutput *keyToCharData =
(UCKeyOutput *)(uchrData + (uchrKeyIX->keyToCharTableOffsets[j]));
/* Check THIS table of the keyboard for the character. */
UInt16 k;
for (k = 0; k < uchrKeyIX->keyToCharTableSize; ++k) {
/* Here's the strange safeguard again... */
if ((keyToCharData[k] & kUCKeyOutputTestForIndexMask) ==
kUCKeyOutputStateIndexMask) {
long keyIndex = (keyToCharData[k] & kUCKeyOutputGetIndexMask);
if (stateRecordsIndex != NULL &&
keyIndex <= (stateRecordsIndex->keyStateRecordCount)) {
UCKeyStateRecord *stateRecord = (UCKeyStateRecord *)
(uchrData +
(stateRecordsIndex->keyStateRecordOffsets[keyIndex]));
if ((stateRecord->stateZeroCharData) == c) {
return (CGKeyCode)k;
}
} else if (keyToCharData[k] == c) {
return (CGKeyCode)k;
}
} else if (((keyToCharData[k] & kUCKeyOutputTestForIndexMask)
!= kUCKeyOutputSequenceIndexMask) &&
keyToCharData[k] != 0xFFFE &&
keyToCharData[k] != 0xFFFF &&
keyToCharData[k] == c) {
return (CGKeyCode)k;
}
}
}
}
return UINT16_MAX;
}
Is there a.) (preferably) a standard function I am overlooking, or b.) (almost certainly) a more elegant way write my own?
是否有一个。)(最好)一个我忽略的标准功能,或者b。)(几乎可以肯定)一种更优雅的方式来写我自己的?
4 个解决方案
#1
27
This is what I ended up using. Much cleaner.
这就是我最终使用的。更清洁。
#include <CoreFoundation/CoreFoundation.h>
#include <Carbon/Carbon.h> /* For kVK_ constants, and TIS functions. */
/* Returns string representation of key, if it is printable.
* Ownership follows the Create Rule; that is, it is the caller's
* responsibility to release the returned object. */
CFStringRef createStringForKey(CGKeyCode keyCode)
{
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
CFDataRef layoutData =
TISGetInputSourceProperty(currentKeyboard,
kTISPropertyUnicodeKeyLayoutData);
const UCKeyboardLayout *keyboardLayout =
(const UCKeyboardLayout *)CFDataGetBytePtr(layoutData);
UInt32 keysDown = 0;
UniChar chars[4];
UniCharCount realLength;
UCKeyTranslate(keyboardLayout,
keyCode,
kUCKeyActionDisplay,
0,
LMGetKbdType(),
kUCKeyTranslateNoDeadKeysBit,
&keysDown,
sizeof(chars) / sizeof(chars[0]),
&realLength,
chars);
CFRelease(currentKeyboard);
return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1);
}
/* Returns key code for given character via the above function, or UINT16_MAX
* on error. */
CGKeyCode keyCodeForChar(const char c)
{
static CFMutableDictionaryRef charToCodeDict = NULL;
CGKeyCode code;
UniChar character = c;
CFStringRef charStr = NULL;
/* Generate table of keycodes and characters. */
if (charToCodeDict == NULL) {
size_t i;
charToCodeDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
128,
&kCFCopyStringDictionaryKeyCallBacks,
NULL);
if (charToCodeDict == NULL) return UINT16_MAX;
/* Loop through every keycode (0 - 127) to find its current mapping. */
for (i = 0; i < 128; ++i) {
CFStringRef string = createStringForKey((CGKeyCode)i);
if (string != NULL) {
CFDictionaryAddValue(charToCodeDict, string, (const void *)i);
CFRelease(string);
}
}
}
charStr = CFStringCreateWithCharacters(kCFAllocatorDefault, &character, 1);
/* Our values may be NULL (0), so we need to use this function. */
if (!CFDictionaryGetValueIfPresent(charToCodeDict, charStr,
(const void **)&code)) {
code = UINT16_MAX;
}
CFRelease(charStr);
return code;
}
#2
6
+ (NSString *)keyStringFormKeyCode:(CGKeyCode)keyCode
{
// Proper key detection seems to want a switch statement, unfortunately
switch (keyCode)
{
case 0: return @"a";
case 1: return @"s";
case 2: return @"d";
case 3: return @"f";
case 4: return @"h";
case 5: return @"g";
case 6: return @"z";
case 7: return @"x";
case 8: return @"c";
case 9: return @"v";
// what is 10?
case 11: return @"b";
case 12: return @"q";
case 13: return @"w";
case 14: return @"e";
case 15: return @"r";
case 16: return @"y";
case 17: return @"t";
case 18: return @"1";
case 19: return @"2";
case 20: return @"3";
case 21: return @"4";
case 22: return @"6";
case 23: return @"5";
case 24: return @"=";
case 25: return @"9";
case 26: return @"7";
case 27: return @"-";
case 28: return @"8";
case 29: return @"0";
case 30: return @"]";
case 31: return @"o";
case 32: return @"u";
case 33: return @"[";
case 34: return @"i";
case 35: return @"p";
case 36: return @"RETURN";
case 37: return @"l";
case 38: return @"j";
case 39: return @"'";
case 40: return @"k";
case 41: return @";";
case 42: return @"\\";
case 43: return @",";
case 44: return @"/";
case 45: return @"n";
case 46: return @"m";
case 47: return @".";
case 48: return @"TAB";
case 49: return @"SPACE";
case 50: return @"`";
case 51: return @"DELETE";
case 52: return @"ENTER";
case 53: return @"ESCAPE";
// some more missing codes abound, reserved I presume, but it would
// have been helpful for Apple to have a document with them all listed
case 65: return @".";
case 67: return @"*";
case 69: return @"+";
case 71: return @"CLEAR";
case 75: return @"/";
case 76: return @"ENTER"; // numberpad on full kbd
case 78: return @"-";
case 81: return @"=";
case 82: return @"0";
case 83: return @"1";
case 84: return @"2";
case 85: return @"3";
case 86: return @"4";
case 87: return @"5";
case 88: return @"6";
case 89: return @"7";
case 91: return @"8";
case 92: return @"9";
case 96: return @"F5";
case 97: return @"F6";
case 98: return @"F7";
case 99: return @"F3";
case 100: return @"F8";
case 101: return @"F9";
case 103: return @"F11";
case 105: return @"F13";
case 107: return @"F14";
case 109: return @"F10";
case 111: return @"F12";
case 113: return @"F15";
case 114: return @"HELP";
case 115: return @"HOME";
case 116: return @"PGUP";
case 117: return @"DELETE"; // full keyboard right side numberpad
case 118: return @"F4";
case 119: return @"END";
case 120: return @"F2";
case 121: return @"PGDN";
case 122: return @"F1";
case 123: return @"LEFT";
case 124: return @"RIGHT";
case 125: return @"DOWN";
case 126: return @"UP";
default:
return @"Unknown key";
// Unknown key, bail and note that RUI needs improvement
//fprintf(stderr, "%ld\tKey\t%c (DEBUG: %d)\n", currenttime, keyCode;
//exit(EXIT_FAILURE;
}
}
+ (CGKeyCode)keyCodeFormKeyString:(NSString *)keyString
{
if ([keyString isEqualToString:@"a"]) return 0;
if ([keyString isEqualToString:@"s"]) return 1;
if ([keyString isEqualToString:@"d"]) return 2;
if ([keyString isEqualToString:@"f"]) return 3;
if ([keyString isEqualToString:@"h"]) return 4;
if ([keyString isEqualToString:@"g"]) return 5;
if ([keyString isEqualToString:@"z"]) return 6;
if ([keyString isEqualToString:@"x"]) return 7;
if ([keyString isEqualToString:@"c"]) return 8;
if ([keyString isEqualToString:@"v"]) return 9;
// what is 10?
if ([keyString isEqualToString:@"b"]) return 11;
if ([keyString isEqualToString:@"q"]) return 12;
if ([keyString isEqualToString:@"w"]) return 13;
if ([keyString isEqualToString:@"e"]) return 14;
if ([keyString isEqualToString:@"r"]) return 15;
if ([keyString isEqualToString:@"y"]) return 16;
if ([keyString isEqualToString:@"t"]) return 17;
if ([keyString isEqualToString:@"1"]) return 18;
if ([keyString isEqualToString:@"2"]) return 19;
if ([keyString isEqualToString:@"3"]) return 20;
if ([keyString isEqualToString:@"4"]) return 21;
if ([keyString isEqualToString:@"6"]) return 22;
if ([keyString isEqualToString:@"5"]) return 23;
if ([keyString isEqualToString:@"="]) return 24;
if ([keyString isEqualToString:@"9"]) return 25;
if ([keyString isEqualToString:@"7"]) return 26;
if ([keyString isEqualToString:@"-"]) return 27;
if ([keyString isEqualToString:@"8"]) return 28;
if ([keyString isEqualToString:@"0"]) return 29;
if ([keyString isEqualToString:@"]"]) return 30;
if ([keyString isEqualToString:@"o"]) return 31;
if ([keyString isEqualToString:@"u"]) return 32;
if ([keyString isEqualToString:@"["]) return 33;
if ([keyString isEqualToString:@"i"]) return 34;
if ([keyString isEqualToString:@"p"]) return 35;
if ([keyString isEqualToString:@"RETURN"]) return 36;
if ([keyString isEqualToString:@"l"]) return 37;
if ([keyString isEqualToString:@"j"]) return 38;
if ([keyString isEqualToString:@"'"]) return 39;
if ([keyString isEqualToString:@"k"]) return 40;
if ([keyString isEqualToString:@";"]) return 41;
if ([keyString isEqualToString:@"\\"]) return 42;
if ([keyString isEqualToString:@","]) return 43;
if ([keyString isEqualToString:@"/"]) return 44;
if ([keyString isEqualToString:@"n"]) return 45;
if ([keyString isEqualToString:@"m"]) return 46;
if ([keyString isEqualToString:@"."]) return 47;
if ([keyString isEqualToString:@"TAB"]) return 48;
if ([keyString isEqualToString:@"SPACE"]) return 49;
if ([keyString isEqualToString:@"`"]) return 50;
if ([keyString isEqualToString:@"DELETE"]) return 51;
if ([keyString isEqualToString:@"ENTER"]) return 52;
if ([keyString isEqualToString:@"ESCAPE"]) return 53;
// some more missing codes abound, reserved I presume, but it would
// have been helpful for Apple to have a document with them all listed
if ([keyString isEqualToString:@"."]) return 65;
if ([keyString isEqualToString:@"*"]) return 67;
if ([keyString isEqualToString:@"+"]) return 69;
if ([keyString isEqualToString:@"CLEAR"]) return 71;
if ([keyString isEqualToString:@"/"]) return 75;
if ([keyString isEqualToString:@"ENTER"]) return 76; // numberpad on full kbd
if ([keyString isEqualToString:@"="]) return 78;
if ([keyString isEqualToString:@"="]) return 81;
if ([keyString isEqualToString:@"0"]) return 82;
if ([keyString isEqualToString:@"1"]) return 83;
if ([keyString isEqualToString:@"2"]) return 84;
if ([keyString isEqualToString:@"3"]) return 85;
if ([keyString isEqualToString:@"4"]) return 86;
if ([keyString isEqualToString:@"5"]) return 87;
if ([keyString isEqualToString:@"6"]) return 88;
if ([keyString isEqualToString:@"7"]) return 89;
if ([keyString isEqualToString:@"8"]) return 91;
if ([keyString isEqualToString:@"9"]) return 92;
if ([keyString isEqualToString:@"F5"]) return 96;
if ([keyString isEqualToString:@"F6"]) return 97;
if ([keyString isEqualToString:@"F7"]) return 98;
if ([keyString isEqualToString:@"F3"]) return 99;
if ([keyString isEqualToString:@"F8"]) return 100;
if ([keyString isEqualToString:@"F9"]) return 101;
if ([keyString isEqualToString:@"F11"]) return 103;
if ([keyString isEqualToString:@"F13"]) return 105;
if ([keyString isEqualToString:@"F14"]) return 107;
if ([keyString isEqualToString:@"F10"]) return 109;
if ([keyString isEqualToString:@"F12"]) return 111;
if ([keyString isEqualToString:@"F15"]) return 113;
if ([keyString isEqualToString:@"HELP"]) return 114;
if ([keyString isEqualToString:@"HOME"]) return 115;
if ([keyString isEqualToString:@"PGUP"]) return 116;
if ([keyString isEqualToString:@"DELETE"]) return 117;
if ([keyString isEqualToString:@"F4"]) return 118;
if ([keyString isEqualToString:@"END"]) return 119;
if ([keyString isEqualToString:@"F2"]) return 120;
if ([keyString isEqualToString:@"PGDN"]) return 121;
if ([keyString isEqualToString:@"F1"]) return 122;
if ([keyString isEqualToString:@"LEFT"]) return 123;
if ([keyString isEqualToString:@"RIGHT"]) return 124;
if ([keyString isEqualToString:@"DOWN"]) return 125;
if ([keyString isEqualToString:@"UP"]) return 126;
return 0;
//fprintf(stderr, "keyString %s Not Found. Aborting...\n", keyString);
//exit(EXIT_FAILURE);
}
original code from here: http://ritter.ist.psu.edu/projects/RUI/macosx/rui.c
来自这里的原始代码:http://ritter.ist.psu.edu/projects/RUI/macosx/rui.c
#3
4
Your own solution works fine under Qt too after a small patch (casting to CFDataRef
):
在一个小补丁(转换为CFDataRef)之后,你自己的解决方案在Qt下运行正常:
Replacing
更换
CFDataRef layoutData = TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
with
同
CFDataRef layoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
avoids the error:
避免错误:
invalid conversion from 'void*' to 'const __CFData*'
从'void *'到'const __CFData *'的无效转换
#4
3
For those like me who searched for a more up-to-date version of what Michael proposed, here is what I ended up doing myself (for me it solved some segfault issue, probably because the garbage collector is doing its job with this version).
对于那些寻找迈克尔提出的最新版本的人来说,这就是我最终自己做的事情(对我而言,它解决了一些段错误问题,可能是因为垃圾收集器正在使用此版本) 。
The first function comes from Convert Virtual Key Code to unicode string.
第一个函数来自转换虚拟密钥代码到unicode字符串。
NSString* keyCodeToString(CGKeyCode keyCode)
{
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
CFDataRef uchr =
(CFDataRef)TISGetInputSourceProperty(currentKeyboard,
kTISPropertyUnicodeKeyLayoutData);
const UCKeyboardLayout *keyboardLayout =
(const UCKeyboardLayout*)CFDataGetBytePtr(uchr);
if(keyboardLayout)
{
UInt32 deadKeyState = 0;
UniCharCount maxStringLength = 255;
UniCharCount actualStringLength = 0;
UniChar unicodeString[maxStringLength];
OSStatus status = UCKeyTranslate(keyboardLayout,
keyCode, kUCKeyActionDown, 0,
LMGetKbdType(), 0,
&deadKeyState,
maxStringLength,
&actualStringLength, unicodeString);
if (actualStringLength == 0 && deadKeyState)
{
status = UCKeyTranslate(keyboardLayout,
kVK_Space, kUCKeyActionDown, 0,
LMGetKbdType(), 0,
&deadKeyState,
maxStringLength,
&actualStringLength, unicodeString);
}
if(actualStringLength > 0 && status == noErr)
return [[NSString stringWithCharacters:unicodeString
length:(NSUInteger)actualStringLength] lowercaseString];
}
return nil;
}
NSNumber* charToKeyCode(const char c)
{
static NSMutableDictionary* dict = nil;
if (dict == nil)
{
dict = [NSMutableDictionary dictionary];
// For every keyCode
size_t i;
for (i = 0; i < 128; ++i)
{
NSString* str = keyCodeToString((CGKeyCode)i);
if(str != nil && ![str isEqualToString:@""])
{
[dict setObject:[NSNumber numberWithInt:i] forKey:str];
}
}
}
NSString * keyChar = [NSString stringWithFormat:@"%c" , c];
return [dict objectForKey:keyChar];
}
I used NSNumber
to get a nullable object, the value returned by charToKeyCode(c)
can then be tested against nil
and then accessed with (CGKeyCode)[charToKeyCode(c) intValue]
.
我使用NSNumber来获取一个可以为空的对象,然后charToKeyCode(c)返回的值可以针对nil进行测试,然后使用(CGKeyCode)[charToKeyCode(c)intValue]进行访问。
#1
27
This is what I ended up using. Much cleaner.
这就是我最终使用的。更清洁。
#include <CoreFoundation/CoreFoundation.h>
#include <Carbon/Carbon.h> /* For kVK_ constants, and TIS functions. */
/* Returns string representation of key, if it is printable.
* Ownership follows the Create Rule; that is, it is the caller's
* responsibility to release the returned object. */
CFStringRef createStringForKey(CGKeyCode keyCode)
{
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
CFDataRef layoutData =
TISGetInputSourceProperty(currentKeyboard,
kTISPropertyUnicodeKeyLayoutData);
const UCKeyboardLayout *keyboardLayout =
(const UCKeyboardLayout *)CFDataGetBytePtr(layoutData);
UInt32 keysDown = 0;
UniChar chars[4];
UniCharCount realLength;
UCKeyTranslate(keyboardLayout,
keyCode,
kUCKeyActionDisplay,
0,
LMGetKbdType(),
kUCKeyTranslateNoDeadKeysBit,
&keysDown,
sizeof(chars) / sizeof(chars[0]),
&realLength,
chars);
CFRelease(currentKeyboard);
return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1);
}
/* Returns key code for given character via the above function, or UINT16_MAX
* on error. */
CGKeyCode keyCodeForChar(const char c)
{
static CFMutableDictionaryRef charToCodeDict = NULL;
CGKeyCode code;
UniChar character = c;
CFStringRef charStr = NULL;
/* Generate table of keycodes and characters. */
if (charToCodeDict == NULL) {
size_t i;
charToCodeDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
128,
&kCFCopyStringDictionaryKeyCallBacks,
NULL);
if (charToCodeDict == NULL) return UINT16_MAX;
/* Loop through every keycode (0 - 127) to find its current mapping. */
for (i = 0; i < 128; ++i) {
CFStringRef string = createStringForKey((CGKeyCode)i);
if (string != NULL) {
CFDictionaryAddValue(charToCodeDict, string, (const void *)i);
CFRelease(string);
}
}
}
charStr = CFStringCreateWithCharacters(kCFAllocatorDefault, &character, 1);
/* Our values may be NULL (0), so we need to use this function. */
if (!CFDictionaryGetValueIfPresent(charToCodeDict, charStr,
(const void **)&code)) {
code = UINT16_MAX;
}
CFRelease(charStr);
return code;
}
#2
6
+ (NSString *)keyStringFormKeyCode:(CGKeyCode)keyCode
{
// Proper key detection seems to want a switch statement, unfortunately
switch (keyCode)
{
case 0: return @"a";
case 1: return @"s";
case 2: return @"d";
case 3: return @"f";
case 4: return @"h";
case 5: return @"g";
case 6: return @"z";
case 7: return @"x";
case 8: return @"c";
case 9: return @"v";
// what is 10?
case 11: return @"b";
case 12: return @"q";
case 13: return @"w";
case 14: return @"e";
case 15: return @"r";
case 16: return @"y";
case 17: return @"t";
case 18: return @"1";
case 19: return @"2";
case 20: return @"3";
case 21: return @"4";
case 22: return @"6";
case 23: return @"5";
case 24: return @"=";
case 25: return @"9";
case 26: return @"7";
case 27: return @"-";
case 28: return @"8";
case 29: return @"0";
case 30: return @"]";
case 31: return @"o";
case 32: return @"u";
case 33: return @"[";
case 34: return @"i";
case 35: return @"p";
case 36: return @"RETURN";
case 37: return @"l";
case 38: return @"j";
case 39: return @"'";
case 40: return @"k";
case 41: return @";";
case 42: return @"\\";
case 43: return @",";
case 44: return @"/";
case 45: return @"n";
case 46: return @"m";
case 47: return @".";
case 48: return @"TAB";
case 49: return @"SPACE";
case 50: return @"`";
case 51: return @"DELETE";
case 52: return @"ENTER";
case 53: return @"ESCAPE";
// some more missing codes abound, reserved I presume, but it would
// have been helpful for Apple to have a document with them all listed
case 65: return @".";
case 67: return @"*";
case 69: return @"+";
case 71: return @"CLEAR";
case 75: return @"/";
case 76: return @"ENTER"; // numberpad on full kbd
case 78: return @"-";
case 81: return @"=";
case 82: return @"0";
case 83: return @"1";
case 84: return @"2";
case 85: return @"3";
case 86: return @"4";
case 87: return @"5";
case 88: return @"6";
case 89: return @"7";
case 91: return @"8";
case 92: return @"9";
case 96: return @"F5";
case 97: return @"F6";
case 98: return @"F7";
case 99: return @"F3";
case 100: return @"F8";
case 101: return @"F9";
case 103: return @"F11";
case 105: return @"F13";
case 107: return @"F14";
case 109: return @"F10";
case 111: return @"F12";
case 113: return @"F15";
case 114: return @"HELP";
case 115: return @"HOME";
case 116: return @"PGUP";
case 117: return @"DELETE"; // full keyboard right side numberpad
case 118: return @"F4";
case 119: return @"END";
case 120: return @"F2";
case 121: return @"PGDN";
case 122: return @"F1";
case 123: return @"LEFT";
case 124: return @"RIGHT";
case 125: return @"DOWN";
case 126: return @"UP";
default:
return @"Unknown key";
// Unknown key, bail and note that RUI needs improvement
//fprintf(stderr, "%ld\tKey\t%c (DEBUG: %d)\n", currenttime, keyCode;
//exit(EXIT_FAILURE;
}
}
+ (CGKeyCode)keyCodeFormKeyString:(NSString *)keyString
{
if ([keyString isEqualToString:@"a"]) return 0;
if ([keyString isEqualToString:@"s"]) return 1;
if ([keyString isEqualToString:@"d"]) return 2;
if ([keyString isEqualToString:@"f"]) return 3;
if ([keyString isEqualToString:@"h"]) return 4;
if ([keyString isEqualToString:@"g"]) return 5;
if ([keyString isEqualToString:@"z"]) return 6;
if ([keyString isEqualToString:@"x"]) return 7;
if ([keyString isEqualToString:@"c"]) return 8;
if ([keyString isEqualToString:@"v"]) return 9;
// what is 10?
if ([keyString isEqualToString:@"b"]) return 11;
if ([keyString isEqualToString:@"q"]) return 12;
if ([keyString isEqualToString:@"w"]) return 13;
if ([keyString isEqualToString:@"e"]) return 14;
if ([keyString isEqualToString:@"r"]) return 15;
if ([keyString isEqualToString:@"y"]) return 16;
if ([keyString isEqualToString:@"t"]) return 17;
if ([keyString isEqualToString:@"1"]) return 18;
if ([keyString isEqualToString:@"2"]) return 19;
if ([keyString isEqualToString:@"3"]) return 20;
if ([keyString isEqualToString:@"4"]) return 21;
if ([keyString isEqualToString:@"6"]) return 22;
if ([keyString isEqualToString:@"5"]) return 23;
if ([keyString isEqualToString:@"="]) return 24;
if ([keyString isEqualToString:@"9"]) return 25;
if ([keyString isEqualToString:@"7"]) return 26;
if ([keyString isEqualToString:@"-"]) return 27;
if ([keyString isEqualToString:@"8"]) return 28;
if ([keyString isEqualToString:@"0"]) return 29;
if ([keyString isEqualToString:@"]"]) return 30;
if ([keyString isEqualToString:@"o"]) return 31;
if ([keyString isEqualToString:@"u"]) return 32;
if ([keyString isEqualToString:@"["]) return 33;
if ([keyString isEqualToString:@"i"]) return 34;
if ([keyString isEqualToString:@"p"]) return 35;
if ([keyString isEqualToString:@"RETURN"]) return 36;
if ([keyString isEqualToString:@"l"]) return 37;
if ([keyString isEqualToString:@"j"]) return 38;
if ([keyString isEqualToString:@"'"]) return 39;
if ([keyString isEqualToString:@"k"]) return 40;
if ([keyString isEqualToString:@";"]) return 41;
if ([keyString isEqualToString:@"\\"]) return 42;
if ([keyString isEqualToString:@","]) return 43;
if ([keyString isEqualToString:@"/"]) return 44;
if ([keyString isEqualToString:@"n"]) return 45;
if ([keyString isEqualToString:@"m"]) return 46;
if ([keyString isEqualToString:@"."]) return 47;
if ([keyString isEqualToString:@"TAB"]) return 48;
if ([keyString isEqualToString:@"SPACE"]) return 49;
if ([keyString isEqualToString:@"`"]) return 50;
if ([keyString isEqualToString:@"DELETE"]) return 51;
if ([keyString isEqualToString:@"ENTER"]) return 52;
if ([keyString isEqualToString:@"ESCAPE"]) return 53;
// some more missing codes abound, reserved I presume, but it would
// have been helpful for Apple to have a document with them all listed
if ([keyString isEqualToString:@"."]) return 65;
if ([keyString isEqualToString:@"*"]) return 67;
if ([keyString isEqualToString:@"+"]) return 69;
if ([keyString isEqualToString:@"CLEAR"]) return 71;
if ([keyString isEqualToString:@"/"]) return 75;
if ([keyString isEqualToString:@"ENTER"]) return 76; // numberpad on full kbd
if ([keyString isEqualToString:@"="]) return 78;
if ([keyString isEqualToString:@"="]) return 81;
if ([keyString isEqualToString:@"0"]) return 82;
if ([keyString isEqualToString:@"1"]) return 83;
if ([keyString isEqualToString:@"2"]) return 84;
if ([keyString isEqualToString:@"3"]) return 85;
if ([keyString isEqualToString:@"4"]) return 86;
if ([keyString isEqualToString:@"5"]) return 87;
if ([keyString isEqualToString:@"6"]) return 88;
if ([keyString isEqualToString:@"7"]) return 89;
if ([keyString isEqualToString:@"8"]) return 91;
if ([keyString isEqualToString:@"9"]) return 92;
if ([keyString isEqualToString:@"F5"]) return 96;
if ([keyString isEqualToString:@"F6"]) return 97;
if ([keyString isEqualToString:@"F7"]) return 98;
if ([keyString isEqualToString:@"F3"]) return 99;
if ([keyString isEqualToString:@"F8"]) return 100;
if ([keyString isEqualToString:@"F9"]) return 101;
if ([keyString isEqualToString:@"F11"]) return 103;
if ([keyString isEqualToString:@"F13"]) return 105;
if ([keyString isEqualToString:@"F14"]) return 107;
if ([keyString isEqualToString:@"F10"]) return 109;
if ([keyString isEqualToString:@"F12"]) return 111;
if ([keyString isEqualToString:@"F15"]) return 113;
if ([keyString isEqualToString:@"HELP"]) return 114;
if ([keyString isEqualToString:@"HOME"]) return 115;
if ([keyString isEqualToString:@"PGUP"]) return 116;
if ([keyString isEqualToString:@"DELETE"]) return 117;
if ([keyString isEqualToString:@"F4"]) return 118;
if ([keyString isEqualToString:@"END"]) return 119;
if ([keyString isEqualToString:@"F2"]) return 120;
if ([keyString isEqualToString:@"PGDN"]) return 121;
if ([keyString isEqualToString:@"F1"]) return 122;
if ([keyString isEqualToString:@"LEFT"]) return 123;
if ([keyString isEqualToString:@"RIGHT"]) return 124;
if ([keyString isEqualToString:@"DOWN"]) return 125;
if ([keyString isEqualToString:@"UP"]) return 126;
return 0;
//fprintf(stderr, "keyString %s Not Found. Aborting...\n", keyString);
//exit(EXIT_FAILURE);
}
original code from here: http://ritter.ist.psu.edu/projects/RUI/macosx/rui.c
来自这里的原始代码:http://ritter.ist.psu.edu/projects/RUI/macosx/rui.c
#3
4
Your own solution works fine under Qt too after a small patch (casting to CFDataRef
):
在一个小补丁(转换为CFDataRef)之后,你自己的解决方案在Qt下运行正常:
Replacing
更换
CFDataRef layoutData = TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
with
同
CFDataRef layoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
avoids the error:
避免错误:
invalid conversion from 'void*' to 'const __CFData*'
从'void *'到'const __CFData *'的无效转换
#4
3
For those like me who searched for a more up-to-date version of what Michael proposed, here is what I ended up doing myself (for me it solved some segfault issue, probably because the garbage collector is doing its job with this version).
对于那些寻找迈克尔提出的最新版本的人来说,这就是我最终自己做的事情(对我而言,它解决了一些段错误问题,可能是因为垃圾收集器正在使用此版本) 。
The first function comes from Convert Virtual Key Code to unicode string.
第一个函数来自转换虚拟密钥代码到unicode字符串。
NSString* keyCodeToString(CGKeyCode keyCode)
{
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
CFDataRef uchr =
(CFDataRef)TISGetInputSourceProperty(currentKeyboard,
kTISPropertyUnicodeKeyLayoutData);
const UCKeyboardLayout *keyboardLayout =
(const UCKeyboardLayout*)CFDataGetBytePtr(uchr);
if(keyboardLayout)
{
UInt32 deadKeyState = 0;
UniCharCount maxStringLength = 255;
UniCharCount actualStringLength = 0;
UniChar unicodeString[maxStringLength];
OSStatus status = UCKeyTranslate(keyboardLayout,
keyCode, kUCKeyActionDown, 0,
LMGetKbdType(), 0,
&deadKeyState,
maxStringLength,
&actualStringLength, unicodeString);
if (actualStringLength == 0 && deadKeyState)
{
status = UCKeyTranslate(keyboardLayout,
kVK_Space, kUCKeyActionDown, 0,
LMGetKbdType(), 0,
&deadKeyState,
maxStringLength,
&actualStringLength, unicodeString);
}
if(actualStringLength > 0 && status == noErr)
return [[NSString stringWithCharacters:unicodeString
length:(NSUInteger)actualStringLength] lowercaseString];
}
return nil;
}
NSNumber* charToKeyCode(const char c)
{
static NSMutableDictionary* dict = nil;
if (dict == nil)
{
dict = [NSMutableDictionary dictionary];
// For every keyCode
size_t i;
for (i = 0; i < 128; ++i)
{
NSString* str = keyCodeToString((CGKeyCode)i);
if(str != nil && ![str isEqualToString:@""])
{
[dict setObject:[NSNumber numberWithInt:i] forKey:str];
}
}
}
NSString * keyChar = [NSString stringWithFormat:@"%c" , c];
return [dict objectForKey:keyChar];
}
I used NSNumber
to get a nullable object, the value returned by charToKeyCode(c)
can then be tested against nil
and then accessed with (CGKeyCode)[charToKeyCode(c) intValue]
.
我使用NSNumber来获取一个可以为空的对象,然后charToKeyCode(c)返回的值可以针对nil进行测试,然后使用(CGKeyCode)[charToKeyCode(c)intValue]进行访问。