以编程方式获取物理键盘布局

4

有没有一种程序化的方法可以找出计算机使用的键盘类型(即按键位置在哪里,以及哪些额外键位于哪些位置)?

如果键盘非常不标准,则允许存在一些小错误,但通常情况下,重点是构建一个类似于屏幕键盘的应用程序,可以在屏幕上动态绘制键盘布局,并且高度精确。


你使用哪种编程语言? - Michael Berry
1
无论 Windows 使用的是什么 :) ... 解决方案是否因语言而异? - user541686
3个回答

5
当键盘连接到计算机时,它会向操作系统发送“扫描码”。在Windows上,扫描码会转换成虚拟键(键盘的硬件无关映射),然后再转换成实际字符。
Windows API的MapVirtualKeyEx()函数允许您在扫描码、虚拟键和字符之间进行转换。它还应该能够告诉您某个键是否不存在。
GetKeyboardLayout()一起使用,可以在任何时候告诉您哪个键盘处于活动状态(不同运行应用程序的键盘布局可能不同),这应该可以帮助您构建一个相当精确的键盘映射。
无论如何,请查看MSDN的键盘输入部分
我会补充一点,所有的键盘几乎都有相同的布局。虽然无法知道键位的物理位置,但你可能可以根据扫描码和对自己键盘的基本了解猜测出来。

但是这样做只能得到键盘布局的键号,对吗? 或者检索到的数字包括媒体按钮吗? - user408141

4

键盘无法告诉Windows它的物理布局。在屏幕键盘osk.exe的Windows版本中很容易看到这一点。它似乎能够猜测机器的形态因素(笔记本电脑与台式机),但在我的笔记本电脑上,它的布局与键盘不匹配。

使用osk.exe布局作为模板,这样就不会有人抱怨你的布局不匹配。


有没有没有办法,比如直接传递数据到/从驱动程序来获取这些信息? - user541686
2
不,就算是驱动程序也不在乎用户把手放在哪里。 - Hans Passant
这可能听起来有些傻,但是否有任何方法可以绕过驱动程序直接查询键盘本身?(例如SCSI通过请求的键盘等效物?) - user541686
是的,那很愚蠢。你仍然没有抓住重点,键盘控制器和驱动程序之间没有协议传递任何类似物理布局信息的东西。它只在按下键时发送一个带有扫描码号的简单字节。 - Hans Passant
嗯...有趣。不知道为什么他们没有决定标准化这个信息并让键盘报告它。感谢提供这个信息! - user541686

1

2023年更新

在Windows 10中新增了一个名为KEYBOARD_EXTENDED_ATTRIBUTES的结构体和IOCTL_KEYBOARD_QUERY_EXTENDED_ATTRIBUTES IOCTL,可以返回额外的键盘信息。

请参阅最新的HID使用表规范中的"15.18描述性控制"。这些内容来自于2013年采纳的HID使用表审查请求42:消费者页面键盘辅助控制

bool QueryInfo(const ScopedHandle& interfaceHandle)
{
    // https://docs.microsoft.com/windows/win32/api/ntddkbd/ns-ntddkbd-keyboard_extended_attributes

    KEYBOARD_EXTENDED_ATTRIBUTES extended_attributes{ KEYBOARD_EXTENDED_ATTRIBUTES_STRUCT_VERSION_1 };
    DWORD len = 0;

    if (!DeviceIoControl(interfaceHandle.get(), IOCTL_KEYBOARD_QUERY_EXTENDED_ATTRIBUTES, nullptr, 0, &extended_attributes, sizeof(extended_attributes), &len, nullptr))
        return false;

    DCHECK_EQ(len, sizeof(extended_attributes));

    FormFactor = extended_attributes.FormFactor;
    KeyType = extended_attributes.IETFLanguageTagIndex;
    PhysicalLayout = extended_attributes.PhysicalLayout;
    VendorSpecificPhysicalLayout = extended_attributes.VendorSpecificPhysicalLayout;
    IETFLanguageTagIndex = extended_attributes.IETFLanguageTagIndex;
    ImplementedInputAssistControls = extended_attributes.ImplementedInputAssistControls;

    return true;
}

但似乎这些并没有被供应商采用,我的现代罗技MX键盘在这些字段中返回零值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接