Android имитирует быстрый салфетки

Я делаю универсальную автоматизацию script.

Мне нужно отправить сложные события салфетки на экран Android, не имея особого доступа к сфокусированным приложениям.

Лучший способ, который я догадался до сих пор, - использовать adb, создать файл с командами sendevent, нажать на него и запустить его оттуда. Даже это, это мучительно медленно (гораздо медленнее, если я записываю его с помощью getevent и возвращаю его обратно).

Мне удалось оптимизировать файл, так как я понял, что каждый блок отправления специально не требует как 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

Итак, я сосредоточен на оптимизации скорости одиночных длинномерных сложностей, а не нескольких небольших.

Кто-нибудь знает лучший способ сделать это?


Итак, идея Криса Стриттона работала в принципе (повторное подключение вывода cat-ed дает тот же салфетки успешно), но я не могу создать свой собственный код, чтобы его снова подключить. Я предполагаю, что это что-то делать с разделителями между командами событий отправки... но я все еще не могу заставить его работать

Я использовал модификацию файла sendevent.c для получения файла с тройками на строку и вывода в другой файл. Вы случайно не знаете, в чем проблема? Конверсия выглядит хорошо...


РЕШЕНИЕ: Мне удалось это решить, в основном благодаря ответам ниже. Вот C script, который принимает файл с значениями 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;
}

Ответ 1

Обратите внимание, что этот ответ относится к версиям Android около 2013 года и может не относиться к текущим версиям. В то время желе было современным, Киткат вышел через несколько недель после того, как был задан вопрос

Ваша задержка, вероятно, является результатом неэффективного повторного запуска нового процесса 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 или другого во input unix-группе, вы должны иметь возможность выполнить то же, что sendevent делает из вашей собственной пользовательской программы или с помощью других инструментов командной строки, таких как cat, таким образом эффективно выдвигая двоичный файл файл записей событий.

Например

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

Сделайте несколько событий на сенсорном экране, затем нажмите Ctrl-C, чтобы убить кота.

Теперь вы можете воспроизвести захваченный файл бинарных событий:

cat events > /dev/input/event2 

(Примечание: sendevent обнуляет timeval часть каждой записи; запись и воспроизведение могут этого не делать; вам придется посмотреть, и если это имеет значение, обнулить эти части каждой записи из файла перед тем, как записать его обратно)

Ответ 2

Если вы просто хотите создать линейные прокрутки, вы можете использовать команду 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

Ответ 3

У кого-нибудь есть успех с лучшим ответом на Android 7.0? Я попытался изменить несколько параметров и попытаться изменить этот параметр, и все, что не будет работать. Даже если я использую исходный код для 7.0 файла sendevent.c из ядра Android, он не работает. Телефон рутирован, разрешение измененного отправителя изменено на 777, скомпилировано с помощью ndk. Когда я запускаю его с помощью терминала, он читает точки из файла и показывает строки printf из sendevent, но не хочет касаться.