天天看點

android getevent sendevent input 接收發送事件geteventsendeventinput注意事項

自動化測試或爬蟲腳本場景經常需要模拟使用者向手機裝置發送各種互動事件,最常見的就是點選事件,這裡面就有一個大前提就是你需要擷取點選位置的 x、y 螢幕坐标。

如何擷取以及如何發送事件,這裡涉及到 Android 系統提供的 getevent 和 sendevent 操作知識點。

通過 getevent 和 sendevent 指令可以檢視和觸發系統的操作事件,包括觸摸屏事件和虛拟實體按鍵事件。除此之外,input 指令也可以做到發送指令。

getevent

我們使用 USB 連接配接一台安卓手機裝置後,通過 

adb shell

 進入 shell 互動式環境,輸入指令 

getevent -help

 可以檢視 getevent 指令的參數介紹:

yifeng:/ $ getevent -help
Usage: getevent [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]
    -t: show time stamps
    -n: don't print newlines
    -s: print switch states for given bits
    -S: print all switch states
    -v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32, props=64)
    -d: show HID descriptor, if available
    -p: show possible events (errs, dev, name, pos. events)
    -i: show all device info and possible events
    -l: label event types and names in plain text
    -q: quiet (clear verbosity mask)
    -c: print given number of events then exit
    -r: print rate events are received
           

參數很多,都有對應的英文解釋,比如 -t 表示顯示事件發生的事件,-l 表示顯示事件類型和名稱。我們先不加任何參數,了解一下 getevent 指令的用法。

執行 

getevent

 指令,開始檢視接收到的事件資訊。開頭這一系列 add device 輸入表示目前裝置支援的事件類型。

yifeng:/ $ getevent
add device 1: /dev/input/event7
  name:     "uinput_nav"
add device 2: /dev/input/event6
  name:     "sdm660-snd-card Button Jack"
add device 3: /dev/input/event5
  name:     "sdm660-snd-card Headset Jack"
add device 4: /dev/input/event3
  name:     "uinput-goodix"
could not get driver version for /dev/input/mice, Not a typewriter
add device 5: /dev/input/event1
  name:     "ant_check-input"
add device 6: /dev/input/event4
  name:     "gpio-keys"
add device 7: /dev/input/event0
  name:     "qpnp_pon"
add device 8: /dev/input/event2
  name:     "NVTCapacitiveTouchScreen"
  
           

備注:上面列印的這段裝置資訊,通過執行 

getevent -p

 指令行也能拿到,需要注意的是,裡面有個螢幕尺寸資訊:

......
add device 8: /dev/input/event2
  name:     "NVTCapacitiveTouchScreen"
  events:
    KEY (0001): 008f  014a
    ABS (0003): 002f  : value 0, min 0, max 9, fuzz 0, flat 0, resolution 0
                0035  : value 0, min 0, max 1079, fuzz 0, flat 0, resolution 0
                0036  : value 0, min 0, max 2339, fuzz 0, flat 0, resolution 0
                0039  : value 0, min 0, max 65535, fuzz 0, flat 0, resolution 0
                003a  : value 0, min 0, max 1000, fuzz 0, flat 0, resolution 0
  input props:
    INPUT_PROP_DIRECT
           

其實是不準确的,不能直接拿來用的,擷取螢幕分辨率等資訊還是要通過這個指令擷取:

adb shell dumpsys window displays
           

或者更簡潔一點的:

adb shell wm size
           

說回正題,開始監聽事件後,我們按一下手機音量上鍵,就會得到這麼一段輸入資訊:

/dev/input/event4: 0001 0073 00000001
/dev/input/event4: 0000 0000 00000000
/dev/input/event4: 0001 0073 00000000
/dev/input/event4: 0000 0000 00000000
           

每一行代表一條指令,每條指令從左到右,依次表示:裝置名稱、事件類型、事件編碼和事件攜帶的資料(十六進制表示)。

裝置名稱可以從 getevent 指令開頭的一段輸出中找到,事件類型和事件編碼可以在 android 系統核心源碼中對照檢視:include/linux/input.h,源碼倉庫 git 位址為:

https://android.googlesource.com/kernel/msm.git/+/android-msm-hammerhead-3.4-kk-r1/include/linux/input.h

比如,input.h 檔案中定義的事件類型有這些(十六進制):

