2012/05/24

Android:キーイベントを追跡する

QWERTYキー等のハードキーを備える端末は少ないですが、需要があるため今後も発売され
続けるでしょう。
しかし、Androidの設計はハードキー操作よりもタッチ操作に重きを置いています。
このことが、ハードキーを意識したアプリ開発を難しくしています。

今回はキーイベントのアップ/ダウンについてです。

キーのアップとダウンは対とならないケースがあります。
下記のようなケースが考えられます。

ケース1:
 手順)
  アプリ起動前にキーAを押下し続ける>タップでアプリ起動>起動後にキーアップ
 結果)
  アプリにはキーアップのみが通知される。

ケース2:
 手順)
  アプリ起動中にキーAを押下し続ける>続けてバックキーを押下する
 結果)
  キーアップしていないのにキーAのキーアップが通知される

キーアップとダウンが対になる前提でコーディングするのは危険です。
上記のようなケースを判断したい場合はKeyEventクラスのAPIを使用します。

●ケース1の判断
キーイベントはトラッキング(追跡)することが可能です。
onKeyDownでevent.startTrackingを実行することでキーイベントの追跡が開始されます。
public boolean onKeyDown(int keyCode, android.view.KeyEvent event) {
    if (event.getRepeatCount() == 0) {
        event.startTracking();
    }
}
RepeatCountをチェックしているのは、押下し続けているキーのイベントがアプリ起動後
にも配信されるためです。
RepeatCountが0であるということは、今まさにキー押下されたことを意味します。

続けて、onKeyUpでキーイベントが追跡されている状態かどうかを判断します。
public boolean onKeyUp(int keyCode, KeyEvent event) {
    event.isTracking();
}
ここでisTrackingがtureを返せば、このキーイベントが自アプリ内でのキーダウンを契機
に開始されたことを意味します。


●ケース2の判断
ユーザが実際にキーアップしていなくてもonKeyUpが呼ばれます。
本当にユーザがキーアップしたイベントかどうかはevent.isCanceledで確認可能です。
event.isCanceled()
キーAを押し続けた状態で、BackキーやHomeキーを押下(あるいはタップ)した場合に、
キーイベントはキャンセルされてisCanceledがtureを返します。


●ユーザがアプリ内でキーダウン⇒アップしたかどうかを判断したい場合
キーAがアプリ内でキーダウン⇒キーアップされたかどうかを判断するコードです。
public boolean onKeyDown(int keyCode, android.view.KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_A && event.getRepeatCount() == 0) {
        event.startTracking();
    }
....
}

public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_A && event.isTracking()
            && !event.isCanceled()) {
        // catch it!
    }
}
以上です。