getkeyboardlayout 返回线程当前输入法上下文(hkl),非系统默认布局;真正默认值需查注册表 hkey_current_user\keyboard layout\preload\1;linux 应优先用 d-bus 或 gsettings,而非 setxkbmap;跨平台无统一方案,须按平台条件编译。

Windows 下用 GetKeyboardLayout 只能拿到线程当前布局句柄,不是“系统默认布局”
很多人以为调用 GetKeyboardLayout(0) 就能读出系统设置的默认键盘布局,其实它返回的是**调用线程关联的输入法上下文(HKL)**,和控制面板里设的“默认布局”不是一回事。比如用户切换过输入法、开了多个窗口、甚至只是焦点在中文输入法框里,GetKeyboardLayout 就可能返回 0x08040804(中文),哪怕系统默认是美式键盘。
- 真正反映“系统默认”的是注册表项:
HKEY_CURRENT_USER\Keyboard Layout\Preload\1,值为类似"00000409"的十六进制字符串(0x0409= 美式英语) -
GetKeyboardLayout适合做实时输入处理(比如判断当前按键是否应被拦截),不适合配置同步或初始化判断 - 如果线程没显式调用过
ActivateKeyboardLayout,它通常继承自创建它的线程,行为更难预测
Linux 下不能靠 setxkbmap 命令反查当前布局
setxkbmap -query 看起来像能读布局,但它查的是 X11 服务器当前的 xkb 配置状态,而这个状态可能被任意客户端(比如桌面环境、ibus、fcitx)随时修改,且不保证与系统级设置一致。更麻烦的是:Wayland 会直接忽略 setxkbmap,命令执行成功但什么也不改。
- 可靠来源是
/etc/default/keyboard(Debian/Ubuntu)或/etc/vconsole.conf(systemd 控制台),但这些只管开机默认,不反映用户会话中动态切换的结果 - 对图形应用,建议用 X11 的
XGetKeyboardControl+XkbGetState(需链接-lX11 -lXkbfile),或 D-Bus 查询桌面环境接口(如 GNOME 的org.gnome.desktop.input-sources) - 别在子进程里反复跑
setxkbmap -query | grep layout—— 慢、易受竞态影响、无法区分用户级 vs 系统级设置
跨平台统一读取几乎不存在,别试图封装一个“通用函数”
Windows 注册表路径、Linux 的 systemd 键盘配置、macOS 的 defaults read -g AppleSelectedInputSource,三者语义不同、权限不同、更新时机也不同。强行抽象成 get_system_keyboard_layout(),只会让逻辑在某个平台永远返回错值。
- Windows:读
HKEY_CURRENT_USER\Keyboard Layout\Substitutes和Preload,再查HKLM\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\{guid}解析名称 - Linux 图形环境:优先走 D-Bus(如
org.freedesktop.portal.InputSources),fallback 到gsettings get org.gnome.desktop.input-sources sources - Linux 终端:看
localectl status输出,但注意它不反映 X11/Wayland 会话中的切换 - C++ 里做这事,建议按 target platform 分条件编译,而不是 runtime 判断 OS 名
最常被忽略的点:布局 ≠ 输入法,也 ≠ 字符映射
用户看到“美式键盘”,实际可能是 US QWERTY,也可能是 US International(带死键),还可能是 Colemak。而中文用户即使布局是 0x0409,输入法引擎(如搜狗、fcitx5)仍可把 A 映射成“啊”。GetKeyboardLayout 或 setxkbmap 都不告诉你当前激活的是哪个输入法引擎。
立即学习“C++免费学习笔记(深入)”;
- 如果你真正想解决的是“为什么用户按 Y 出来的是 Z”,那问题大概率不在布局,而在 XKB rules / symbols 文件或输入法的按键重映射表
- 调试时先确认是全局布局生效了(比如 CapsLock 行为变了),还是仅特定应用内异常(那八成是应用自己 hook 了 WM_KEYDOWN 或 X11 KeyPress)
- 没有“键盘布局 ID 到可读名称”的标准映射表;Windows 的
LoadKeyboardLayout名称、Linux 的 xkb rules 名称、macOS 的 input source identifier 全部不兼容










