使用 Windows 键盘 DLL 的多语言屏幕键盘





5.00/5 (13投票s)
Windows 内置支持许多键盘语言,此类使我们能够以简单的方式提取该信息并将其呈现到屏幕上。
- 下载 OnScreenKeyboard.zip - 267 KB
- 下载 ConsoleKeyboard.zip - 55.6 KB
- 下载 CKLL_-_MFC.zip - 51.1 KB
- 下载 CKLL_-_Non_MFC.zip - 43.8 KB
引言
这个多语言屏幕键盘是“懒惰”的结果,不想重复造轮子。它读取 Windows 目录中所有可用的键盘布局,并以类似 Apple / Android / Windows 8 的外观呈现布局。死键呈黄色,显示在单独的一行上,并显示所有可用按键。
该键盘已在 Windows XP / 2003 服务器 / Vista / 7 / 2008 服务器 / 8 上进行了测试,所有操作系统似乎都能按预期工作。
背景
我最初的开始是手动创建自己的键盘映射,逐一处理每种语言,使用 Microsoft 屏幕键盘。在我开始制作第三个键盘映射后,我感到厌倦,并开始寻找读取现有布局的解决方案。
在我的探索过程中,我发现了在 x86/x64 系统上加载键盘时的一个 bug,解决方案可以在此处找到。此应用程序中使用了相同的技术。解决方案是两个不同的 kbd.h 版本,一个用于 x86,一个用于 x64。我想知道是什么导致了这个问题,所以我联系了 Microsoft 键盘专家 Michael Kaplan,但他的回答是否定的,因为这是“未文档化的”。他的反对使我更加坚持要完成这个项目,我们在这里 。另一位聪明的家伙“kwhat”提出了一个解决方案,更清晰地展示了 x86/x64 位移位,他的代码也可与 GNU Compiler Collection (GCC) 一起使用。
(注意:如果您知道任何获取键盘布局的好 API,请分享。我正在寻找提取扫描码 + 字符关系的实现/API/函数;请在下方评论您的解决方案!)
扫描码
扫描码是键盘上按键的实际物理参考,一个十六进制数字。请看图片以获得概览,英文布局使用 0x10 作为“q”键,0x11 是“w”,0x1E 是“a”,依此类推……
此类完成的主要工作是整理所有字符并将它们链接到正确的扫描码。如维基中所述,有三个不同的扫描码寄存器,Microsoft 使用集 1;IBM PC XT。
使用代码
代码分为加载键盘布局和呈现键盘布局。
加载键盘 DLL
有一个类负责加载 DLL 布局;CKLL
(键盘布局加载器)。LoadDLL
函数加载键盘布局,然后使用 GetCharFromSC
函数根据扫描码和键盘状态检索 VK_CHAR
。返回的变量是
struct VK_CHAR
{
WCHAR wChar; //Actual char
OSKState nState; //Which state it are in
BOOL bDead; //Dead key
};
键盘状态是常见修饰符的变体。
enum OSK_KEYBOARD_STATES
{
Normal, //000
Shift, //001
Alt, //010
ShiftAlt, //011
Ctrl, //100
ShiftCtrl, //101
CtrlAlt, //110
ShiftCtrlAlt, //111
};
每个键盘布局 DLL 都有一个文件描述,使其对布局有一个合理的描述。可以通过调用 GetKeyboardName()
(仅在 MFC 版本中可用)来检索此信息。
演示
呈现由一个名为 CKeyboardStatic
的 CStatic
派生类完成。它有一个名为 CKeyButton
的子类,其中包含每个带有扫描码、字符和状态的字符。按键的位置与数组 OSKScanCodes
相关联,在此版本中使用了标准的 qwerty 布局。更改此表将直接影响呈现。
const char OSKScanCodes[4][13] = {
{0x29, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D},
{0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x00},
{0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x2B, 0x00},
{0x56, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x00, 0x00}
};
不同的呈现只是为了好玩 。下图显示了呈现的变化,键盘的功能在这三个中是相同的。
通过使用 GDI+,可以使用 AA 和 ARGB 着色创建外观精美的图形,这就是这里使用的技术。Apple 风格需要大量的绘制才能复制,但它确实看起来是这三者中最好的(在我看来……)CKeyboardStatic
具有这些公共函数,阅读其描述的注释。
void Clear(); //Resets the static from all keys
BOOL SetKey(...); //Adds a character linked to a scan code + deadkey info
void SetKeyboardState(...); //Sets the state the keyboard are in
OSKState GetKeyboardState(...); //Returns the state the keyboard are in
void SetKeyboardPresentation(...);
//Sets the presentation of the static; Apple, Android or Windows 8
使用 CKLL
类,您可以通过 SetKey()
链接到“物理”按键来设置扫描码 + 字符,基于 OSKScanCodes
数组。SetKeyboardPresentation()
根据 OSK_KEYBOARD_STATES
数组的值更改字符。SetKeyboardLayout()
更改键盘的呈现。
MFC 或不 MFC
CKLL
类有两种风格,一种是 MFC 版本,一种是不带 MFC 的版本。无 MFC 的 CKLL
使用基于向量的数组来跟踪扫描码和字符,而不是 CPtrArray
。CKeyboardStatic
是纯 MFC,不易转换为其他类型。项目“ConsoleKeyboard”是一个纯 Win32 控制台应用程序,CKLL
之间的字符串处理已更改为 wstring
(用于此修改)。它的目的是展示呈现键盘所需的代码量很少。请参阅下图的结果。
您必须将控制台字体更改为支持 Unicode 的字体,选择 Lucida Console 或 Consolas。右键单击标题栏并选择“属性”进行更改。获取此呈现的源代码很简单(为便于阅读,已剥离错误处理的代码)。
int _tmain(int argc, _TCHAR* argv[])
{
//Set unicode mode
_setmode(_fileno(stdout), _O_U16TEXT);
//Load the keyboard-dll
CKLL m_kll;
m_kll.LoadDLL(argv[1]);
//Set our state to "Normal"
OSKState nState = OSK::Normal;
wprintf(L"\n");
//Loop through each row
for(int nRow = 0; nRow < ( sizeof(OSK::OSKScanCodes) /
sizeof(OSK::OSKScanCodes[0]) ) ; nRow++)
{
wprintf(L"-----------------------------------------------------\n");
//Loop through each scan code in that row
for(int nScanCode = 0; nScanCode < (sizeof(OSK::OSKScanCodes[0]) /
sizeof(OSK::OSKScanCodes[0][0])); nScanCode++)
{
//The non 0x00 are actually keys
if(OSK::OSKScanCodes[nRow][nScanCode] != 0x00)
{
CKLL::VK_CHAR aChar;
if(m_kll.GetCharFromSC(OSK::OSKScanCodes[nRow][nScanCode], nState, aChar))
wprintf(L"| %c ", aChar.wChar);
}
}
wprintf(L"|\n");
}
wprintf(L"-----------------------------------------------------\n");
return 0;
}
通过使用 CKLL
类,您可以轻松地为 Windows 中的 OpenGL、QT 或任何其他实现制作多语言屏幕键盘。
问题
大多数布局尚未得到确认,坦率地说,我并不“理解”所有这些布局。请花时间检查您日常使用的键盘布局,看看按键是否位于正常位置。键盘不显示修饰键和功能键,如 shift、control、enter、space、tab 等。我没有花时间包含这些,所以请将此呈现视为概念验证。在某些布局中,方框被显示为字符,这通常**不是** Unicode 字符,这尚未处理。这可能会在未来版本中修复。Microsoft 键盘 DLL 可能包含多个布局,此类仅处理我们找到的第一个项目。
历史
- v1.00 - 首次公开发布。