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

上一篇介绍了Win7的touch和手势识别状态机。在Win8中,touch API虽然还存在,但新增了一个更方便使用的Pointer API,本篇会介绍一下它的使用。

Win8桌面的Pointer

和Win7的Touch相比,Win8的Pointer成熟得多了。它分为down、up、update等多个消息,甚至还有wheel消息。也就是说,相当于鼠标消息被完全移植过来了,并加入了触点ID。所以可以和容易地把原先处理鼠标消息的经验和代码都转移到WM_POINTER的系列消息来。在功能上还胜过Touch的一点在于,Pointer不光支持触摸屏,还支持鼠标、电子笔等多种设备,并可以返回之前n帧的历史坐标。目前KlayGE并没有用那些功能,仍是把几个基本的消息转到一个经过抽象平台无关的数据结构上。

需要注意的是,在Win8桌面上,鼠标消息默认是不转到Pointer消息的,需要调用EnableMouseInPointer(true)之后才会。另一个需要注意的是,触点ID的顺序是从1开始的,而不是0。这样在只有wheel而没有触点的情况下也不会误认一个触点。

Win8 Metro的Pointer

Metro下的Pointer和桌面的几乎完全相同,只是消息参数的风格不同而已。所以要兼容Metro相当轻松。有个显现相反的地方是,鼠标消息默认会转到Pointer,除非调用了EnableMouseInPointer(false)才能关闭。

Android上的触摸支持

Android NDK上的输入也很简单,只要给android_app的onInputEvent绑个处理函数就可以了。在一些细节上,Android的输入系统逻辑是比较奇怪的,估计是因为需要兼容高低各种配置的原因。

首先是多触点的发送。up和down的消息里,每个消息只会有一个触点,触点ID包含在AMotionEvent_getAction的返回值里。而move消息则会包含多个触点,个数在AMotionEvent_getPointerCount的返回值里,需要循环一次获取所有触点。

第二个奇怪的地方是网友ForthBlue提到的。在只支持单触摸的时代,触摸的消息有AMOTION_EVENT_ACTION_DOWN和AMOTION_EVENT_ACTION_UP,触点ID永远是0。后来到了多触摸时代,又增加了AMOTION_EVENT_ACTION_POINTER_DOWN和AMOTION_EVENT_ACTION_POINTER_UP这两个消息,触点ID可以不是0。但是,Android的逻辑是如果只有一个点被触摸,就发送ACTION_DOWN/UP,否则才发送ACTION_POINTER_DOWN/UP。那么如果有这么一个触摸序列:触点0按下、触点1按下、触点0抬起、触点1抬起,程序收到的消息会是:ACTION_DOWN、ACTION_POINTER_DOWN 1、ACTION_POINTER_UP 0、ACTION_UP。前三个都没问题,但最后一个消息出发的时候只有一个触点(虽然是触点1),只会发送触点ID是0的ACTION_UP。所以这里需要程序自己跟踪最后抬起的到底是那个触点。

由此,KlayGE的输入系统也第一次完成了跨平台。而且,不论在Win7、Win8桌面、Win8 Metro还是Android上,触摸部分虽然不同,但由于有一层抽象,手势识别可以共享同样的状态机,代码复用率很高。