前言
我们在使用安卓手机的时候,已经很少有人会不借助触摸操作来操作手机了,也就是说对手机的触摸操作已经是我们使用手机时最常见的方式了。那么我们究竟是如何使用这种方式操控手机的呢?手机又是如何处理这些信息的呢?
我们对于手机的触摸操作产生的信息,由Linux/Android多点触摸协议规定了如何进行组织和传输。而对于不同的手机设备,多点触摸协议又分为TypeA和TypeB两种,我的新手机(嘿嘿嘿开心)OnePlus7 pro是属于TypeB类型的,那么在这里就用TypeB来举例说明。
而选择Go语言来进行编写而不是使用诸如Python这种更加成熟,更加适合写脚本的语言来进行数据的解析和组织的原因是,我最近比较迷golang,仅此而已。而且使用Python现成的包我又有什么能学到呢?
概念解释
- 多点触摸协议
- TypeA
- TypeB
- ADB
多点触摸协议(Multi-touch Protocol)
为了满足现在的先进设备在面对多点和多用户时的数据采集,Linux实现了现在的多点触摸协议,多点触摸协议分为TypeA和TypeB两种,分别面对不同的硬件。TypeA是面对没有多用户的设备,通过所有的点的发送报告来跟踪不同的触点行为。而TypeB则是支持多用户的设备,通过使用不同的信号槽(slot)和信号轨道(track)来发送数据。
TypeA
举一个TypeA设备中多点触摸协议产生的数据的小例子(两个触摸点的最小发送序列):
ABS_MT_POSITION_X x[0]
ABS_MT_POSITION_Y y[0]
SYN_MT_REPORT
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_MT_REPORT
SYN_REPORT
可以很清晰的看出,多点触摸协议的内容是通过报告的形式发送的,即SYN_MT_REPORT和SYN_REPORT。
前者代表一个时刻中一个点发送了一个数据点的报告,也就是说,x[0]y[0]这个点的触摸记录和x[1]y[1]的触摸记录是同时被报告的,它们都通过一个SYN_REPORT被发送到上级应用或者协议。
在报告的时候,有时不仅仅包含坐标点的信息:触摸宽度和压力在某些设备上也会被记录。
TypeB
接下来是同样的只有两个触摸点的最小发送序列。
ABS_MT_SLOT 0
ABS_MT_TRACKING_ID 45
ABS_MT_POSITION_X x[0]
ABS_MT_POSITION_Y y[0]
ABS_MT_SLOT 1
ABS_MT_TRACKING_ID 46
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_REPORT
可以清晰的看出,每一个单独的触摸轨迹,在一个SYN_REPORT中通过一个信号槽发送。
信号槽是可以复用的,当一个slot中的tracking id为-1的时候,回收一个slot。
ADB - Android Debug Bridge
Android 调试桥 (adb) 是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试应用,并提供对 Unix shell(可用来在模拟器或连接的设备上运行各种命令)的访问。
可以很简单的在你的电脑上使用ADB和你的手机进行连接。
安装
sudo apt-get install adb
启动
adb shell
更多的使用方法读者可以自己去查找,这里不是专门讲解adb的文章,所以就不赘述了。
流程
数据结构
代码:
文件结构
.
├── analysis
│ ├── analysis.go
│ ├── dataStructure.go
│ ├── factory.go
│ └── out.txt
└── getevent
├── getevent.go
└── out.txt
./getevent/getevent.go
package main
import (
"bufio"
"fmt"
"os/exec"
"os"
"time"
)
func main() {
start := time.Now()
cmd := exec.Command("adb", "shell", "getevent", "-lt")
file, err := os.OpenFile("out.txt", os.O_WRONLY|os.O_APPEND, 0644)
defer file.Close()
stdout, err := cmd.StdoutPipe()
if err != nil {
fmt.Printf("Error:can not obtain stdout pipe for command:%s\n", err)
return
}
if err := cmd.Start(); err != nil {
fmt.Println("Error:The command is err,", err)
return
}
outputBuf := bufio.NewReaderSize(stdout, 128)
errChan := make(chan error)
count := 0
go func() {
for {
output, _, _ := outputBuf.ReadLine()
file.Write(append(output, '\n'))
go func() {
count += 1
fmt.Printf("%s Now: %d\r", fmtDuration