/*
 * Event types
 */
#define EV_SYN          0x00
#define EV_KEY          0x01
#define EV_REL          0x02
#define EV_ABS          0x03
#define EV_MSC          0x04
#define EV_SW               0x05
#define EV_LED          0x11
#define EV_SND          0x12
#define EV_REP          0x14
#define EV_FF               0x15
#define EV_PWR          0x16
#define EV_FF_STATUS    0x17
#define EV_MAX          0x1f
#define EV_CNT          (EV_MAX+1)
           

可以看到,前面我們操作的音量上鍵使用到了 EV_SYN 和 EV_KEY 兩個類型,對應 input.h 定義的事件編碼(十進制)為:

#define KEY_VOLUMEDOWN      114
#define KEY_VOLUMEUP        115
           

注意,對比檢視事件編碼時,需要進行十六進制與十進制的轉換,可以找個線上工具,比如:

https://tool.oschina.net/hexconvert

這樣對比下來,我們就能了解 

getevent

 不帶任何參數時輸出資訊的含義。不過還是有點繁瑣,不如直接給到事件名字更加清晰一些。

比如,使用 

-l

 參數直接列印事件名稱,再來看下同樣的音量上鍵對應的輸出資訊,這樣看起來是不是舒服多了:

yifeng:/ $ getevent -l
......
/dev/input/event4: EV_KEY       KEY_VOLUMEUP         DOWN
/dev/input/event4: EV_SYN       SYN_REPORT           00000000
/dev/input/event4: EV_KEY       KEY_VOLUMEUP         UP
/dev/input/event4: EV_SYN       SYN_REPORT           00000000
           

同樣的,我們看下添加 

-l

 參數前後,手指觸摸螢幕的事件輸出情況。這是 

getevent

指令下觸摸螢幕的輸出資訊:

/dev/input/event2: 0003 0039 0000008b
/dev/input/event2: 0003 0035 000003c2
/dev/input/event2: 0003 0036 00000134
/dev/input/event2: 0003 003a 000003e8
/dev/input/event2: 0001 014a 00000001
/dev/input/event2: 0000 0000 00000000
/dev/input/event2: 0003 003a 00000000
/dev/input/event2: 0003 0039 ffffffff
/dev/input/event2: 0001 014a 00000000
/dev/input/event2: 0000 0000 00000000
           

翻譯一下,十六進制 0003 對應的事件類型為 EV_ABS,表示觸摸螢幕對應的坐标相關資料,input.h 檔案中的定義有:

#define ABS_MT_SLOT     0x2f    /* MT slot being modified */
#define ABS_MT_TOUCH_MAJOR  0x30    /* Major axis of touching ellipse */
#define ABS_MT_TOUCH_MINOR  0x31    /* Minor axis (omit if circular) */
#define ABS_MT_WIDTH_MAJOR  0x32    /* Major axis of approaching ellipse */
#define ABS_MT_WIDTH_MINOR  0x33    /* Minor axis (omit if circular) */
#define ABS_MT_ORIENTATION  0x34    /* Ellipse orientation */
#define ABS_MT_POSITION_X   0x35    /* Center X ellipse position */
#define ABS_MT_POSITION_Y   0x36    /* Center Y ellipse position */
#define ABS_MT_TOOL_TYPE    0x37    /* Type of touching device */
#define ABS_MT_BLOB_ID      0x38    /* Group a set of packets as a blob */
#define ABS_MT_TRACKING_ID  0x39    /* Unique ID of initiated contact */
#define ABS_MT_PRESSURE     0x3a    /* Pressure on contact area */
#define ABS_MT_DISTANCE     0x3b    /* Contact hover distance */
           

其實我們比較常用的就是觸摸中心點的螢幕絕對坐标 x、y 值。添加 

-l

 參數,再來操作一遍,看下 

getevent -l

 指令的輸出資訊:

/dev/input/event2: EV_ABS       ABS_MT_TRACKING_ID   0000008a
/dev/input/event2: EV_ABS       ABS_MT_POSITION_X    000003b3
/dev/input/event2: EV_ABS       ABS_MT_POSITION_Y    0000014c
/dev/input/event2: EV_ABS       ABS_MT_PRESSURE      000003e8
/dev/input/event2: EV_KEY       BTN_TOUCH            DOWN
/dev/input/event2: EV_SYN       SYN_REPORT           00000000
/dev/input/event2: EV_ABS       ABS_MT_PRESSURE      00000000
/dev/input/event2: EV_ABS       ABS_MT_TRACKING_ID   ffffffff
/dev/input/event2: EV_KEY       BTN_TOUCH            UP
/dev/input/event2: EV_SYN       SYN_REPORT           00000000
           

