问题:
学习如何创建自己的输入/输出系统需要哪些资源?
我自己的理解:
我知道它依赖于操作系统,所以让我们分开Linux和Windows并列出两个操作系统的资源(如果可能的话)。对于Linux,我猜测需要对X Window系统有一定的了解。对于Windows,我猜测win32
API。尽管如此,我猜测还有更多内容,而不仅仅是知道这些,好像我希望用C ++编写输入系统。
提问的理由:
我尝试阅读OIS
源代码(因为这将用C
或C++
编写),并且不喜欢它的编写方式。因此,我自己学会了如何编写自己的键盘输入/输出系统来进行简单的乒乓球游戏(用C++
编写)。
答案 0 :(得分:37)
更新:这是我为处理键盘输入而编写的库。它使用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上,如果按最左侧的主行键,则会得到代码4。
Linux有几组不同的密钥代码。所以在Linux上,你有几个选择。你可以使用关键的syms(它有我将在下面解释的缺点),你可以假设用户正在使用特定的输入驱动程序(Evdev这些天是非常好猜测),或者你可以以某种方式弄清楚机器使用哪个输入驱动程序。要获取密钥代码,您必须阅读键盘定义文件。例如,查看/usr/share/X11/xkb/keycodes/evdev
以获取Evdev密钥代码。使用Evdev,如果按最左侧的主行键,则会得到代码38。
当然,如果关键代码在不同平台上相同,那就太容易了。您可以使用特定于平台的密钥代码,也可以将其转换为与平台无关的值。我建议使用USB HID代码(pdf)作为与平台无关的代码,因为许多聪明的人已经遇到了同意每个密钥调用的麻烦。
我上面发布的库包含每个平台的表格,例如WIN_NATIVE_TO_HID
,用于将密钥代码转换为USB HID代码。
困难的部分是向用户传达他们应该按什么按钮,但至少来自其他国家的人可以玩你的游戏。
您不想使用字符代码,即使您居住在美国并且您的受众也居住在美国,它们也更容易使用。
将按钮翻译成按键代码后,操作系统会将密钥代码转换为字符代码。字符代码受当前键盘布局的影响,并且通常也会受到修改键的影响。
因此,如果您按键盘上的 A ,您将获得键码65,4或38,具体取决于您所使用的平台。但是,您将获得字符代码'a'
或'A'
,具体取决于shift键是否已关闭,或者如果键盘布局设置为法语,则可能会获得'Q'
,或{{1如果键盘布局设置为俄语。因此,如果您将WASD编码到游戏中并使用字符代码,当来自其他国家/地区的某人玩您的游戏时,输入将完全被破坏。你必须在法国使用ZQSD,在俄罗斯使用ÖФЫВ,很快你就会头疼。
我自己使用非QWERTY布局(Dvorak),大多数游戏都完全被打破了。在 W 键的位置是,,如果您按下shift键,则变为&lt; ,并且某些游戏无法识别那同样的关键。例如,我按,向前移动,但是如果我在Shift键关闭时释放按钮,则游戏会认为我已经释放了&lt; 并认为,仍在下降,所以我继续前进。即使我切换到美国键盘布局(我认为这是SDL中的一个小故障),大多数使用SDL的游戏都会在我的Mac上被打破。
SDL 2.0提供与平台无关的密钥代码,称为扫描代码。使用'Ф'
标题。 SDL开发人员得出的结论是扫描代码应该转换回USB HID代码,因此SDL扫描代码与我上面发布的库完全兼容(参见keycode.h和SDL_scancode.h,数值相同)。
由于这个原因和其他原因,如果您使用的是SDL 1.2,我强烈建议您升级到2.0。
答案 1 :(得分:0)
以下内容仅与在Windows上处理输入有关。
正如capr在对Dietrich Epp的答案的评论中所提到的那样,VK_代码会根据您所使用的键盘布局的语言而变化。因此,如果您的键盘布局是法语,并且您在QWERTY键盘上按“ Q”,则将产生“ A”的虚拟键。如果您的布局是例如在美国,按预期方式生成了“ 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/