首页
论坛
专栏
课程

[原创]通过sendevent实现多点连续滑动

2019-6-18 17:31 3354

[原创]通过sendevent实现多点连续滑动

2019-6-18 17:31
3354

0x00 ...

最近在瞎琢磨Android设备的云控,想要实现一个多点滑动的功能。我们知道通过shell执行input swipe x1 y1 x2 y2 t可以实现t毫秒内从坐标(x1, y1)滑动到(x2, y2),滑动完成后模拟的动作就“被抬起”,很难直接通过input实现滑动”转弯“。于是花了半天时间看了一下sendevent的参数含义,简单实现了连续滑动的功能。

0x01 简述

sendevent需要4个参数,如下:
use: sendevent device type code value
含义分别是设备、事件类型、事件代码以及传递的数据。
在分析之前可以通过getevent获取事件的数据以便参照,如下为简单滑动后获取的数据:

/dev/input/event0: 0003 0039 00000c3a
/dev/input/event0: 0001 014a 00000001
/dev/input/event0: 0001 0145 00000001
/dev/input/event0: 0003 0035 00000124
/dev/input/event0: 0003 0036 00000393
/dev/input/event0: 0003 0031 00000005
/dev/input/event0: 0000 0000 00000000
/dev/input/event0: 0003 0031 00000006
/dev/input/event0: 0000 0000 00000000
/dev/input/event0: 0003 0030 00000007
/dev/input/event0: 0000 0000 00000000
/dev/input/event0: 0003 0030 00000006
/dev/input/event0: 0000 0000 00000000
/dev/input/event0: 0003 0036 00000391
/dev/input/event0: 0003 0030 00000007
/dev/input/event0: 0000 0000 00000000
/dev/input/event0: 0003 0036 0000038f
/dev/input/event0: 0003 0030 00000006
/dev/input/event0: 0000 0000 00000000
/dev/input/event0: 0003 0035 00000125
/dev/input/event0: 0003 0036 00000389
/dev/input/event0: 0000 0000 00000000
/dev/input/event0: 0003 0035 00000126
/dev/input/event0: 0003 0036 00000380
/dev/input/event0: 0000 0000 00000000
/dev/input/event0: 0003 0035 00000133
/dev/input/event0: 0003 0036 00000353
/dev/input/event0: 0000 0000 00000000
/dev/input/event0: 0003 0035 0000013a
/dev/input/event0: 0003 0036 00000341
/dev/input/event0: 0003 0031 00000005
/dev/input/event0: 0000 0000 00000000

....
/dev/input/event0: 0003 0035 0000031c
/dev/input/event0: 0003 0036 000002a3
/dev/input/event0: 0000 0000 00000000
/dev/input/event0: 0003 0039 ffffffff
/dev/input/event0: 0001 014a 00000000
/dev/input/event0: 0001 0145 00000000
/dev/input/event0: 0000 0000 00000000

type和code的含义可参照内核源码中的input.h,笔者用的Nexus6P,msm-android-msm-angler-3.10-nougat-mr2,该头文件位于include/uapi/linux/input.h。

 

滑动所需的type含义如下:

type 0000 Synchronization events
type 0001 Keys and buttons
type 0003 Absolute axes,即描述运动事件的值

 

code含义如下

0000 0000 SYN_REPORT,这里笔者简单理解为与io的flush类似
0003 0039 开始接触设备的唯一标识号,这里为0xc3a, 0xffffffff代表结束接触
0001 014a 标明触摸事件,1代表按下,0代表放开
0001 0145 表明是用手指触摸的,同样1代表按下,0代表放开
0003 0035 触摸的x坐标
0003 0036 触摸的y坐标
0003 0030 接触面椭圆长轴,非必需
0003 0031 接触面椭圆短轴,非必需

0x02 实现

其实到这里已经很清晰了,开始接触->按下->一系列坐标移动->结束接触->放开,通过坐标的移动可以控制滑动的痕迹,sendevent执行的快慢控制滑动的快慢。要注意最好执行在同一个shell,并且不要阻塞(waitfor)。
给出的代码直接调用即可:

EventEmulator.swipeStart();
EventEmulator.swipeRun(357, 2054, 1112, 1308);
EventEmulator.swipeRun(1112, 1308, 1112, 2032);
EventEmulator.swipeEnd();

即从(357, 2054)滑动到(1112, 1308),接着又滑到(1112, 2032)。代码写得很粗糙。

 

