J2ME中的按键处理

MIDP1.0中的按键处理是用keyPressed、keyReleased、keyRepeated几个回调函数来实现的。这样的处理有2个缺
点:1,不支持多按键同时按下的处理(这个是MIDP1.0标准本身的缺陷),这对于很多动作复杂的游戏是非常致命的限制。2,由于程序的UI使用同一个
线程,这样在同一时刻按键处理和paint刷屏动作只能执行其一,而很多情况下在按键处理的同时都会引起较长较复杂的逻辑处理。

在MIDP2.0里,我们可以摆脱这样的限制。它提供了新的GameCanvas,支持新的按键处理模式:按键状态字。

先使用一个GameCanvas,构造函数参数suppressKeyEvents表示是否抑止keyPressed等按键事件,抑止的话会减少系统不必
要的函数调用,带来性能上的提高。然后,在线程每次循环的初始,使用GameCanvas.getKeyStates()方法得到系统的按键状态。这个状
态字是一个int值,其中每一位表示一个按键是否是按下状态。这样既支持了多按键,又完全不会抢用系统调用paint的时间,还在一定程度上提高了性能。

得到keyState之后,一般采用位运算来判断某键是否按下:
int keyState = getKeyStates();
if ((keyState & LEFT_KEY) != 0) {//如果左键按下
 //处理代码
}
else if ((keyState & RIGHT_KEY) != 0) {//如果右键按下
 //处理代码
}
通过位运算,还可以得到其他好处。比如,如果你记录上次按键信息的话,那么
newKeys=~lastKeyState&curKeyState;  //上次检测之后新按下的键,相当于keyPressed捕获到的键
lostKeys=lastKeyState&~curKeyState;  //上次检测之后松开的键,相当于keyReleased捕获到的键
changedKeys=lastKyeState^curKeyState; //改变了状态的按键

还有几个要注意的问题:
如果当前GameCanvas不是正在显示的Displayble对象,那这个方法总返回0。
当你在保持按键的时候将GameCanvas重新显示在屏幕上时,getKeyState不会立即得到当前按下的键的信息,而是仍然保持为0,直到保持的按键松开再重新按下的时候,这时才可以得到正确的按键状态信息。


前Foma和Vodafone下很多程序的按键处理都是用MIDP1.0的keyPressed和keyReleased还有commandAction
来做的。最近在VT603等新机型上测出来一个bug,软键切换菜单或状态时如果按下软键不放,这个键将会不停的产生效果,最常见的就是游戏中Pause
状态的切换。初步猜测是系统自动实现软键的连续按键,多次回调commandAction函数所致。
一个暂时的解决办法是把
keyPressed、keyReleased改为keyPressedEx、keyReleasedEx,去除commandListener接口,把
按键接收改为在每次线程刷新的初始主动查询keyState,根据具体的位判断哪个按键按下,然后手动调用keyPressedEx、
keyReleasedEx、commandAction函数。

注意:以后写新游戏请大家尽量改为使用getKeyStatus的方式来处理按键。

Foma下按键状态:
Canvas的getKeypadState()方法。此函数不像MIDP2.0的,不管canvas是否是当前正在显示的canvas,都返回按键值。
返回的int共32位,第15位和16位为soft1和soft2。
其余键对应位参见文档Display类。

Vodafone下按键状态:
首先用DeviceControl.getDefaultDeviceControl()得到一个DeviceControl对象的实例dc。
然后调用dc.getDeviceState(DeviceControl.KEY_STATE)得到按键状态。
返回的按键状态值第17位和18位位soft1和soft2。
其余键对应位参见文档DeviceControl类。