是否可以创建与所使用的键盘相同的键盘布局?
-
26-10-2019 - |
题
如果我需要为看起来像他/她的键盘的用户生成键盘布局以自定义,我该怎么做?
例如这样的事情:
法语,瑞典语,英语,加拿大人等将有不同的布局。这是很多工作,还是仅使用某种内置的.NET区域课程?
解决方案
键按生成硬件事件,该事件向Windows操作系统报告“扫描代码”。然后,此扫描代码将基于扫描代码以及其他键盘状态因素转换为“虚拟键代码”(大写锁定 状态, 转移/alt/Ctrl KeyState,以及任何未决的死钥匙中风)。转换后的VK值是由 KeyDown
事件等
从扫描代码到VK代码的转换取决于当前输入语言环境 - 简单地,输入语言环境定义了扫描代码和虚拟键代码之间的映射。看 MSDN文档 有关键盘输入的完整说明。
通过逆转此查找过程,可以确定与每个虚拟密钥代码相对应的扫描代码(当然,由于Shift/Ctrl/Alt状态等,相同的扫描代码将映射到多个VK代码)。 Win32 API提供了 MapVirtualKeyEx
通过使用 MAPVK_VK_TO_VSC_EX
选项。您可以使用它来确定哪个扫描代码生成特定的VK代码。
不幸的是,这是您可以通过编程方式进行的 - 无法确定键盘的物理布局或每个扫描代码的键位置。但是,大多数物理键盘都以相同的方式接线,因此(例如)左上角键在大多数物理键盘设计上都具有相同的扫描代码。您可以使用此假定的约定来推断与扫描代码相对应的物理位置,具体取决于基本的物理键盘布局(101键,102键等)。不能保证,但这是一个非常安全的猜测。
以下代码是我编写的较大键盘处理库的摘录(我一直打算开源但没有时间)。该方法初始化一个数组(this._virtualKeyScanCodes
)由给定输入语言环境的VK代码索引(存储在 this._inputLanguage
被称为 System.Windows.Forms.InputLanguage
. 。您可以使用数组来通过检查EG来确定与VK代码相对应的扫描代码 this._virtualKeyScanCodes[VK_NUMPAD0]
- 如果扫描代码为零,则该VK在当前输入语言环境中的键盘上不可用;如果不是零,则可以从中推断出物理密钥的扫描代码。
不幸的是,当您进入死键的领域时,事情比这要复杂得多(例如,产生重音字符的多个钥匙组合)。这一切都太复杂了,无法现在进入,但是迈克尔·卡普兰(Michael S. 博客文章 如果您想进一步探索。祝你好运!
private void Initialize()
{
this._virtualKeyScanCodes = new uint[MaxVirtualKeys];
// Scroll through the Scan Code (SC) values and get the Virtual Key (VK)
// values in it. Then, store the SC in each valid VK so it can act as both a
// flag that the VK is valid, and it can store the SC value.
for (uint scanCode = 0x01; scanCode <= 0xff; scanCode++)
{
uint virtualKeyCode = NativeMethods.MapVirtualKeyEx(
scanCode,
NativeMethods.MAPVK_VSC_TO_VK,
this._inputLanguage.Handle);
if (virtualKeyCode != 0)
{
this._virtualKeyScanCodes[virtualKeyCode] = scanCode;
}
}
// Add the special keys that do not get added from the code above
for (KeysEx ke = KeysEx.VK_NUMPAD0; ke <= KeysEx.VK_NUMPAD9; ke++)
{
this._virtualKeyScanCodes[(uint)ke] = NativeMethods.MapVirtualKeyEx(
(uint)ke,
NativeMethods.MAPVK_VK_TO_VSC,
this._inputLanguage.Handle);
}
this._virtualKeyScanCodes[(uint)KeysEx.VK_DECIMAL] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_DECIMAL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
this._virtualKeyScanCodes[(uint)KeysEx.VK_DIVIDE] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_DIVIDE, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
this._virtualKeyScanCodes[(uint)KeysEx.VK_CANCEL] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_CANCEL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
this._virtualKeyScanCodes[(uint)KeysEx.VK_LSHIFT] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_LSHIFT, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
this._virtualKeyScanCodes[(uint)KeysEx.VK_RSHIFT] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_RSHIFT, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
this._virtualKeyScanCodes[(uint)KeysEx.VK_LCONTROL] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_LCONTROL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
this._virtualKeyScanCodes[(uint)KeysEx.VK_RCONTROL] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_RCONTROL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
this._virtualKeyScanCodes[(uint)KeysEx.VK_LMENU] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_LMENU, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
this._virtualKeyScanCodes[(uint)KeysEx.VK_RMENU] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_RMENU, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
this._virtualKeyScanCodes[(uint)KeysEx.VK_LWIN] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_LWIN, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
this._virtualKeyScanCodes[(uint)KeysEx.VK_RWIN] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_RWIN, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
this._virtualKeyScanCodes[(uint)KeysEx.VK_PAUSE] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_PAUSE, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
this._virtualKeyScanCodes[(uint)KeysEx.VK_VOLUME_UP] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_VOLUME_UP, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
this._virtualKeyScanCodes[(uint)KeysEx.VK_VOLUME_DOWN] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_VOLUME_DOWN, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
this._virtualKeyScanCodes[(uint)KeysEx.VK_VOLUME_MUTE] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_VOLUME_MUTE, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_NEXT_TRACK] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_MEDIA_NEXT_TRACK, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_PREV_TRACK] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_MEDIA_PREV_TRACK, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_PLAY_PAUSE] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_MEDIA_PLAY_PAUSE, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_STOP] =
NativeMethods.MapVirtualKeyEx(
(uint)KeysEx.VK_MEDIA_STOP, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
this._stateController = new KeyboardStateController();
this._baseVirtualKeyTable = new VirtualKeyTable(this);
}
编辑:另请参阅 这个问题 这与您的相似。
其他提示
没有包含键盘布局的内置.NET类。键盘布局是操作系统(通常是Windows)的函数。到了.NET参与时,按键已从硬件事件转换为软件。如果您想查看此操作,请找到2个键盘布局,其中键在它们之间移动。设置带有事件处理程序的虚拟应用程序 Key_Down
事件,然后注意事件ARGS是相同的;如果您按下 - 钥匙你按 - 关键不管在哪里 - 钥匙已找到。