如果需要改变滑动的速度,可以将代码里控制坐标间隔次数的值SWIPE_RUN_INTERVAL改小一点,间隔次数越少,滑动越快。

    private static final int SWIPE_RUN_INTERVAL = 5;

    public static void swipeRun(int x1, int y1, int x2, int y2) {
        int xStep = (x2 - x1) / SWIPE_RUN_INTERVAL;
        int yStep = (y2 - y1) / SWIPE_RUN_INTERVAL;

        int x = x1, y = y1;
        for (int step = 0; step <= SWIPE_RUN_INTERVAL; ++step) {
            sendEvent(EV_ABS, ABS_MT_POSITION_X, x);
            sendEvent(EV_ABS, ABS_MT_POSITION_Y, y);
            sendEvent(EV_SYN, SYN_REPORT, 0);
            x += xStep;
            y += yStep;
        }
    }

0x03 TODO

为了更好地拟人,滑动速度的大小以及变化、路线是否弯曲都应该做相应调整,并且需要加上接触面长短轴变化的时间。



[招生]科锐逆向工程师培训(3月6日远程教学班首开特惠, 第37期) !

最后于 2019-11-20 10:02 被Umiade编辑 ,原因:
上传的附件:
最新回复 (10)
scxc 2 2019-6-19 13:21
2
0
qqsunqiang 2019-6-19 13:48
3
0
谢谢楼主。
雨天不带鱼 2019-11-19 14:21
4
0
谢谢
雨天不带鱼 2019-11-19 20:22
5
0
雨天不带鱼 谢谢
为啥滑动的时候会停顿一下然后继续滑动、好像不太流畅。是因为shell的问题?
Umiade 2019-11-20 09:54
6
0
雨天不带鱼 为啥滑动的时候会停顿一下然后继续滑动、好像不太流畅。是因为shell的问题?

之前测试的时候影响速度的一个是shell,一个是移动坐标间隔的次数
shell就是我上面说的用同一个进程,直接将命令写入流

    public static Process nonBlockShell;
    public static DataOutputStream nonBlockOutputStream;

    public static BufferedReader nonBlockSuccessResult = null;
    public static BufferedReader nonBlockErrorResult = null;

    static {
        initNonBlockShell();
    }

    public static int initNonBlockShell() {
        try {
            nonBlockShell = Runtime.getRuntime().exec("su");
            nonBlockOutputStream = new DataOutputStream(nonBlockShell.getOutputStream());
            nonBlockSuccessResult = new BufferedReader(new InputStreamReader(nonBlockShell.getInputStream()));
            nonBlockErrorResult = new BufferedReader(new InputStreamReader(nonBlockShell.getErrorStream()));
            readNonBlockStream();
        } catch (Throwable e) {
            e.printStackTrace();
            return -1;
        }
        return 0;
    }

    public static void readNonBlockStream() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    while (nonBlockSuccessResult != null) {

                        String s;
                        while ((s = nonBlockSuccessResult.readLine()) != null) {
                            Logger.i("[<< EXEC SUCCESS]" + s);
                        }
                    }
                } catch (Exception e) {
                    Logger.e("read nonBlockSuccessResult error:", e);
                }
            }
        }).start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    while (nonBlockErrorResult != null) {
                        String e;
                        while ((e = nonBlockErrorResult.readLine()) != null) {
                            Logger.e("[<< EXEC ERROR]" + e);
                        }
                    }
                } catch (Exception e) {
                    Logger.e("read nonBlockErrorResult error:", e);
                }
            }
        }).start();

    }

    public static int execNonBlockRootCmd(String cmd) {
        int ret = 0;
        if (null == nonBlockShell || null == nonBlockOutputStream) {
            if (initNonBlockShell() < 0) {
                Logger.e("execNonBlockRootCmd getRuntime for su error!");
                return -1;
            }
        }
        Logger.d("[>>]" + cmd);
        try {
            nonBlockOutputStream.writeBytes(cmd + "\n");
            nonBlockOutputStream.flush();

        } catch (Exception e) {
            Logger.e("execNonBlockRootCmd error:", e);
            ret = -1;
        }
        return ret;
    }

至于坐标之间的间隔,将上面代码里面SWIPE_RUN_INTERVAL改小一点,可以明显提高滑动速度。

雨天不带鱼 2019-11-20 10:10
7
0
Umiade 之前测试的时候影响速度的一个是shell,一个是移动坐标间隔的次数 shell就是我上面说的用同一个进程,直接将命令写入流 ``` public static Process nonBlock ...
好的、我试试!谢谢!
supperlitt 2019-11-21 10:59
8
0
能用不?,听说发送要把,16进制改成10进制?
Umiade 2019-11-21 13:53
9
0
supperlitt 能用不?,听说发送要把,16进制改成10进制?
都用字符串写入流了默认当然是十进制的
雨天不带鱼 2019-11-21 18:30
10
0
supperlitt 能用不?,听说发送要把,16进制改成10进制?
可以使用、项目已经跑起来了 很不错的!
gqm 2019-12-16 18:28
11
0
老兄可以找你定做个这 控制器吗?
游客
登录 | 注册 方可回帖
返回