除了兩次觸摸螢幕引發的事件攜帶資料上非常小的 x、y 值差異外,其他都是一樣的。

sendevent

了解完 getevent 擷取事件,通過 sendevent 就能夠發送事件。還是使用 help 參數先看下介紹和用法:

yifeng:/ $ sendevent --help
usage: sendevent DEVICE TYPE CODE VALUE

Sends a Linux input event.
           

可以看到,sendevent 指令需要的四個參數(裝置、類型、編碼和資料)剛好就是 getevent 指令擷取到的。那麼模拟前面擷取到的觸摸螢幕事件,就是執行這樣一組指令(需要全部完整執行完一組,不同手機裝置參數也不同):

sendevent /dev/input/event2 0003 0039 00000095
sendevent /dev/input/event2 0003 0035 0000039b
sendevent /dev/input/event2 0003 0036 0000014a
sendevent /dev/input/event2 0003 003a 000003e8
sendevent /dev/input/event2 0001 014a 00000001
sendevent /dev/input/event2 0000 0000 00000000
sendevent /dev/input/event2 0003 003a 00000000
sendevent /dev/input/event2 0003 0039 ffffffff
sendevent /dev/input/event2 0001 014a 00000000
sendevent /dev/input/event2 0000 0000 00000000
           

需要注意的是,真機裝置測試中,可能會遇到 sendevent 不起作用的情況,可能是沒有 input 目錄檔案寫入權限的問題,試着修改一下:

chmod 777 /dev/input/event2
           

input

sendevent 指令通過一組指令才能完成一個事件,而且參數複雜。相比較而言,input 指令就簡單直接多了。

yifeng:/ $ input
Usage: input [<source>] <command> [<arg>...]

The sources are:
      dpad
      keyboard
      mouse
      touchpad
      gamepad
      touchnavigation
      joystick
      touchscreen
      stylus
      trackball

The commands and default sources are:
      text <string> (Default: touchscreen)
      keyevent [--longpress] <key code number or name> ... (Default: keyboard)
      tap <x> <y> (Default: touchscreen)
      swipe <x1> <y1> <x2> <y2> [duration(ms)] (Default: touchscreen)
      draganddrop <x1> <y1> <x2> <y2> [duration(ms)] (Default: touchscreen)
      press (Default: trackball)
      roll <dx> <dy> (Default: trackball)
      tmode <tmode>
           

比如,向手機上已經擷取焦點的輸入框輸入一段文本内容,就是這樣:

input text "hello world"
           

再比如,發送觸摸螢幕事件,使用 tap 指令,提供 x、y 坐标即可:

input tap 100 500
           

input 指令還有 swipe、press 等其他用法,這裡就不一一介紹了。

注意事項

前面提到的 getevent、sendevent 和 input 操作事件的指令,在部分手機上還存在另一個操作權限的問題。

如果你在操作時遇到這樣的提示資訊,比如 getevent 指令遇到權限拒絕提示:

yifeng:/ $ getevent
could not open /dev/input/event7, Permission denied
could not open /dev/input/event6, Permission denied
could not open /dev/input/event5, Permission denied
could not open /dev/input/event3, Permission denied
could not open /dev/input/mice, Permission denied
could not open /dev/input/event1, Permission denied
could not open /dev/input/event4, Permission denied
could not open /dev/input/event0, Permission denied
could not open /dev/input/event2, Permission denied
           

input 指令遇到 killed 提示資訊:

yifeng:/ $ input text "hello world"
Killed
           

這個時候,隻需要到手機「開發者選項」設定中,找到 USB 調試子產品中的這個選項:

USB調試(安全設定)

按照提示,一步步操作,打開即可。

android getevent sendevent input 接收發送事件geteventsendeventinput注意事項

長按識别二維碼,即可關注我

原創推薦

高精度高仿「開眼」,這個開源項目值得學習

禁用 testOnly 屬性,解決 debug 包安裝失敗

解決 Adb Unavailable,嘗試了一千種方案後