【问题标题】:Android simulate fast swipeAndroid模拟快速滑动
【发布时间】:2013-09-28 03:55:45
【问题描述】:

我正在做一个通用的自动化脚本。

我需要将复杂的滑动事件发送到 Android 屏幕,而无需专门访问重点应用程序

到目前为止,我认为最好的方法是使用 adb,使用 sendevent 命令创建一个文件,将其推送到设备上并从那里运行它。即便如此,它还是非常缓慢(与我使用 getevent 记录并通过管道重新输入相比要慢得多)。

我设法优化了文件,因为我发现每个 sendevent 块并不特别需要 X 和 Y,但它仍然慢了几个数量级

部分文件示例(我正在尝试使用 HTC One):

sendevent /dev/input/event5 3 57 49
sendevent /dev/input/event5 3 53 942
sendevent /dev/input/event5 3 54 2747
sendevent /dev/input/event5 0 0 0

sendevent /dev/input/event5 3 53 1207
sendevent /dev/input/event5 3 54 2483
sendevent /dev/input/event5 0 0 0

sendevent /dev/input/event5 3 53 1472
sendevent /dev/input/event5 0 0 0

sendevent /dev/input/event5 3 54 2218
sendevent /dev/input/event5 0 0 0

sendevent /dev/input/event5 3 53 1207
sendevent /dev/input/event5 3 54 2483
sendevent /dev/input/event5 0 0 0

sendevent /dev/input/event5 3 53 1472

所以我的重点是优化单次长而复杂的滑动速度,而不是多次小的滑动速度。

有人知道更好的方法吗?


所以,Chris Stratton 的想法在原则上是有效的(重新对 cat-ed 输出进行管道化会成功生成相同的滑动),但我无法创建自己的代码来将其重新输入。我猜是与发送事件命令之间的分隔符有关......但我仍然无法让它工作

我使用了 sendevent.c 文件的修改来获得一个每行包含三元组的文件并输出到另一个文件。你碰巧知道可能是什么问题吗?转换看起来不错...


解决方案:我设法解决了它,主要归功于下面的答案。这是一个 C 脚本,它接受一个具有 HEX 值的文件并输出相应的二进制文件。

用法:(对我来说,触摸驱动程序文件是 /dev/input/event5 - HTC One - 对于其他设备,它可能是不同的文件!!!)

 $> adb shell getevent > tmp.in
 $> ./sendevent tmp.in tmp.out
 $> adb shell push tmp.out /mnt/sdcard/
 $> adb shell "cd /mnt/sdcard/ && cat tmp.out > /dev/input/event5"

来源:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>

typedef uint32_t        __u32;
typedef uint16_t        __u16;
typedef __signed__ int  __s32;

__attribute__((aligned(1),packed)) struct input_event {
    __u32 time_dummy_1;
    __u32 time_dummy_2;
    __u16 type;
    __u16 code;
    __s32 value;
};

int convert (char * str) {
    return (int) strtol(str, NULL, 16);
}

#define S_ALL (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH)

int main (int argc, char *argv[]) {
    int i;
    int fd;
    int ret;

    if(argc < 3) {
        fprintf(stderr, "use: %s in-file out-file\n", argv[0]);
        return 1;
    }

    fd = open(argv[2], O_CREAT | O_WRONLY, S_ALL);
    if(fd < 0) {
        fprintf(stderr, "could not open %s, %s\n", argv[2], strerror(errno));
        return 1;
    }

    FILE * fd_in = fopen(argv[1], "r");
    if (fd_in == NULL) {
        fprintf(stderr, "Can't open input file: %s\n", argv[1]);
        return 1;
    }

    struct input_event event;
    char type[32];
    char code[32];
    char value[32];
    int count = 0;
    while (fscanf(fd_in, "%s %s %s", type, code, value) != EOF) {
        memset(&event, 0, sizeof(event));
        // printf("%d) %s %s %s\n", ++count, type, code, value);
        event.type = convert(type);
        event.code = convert(code);
        event.value = convert(value);
        memset(type, 0, sizeof(type));
        memset(code, 0, sizeof(code));
        memset(value, 0, sizeof(value));
        ret = write(fd, &event, sizeof(event));
        if(ret < sizeof(event)) {
            fprintf(stderr, "write event failed, %s\n", strerror(errno));
            return -1;
        }
    }

    return 0;
}

【问题讨论】:

  • 我知道这是一个老问题,但你能解释一下如何把这个新的 sendevents.c 文件放到安卓设备上吗,我想你会使用 adb push 但不知道我在哪个目录可以放置文件,使其成为可执行文件。
  • 我现在创建了一个更合适的问题。您的帮助将不胜感激。 stackoverflow.com/questions/23131081/…
  • 我发布了您问题的答案。希望对您有所帮助:stackoverflow.com/questions/23131081/…

标签: android adb


【解决方案1】:

请注意,此答案适用于大约 2013 年的 Android 版本,可能不适用于当前版本。 Jellybean 当时是同时代的,Kitkat 在被问到问题几周后就出来了

