ADB 模拟输入事件总结
ADB 模拟输入事件
通过 adb shell 命令可以模拟用户的输入行为,通过脚本的形式操作手机。有两个命令支持进行模拟行为:input 和 sendevent 。
input command
通过 help 命令查看用法:
```shell ➜ ~ adb shell input help Usage: input [
The sources are: dpad keyboard mouse touchpad gamepad touchnavigation joystick touchscreen stylus trackball
-d: specify the display ID. (Default: -1 for key event, 0 for motion event if not specified.)
The commands and default sources are:
text
source 的类型包括:
| Source 类型 | 含义 | | --------------- | -------------------------------- | | dpad | 十字键,通常是游戏手柄上的方向键 | | keyboard | 键盘 | | mouse | 鼠标 | | touchpad | 触控板 | | gamepad | 手柄 | | touchnavigation | 导航条 | | joystick | 操纵杆 | | touchscreen | 触屏 | | stylus | 手写笔 | | trackball | 轨迹球 |
第三个参数是 -d
,特指显示 ID ,默认 -1 代表键值事件, 0 代表手势事件。
命令的用途和默认的源目标设备类型配置:
| 命令 | 用途 | 默认目标设备类型 |
| ------------------------------------------------------ | ---------------------- | ---------------- |
| text <string>
| 模拟输入文字 | touchscreen |
| keyevent [--longpress] <key code number or name> ...
| 模拟键值事件 | keyboard |
| tap <x> <y>
| 模拟手势点击事件 | touchscreen |
| swipe <x1> <y1> <x2> <y2> [duration(ms)]
| 模拟滑动 | touchscreen |
| draganddrop <x1> <y1> <x2> <y2> [duration(ms)]
| 模拟拖拽 | touchscreen |
| press
| 模拟按下轨迹球 | trackball |
| roll <dx> <dy>
| 模拟滚动轨迹球 | trackball |
| motionevent <DOWN|UP|MOVE> <x> <y>
| 模拟 motion event 事件 | touchscreen |
从这里可以看出,通过 ADB 的 input 命令,可以模拟两大类事件:KeyEvent 和 MotionEvent 。
模拟 KeyEvent 事件
adb shell input keyevent <keycode>
keycode 是 int 类型,它支持的事件定义在 android.view.KeyEvent
类中带有 KEYCODE_
前缀的常量值。
参看官方 Wiki:http://developer.android.com/reference/android/view/KeyEvent
这里举个简单的例子:
```shell
模拟点击音量 - 键
adb shell input keyevent EYCODE_VOLUME_DOWN
也可以换成数字
adb shell input keyevent 25
模拟长按事件,触发长按事件后就会取消按压。长按时间短,仅触发长按需要的最短时间。
adb shell input --longpress keyevent 25 ```
支持模拟的按键包括键盘、鼠标、游戏手柄等等,基本涵盖了所有可能的外设。
模拟 MotionEvent 事件
```shell
模拟 ACTION_DOWN ,坐标位置 100,200
adb shell input motionevent DOWN 100 200 ```
MotionEvent 支持三种类型的事件,对应 ACTION_DOWN / ACTION_MOVE / ACTION_UP ,再输入对应的坐标就可以了。
但是测试发现,在 MOVE 的情况下,命令输入的距离不适合过长,例如:
shell
adb shell input motionevent DOWN 500 1000
adb shell input motionevent MOVE 500 900
adb shell input motionevent UP 500 900
这样是没有出现明显的滑动的。
但每次更新距离变小:
adb shell input motionevent DOWN 500 1000
adb shell input motionevent MOVE 500 990
adb shell input motionevent MOVE 500 980
adb shell input motionevent MOVE 500 970
adb shell input motionevent MOVE 500 960
adb shell input motionevent MOVE 500 950
adb shell input motionevent MOVE 500 940
adb shell input motionevent MOVE 500 930
adb shell input motionevent MOVE 500 920
adb shell input motionevent MOVE 500 910
adb shell input motionevent MOVE 500 900
adb shell input motionevent UP 500 900
这样屏幕上就会出现明显的滑动了,这里建议使用 for 来循环执行一个连续的移动。
当然上面的一组代码可以直接使用 adb shell input swipe x1 y1 x2 y2
来执行,更加方便。
getevent / sendevent command
getevent
通过 adb shell sendevent
也可以完成模拟 KeyEvent 和 MotionEvent 操作。但在模拟操作前,先通过监听设备的输入事件来分析下事件内容,终端输入:
shell
➜ ~ adb shell getevent
add device 1: /dev/input/event6
name: "sdm660-snd-card-mtp Button Jack" # 高通 660 平台上的按钮
add device 2: /dev/input/event5
name: "sdm660-snd-card-mtp Headset Jack" # 高通 660 平台上的耳机接口
add device 3: /dev/input/event1
name: "touchpanel" # 触控面板
add device 4: /dev/input/event4
name: "gpio-keys" # linux内核中的驱动, 这里定义了输入音量加减键的事件
add device 5: /dev/input/event2
name: "touchpanel_kpd" # 虚拟按键
add device 6: /dev/input/event0
name: "qpnp_pon" # 高通平台按键驱动 (电源键)
add device 7: /dev/input/event3
name: "STM VL53L0 proximity sensor" # 距离传感器
could not get driver version for /dev/input/mice, Not a typewriter
输入 adb shell getevent
后,会打印出几个设备信息,此时如果你操作手机,就会在终端中不断输出输入事件。例如这里按了一下电源键:
/dev/input/event0: 0001 0074 00000001
/dev/input/event0: 0000 0000 00000000
/dev/input/event0: 0001 0074 00000000
/dev/input/event0: 0000 0000 00000000
按音量键:
/dev/input/event4: 0001 0072 00000001
/dev/input/event4: 0000 0000 00000000
/dev/input/event4: 0001 0072 00000000
/dev/input/event4: 0000 0000 00000000
触摸屏幕:
/dev/input/event1: 0003 0039 00003b0e
/dev/input/event1: 0001 014a 00000001
/dev/input/event1: 0003 0032 00000007
/dev/input/event1: 0003 003a 0000000a
/dev/input/event1: 0003 0035 00000071
/dev/input/event1: 0003 0036 000000d2
/dev/input/event1: 0000 0000 00000000
/dev/input/event1: 0003 0039 ffffffff
/dev/input/event1: 0001 014a 00000000
/dev/input/event1: 0000 0000 00000000
通过 -l
参数以字符串的形式输出内容:
``` ➜ ~ adb shell getevent -l ...
按下音量 - 键
/dev/input/event4: EV_KEY KEY_VOLUMEDOWN DOWN /dev/input/event4: EV_SYN SYN_REPORT 00000000 /dev/input/event4: EV_KEY KEY_VOLUMEDOWN UP /dev/input/event4: EV_SYN SYN_REPORT 00000000
点击屏幕
/dev/input/event1: EV_ABS ABS_MT_TRACKING_ID 00003b19 /dev/input/event1: EV_KEY BTN_TOUCH DOWN /dev/input/event1: EV_ABS ABS_MT_WIDTH_MAJOR 00000009 /dev/input/event1: EV_ABS ABS_MT_PRESSURE 0000000a /dev/input/event1: EV_ABS ABS_MT_POSITION_X 00000219 /dev/input/event1: EV_ABS ABS_MT_POSITION_Y 0000059b /dev/input/event1: EV_SYN SYN_REPORT 00000000 /dev/input/event1: EV_ABS ABS_MT_PRESSURE 00000008 /dev/input/event1: EV_SYN SYN_REPORT 00000000 /dev/input/event1: EV_ABS ABS_MT_PRESSURE 00000005 /dev/input/event1: EV_SYN SYN_REPORT 00000000 /dev/input/event1: EV_ABS ABS_MT_TRACKING_ID ffffffff /dev/input/event1: EV_KEY BTN_TOUCH UP /dev/input/event1: EV_SYN SYN_REPORT 00000000 ```
以 /dev/input/event4: 0001 0072 00000001
为例,说明一下事件的格式和含义:
| 日志组成部分 | /dev/input/event4 | 0001 | 0072 | 00000001 | | ------------ | ----------------- | -------- | -------------------------------- | --------------------- | | 含义 | 代表输入设备 | 事件类型 | 事件唯一 ID,例如 KEY_VOLUMEDOWN | ACTION 类型或其他参数 |
getevent 命令的其他参数和用法
shell
➜ ~ adb shell getevent --help
getevent: invalid option --
Usage: getevent [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]
-t: 展示时间戳
-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
sendevent
在了解了 getevent 抓取到的事件内容后,我们可以模仿事件日志来输入,通过 adb shell sendevent
命令来完成:
```shell
按下 Power 键
adb shell sendevent /dev/input/event0 1 116 1 adb shell sendevent /dev/input/event0 0 0 0
adb shell sendevent /dev/input/event0 1 116 0 adb shell sendevent /dev/input/event0 0 0 0 ```
通过 sendevent 我们可以模拟自定义时间的长按:
```shell adb shell sendevent /dev/input/event0 1 116 1 adb shell sendevent /dev/input/event0 0 0 0
长按 3s
sleep 3 adb shell sendevent /dev/input/event0 1 116 0 adb shell sendevent /dev/input/event0 0 0 0 ```
sendevent 的事件格式和 getevent 接收到的格式相同。
- 通知监控 NotificationListenerService 的 onNotificationPosted 重复回调问题
- Android View 知识体系
- Kotlin 协程的取消机制超详细解读
- Android ViewPager2 使用 自定义指示器视图
- Android ViewModel 超详细分析
- Android 无障碍监听通知的过程
- ADB 模拟输入事件总结
- Android 单元测试基础
- Java 多线程并发【13】FutureTask
- Android UI 测试基础
- Android 无障碍全局悬浮窗实现方案
- Java 多线程并发 【11】ReentrantReadWriteLock
- Java 多线程并发 【10】ReentrantLock
- Java 多线程并发【8】LockSupport
- Java 多线程并发【4】虚拟机锁优化方案
- 散列表 及其在 JDK 中的实现
- Android 应用架构指南
- Kotlin/Java 数据类型的底层逻辑
- Android 主线程一定是 UI 线程吗?
- Context.getSystemService 获取 Manager 的底层实现