转载请注明出处为KlayGE游戏引擎,本文的永久链接为http://www.klayge.org/?p=2344

KlayGE的输入系统从2003年完成之后,几乎就没有大的修改。谁想到在10年后的今天,输入系统几乎完全重写了。

DirectInput的缺点

原先KlayGE的输入系统只有DirectInput一个插件,基本就是简单地把DirectInput包一层,实现对键盘、鼠标和手柄的支持。在核心层,获取了设备的输入之后,经过action mapping系统,把输入转化成具体动作传给应用程序。这套系统就这么工作了很久,直到这两年触摸输入设备软硬件的发展,只支持传统输入就显得限制很大了。

即便是在键盘、鼠标上,DirectInput也不像它的名字那样direct了。根据Taking Advantage of High-Definition Mouse Movement,在系统内部,DirectInput会建立一个独立线程,读取WM_INPUT,所以用DirectInput会比直接使用WM_INPUT的开销更大。

Raw Input

既然如此,就干脆灭掉DirectInput插件,改用WM_INPUT,也就是raw input系统。这个过程在鼠标和键盘上比较顺利,按照MSDN的文档来就可以了。新的插件叫做MsgInput,表示基于消息的输入系统。代码上它比原先的简单很多,也不用和COM和各种GUID打交道。唯一需要注意的是,键盘输入会返回设备相关的scan code或者设备无关但只适用于Windows的virtual key code。为了跨平台,这里需要有一种那个转换表,把virtual key code转换成唯一的输入表示。

手柄输入就是另一回事了,MSDN几乎一句没说。在raw input系统里,除了鼠标键盘,其他设备都被抽象为HID设备。经过搜索,在codeproject上找到一个很好的文章。按照他的做法,通过调用hid.dll提供的几个函数,终于解决了问题。需要注意的是,hid提供的那些函数,在VS2010的Windows SDK 7里并没有提供.h和.lib。而VS2012的Windows SDK 8里虽然提供了hid的一系列.h,但hid.lib却不知为何链接不上,总是提示找不到入口函数。完整的hid开发支持实际上在WDK,也就是以前的DDK里。因为要编译这么个东西如果就要求装WDK液态得不偿失了,所以我选择了动态从hid.dll导入那几个函数,好在不多。同时也提供了需要的几个struct和macro的声明,以便在VS2010中使用。

遗留的问题

现在鼠标、键盘、手柄都已经可以正常工作了,但还有些小问题还没解决。比如在我的笔记本上,识别出了一个只有一个键的手柄,实际上是无线鼠标的连接器。而且在很多鼠标上,DPI返回的是0。

下一步

传统输入设备都解决之后,自然下一步就是扩展到触摸设备。第一批打算支持的触摸API有:

  • Win7+的Touch API
  • Win8+的Pointer API,包括Desktop和Metro
  • Android的输入事件