无需NSEvent,通过CoreServices将KeyCode映射为当前键盘布局对应Unicode字符
问题背景
我正在某应用中实现键盘热图功能,为保证热图与键盘布局无关,我将KeyCode与对应字符分开存储,热图将在以下视图集合上渲染:
我的需求是将KeyCode(例如标准美式Qwerty键盘上对应G的KeyCode为5)关联到正确的Unicode字符,优先渲染用户当前正在使用的键盘布局对应的字符,无对应字符时可留白。
实现方案
完全不需要逆向解析AppleKeyboardLayouts-L.dat文件,直接使用macOS原生提供的CoreServices + TextInputMenu框架API即可实现需求,核心步骤如下:
- 获取当前活跃的键盘输入源:调用
TISCopyCurrentKeyboardInputSource()获取当前用户正在使用的键盘输入源对象TISInputSourceRef - 提取键盘布局数据:调用
TISGetInputSourceProperty(inputSource, kTISPropertyUnicodeKeyLayoutData)获取对应键盘布局的二进制数据,数据结构就是标准的UCKeyboardLayout类型 - 执行KeyCode到Unicode的转换:调用CoreServices提供的
UCKeyTranslate方法完成映射,核心参数说明:- 第一个参数传入上述获取到的
UCKeyboardLayout指针 - 第二个参数传入你要转换的硬件KeyCode
- 第三个参数传入修饰键状态,无修饰键传0即可,需要展示Shift/Option等组合键字符时传入对应修饰位
- 第四个参数传入当前系统的键盘类型,可通过
LMGetKbdType()获取 - 第五个参数传入
kUCKeyTranslateNoDeadKeysMask,避免死键(例如法语布局的重音键)返回组合占位符,适配热图静态展示的场景 - 最后输出转换得到的Unicode字符数组
- 第一个参数传入上述获取到的
- 边界处理:功能键(F1-F12、修饰键、媒体键等)转换后无有效可打印字符,直接留白即可
核心代码示例(Objective-C)
#import <CoreServices/CoreServices.h> #import <Carbon/Carbon.h> NSString *getStringForKeyCode(uint16_t keyCode, UInt32 modifierFlags) { TISInputSourceRef inputSource = TISCopyCurrentKeyboardInputSource(); CFDataRef layoutData = TISGetInputSourceProperty(inputSource, kTISPropertyUnicodeKeyLayoutData); const UCKeyboardLayout *keyLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData); UInt32 deadKeyState = 0; UniChar chars[4]; UniCharCount realLength; OSStatus status = UCKeyTranslate(keyLayout, keyCode, kUCKeyActionDisplay, modifierFlags >> 16, LMGetKbdType(), kUCKeyTranslateNoDeadKeysMask, &deadKeyState, 4, &realLength, chars); CFRelease(inputSource); if (status == noErr && realLength > 0) { return [[NSString alloc] initWithCharacters:chars length:realLength]; } return nil; }
调用时如果要获取普通无修饰的字符,直接传modifierFlags = 0即可,返回nil时直接在热图上留白即可。
内容的提问来源于stack exchange,提问作者Antwan van Houdt
相关产品推荐
相关产品推荐

