ミニ四駆ラジコンのプロポアプリを作って痛感したのは、タッチパネルUIだとスティックの感触がないから画面から目を離して操作しづらい、ということです。これはラジコンやロボットのコントローラとしては致命的です。というわけで、ゲームパッドを使えるようにしたいと思いました。
購入したゲームパッド
今回購入したゲームパッドは、ipegaのPG9023という機種。Bluetooth接続のゲームパッドで、スマホやタブレットをがっちり挟み込める構造になっています。
このゲームパッドはペアリング時のボタン押下でモードが決まります。
- Xボタン+HOMEボタン → ゲームパッドモード (Android用)
- Aボタン+HOMEボタン → キーボードモード
- Bボタン+HOMEボタン → iCadeモード (iOS用)
- Yボタン+HOMEボタン → SPPモード
今回はゲームパッドモードで使用します。ちなみにHOMEボタン長押しで電源OFF、一度ペアリングした後はHOMEボタン押下で電源ON&再接続できる仕様です。
イベントの取得
- ボタンのイベントは onKeyDown/onKeyUp/onKeyLongPress
- アナログスティックのイベントは onGenericMotionEvent
をActivityでオーバーライドすれば取得できます。
ボタンやスティックによってはプライマリ/セカンダリの2個のイベントを発生するものがあります。まずプライマリイベントが発生し、それがアプリによって処理されなかったときにセカンダリイベントが発生します。上記のイベントハンドラでtrueを返すと、イベントは処理されたことになります。
ボタンのイベント
どのボタンが押されたかはonKeyDownの引数のkeyCodeの値で得られます。PG9023で実際の各ボタンのkeyCode値を調べてみました。機種によって細かい違いはあろうかと思いますが、主要なボタンはたぶん互換性があるでしょう。値1/値2はプライマリ/セカンダリの値を示します。
【主なボタン】
ボタン | プライマリ | 値 | セカンダリ | 値 |
---|---|---|---|---|
十字↑ | - | - | KEYCODE_DPAD_UP | 19 |
十字↓ | - | - | KEYCODE_DPAD_DOWN | 20 |
十字← | - | - | KEYCODE_DPAD_LEFT | 21 |
十字→ | - | - | KEYCODE_DPAD_RIGHT | 22 |
A | KEYCODE_BUTTON_A | 96 | KEYCODE_DPAD_CENTER | 23 |
B | KEYCODE_BUTTON_B | 97 | KEYCODE_BACK | 4 |
X | KEYCODE_BUTTON_X | 99 | KEYCODE_DEL | 67 |
Y | KEYCODE_BUTTON_Y | 100 | KEYCODE_SPACE | 62 |
L1 | KEYCODE_BUTTON_L1 | 102 | - | - |
R1 | KEYCODE_BUTTON_R1 | 103 | - | - |
L2 | - | - | KEYCODE_BUTTON_L2 | 104 |
R2 | - | - | KEYCODE_BUTTON_R2 | 105 |
【左ジョイスティック】
ボタン | プライマリ | 値 | セカンダリ | 値 |
---|---|---|---|---|
押し下げ | KEYCODE_BUTTON_THUMBL | 106 | KEYCODE_DPAD_CENTER | 23 |
↑ | - | - | KEYCODE_DPAD_UP | 19 |
↓ | - | - | KEYCODE_DPAD_DOWN | 20 |
← | - | - | KEYCODE_DPAD_LEFT | 21 |
→ | - | - | KEYCODE_DPAD_RIGHT | 22 |
【右ジョイスティック】
ボタン | プライマリ | 値 | セカンダリ | 値 |
---|---|---|---|---|
押し下げ | KEYCODE_BUTTON_THUMBR | 107 | KEYCODE_DPAD_CENTER | 23 |
↑ | - | - | - | - |
↓ | - | - | - | - |
← | - | - | - | - |
→ | - | - | - | - |
【その他のボタン】
ボタン | プライマリ | 値 | セカンダリ | 値 |
---|---|---|---|---|
SELECT | KEYCODE_BUTTON_SELECT | 109 | KEYCODE_MENU | 82 |
HOME | - | - | - | - |
START | KEYCODE_BUTTON_START | 108 | KEYCODE_DPAD_CENTER | 23 |
- | KEYCODE_VOLUME_DOWN | 25 | - | - |
+ | KEYCODE_VOLUME_UP | 24 | - | - |
巻き戻し | KEYCODE_MEDIA_PREVIOUS | 88 | - | - |
再生/停止 | KEYCODE_MEDIA_PLAY_PAUSE | 85 | - | - |
早送り | KEYCODE_MEDIA_NEXT | 87 | - | - |
アナログスティックのイベント
各軸の値は、onGenericMotionEventのevent.getAxisValue(MotionEvent.軸名)で得られます。値の型はfloatです。
軸 | 軸名 | 値の範囲 |
---|---|---|
左ジョイスティック 横 | AXIS_X | -1〜+1 |
左ジョイスティック 縦 | AXIS_Y | -1〜+1 |
右ジョイスティック 横 | AXIS_Z | -1〜+1 |
右ジョイスティック 縦 | AXIS_RZ | -1〜+1 |
十字 横 | AXIS_HAT_X | -1〜+1 |
十字 縦 | AXIS_HAT_Y | -1〜+1 |
Lトリガ(L2) | AXIS_LTRIGGER | 0〜1 ※ |
Rトリガ(R2) | AXIS_RTRIGGER | 0〜1 ※ |
※ PG9023のL2,R2はアナログではないただのボタンのためか、アナログ値は常に0でした。
ソースコード
// ボタンのイベント @Override public boolean onKeyDown(int keyCode, KeyEvent event){ boolean handled = false; // 処理したらtrueに // キーコードをログ出力してみる String msg = "keyCode:" + keyCode; Log.e("GamePad", msg); return handled || super.onKeyDown(keyCode, event); } // アナログのイベント @Override public boolean onGenericMotionEvent(MotionEvent event){ boolean handled = false; // 処理したらtrueに // 左ジョイスティックの値をログ出力してみる float x = event.getAxisValue(MotionEvent.AXIS_X); float y = event.getAxisValue(MotionEvent.AXIS_Y); String msg = "(x,y)=" + x + "," + y; Log.e("GamePad", msg); return handled || super.onGenericMotionEvent(event); }