【问题标题】:Rolling One's Own Keyboard/Input system in C/C++在 C/C++ 中滚动自己的键盘/输入系统
【发布时间】:2012-02-02 23:39:54
【问题描述】:

问题:

学习如何创建自己的输入/输出系统需要什么样的资源?

我自己的理解:

我知道它非常依赖于操作系统,所以让我们将 Linux 和 Windows 分开,并列出这两个操作系统的资源(如果可能的话)。对于 Linux,我猜需要对 X Window 系统有一定的了解。对于 Windows,我猜是 win32 API。不过,我猜想它不仅仅是知道这些,可能我宁愿用 C++ 编写输入系统。

询问原因:

我尝试阅读OIS 源代码(因为它将以CC++ 编写),只是不喜欢它的编写方式。因此,我开始自己学习如何为一个简单的乒乓球游戏编写自己的键盘输入/输出系统(写在C++)。

【问题讨论】:

    标签: c++ c winapi visual-c++ keyboard


    【解决方案1】:

    以下内容仅与在 Windows 上处理输入有关。

    正如 capr 在对 Dietrich Epp 的回答的评论中提到的那样,VK_ 代码会根据您使用的键盘布局的语言而变化。因此,如果您的键盘布局是法语并且您在 QWERTY 键盘上按“Q”,则会生成“A”的虚拟键。如果您的布局是例如zh-CN,“Q”的虚拟键按预期生成。

    由于实际的扫描代码依赖于硬件(因此不可用),因此我通过将生成的扫描代码转换为对应于 en-US 键盘布局的虚拟键来绕过布局依赖的问题。然后可以按照 Dietrich Epp 描述的方式将其转换为 USB HID 代码。无论布局的语言如何,这都会产生相同的预期 USB HID 代码。

    将扫码翻译成en-US的VK的方法,

    // Get and store the name of the currently used locale
    wchar_t defaultLayoutName[KL_NAMELENGTH];
    GetKeyboardLayoutName(defaultLayoutName)
    
    // Load and store a handle to the locale for en-US ("00000409")
    HKL defaultEnUSInputLocale = LoadKeyboardLayout(TEXT("00000409"), KLF_NOTELLSHELL);
    
    // Load the locale that was in use before so as not to change the keyboard layout of the user
    LoadKeyboardLayout(defaultLayoutName, KLF_ACTIVATE);
    
    --- (at windowProc) ---
    case WM_INPUT:
        // Use the handle to the en-US locale to translate the scan codes to VK_.
        virtualKey = MapVirtualKeyExW(scanCode, MAPVK_VSC_TO_VK_EX, defaultEnUSInputLocale);
    
        // translate virtualKey to USB HID by using e.g. the codes supplied by Dietrich Epp
        int8_t usbHIDkey = VK_TO_HID[virtualKey];
    

    请注意,在 Windows 上还有一些与虚拟键相关的额外障碍。我发现这个网站对这件事有很好的帮助:https://blog.molecular-matters.com/2011/09/05/properly-handling-keyboard-input/

    【讨论】:

      【解决方案2】:

      更新:这是我编写的用于处理键盘输入的库。它使用 FreeBSD 许可证。我什至把它标记为v1.0,所以我认为它是“发布质量”。

      https://github.com/depp/keycode

      我最近非常努力地让这款游戏“恰到好处”,但我还没有完成。我会分享我所知道的。

      键码

      对于游戏,键码通常是你想要的。

      当您按下键盘上的某个键时,操作系统首先将按下的按钮转换为键码。键码指定键盘上键的物理位置。例如,代码 4 可能对应于美国键盘上标记为 A 的键(即使该键在法国或俄罗斯具有不同的标签)。每个平台都有一组不同的密钥代码,或者可能有多组。您可能通过不同的名称来认识它们,例如扫描码虚拟键码

      • Windows 使用虚拟键代码 (MSDN documentation)。它们在各种硬件和软件配置中都很稳定。您可以在 <Winuser.h> 头文件中找到定义。在 Windows 上,如果您按最左侧的主行键(美国为 A,法国为 Q),您将获得代码 65。

      • Mac OS X 的键码自 80 年代以来就一直稳定。它们在<Carbon/Events.h> 中定义。您实际上不需要链接到 Carbon 来使用密钥代码,但您需要标题。在 OS X 上,如果你按下最左边的 home 行键,你会得到代码 4。

      • Linux 有几组不同的关键代码。所以在 Linux 上,你有几个选择。您可以使用 key syms(我将在下面解释它的缺点),您可以假设用户正在使用特定的输入驱动程序(如今 Evdev 是一个非常的好猜测),或者你可以以某种方式找出机器使用的输入驱动程序。为了获得键码,您必须阅读键盘定义文件。例如,查看 /usr/share/X11/xkb/keycodes/evdev 获取 Evdev 密钥代码。使用 Evdev,如果您按最左边的 home 行键,您会得到代码 38。

      当然,如果跨平台的关键代码相同,那就太容易了。您可以使用特定于平台的密钥代码或将其转换为与平台无关的值。我建议使用 USB HID 代码 (pdf) 作为独立于平台的代码,因为许多聪明人已经就每个键的调用方式达成了一致。

      我在上面发布的库有每个平台的表格,例如WIN_NATIVE_TO_HID,用于将密钥代码转换为 USB HID 代码。

      困难的部分是告诉用户他们应该按下哪个按钮,但至少其他国家的人可以玩你的游戏。

      字符代码

      您不想使用字符代码,即使如果您居住在美国并且您的受众也居住在美国,它们更容易使用。

      在将按键转换为按键代码后,操作系统将按键代码转换为字符代码。字符代码受当前键盘布局的影响,通常也受修饰键的影响。

      因此,如果您按键盘上的 A,您将获得 65、4 或 38 键码,具体取决于您使用的平台。但是你会得到字符代码'a''A',这取决于shift键是否按下,或者如果键盘布局设置为法语,你可能会得到'Q',或者如果键盘布局设置为'Ф'到俄语。因此,如果您将 WASD 编码到您的游戏中并使用字符代码,那么当来自另一个国家的人玩您的游戏时,输入将完全被破坏。你必须在法国使用 ZQSD,在俄罗斯使用 ЦФЫВ,很快你就会头疼。

      我自己使用非 QWERTY 布局 (Dvorak),大多数游戏都被彻底破坏了。 W 键的位置是 ,,如果您按下 shift 键,则变为 ,并且某些游戏无法识别作为同一个键。例如,我会按 , 向前移动,但如果我在按下 shift 键时松开按钮,游戏会认为我已经松开了 并认为 , 仍然下降,所以我会继续前进。即使我切换到美式键盘布局,大多数使用 SDL 的游戏在 Mac 上都会损坏(我认为这是 SDL 中的一个小故障)。

      LibSDL

      SDL 2.0 提供独立于平台的键码,称为扫描码。使用 "SDL_scancode.h" 标头。 SDL 开发人员得出了相同的结论,即扫描码应转换回 USB HID 码,因此 SDL 扫描码与我上面发布的库完全兼容(参见keycode.hSDL_scancode.h,数值相同)。

      出于这个和其他原因,如果您使用的是 SDL 1.2,我强烈建议您升级到 2.0。

      【讨论】:

      • 我在问题中收到的最佳答案之一。您应该得到的不仅仅是 +1 和接受。不幸的是,这就是我所能给予的。
      • 实际上这个答案对于 Windows 是错误的,VK_ 代码是独立于硬件的,但它们不是独立于布局的,尝试将布局切换为法语,看看 VK_Q 响应的键。 Windows需要用到的是扫码。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-27
      • 2013-04-20
      • 1970-01-01
      相关资源
      最近更新 更多