在 32/64 位环境下加载键盘布局 (KbdLayerDescriptor)






4.75/5 (12投票s)
当在一个 64 位系统上以 32 位应用程序加载键盘 DLL 时,键盘 DLL 文件无法按预期工作,此类可以解决此问题。
引言
Windows 使用 kbd**.dll 文件加载键盘。当在 64 位系统上的 32 位应用程序中加载键盘时,会得到一个损坏的数组。
这个小小的技巧可以处理在 64 位系统上运行的 32 位应用程序的键盘 DLL 加载。
背景
这个问题是在我创建一个想要支持多语言的屏幕键盘时发现的。
在搜索了几个论坛后,我没有找到任何好的解决方案。DLL 导入在两个系统上是相同的,但在运行 `KbdLayerDescriptor()` 初始化后,数组实际上是损坏的。一个名为 `pVkToWcharTable` 的元素始终为 `NULL`。这个数组显示了虚拟键 (VK) 和字符之间的关联,这对于显示键盘至关重要。
在 Microsoft DDK 的 `kbd.h` 头文件中,这个指针被定义为:
#if defined(BUILD_WOW6432)
#define KBD_LONG_POINTER __ptr64
#else
#define KBD_LONG_POINTER
#endif
这在 32 位系统上运行的 32 位应用程序上效果很好,但在 64 位系统上则不然。
如果您定义 `BUILD_WOW6432` 并将应用程序编译为 64 位,程序将按预期工作。
是什么导致了这种奇怪的行为?在对该主题进行了一些研究后,我在 MSDN 上找到了 可能的原因。一个定义为 `__ptr32` 的指针在 64 位系统上会被强制转换。如果 `KbdLayerDescriptor()` 实际上使用了 `sizeof()` 和其他函数来获取长度,它可能会超出数组的范围。
我的解决方案是使用此定义创建“我自己的” 64 位变量:
#define KBD_LONG_POINTER64 __ptr64
查看 kbd64.h 文件,了解围绕此 64 位定义重命名的所有变量/函数。`kbd64.h` 只是一个重命名的 `kbd.h`,以确保自定义 64 位指针的定义。Kbd64.h 只是一个重命名的 kbd.h,以确保自定义 64 位指针的定义。
演示
包含的演示显示了如何正确初始化 DLL 和填充数组。它没有显示如何处理修饰键和死键,这不是主题的关键部分。
如果您正在研究如何处理死键或对这些“奇怪”的 kbd**.dll 文件有任何疑问,请查看 Michael Kaplan 的 Sorting it all Out 并搜索 KbdLayerDescriptor。
使用代码
CKLL 类有四个公共函数 + 一个辅助函数(来自 KLL.h)。
//Loads the DLL into the handler
BOOL LoadDLL(CString sKeyboardDll);
//Get the counts of virtual keys (VK)
USHORT GetVKCount();
//Get the char(s) linked to that VK
CString GetChar(USHORT iVK);
//Get the scan code(s) linked to that VK
CString GetSC(USHORT iVK);
//Helper: Return TRUE if 64-bit, false if 32-bit
BOOL Is64BitWindows();
如果您已经根据 Microsoft 的 `kbd.h` 头文件编写了自己的函数,那么您可以使用 kbd64.h 头文件,替换变量并将 64 添加到末尾;例如 PKBDTABLES -> PKBDTABLES64。然后,您可以使用 `Is64BitWindows()` 来检查应用程序正在运行的系统类型。
查看 `CKLL` 类中的 `Fill32()` 和 `Fill64()` 函数,以了解其工作原理。
关注点
键盘 DLL 是使用 Microsoft Keyboard Layout Creator 创建的,通过使用内置函数,您可以轻松地创建自定义 DLL,而无需任何麻烦。
扫描码 (SC) 与物理布局之间的关系非常有趣。
来源 - 将上图中的扫描码值与 `KeyboardLayout` 的结果进行比较。
有了这些知识,创建屏幕键盘并呈现您以前从未使用过的键盘语言就会容易得多。
QWERTY 范围似乎每次都能匹配,您还可以将其与 Microsoft 自己的 键盘布局 进行匹配,以确保其正确性。
反馈
如果您以不同的方式解决了这个问题,我希望在评论区听到您的反馈!
历史
v1.0 发布给公众。