如果我需要为看起来像他/她的键盘的用户生成键盘布局以自定义,我该怎么做?

例如这样的事情:

enter image description here

法语,瑞典语,英语,加拿大人等将有不同的布局。这是很多工作,还是仅使用某种内置的.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是相同的;如果您按下 - 钥匙你按 - 关键不管在哪里 - 钥匙已找到。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top