引き続き Android OS 3.1 に Xbox360 Pad と Playstation3 Pad を
つないだ場合の値の取り方です。(前回)
アナログスティックの情報は onGenericMotionEvent で受け取れます。
@Override public boolean onGenericMotionEvent( MotionEvent event ) { float posx= event.getAxisValue( MotionEvent.AXIS_X ); ~ }
入力値に差が生じた場合のみイベントが発生します。
getX()/getY() は getAxisValue() の AXIS_X, AXIS_Y と同値です。
対応付は下記の通り
axis Xbox360Pad PS3 Pad 範囲 Source ----------------------------------------------------------------------- AXIS_X 左stick 横 左stick 横 -1~1 SOURCE_CLASS_JOYSTICK AXIS_Y 左stick 縦 左stick 縦 -1~1 SOURCE_CLASS_JOYSTICK AXIS_Z 右stick 横 右stick 横 -1~1 SOURCE_CLASS_JOYSTICK AXIS_RZ 右stick 縦 右stick 縦 -1~1 SOURCE_CLASS_JOYSTICK AXIS_HAT_X 十字キー横 ---- -1~1 SOURCE_CLASS_JOYSTICK AXIS_HAT_Y 十字キー縦 ---- -1~1 SOURCE_CLASS_JOYSTICK AXIS_LTRIGGER Lトリガ L2 0~1 AXIS_RTRIGGER Rトリガ R2 0~1 左上が (-1,-1), 右下が (1,1)
Xbox360 Pad のみ、デジタル方向ボタン(十字キー) が MotionEvent の
AXIS_HAT_X/AXIS_HAT_Y を返します。(KeyEvent も発生します)
他にも MotionEvent と同時に KeyEvent を発生させるものがあります。
◎Xbox360 Pad / PS3 Pad ・AXIS_X KEYCODE_DPAD_LEFT/KEYCODE_DPAD_RIGHT ・AXIS_Y KEYCODE_DPAD_UP/KEYCODE_DPAD_DOWN ◎PS3 Pad のみ ・AXIS_LTRIGGER KEYCODE_L2 ・AXIS_RTRIGGER KEYCODE_R2 ◎Xbox360 Pad のみ ・AXIS_HAT_X KEYCODE_DPAD_LEFT/KEYCODE_DPAD_RIGHT ・AXIS_HAT_Y KEYCODE_DPAD_UP/KEYCODE_DPAD_DOWN
●デジタル方向キーとアナログスティックの区別方法
ここで問題となるのは、左アナログスティックで MotionEvent だけでなく
KeyEvent も発生してしまうことです。
デジタル方向ボタンの代わりに左アナログスティックを使うことができる反面、
アナログとデジタルに異なる操作を割り当てたいときに困ります。
KeyCode だけではこの両者を区別できないので方法を探しました。
Xbox360 Pad の方向キーは AXIS_HAT_X/AXIS_HAT_Y からも値をとれるため
KeyEvent を参照せずにこちらを使えば区別することができます。
PS3 Pad の場合は SOURCE_CLASS で区別できるようです。
訂正 2011/08/11 不要でした。Xbox360 のみ AXIS → KeyCode 変換だけで OK です。
KeyEvent.getSource() & InputDevice.SOURCE_CLASS_MASK
PS3 のみデジタル方向キーが SOURCE_CLASS_BUTTON となります。
◎KeyEvent の SOURCE_CLASS 値 Xbox360 Pad PS3 Pad -------------------------------------------------------------------- デジタル方向キー SOURCE_CLASS_JOYSTICK SOURCE_CLASS_BUTTON アナログ方向キー SOURCE_CLASS_JOYSTICK SOURCE_CLASS_JOYSTICK ◎MotionEvent の情報 Xbox360 Pad PS3 Pad -------------------------------------------------------------------- デジタル方向キー AXIS_HAT_X/AXIS_HAT_Y 無し アナログ方向キー AXIS_X/AXIS_Y AXIS_X/AXIS_Y
実際のコード(Activity 抜粋)は下記の通り。
これで Xbox360 Pad / PS3 Pad 共に、デジタル方向ボタンを
KEYCODE_DPAD_UP/DOWN/LEFT/RIGHT を受け取れるようになります。
(プログラムコード訂正しました 2011/08/11 )
final static int SENDKEY_UP = 0; final static int SENDKEY_DOWN = 1; private int mPrevState= 0; private boolean sendKey( int KeyCode, int up_down ) { // 実際のキーコード処理 ~ } @Override public boolean onKeyDown( int KeyCode, KeyEvent event ) { return sendKey( KeyCode, SENDKEY_DOWN ); } @Override public boolean onKeyUp( int KeyCode, KeyEvent event ) { return sendKey( KeyCode, SENDKEY_UP ); } @Override public boolean onGenericMotionEvent( MotionEvent event ) { // Xbox360 の 十字キーはこれで判別 final int KEYFLAG_UP = (1<<0); final int KEYFLAG_DOWN = (1<<1); final int KEYFLAG_LEFT = (1<<2); final int KEYFLAG_RIGHT = (1<<3); final float HAT_BORDER= 0.5f; float hatx= event.getAxisValue( MotionEvent.AXIS_HAT_X ); float haty= event.getAxisValue( MotionEvent.AXIS_HAT_Y ); int code= 0; if( hatx < -HAT_BORDER ){ code|= KEYFLAG_LEFT; } if( hatx > HAT_BORDER ){ code|= KEYFLAG_RIGHT; } if( haty < -HAT_BORDER ){ code|= KEYFLAG_UP; } if( haty > HAT_BORDER ){ code|= KEYFLAG_DOWN; } int diff= code ^ mPrevState; mPrevState= code; for( int kc= KeyEvent.KEYCODE_DPAD_UP ; diff != 0 ; diff>>= 1, code>>= 1, kc++ ){ if( (diff & 1) != 0 ){ // 代わりのキーコードを発生させる sendKey( kc, (code & 1) != 0 ? SENDKEY_DOWN : SENDKEY_UP ); } } // アナログ値の受け取り float lx= event.getAxisValue( MotionEvent.AXIS_X ); float ly= event.getAxisValue( MotionEvent.AXIS_Y ); float rx= event.getAxisValue( MotionEvent.AXIS_Z ); float ry= event.getAxisValue( MotionEvent.AXIS_RZ ); float tl= event.getAxisValue( MotionEvent.AXIS_LTRIGGER ); float tr= event.getAxisValue( MotionEvent.AXIS_RTRIGGER ); ~ }
●複数のパッドの認識
USB ハブを経由して、同時に複数のコントローラを接続することができました。
どのコントローラも上記の同じイベントを発生させます。
getDeviceId() を参照することで、どのコントローラが送ったイベントなのか
区別できるようです。
Xbox360 Pad と PS3 Pad の組み合わせは OK、PS3 Pad を同時に 2個つないでも
きちんと区別できました。バスパワーハブだったため 3個以上は試していません。
● Playstation3 Pad (PS3 Pad) の注意点
PS3 Pad はもともとワイヤレスコントローラですが、Android 3.1 の場合
USB ケーブルで繋ぎます。
1. PS3 Pad が電源 OFF の状態を確認
2. USB ケーブルで Android 3.1 端末に繋ぐ
3. (PS) ボタンを押す
4. LED 4つが点滅したままだけど問題なし。そのまま使える。
接続前に (PS) ボタンを押してしまうとペアリングしてある PS3 本体の
電源が入ってしまうので要注意です。
ワイヤレスで PS3 本体につながってしまうと USB ケーブルをつないでも
PS3 が優先され Android で認識できません。
最初の頃、遠くにある PS3 本体の電源がいつの間にか入っていて、
なかなかつながらずにはまりました。
関連エントリ
・Android 3.1 と GamePad のイベントコード