您的延迟可能是由于必须重复启动新的sendevent 进程、解析文本事件记录并打开设备节点(针对每个单独的事件)效率低下的结果。如果您改为在一个进程中执行所有操作,只打开一次设备文件,效率会高得多。

如果我们在工具箱中查看 sendevent 的来源与问题的日期同时发生(例如,https://android.googlesource.com/platform/system/core/+/jb-release/toolbox/sendevent.c),我们会看到它所做的核心是将事件编码为二进制记录

struct input_event {
    struct timeval time;
    __u16 type;
    __u16 code;
    __s32 value;
};

并将它们写入适当的设备

memset(&event, 0, sizeof(event));
event.type = atoi(argv[2]);
event.code = atoi(argv[3]);
event.value = atoi(argv[4]);
ret = write(fd, &event, sizeof(event));

假设您正在以shell 用户ID 或input unix 组中的另一个身份执行某些操作,您应该能够通过您自己的自定义程序或使用其他命令行来完成sendevent 所做的相同操作cat 之类的工具,从而有效地推送事件记录的二进制文件。

例如

adb shell
cd /mnt/sdcard
cat /dev/input/event2 > events

做几个触屏事件,然后ctrl-C杀猫

现在您可以回放捕获的二进制事件文件:

cat events > /dev/input/event2 

(注意:sendevent 将每条记录的timeval 部分归零;录制和播放可能不会这样做;您必须先查看,如果重要,请在写入文件之前将文件中的每条记录的这些部分归零返回)

【讨论】:

  • 这似乎是个好主意。让我试试看,我会回复你的
  • 它几乎可以工作,你能看看我更新的帖子,也许你知道出了什么问题
  • @tak3r - 虽然我不知道这是否是您唯一的问题,但看起来您正在为 int 使用格式说明符,即“%d”,但传递了一个指向 __u16 的指针(实际上是 fscanf 的 unsigned short)。您可能想要“%hu”,或者将它读入一个临时的无符号整数,然后将其复制过来。
  • 好的,改变了,但仍然没有效果。不确定它有多重要,但是如果我用 cat 记录它,那么对于随机复杂的滑动... | wc 它给出:52 301 8640 并行我还注册了 adb getevent 输出,将值转换为基数 10 并在其上运行 ./sendevent,之后结果为:0 11 7704 使用 sendevent 记录的事件数为 321,即非常接近 wc 报告的单词数量,这就是为什么(以及我的没有线条的事实)我认为这主要与某种分隔符有关
  • 尝试在您的开发机器上针对常规文件目标运行,并使用十六进制转储输出进行比较。或者只是将您的输入与输出的 hexdump 进行比较。
【解决方案2】:

如果你只是想产生线性滑动,你可以在 shell 上使用input swipe 命令。

$ adb shell input
usage: input ...
       input text <string>
       input keyevent <key code number or name>
       input [touchscreen|touchpad|touchnavigation] tap <x> <y>
       input [touchscreen|touchpad|touchnavigation] swipe <x1> <y1> <x2> <y2> [duration(ms)]
       input trackball press
       input trackball roll <dx> <dy>

下面的命令在绘图应用程序中为我画了一条漂亮的线

$ adb shell input swipe 300 300 500 1000

还有一个更快的

$ adb shell input touchscreen swipe 300 300 500 1000 100

【讨论】:

  • 不幸的是,我需要复杂的滑动,或者如果有线性滑动,那么我需要它们最后没有 keyup 事件,这样我就可以在一次复杂的滑动中组合它们
  • @tak3r 你有root权限吗?
  • 我认为不需要 root 访问权限。这似乎可以从 adb shell 使用,这意味着 shell 用户 ID 有权执行所需的任何操作。输入命令是一个脚本,它使用 app-process 来启动 input.java(非官方 repo github.com/android/platform_frameworks_base/blob/master/cmds/…),大概可以用类似编译和存储的自定义版本替换。并且类似地从 adb shell 调用 - 您将无法从具有最终运行安全模型的应用程序中执行此操作。
  • @ChrisStratton 不幸的是没有。在系统目录下使该应用程序与组件交谈,否则是不可能的。您甚至无法在 Android 存储库之外构建该应用,因为它使用隐藏的 API。
  • 大家好。回答上一个问题:我还没有root(我认为HTC One 还没有root)。目前我只从我的 Mac 上的应用程序运行它,我将包含所有发送事件的脚本文件推送到设备,然后从那里运行它,它工作正常。我尝试使用 adb shell 和 cat-ing 进入 /dev/input/event5 (这是我的触摸事件)并且它有效。检查更新的帖子^^
猜你喜欢
  • 2014-10-31
  • 1970-01-01
  • 2014-09-11
  • 2015-12-27
  • 1970-01-01
  • 1970-01-01
  • 2016-12-03
  • 2011-06-16
  • 1970-01-01
相关资源
最近更新 更多