【问题标题】:How to capture Unicode from key events without an NSTextView如何在没有 NSTextView 的情况下从关键事件中捕获 Unicode
【发布时间】:2014-04-29 06:53:19
【问题描述】:

我想从应用程序的任何窗口中捕获关键事件并将它们解释为 Unicode。例如,如果用户键入 Option-e-e(在默认配置的美式英语键盘上),我想将其识别为“é”。

我尝试捕获按键事件并调用-[NSEvent characters]。但是,正如它在文档中所说,“此方法为死键返回一个空字符串,例如 Option-e。”如果我键入 Option-ee,那么对于 Option-e 并没有给我任何东西,而对于第二个 e 来说它是纯“e”。

有没有办法将一系列键码(来自-[NSEvent keyCode])组合成一个 Unicode 字符?

或者为每个输入的 Unicode 字符(如Java's key-typed event)接收事件?

【问题讨论】:

    标签: cocoa unicode nsevent


    【解决方案1】:

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

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

    例子:

    • 接收 Option-e 的按键事件。
    • 使用虚拟键代码(对于e)、修饰键状态(对于Option)和用于存储死键状态的变量调用UCKeyTranslate()
      • UCKeyTranslate() 输出一个空字符串并更新死键状态。
    • 接收 e 的按键事件。
    • 使用虚拟键代码(对于e)和保持死键状态的变量调用UCKeyTranlate()
      • 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);
    }
    

    【讨论】:

    • @ErikAigner 我不记得了。您是否进行了测试以确认 8 确实是正确的数量?随意编辑答案。
    【解决方案2】:

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

    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。最后的“超级”调用允许用户仍然能够正常键入所有事件

    【讨论】:

    • 有趣的是你使用-[NSEvent charactersIgnoringModifiers]——我没想过用它来捕获死键。但是,我正在寻找比您的答案更通用的解决方案。它需要适用于任何组合键和键盘布局,而不仅仅是默认美国键盘布局上的 Option-e-e。如果你能想出一种方法来相应地调整你的答案,请这样做。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多