そんな1年半目の発見として(?)
タッチイベントのリピーター(ユーザが入力したイベントをそっくりそのまま、コマンドを送り込んで再現させる)を作ってみました。
(とるのがヘタでごめんなさい)
目的は
・何度も何度も試験をしないといけないときに、PCとスマホをUSB接続して、試験ツール的なものをかけて夜帰って、朝に結果を見る、ということができるようにする。
・そのために、入力の基本である、キーイベントやタッチイベントをUSB経由でインジェクションする。
しかし
・キーイベントにくらべてタッチイベントのシナリオって、書くのがすごく難しい
なので
・タッチイベントの再現シナリオを簡単に作れるようにしました。
というストーリー。
キーイベントをUSB経由で送り込む
すでに多くのサイトで書かれているので、省略。
adb shell input text 文字列
adb shell input keyevent キーコード
タッチイベントの意味を解析しよう
タッチイベントのシナリオを作るには、最低限のタッチイベントがどういうものかくらいは知っておく必要がある。
Nexus 7で、
adb shell getevent /dev/input/event0とやって、タッチパネルから上がってくるイベントを観察してみた。
iwaki-yuusuke-no-MacBook-Air:~ yi01$ adb shell getevent /dev/input/event0 0003 0039 00000001 0003 0030 00000005 0003 003a 00000011 0003 0035 000000b4 0003 0036 000000fd 0000 0000 00000000 0003 0039 ffffffff 0000 0000 00000000
コマンドを打って、画面の左上の方を軽くタップした様子
うん、よくわからん
少し移動を加えてみた。
iwaki-yuusuke-no-MacBook-Air:~ yi01$ adb shell getevent /dev/input/event0 0003 0039 00000005 0003 0030 00000007 0003 003a 0000000d 0003 0035 000000ba 0003 0036 00000189 0000 0000 00000000 0003 003a 00000054 0003 0035 000000bf 0003 0036 0000018e 0000 0000 00000000 0003 003a 00000058 0003 0035 000000c5 0000 0000 00000000 0003 003a 0000004b 0003 0035 000000cb 0000 0000 00000000 0003 0039 ffffffff 0000 0000 00000000うん。よくわからんけど、00000000・・・00ってのが区切り文字的なものに見える。あと、3つの値が常に並んでいるようだ。
少し解析スクリプトを書いてみた。
# -*- coding:utf-8 -*- import os pipe=os.popen("adb shell getevent /dev/input/event0") for line in iter(pipe.readline,""): data = line.strip().split() if len(data)!=3: continue kind,key,value = [int(a,16) for a in data] if kind==0: if key==0 and value==0: print "="*20 else: print "cmd",key,value else: print kind,key,value
すると。
iwaki-yuusuke-no-MacBook-Air:~ yi01$ python analyze_touchevent.py 3 57 10 3 48 9 3 58 32 3 53 517 3 54 393 ==================== 3 57 4294967295 ====================おお、だいぶ見やすくなった。
さて、次に気になるのは、「3 57」から始まるやつ。↑の結果を出すまでに何度かタップ試していたのだが
3 57 8 3 48 6 3 58 18 3 53 630 3 54 1442 ==================== 3 57 4294967295 ==================== 3 57 9 3 48 4 3 58 21 3 53 479 3 54 542 ==================== 3 58 84 3 54 547 ==================== 3 57 4294967295 ====================
なんかカウントアップしているように見える。あと、4294967295=0xffffffffである。
あとは、タッチ関連のイベントは、左1桁目はかならず「3」のようだ。
if kind==0: if key==0 and value==0: print "="*20 else: print "cmd",key,value elif kind==3: if key==57: if value==0xffffffff: print "touch","end","-" else: print "touch","start","seq_No."+str(value) else: print "touch",key,value else: print kind,key,value
ちょっとこんなかんじにスクリプトの条件文を書き換えたら
touch start seq_No.13 touch 58 26 touch 53 387 touch 54 1106 ==================== touch 58 91 touch 53 382 touch 54 1103 ==================== touch end - ==================== touch start seq_No.14 touch 58 30 touch 53 257 touch 54 473 ==================== touch end - ==================== touch start seq_No.15 touch 58 28 touch 53 470 touch 54 725 ==================== touch end - ====================
こんなかんじになった。だんだんそれっぽくなってきた。
次に目につくのは、53と54。これはどうもx座標とy座標のようだ。タップした座標に近いからだ。58ってのはよくわからないので、保留。
ここまでやったところで、「マルチタッチ」ということを思いつく。
iwaki-yuusuke-no-MacBook-Air:~ yi01$ python analyze_touchevent.py touch start seq_No.17 touch 48 7 touch 58 24 touch 53 404 touch 54 523 ==================== touch 58 75 touch 47 1 touch start seq_No.18 touch 48 7 touch 58 29 touch 53 757 touch 54 409 ==================== touch 47 0 touch end - touch 47 1 touch 48 6 touch 58 35 ==================== touch end - ==================== touch 47 0 touch start seq_No.19 touch 58 26 touch 53 391 touch 54 631 ==================== touch 58 79 touch 47 1 touch start seq_No.20 touch 48 8 touch 58 26 touch 53 939 touch 54 589 touch 47 2 touch start seq_No.21 touch 48 8 touch 58 27 touch 53 674 touch 54 514 ==================== touch 47 0 touch 58 35 touch 47 1 touch 48 7 touch 58 32 touch 47 2 touch end - ==================== touch 47 0 touch end - touch 47 1 touch end - ====================
2点、3点タップを試した結果が上記。ぱっと見だが、「touch 47」というのが「これからX番目の値を言いますよー」という宣言に見える。
if kind==0: if key==0 and value==0: print "="*20 else: print "cmd",key,value elif kind==3: if key==57: if value==0xffffffff: print "touch","end","-" else: print "touch","start","seq_No."+str(value) elif key==53: print "touch","x",value elif key==54: print "touch","y",value elif key==47: print "touch","index",value else: print "touch",key,value else: print kind,key,value
if文はこんなかんじに。だんだんと充実してきた。
しばらくグリグリタッチして遊んでみる。
まだ残っているのは48と58・・・。なんだろう。accuracyとかそういう系の指標っぽくもある。そんなに重要そうではない。
==================== touch 48 18 touch 58 248 touch x 398 touch y 1127 ==================== touch 58 226 touch x 394 touch y 1122 ==================== touch 58 202 touch x 389 touch y 1117 ==================== touch 48 16 touch 58 193 touch x 385 touch y 1112 ==================== touch 48 15 touch 58 176 touch x 380 touch y 1107 ==================== touch 48 13 touch 58 164 touch x 375 touch y 1104 ==================== touch 58 158 touch x 370 ====================
まあ、リピーターなので、べつに意味を100%理解してなくてもよかろう。
とか言っているうちに、ソースコードから正解を見つけてしまった。(笑)
48はタッチの面積の半径、58はタッチの圧力のようだ。
うん。やっぱりそんなに重要じゃなさそうだ。
んん??圧力?タッチパネルって感圧なの??
iwaki-yuusuke-no-MacBook-Air:~ yi01$ adb shell getevent /dev/input/event0 | grep 3a 0003 003a 00000007 0003 003a 0000004d 0003 003a 0000008b 0003 003a 00000049 0003 003a 00000009 0003 003a 000000ac 0003 003a 000000b0 0003 003a 000000b9 0003 003a 000000ba 0003 003a 000000b8 0003 003a 000000b6 0003 003a 000000b5 0003 003a 000000b8 0003 003a 000000ba 0003 003a 000000c2 0003 003a 000000cb 0003 003a 000000cd 0003 003a 000000d3
実際見てみた(ぐいっと指を押し込んでみた)が、お世辞にも感度がいいとは言えない。むしろ、接地面積に比例した値を返しているだけのようだ。
ないよりはマシ、おまけ程度と考えていいだろう。
# -*- coding:utf-8 -*- import os pipe=os.popen("adb shell getevent /dev/input/event0") for line in iter(pipe.readline,""): data = line.strip().split() if len(data)!=3: continue kind,key,value = [int(a,16) for a in data] if kind==0: if key==0 and value==0: print "="*20 else: print "cmd",key,value elif kind==3: if key==57: if value==0xffffffff: print "touch","end","-" else: print "touch","start","seq_No."+str(value) elif key==53: print "touch","x",value elif key==54: print "touch","y",value elif key==47: print "touch","index",value elif key==48: print "touch","radius",value elif key==58: print "touch","pressure",value else: print "touch",key,value else: print kind,key,value
さて、突貫工事で、タッチイベントの解析スクリプトはできた。
タッチイベントをUSB経由で送り込む
ここまでできれば、あとは簡単。
adb shell sendevent type key dataを使って送り込むだけである。
StackOverflowとかの情報を見ると、type, key, dataは16進数ではなく10進数で表記するらしい。
↑のシナリオを逆解析するのは、簡単なので省略。
問題は、adb shellを実行するところだ。
簡単な例があるのでそれだけ示しておく。
# -*- coding: utf-8 -*- import os class ADBTestShell: def __init__(self): print "adb shell" def execute(self,cmd): print "> "+cmd def __del__(self): self.execute("exit") print "EXIT" class ADBShell: def __init__(self): self.pipe=os.popen("adb shell","w") def execute(self,cmd): self.pipe.write(cmd+"\n") def __del__(self): self.execute("exit") self.pipe.close() adb=ADBShell() adb.execute("ls /system/app") del adb
これを組み合わせることで、冒頭に載せたようなキーイベントの送信のシナリオ作成・再現ができる。