2011年06月21日

Androidでkeyイベントを発生させるinputコマンドをサクサクにする

以下のページでAndroidのinputコマンドが紹介されていました。

adbを使って端末にキーイベントを送る - TechBooster

このコマンドを詳しく見てみます。



inputコマンドの使い方

コンソールかadbのshellから単にinputと打ってみます。

# input
usage: input [text|keyevent]
       input text <string>
       input keyevent <event_code>

このinputコマンドを使うと任意のキーイベントをコマンドラインから発行することができます。

実際のキーイベントのコードはandroid.view.KeyEvent.javaに定義されています。

便利そうなものをピックアップすると

    public static final int KEYCODE_HOME            = 3;
    public static final int KEYCODE_BACK            = 4;
    public static final int KEYCODE_DPAD_UP         = 19;
    public static final int KEYCODE_DPAD_DOWN       = 20;
    public static final int KEYCODE_DPAD_LEFT       = 21;
    public static final int KEYCODE_DPAD_RIGHT      = 22;
    public static final int KEYCODE_DPAD_CENTER     = 23;
    public static final int KEYCODE_ENTER           = 66;
    public static final int KEYCODE_MENU            = 82;
    public static final int KEYCODE_SEARCH          = 84;

メニューキーのイベントを発行したいときには

# input keyevent 82

起動後のロック画面はこれで解除することができます。

検索窓を開いて"kmckk"を検索するには

# input keyevent 84
# input text kmckk
# input keyevent 66

inputコマンドを改良してサクサクにする

実際に試してみるとわかりますが、このinputコマンドはけっこう重いです。

/system/bin/input は以下のようなshell scriptでした。

# Script to start "input" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/framework/input.jar
exec app_process $base/bin com.android.commands.input.Input $*

app_process はDalvikVMそのものです。つまり毎回DalvikVMを新たに起動していました。そのためにこのコマンドは起動に時間がかかるのです。

これを以前紹介したdvzコマンドを使って書き直してみます。以下のようになりました。

input2

#
base=/system
exec dvz -classpath $base/framework/input.jar com.android.commands.input.Input $*

これはDalvikVMを新たに起動するのでなく、待機中のZygoteに依頼して、そこからforkした子プロセスで指定したクラスを実行します。

修正したinput2コマンドを使ってさきほどと全く同じことができます。

# input2 keyevent 84
# input2 text kmckk
# input2 keyevent 66

今度はさっきよりもずっと軽快です。

自作のコマンドを作る

com.android.commands.input.Inputのソースを見てみましょう。

frameworks/base/cmds/input/src/com/android/commands/input/Input.java

特に参考になるのは以下の箇所です。

    /**
     * Send a single key event.
     *
     * @param event is a string representing the keycode of the key event you
     * want to execute.
     */
    private void sendKeyEvent(String event) {
        int eventCode = Integer.parseInt(event);
        long now = SystemClock.uptimeMillis();
        Log.i("SendKeyEvent", event);
        try {
            KeyEvent down = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, eventCode, 0);
            KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, eventCode, 0);
            (IWindowManager.Stub
                .asInterface(ServiceManager.getService("window")))
                .injectKeyEvent(down, true);
            (IWindowManager.Stub
                .asInterface(ServiceManager.getService("window")))
                .injectKeyEvent(up, true);
        } catch (RemoteException e) {
            Log.i("Input", "DeadOjbectException");
        }
    }

つまり、"window"サービスのinjectKeyEventをリモートで呼び出せば、キーイベントを発行できることがわかります。これを利用すれば、自動でキーイベントを発行するロボットプログラムが作れますね。(必要なPermissionについては別途調査してください。)



トラックバックURL

コメント一覧

1. Posted by dvz...   2014年11月21日 21:56
一つ質問があるので投稿させていただきます。
この記事をみてinputコマンド書き換え、dvzコマンドを追加して実行してみると、
u0_a290@SC-04F:/ $ dvz
/system/bin/dvz[1]: /acct: can't execute: Is a directory
/system/bin/dvz[2]: syntax error: '(' unexpected
となり実行できません。
試した環境はNexus7 2013でCM11を焼いて使用しています。
dvzはGBの端末から抜き出しました。
この場合の解決方法はあるのでしょうか?
アドバイスいただけると幸いです。
2. Posted by 若槻   2014年12月01日 14:29
コメントありがとうございます。

この記事は3年以上前の記事ですので、現在とは状況が異なることが多々あると思います。当時この記事を書いた担当者は、現在は弊社に在籍しておりませんので、質問への回答等は難しい状況になっております。お役に立てず、申し訳ありません。

コメントする

名前
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード