6

I'd like to capture key events from any window in the application and interpret them as Unicode. For example, if the user types Option-e-e (on a default-configured US English keyboard), I would like to recognize that as "é".

I tried capturing keypress events and calling -[NSEvent characters]. However, as it says in the documentation, "This method returns an empty string for dead keys, such as Option-e." If I type Option-e-e, then it gives me nothing for the Option-e and plain "e" for the second e.

Is there a way to combine a series of keycodes (from -[NSEvent keyCode]) into a Unicode character?

Or a way to receive an event for each Unicode character typed (like Java's key-typed event)?

4

2 回答 2

12

这是一种获取一系列按键事件并获取他们键入的 Unicode 字符的方法。

基本上,为收到的每个按键事件调用UCKeyTranslate() 。使用它的deadKeyState参数来捕获一个死键并将其传递给后续调用。

例子:

  • 接收Option-e 的按键事件。
  • UCKeyTranslate()使用虚拟键代码(对于e)、修饰键状态(对于Option)和用于存储死键状态的变量进行 调用。
    • UCKeyTranslate()输出一个空字符串并更新死键状态。
  • 接收e的按键事件。
  • UCKeyTranlate()使用虚拟键代码(对于e)和保存死键状态的变量 进行调用。
    • UCKeyTranslate()输出“é”。

示例代码(为每个按键事件调用的函数):

/**
 * Returns the Unicode characters that would be typed by a key press.
 *
 * @param event A key press event.
 * @param deadKeyState To capture multi-keystroke characters (e.g. Option-E-E for "é"), pass a reference to the same
 *      variable on consecutive calls to this function. Before the first call, you should initialize the variable to 0.
 * @return One or more Unicode characters.
 */
CFStringRef getCharactersForKeyPress(NSEvent *event, UInt32 *deadKeyState)
{
    // http://stackoverflow.com/questions/12547007/convert-key-code-into-key-equivalent-string
    // http://stackoverflow.com/questions/8263618/convert-virtual-key-code-to-unicode-string

    TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
    CFDataRef layoutData = TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
    const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData);

    CGEventFlags flags = [event modifierFlags];
    UInt32 modifierKeyState = (flags >> 16) & 0xFF;

    const size_t unicodeStringLength = 4;
    UniChar unicodeString[unicodeStringLength];
    UniCharCount realLength;

    UCKeyTranslate(keyboardLayout,
                   [event keyCode],
                   kUCKeyActionDown,
                   modifierKeyState,
                   LMGetKbdType(),
                   0,
                   deadKeyState,
                   unicodeStringLength,
                   &realLength,
                   unicodeString);
    CFRelease(currentKeyboard);
    return CFStringCreateWithCharacters(kCFAllocatorDefault, unicodeString, realLength);
}
于 2014-03-27T03:28:27.793 回答
0

子类化要在其中捕获“é”事件的视图/窗口并添加此实例变量

BOOL optionE_Pressed;

然后,用这个覆盖 keyDown:

-(void) keyDown:(NSEvent *)theEvent {

    NSString *chars = theEvent.charactersIgnoringModifiers;
    unichar aChar = [chars characterAtIndex: 0];

    if (aChar==101 && [theEvent modifierFlags]&NSAlternateKeyMask) {
        optionE_Pressed=YES;
    }
    else if (aChar==101 && optionE_Pressed) {
        NSLog(@"spanish é pressed");
    }
    else {
        optionE_Pressed=NO;
    }

    [super keyDown:theEvent];
}

当用户按住 option 和 e 键时,布尔变量“optionE_Pressed”被激活。如果按下的下一个键是 e,这意味着他们已经有效地创建了一个西班牙文 é,那么它将记录“按下西班牙文 é”。否则,布尔值切换回 NO。最后的“超级”调用允许用户仍然能够正常键入所有事件

于 2014-03-24T00:50:10.620 回答