【发布时间】:2009-12-17 01:00:46
【问题描述】:
我需要一个函数,给定一个字符,返回与该字符在当前键盘布局上的位置相关联的CGKeyCode。例如,给定“b”,如果使用 U.S. QWERTY,则应返回 kVK_ANSI_B,如果使用 Dvorak,则应返回 kVK_ANSI_N。
Win32 API 有函数VkKeyScan() 用于此目的; X11 有函数XStringToKeySym()。 CG API中有这样的功能吗?
我需要这个才能将参数传递给CGEventCreateKeyboardEvent()。我尝试使用CGEventKeyboardSetUnicodeString() 代替,但显然does not support 修饰符标志(我需要)。
我对此进行了广泛搜索,但找不到合适的答案。目前我正在使用以下代码 (found online),它可以工作,但并不完全优雅(而且很难破译如何简化),我不想在生产代码中使用它:
#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;
}
是否有 a.)(最好)一个我忽略的标准函数,或者 b.)(几乎可以肯定)一种更优雅的方式来编写我自己的?
【问题讨论】:
-
@Sneakyness:我不想硬编码关键常量。它们是 a.) 由用户输入生成的,b.) 可能是多种键盘布局的结果。
-
@Michael - 你得到键盘记录器的工作版本了吗?我正在寻找一个。我尝试了几个 git 包。但无法按预期工作/无法捕获所有击键。或者你对此有什么建议?任何开源软件包?会很有帮助的
标签: c macos quartz-graphics keypress keycode