You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt在Mac平台下如何将虚拟键码转换为对应键盘Unicode字符

问题原因

你现在的转换逻辑失效是必然的,核心问题有三个:

  1. 接口适用范围不对:UCKeyTranslate配合kTISPropertyUnicodeKeyLayoutData只能读取纯键盘布局的映射表,日文Kana、韩文2Set这类带输入法转换逻辑的输入源,根本不会把键位映射存在这个属性里,你拿到的要么是空值要么是底层基础键盘的布局,自然出不来「つ」「ㅋ」这类字符。
  2. 代码有硬bug:修饰键映射写反了——Qt::MetaModifier对应Mac的Command键(cmdKey),Qt::ControlModifier才对应controlKey,你现在的映射关系是错的;另外UCKeyTranslate的字符缓冲区只开了1个UniChar长度,遇到需要UTF-16代理对的字符直接内存溢出;还有Copy出来的TISInputSourceRef没释放,会长期内存泄漏。
  3. 事件时机不对:你在QEvent::ShortcutOverride事件里做转换,这个事件触发在输入法逻辑执行之前,日文、韩文输入法的键位转换、候选词处理根本还没跑,就算接口对也拿不到最终输出的字符。

另外你自己打日志的时候其实已经拿到正确值了:日文场景下Key=12388就是「つ」的Unicode编码,韩文场景下Key=12619就是「ㅋ」的Unicode编码,根本不需要再拿nativeVirtualKey二次转换。

正确实现方式

优先直接用Qt自带的keyEvent->text()取值,这是Qt对接完系统输入法、所有键盘布局之后返回的最终字符,不管是哪国布局、哪种输入法都能拿到正确结果,完全没必要自己重复实现键码转换逻辑。
如果确实有脱离按键事件、主动转换虚拟键码的需求,分场景处理:

纯键盘布局场景(美式、瑞士德语这类无输入法的布局)

修正原有ConvertKeyCodeToText的bug即可,修正后代码:

std::pair<bool, std::string> ConvertKeyCodeToText(int mac_key_code, Qt::KeyboardModifiers qt_modifiers) {
    TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
    CFDataRef layout_data = static_cast<CFDataRef>(TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData));
    if (!layout_data) {
        CFRelease(currentKeyboard);
        return {false, ""};
    }
    const UCKeyboardLayout *keyboard_layout = (const UCKeyboardLayout *)CFDataGetBytePtr(layout_data);
    
    UInt32 mac_modifiers = 0;
    // 修正之前写反的修饰键映射
    if (qt_modifiers & Qt::ShiftModifier)
        mac_modifiers |= shiftKey;
    if (qt_modifiers & Qt::ControlModifier)
        mac_modifiers |= controlKey;
    if (qt_modifiers & Qt::AltModifier)
        mac_modifiers |= optionKey;
    if (qt_modifiers & Qt::MetaModifier)
        mac_modifiers |= cmdKey;
    
    UInt32 modifier_key_state = (mac_modifiers >> 8) & 0xFF;
    UInt32 dead_key_state = 0;
    UniCharCount char_count = 0;
    // 缓冲区开4位长度,兼容UTF-16代理对、多字符输出
    UniChar characters[4] = {0};
    
    OSStatus status = UCKeyTranslate(
        keyboard_layout,
        static_cast<UInt16>(mac_key_code),
        kUCKeyActionDown,
        modifier_key_state,
        LMGetKbdLast(),
        kUCKeyTranslateNoDeadKeysBit,
        &dead_key_state,
        4,
        &char_count,
        characters
    );

    bool is_dead_key = false;
    if (status == noErr && char_count == 0 && dead_key_state != 0) {
        is_dead_key = true;
        dead_key_state = 0;
        status = UCKeyTranslate(
            keyboard_layout,
            static_cast<UInt16>(mac_key_code),
            kUCKeyActionDown,
            modifier_key_state,
            LMGetKbdLast(),
            kUCKeyTranslateNoDeadKeysBit,
            &dead_key_state,
            4,
            &char_count,
            characters
        );
    }
    CFRelease(currentKeyboard);

    if (status == noErr && char_count > 0) {
        QString res = QString::fromUtf16(characters, char_count);
        if (!res.isEmpty() && !res.at(0).isPrint()) {
            return {is_dead_key, ""};
        }
        return {is_dead_key, res.toStdString()};
    }
    return {false, ""};
}

输入法类场景(日文、韩文、中文输入法)

别尝试用UCKeyTranslate做转换,这个系统接口本身就不支持输入法级别的键位映射。正确做法是监听QEvent::KeyPress事件,这个事件触发时输入法逻辑已经执行完毕,直接读keyEvent->text()就能拿到正确的输出字符,不需要做任何额外转换。

其他问题

你写的g_nativeKeycode函数里同样存在修饰键映射写反的问题,而且在输入法激活场景下,反向从Qt::Key查询虚拟键码的逻辑也会失效,这类场景直接用Qt提供的标准接口即可,不要自己手动解析系统的键盘布局结构,后续系统版本更新很容易出现兼容性问题。

内容的提问来源于stack exchange,提问作者Xenius

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 04:54:24