#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/ioctl.h>
//#include <linux/input.h> // this does not compile
#include <errno.h>
// from <linux/input.h>
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
#define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */
#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */
#define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */
#define EVIOCSKEYCODE _IOW('E', 0x04, int[2]) /* set keycode */
#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */
#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */
#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */
#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */
#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */
#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */
#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */
#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */
#define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) /* get abs value/limits */
#define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, struct input_absinfo) /* set abs value/limits */
#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */
#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */
#define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */
#define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */
// end <linux/input.h>
int sendevent_main(int argc, char *argv[])
{
int i;
int fd;
int ret;
int version;
struct input_event event;
if(argc != 5) {
fprintf(stderr, "use: %s device type code value\n", argv[0]);
return 1;
}
fd = open(argv[1], O_RDWR);
if(fd < 0) {
fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno));
return 1;
}
if (ioctl(fd, EVIOCGVERSION, &version)) {
fprintf(stderr, "could not get driver version for %s, %s\n", argv[optind], strerror(errno));
return 1;
}
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));
if(ret < sizeof(event)) {
fprintf(stderr, "write event failed, %s\n", strerror(errno));
return -1;
}
return 0;
}
https://github.com/joneschrisg/android-system-core/blob/master/toolbox/sendevent.c
网上复制的代码怎么都没搞定
离线
sendevent.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/ioctl.h>
//#include <linux/input.h> // this does not compile
#include <errno.h>
extern char *optarg;
extern int optind, optopt, opterr;
// from <linux/input.h>
struct input_event {
struct timeval time;
uint16_t type;
uint16_t code;
int32_t value;
};
#define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */
#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */
#define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */
#define EVIOCSKEYCODE _IOW('E', 0x04, int[2]) /* set keycode */
#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */
#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */
#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */
#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */
#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */
#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */
#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */
#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */
#define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) /* get abs value/limits */
#define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, struct input_absinfo) /* set abs value/limits */
#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */
#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */
#define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */
#define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */
// end <linux/input.h>
int main(int argc, char *argv[])
{
int i;
int fd;
int ret;
int version;
struct input_event event;
if(argc != 5) {
fprintf(stderr, "use: %s device type code value\n", argv[0]);
return 1;
}
fd = open(argv[1], O_RDWR);
if(fd < 0) {
fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno));
return 1;
}
if (ioctl(fd, EVIOCGVERSION, &version)) {
fprintf(stderr, "could not get driver version for %s, %s\n", argv[optind], strerror(errno));
return 1;
}
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));
if(ret < sizeof(event)) {
fprintf(stderr, "write event failed, %s\n", strerror(errno));
return -1;
}
return 0;
}
getevent.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/inotify.h>
#include <limits.h>
#include <sys/poll.h>
#include <linux/input.h> // this does not compile
#include <errno.h>
extern char *optarg;
extern int optind, optopt, opterr;
static struct pollfd *ufds;
static char **device_names;
static int nfds;
enum {
PRINT_DEVICE_ERRORS = 1U << 0,
PRINT_DEVICE = 1U << 1,
PRINT_DEVICE_NAME = 1U << 2,
PRINT_DEVICE_INFO = 1U << 3,
PRINT_VERSION = 1U << 4,
PRINT_POSSIBLE_EVENTS = 1U << 5,
};
static int print_possible_events(int fd)
{
uint8_t *bits = NULL;
ssize_t bits_size = 0;
const char* label;
int i, j, k;
int res, res2;
printf(" events:\n");
for(i = 0; i <= EV_MAX; i++) {
int count = 0;
while(1) {
res = ioctl(fd, EVIOCGBIT(i, bits_size), bits);
if(res < bits_size)
break;
bits_size = res + 16;
bits = realloc(bits, bits_size * 2);
if(bits == NULL) {
fprintf(stderr, "failed to allocate buffer of size %d\n", bits_size);
return 1;
}
}
res2 = 0;
switch(i) {
case EV_SYN:
label = "SYN";
break;
case EV_KEY:
res2 = ioctl(fd, EVIOCGKEY(res), bits + bits_size);
label = "KEY";
break;
case EV_REL:
label = "REL";
break;
case EV_ABS:
label = "ABS";
break;
case EV_MSC:
label = "MSC";
break;
case EV_LED:
res2 = ioctl(fd, EVIOCGLED(res), bits + bits_size);
label = "LED";
break;
case EV_SND:
res2 = ioctl(fd, EVIOCGSND(res), bits + bits_size);
label = "SND";
break;
case EV_SW:
res2 = ioctl(fd, EVIOCGSW(bits_size), bits + bits_size);
label = "SW ";
break;
case EV_REP:
label = "REP";
break;
case EV_FF:
label = "FF ";
break;
case EV_PWR:
label = "PWR";
break;
default:
res2 = 0;
label = "???";
}
for(j = 0; j < res; j++) {
for(k = 0; k < 8; k++)
if(bits[j] & 1 << k) {
char down;
if(j < res2 && (bits[j + bits_size] & 1 << k))
down = '*';
else
down = ' ';
if(count == 0)
printf(" %s (%04x):", label, i);
else if((count & 0x7) == 0 || i == EV_ABS)
printf("\n ");
printf(" %04x%c", j * 8 + k, down);
if(i == EV_ABS) {
struct input_absinfo abs;
if(ioctl(fd, EVIOCGABS(j * 8 + k), &abs) == 0) {
printf(" value %d, min %d, max %d, fuzz %d flat %d", abs.value, abs.minimum, abs.maximum, abs.fuzz, abs.flat);
}
}
count++;
}
}
if(count)
printf("\n");
}
free(bits);
return 0;
}
static int open_device(const char *device, int print_flags)
{
int version;
int fd;
struct pollfd *new_ufds;
char **new_device_names;
char name[80];
char location[80];
char idstr[80];
struct input_id id;
fd = open(device, O_RDWR);
if(fd < 0) {
if(print_flags & PRINT_DEVICE_ERRORS)
fprintf(stderr, "could not open %s, %s\n", device, strerror(errno));
return -1;
}
if(ioctl(fd, EVIOCGVERSION, &version)) {
if(print_flags & PRINT_DEVICE_ERRORS)
fprintf(stderr, "could not get driver version for %s, %s\n", device, strerror(errno));
return -1;
}
if(ioctl(fd, EVIOCGID, &id)) {
if(print_flags & PRINT_DEVICE_ERRORS)
fprintf(stderr, "could not get driver id for %s, %s\n", device, strerror(errno));
return -1;
}
name[sizeof(name) - 1] = '\0';
location[sizeof(location) - 1] = '\0';
idstr[sizeof(idstr) - 1] = '\0';
if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
//fprintf(stderr, "could not get device name for %s, %s\n", device, strerror(errno));
name[0] = '\0';
}
if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
//fprintf(stderr, "could not get location for %s, %s\n", device, strerror(errno));
location[0] = '\0';
}
if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
//fprintf(stderr, "could not get idstring for %s, %s\n", device, strerror(errno));
idstr[0] = '\0';
}
new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1));
if(new_ufds == NULL) {
fprintf(stderr, "out of memory\n");
return -1;
}
ufds = new_ufds;
new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1));
if(new_device_names == NULL) {
fprintf(stderr, "out of memory\n");
return -1;
}
device_names = new_device_names;
if(print_flags & PRINT_DEVICE)
printf("add device %d: %s\n", nfds, device);
if(print_flags & PRINT_DEVICE_INFO)
printf(" bus: %04x\n"
" vendor %04x\n"
" product %04x\n"
" version %04x\n",
id.bustype, id.vendor, id.product, id.version);
if(print_flags & PRINT_DEVICE_NAME)
printf(" name: \"%s\"\n", name);
if(print_flags & PRINT_DEVICE_INFO)
printf(" location: \"%s\"\n"
" id: \"%s\"\n", location, idstr);
if(print_flags & PRINT_VERSION)
printf(" version: %d.%d.%d\n",
version >> 16, (version >> 8) & 0xff, version & 0xff);
if(print_flags & PRINT_POSSIBLE_EVENTS) {
print_possible_events(fd);
}
ufds[nfds].fd = fd;
ufds[nfds].events = POLLIN;
device_names[nfds] = strdup(device);
nfds++;
return 0;
}
int close_device(const char *device, int print_flags)
{
int i;
for(i = 1; i < nfds; i++) {
if(strcmp(device_names[i], device) == 0) {
int count = nfds - i - 1;
if(print_flags & PRINT_DEVICE)
printf("remove device %d: %s\n", i, device);
free(device_names[i]);
memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
nfds--;
return 0;
}
}
if(print_flags & PRINT_DEVICE_ERRORS)
fprintf(stderr, "remote device: %s not found\n", device);
return -1;
}
static int read_notify(const char *dirname, int nfd, int print_flags)
{
int res;
char devname[PATH_MAX];
char *filename;
char event_buf[512];
int event_size;
int event_pos = 0;
struct inotify_event *event;
res = read(nfd, event_buf, sizeof(event_buf));
if(res < (int)sizeof(*event)) {
if(errno == EINTR)
return 0;
fprintf(stderr, "could not get event, %s\n", strerror(errno));
return 1;
}
//printf("got %d bytes of event information\n", res);
strcpy(devname, dirname);
filename = devname + strlen(devname);
*filename++ = '/';
while(res >= (int)sizeof(*event)) {
event = (struct inotify_event *)(event_buf + event_pos);
//printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
if(event->len) {
strcpy(filename, event->name);
if(event->mask & IN_CREATE) {
open_device(devname, print_flags);
}
else {
close_device(devname, print_flags);
}
}
event_size = sizeof(*event) + event->len;
res -= event_size;
event_pos += event_size;
}
return 0;
}
static int scan_dir(const char *dirname, int print_flags)
{
char devname[PATH_MAX];
char *filename;
DIR *dir;
struct dirent *de;
dir = opendir(dirname);
if(dir == NULL)
return -1;
strcpy(devname, dirname);
filename = devname + strlen(devname);
*filename++ = '/';
while((de = readdir(dir))) {
if(de->d_name[0] == '.' &&
(de->d_name[1] == '\0' ||
(de->d_name[1] == '.' && de->d_name[2] == '\0')))
continue;
strcpy(filename, de->d_name);
open_device(devname, print_flags);
}
closedir(dir);
return 0;
}
static void usage(int argc, char *argv[])
{
fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-p] [-q] [-c count] [-r] [device]\n", argv[0]);
fprintf(stderr, " -t: show time stamps\n");
fprintf(stderr, " -n: don't print newlines\n");
fprintf(stderr, " -s: print switch states for given bits\n");
fprintf(stderr, " -S: print all switch states\n");
fprintf(stderr, " -v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32)\n");
fprintf(stderr, " -p: show possible events (errs, dev, name, pos. events)\n");
fprintf(stderr, " -q: quiet (clear verbosity mask)\n");
fprintf(stderr, " -c: print given number of events then exit\n");
fprintf(stderr, " -r: print rate events are received\n");
}
int main(int argc, char *argv[])
{
int c;
int i;
int res;
int pollres;
int get_time = 0;
int print_device = 0;
char *newline = "\n";
uint16_t get_switch = 0;
struct input_event event;
int version;
int print_flags = PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME;
int print_flags_set = 0;
int dont_block = -1;
int event_count = 0;
int sync_rate = 0;
int64_t last_sync_time = 0;
const char *device = NULL;
const char *device_path = "/dev/input";
opterr = 0;
do {
c = getopt(argc, argv, "tns:Sv::pqc:rh");
if (c == EOF)
break;
switch (c) {
case 't':
get_time = 1;
break;
case 'n':
newline = "";
break;
case 's':
get_switch = strtoul(optarg, NULL, 0);
if(dont_block == -1)
dont_block = 1;
break;
case 'S':
get_switch = ~0;
if(dont_block == -1)
dont_block = 1;
break;
case 'v':
if(optarg)
print_flags = strtoul(optarg, NULL, 0);
else
print_flags |= PRINT_DEVICE | PRINT_DEVICE_NAME | PRINT_DEVICE_INFO | PRINT_VERSION;
print_flags_set = 1;
break;
case 'p':
print_flags = PRINT_DEVICE_ERRORS | PRINT_DEVICE | PRINT_DEVICE_NAME | PRINT_POSSIBLE_EVENTS;
print_flags_set = 1;
if(dont_block == -1)
dont_block = 1;
break;
case 'q':
print_flags = 0;
print_flags_set = 1;
break;
case 'c':
event_count = atoi(optarg);
dont_block = 0;
break;
case 'r':
sync_rate = 1;
break;
case '?':
fprintf(stderr, "%s: invalid option -%c\n",
argv[0], optopt);
case 'h':
usage(argc, argv);
exit(1);
}
} while (1);
if(dont_block == -1)
dont_block = 0;
if (optind + 1 == argc) {
device = argv[optind];
optind++;
}
if (optind != argc) {
usage(argc, argv);
exit(1);
}
nfds = 1;
ufds = calloc(1, sizeof(ufds[0]));
ufds[0].fd = inotify_init();
ufds[0].events = POLLIN;
if(device) {
if(!print_flags_set)
print_flags = PRINT_DEVICE_ERRORS;
res = open_device(device, print_flags);
if(res < 0) {
return 1;
}
}
else {
print_device = 1;
res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
if(res < 0) {
fprintf(stderr, "could not add watch for %s, %s\n", device_path, strerror(errno));
return 1;
}
res = scan_dir(device_path, print_flags);
if(res < 0) {
fprintf(stderr, "scan dir failed for %s\n", device_path);
return 1;
}
}
if(get_switch) {
for(i = 1; i < nfds; i++) {
uint16_t sw;
res = ioctl(ufds[i].fd, EVIOCGSW(1), &sw);
if(res < 0) {
fprintf(stderr, "could not get switch state, %s\n", strerror(errno));
return 1;
}
sw &= get_switch;
printf("%04x%s", sw, newline);
}
}
if(dont_block)
return 0;
while(1) {
pollres = poll(ufds, nfds, -1);
//printf("poll %d, returned %d\n", nfds, pollres);
if(ufds[0].revents & POLLIN) {
read_notify(device_path, ufds[0].fd, print_flags);
}
for(i = 1; i < nfds; i++) {
if(ufds[i].revents) {
if(ufds[i].revents & POLLIN) {
res = read(ufds[i].fd, &event, sizeof(event));
if(res < (int)sizeof(event)) {
fprintf(stderr, "could not get event\n");
return 1;
}
if(get_time) {
printf("%ld-%ld: ", event.time.tv_sec, event.time.tv_usec);
}
if(print_device)
printf("%s: ", device_names[i]);
printf("%04x %04x %08x", event.type, event.code, event.value);
if(sync_rate && event.type == 0 && event.code == 0) {
int64_t now = event.time.tv_sec * 1000000LL + event.time.tv_usec;
if(last_sync_time)
printf(" rate %lld", 1000000LL / (now - last_sync_time));
last_sync_time = now;
}
printf("%s", newline);
if(event_count && --event_count == 0)
return 0;
}
}
}
}
return 0;
}
改了几行代码, 通过编译, 试了一下, 居然可以了.
Ubuntu 模拟鼠标中键上下滚动:
sudo ./sendevent /dev/input/event3 2 8 -1
sudo ./sendevent /dev/input/event3 2 8 1
@ubuntu:/disk2/licheepi/linux$ sudo ./getevent /dev/input/event3
0002 0008 ffffffff
0000 0000 00000000
0002 0008 00000001
0000 0000 00000000
居然可以用了
离线
pc ubuntu 用得好好的, 居然在嵌入式Linux下面不能用,悲剧.
无论 sendevent 怎么发送数据, getevent / evtest 都纹丝不动。
离线
感觉驱动配置应该没有问题, /dev/uinput 设备也有了。
离线
终于搞定, 原来并没有问题, 而是命令没有发全:
正确的姿势是, 先用 evtest 记录按键或者触摸屏的触发记录
比如这个是按下电阻屏某个点:
Supported events:
Event type 0 (EV_SYN)
Event type 1 (EV_KEY)
Event code 330 (BTN_TOUCH)
Event type 3 (EV_ABS)
Event code 0 (ABS_X)
Value 0
Min 0
Max 4095
Fuzz 32
Event code 1 (ABS_Y)
Value 0
Min 0
Max 4095
Fuzz 16
Properties:
Testing ... (interrupt to exit)
Event: time 13499.431064, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 1
Event: time 13499.431064, type 3 (EV_ABS), code 0 (ABS_X), value 2558
Event: time 13499.431064, type 3 (EV_ABS), code 1 (ABS_Y), value 357
Event: time 13499.431064, -------------- SYN_REPORT ------------
Event: time 13499.483417, type 3 (EV_ABS), code 1 (ABS_Y), value 365
Event: time 13499.483417, -------------- SYN_REPORT ------------
Event: time 13499.524761, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 0
Event: time 13499.524761, -------------- SYN_REPORT ------------
这样模拟发送就妥妥的了:
./sendevent /dev/input/event1 1 330 1
./sendevent /dev/input/event1 3 0 2558
./sendevent /dev/input/event1 3 1 357
./sendevent /dev/input/event1 0 0 0
./sendevent /dev/input/event1 3 1 365
./sendevent /dev/input/event1 0 0 0
./sendevent /dev/input/event1 1 330 0
./sendevent /dev/input/event1 0 0 0
离线
再来一个, 比如evtest 采集到的按下按键是以下数据:
Input driver version is 1.0.1
Input device ID: bus 0x19 vendor 0x1 product 0x1 version 0x100
Input device name: "1c22800.lradc"
Supported events:
Event type 0 (Sync)
Event type 1 (Key)
Event code 114 (VolumeDown)
Event code 115 (VolumeUp)
Event code 352 (Ok)
Event code 353 (Select)
Testing ... (interrupt to exit)
Event: time 228.055444, type 1 (Key), code 352 (Ok), value 1
Event: time 228.055444, -------------- Report Sync ------------
Event: time 228.251432, type 1 (Key), code 352 (Ok), value 0
Event: time 228.251432, -------------- Report Sync ------------
那么sendevent模拟事件注入:
./sendevent /dev/input/event0 1 352 1;./sendevent /dev/input/event0 0 0 0
./sendevent /dev/input/event0 1 352 0;./sendevent /dev/input/event0 0 0 0
仍然妥妥的
离线
终于通过event injecting 把按键整合到 vnc 协议里面了 ^_^
vnc 可以用键盘控制 ubuntu 的 framebuffer 了。
离线
好麻烦哦,终于搞定了Ubuntu 下面 VNC 操作 littlevgl@Framebuffer, 我用的是鼠标的 ABS_X/ABS_Y/BTN_LEFT组合,想着去君正X1000下面把BTN_LEFT改为 BTN_TOUCH就可以了,结果根本不触发,最后使用 evtest才发现,还得还原成原始 ADC 值,今晚还得加班。
离线
VNC 操作 Framebuffer, 基本OK, 但是vnc 客户端的刷新有点不正常,但是不影响使用。
如果有强制刷新的vnc客户端, 按下强制刷新显示就正常了。
离线
终于搞定在局域网下用 VNC 控制 君正X1000E soc 了, 挺流畅的, 接着整合一个 frp 进去, 可以远程随时控制了, 舒服舒服。
离线
为了做类似 teamview 之类的东东?
对的, 就是这样,配合FRP内网穿透, 可以在家VNC操作地球上任何一台机器。
离线
发现连续两次用sendevent 发送x,y绝对坐标, 这样触发才比较精确,否则有可能变成了长按。
./sendevent /dev/input/event1 1 330 1
./sendevent /dev/input/event1 3 0 2558
./sendevent /dev/input/event1 3 1 357
./sendevent /dev/input/event1 0 0 0
./sendevent /dev/input/event1 3 0 2558
./sendevent /dev/input/event1 3 1 365
./sendevent /dev/input/event1 0 0 0
./sendevent /dev/input/event1 1 330 0
./sendevent /dev/input/event1 0 0 0
./sendevent /dev/input/event1 1 330 1
./sendevent /dev/input/event1 3 0 1246
./sendevent /dev/input/event1 3 1 376
./sendevent /dev/input/event1 0 0 0
./sendevent /dev/input/event1 3 0 1246
./sendevent /dev/input/event1 3 1 376
./sendevent /dev/input/event1 0 0 0
./sendevent /dev/input/event1 1 330 0
./sendevent /dev/input/event1 0 0 0
离线