Files
MeowOS-For-R3P2/patch_v2/meow_launcherd/evtool.c
T

266 lines
9.1 KiB
C

/* evtool.c — tiny evdev probe tool for R3 Pro II (static MIPS32r2 musl).
*
* Subcommands:
* evtool codes <dev> dump EV bits (types + key codes)
* evtool dump <dev> [dev...] read + print events (no grab)
* evtool send <dev> <type> <code> <value> inject one event via write()
* evtool grab <dev> [dev...] EVIOCGRAB, then read + print
* evtool fwd <dev> EVIOCGRAB, read, write back every event
* (forward experiment) + print
* evtool keys <dev> EVIOCGKEY poll loop; print state changes
* evtool grabchk <dev> EVIOCGRAB result only (0 / errno)
*
* Event struct is fixed 16 bytes on MIPS32: timeval(8) + type(2) + code(2) + value(4).
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdint.h>
#include <time.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <linux/input.h>
#ifndef EVIOCGRAB
#define EVIOCGRAB _IOW('E', 0x90, int)
#endif
#ifndef EVIOCGKEY
#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len)
#endif
#define EV_MAXC 0x1f
#define KEY_MAXC 0x2ff
#define KEY_WORDS ((KEY_MAXC + 1 + 31) / 32)
static unsigned long long now_ms(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (unsigned long long)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
}
static int open_dev(const char *dev, int wr)
{
int fd = open(dev, wr ? O_RDWR : O_RDONLY);
if (fd < 0) { fprintf(stderr, "open %s: %s\n", dev, strerror(errno)); return -1; }
return fd;
}
static void print_ev(const char *tag, const unsigned char *ev)
{
uint16_t type = *(uint16_t *)(ev + 8);
uint16_t code = *(uint16_t *)(ev + 10);
int32_t val = *(int32_t *)(ev + 12);
fprintf(stderr, "%s t=%llu type=%d code=%d val=%d\n",
tag, now_ms(), type, code, val);
}
/* ---------- codes ---------- */
static void cmd_codes(const char *dev)
{
int fd = open_dev(dev, 0);
if (fd < 0) return;
unsigned long evbits[EV_MAXC / 32 + 1];
memset(evbits, 0, sizeof evbits);
if (ioctl(fd, EVIOCGBIT(0, sizeof evbits), evbits) < 0) {
perror("EVIOCGBIT(0)"); return;
}
printf("EV bits:");
for (int i = 0; i <= EV_MAXC; i++)
if (evbits[i / 32] & (1UL << (i % 32))) printf(" %d", i);
printf("\n");
unsigned long kb[KEY_WORDS];
memset(kb, 0, sizeof kb);
if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof kb), kb) >= 0) {
printf("KEY codes:");
for (int i = 0; i <= KEY_MAXC; i++)
if (kb[i / 32] & (1UL << (i % 32))) printf(" %d", i);
printf("\n");
} else {
perror("EVIOCGBIT(EV_KEY)");
}
close(fd);
}
/* ---------- dump ---------- */
static void dump_dev(const char *dev, const char *tag)
{
int fd = open_dev(dev, 0);
if (fd < 0) return;
printf("opened %s as %s\n", dev, tag);
fflush(stdout);
struct pollfd pfd = { fd, POLLIN, 0 };
unsigned char ev[16];
for (;;) {
int r = poll(&pfd, 1, -1);
if (r < 0) { perror("poll"); break; }
if (pfd.revents & POLLIN) {
ssize_t n = read(fd, ev, sizeof ev);
if (n == 16) print_ev(tag, ev);
else if (n < 0) { perror("read"); break; }
}
}
close(fd);
}
static void cmd_dump(int argc, char **argv)
{
for (int i = 0; i < argc; i++) {
pid_t p = fork();
if (p == 0) { dump_dev(argv[i], argv[i]); _exit(0); }
}
for (;;) pause();
}
/* ---------- send ---------- */
static void cmd_send(const char *dev, int type, int code, int value)
{
int fd = open_dev(dev, 1);
if (fd < 0) return;
struct input_event ev;
memset(&ev, 0, sizeof ev);
ev.type = type; ev.code = code; ev.value = value;
ssize_t n = write(fd, &ev, sizeof ev);
printf("write(%s) -> %zd errno=%d (%s)\n", dev, n, errno, strerror(errno));
close(fd);
}
/* ---------- grab / fwd ---------- */
static int do_grab(int fd, int on)
{
int v = on ? 1 : 0;
int r = ioctl(fd, EVIOCGRAB, v);
printf("EVIOCGRAB(%d) -> %d errno=%d (%s)\n", on, r, errno, strerror(errno));
return r;
}
static void loop_forward(const char *dev, int fwd)
{
int fd = open_dev(dev, 1);
if (fd < 0) return;
if (do_grab(fd, 1) < 0) return;
printf("GRABBED %s (fwd=%d), reading...\n", dev, fwd);
fflush(stdout);
struct pollfd pfd = { fd, POLLIN, 0 };
unsigned char ev[16];
for (;;) {
int r = poll(&pfd, 1, -1);
if (r < 0) { perror("poll"); break; }
if (pfd.revents & POLLIN) {
ssize_t n = read(fd, ev, sizeof ev);
if (n != 16) { if (n < 0) perror("read"); continue; }
print_ev("G", ev);
if (fwd) {
ssize_t w = write(fd, ev, sizeof ev);
if (w != 16) fprintf(stderr, " write-back failed: %s\n", strerror(errno));
}
}
}
close(fd);
}
/* ---------- fwdt: grab + self-inject + forward ---------- */
/* Sequence: grab <dev>; after wait_ms inject press(code); after +300ms inject
* release(code); meanwhile forward every read event back to <dev>.
* Optional 5th arg: total duration ms (0 = run forever).
* A second reader on <dev> tells us whether write-back reaches non-grabbers. */
static void loop_fwdt(const char *dev, int code, int wait_ms, int dur_ms)
{
int fd = open_dev(dev, 1);
if (fd < 0) return;
if (do_grab(fd, 1) < 0) return;
printf("FWDT grabbed %s code=%d wait=%d dur=%d\n", dev, code, wait_ms, dur_ms);
fflush(stdout);
struct pollfd pfd = { fd, POLLIN, 0 };
unsigned char ev[16];
unsigned long long t0 = now_ms(), inject_done = 0;
int phase = 0; /* 0=idle, 1=pressed, 2=released */
for (;;) {
unsigned long long t = now_ms();
if (dur_ms > 0 && t - t0 >= (unsigned long long)dur_ms) break;
if (!inject_done && t - t0 >= (unsigned long long)wait_ms) {
struct input_event e; memset(&e, 0, sizeof e);
e.type = EV_KEY; e.code = code; e.value = 1;
if (write(fd, &e, sizeof e) != sizeof e) fprintf(stderr, "inject press fail\n");
printf("== injected PRESS %d\n", code);
phase = 1; inject_done = 1;
} else if (phase == 1 && t - t0 >= (unsigned long long)wait_ms + 300) {
struct input_event e; memset(&e, 0, sizeof e);
e.type = EV_KEY; e.code = code; e.value = 0;
if (write(fd, &e, sizeof e) != sizeof e) fprintf(stderr, "inject release fail\n");
printf("== injected RELEASE %d\n", code);
phase = 2;
}
int r = poll(&pfd, 1, 100);
if (r < 0) { perror("poll"); break; }
if (pfd.revents & POLLIN) {
ssize_t n = read(fd, ev, sizeof ev);
if (n == 16) {
print_ev("RD", ev);
ssize_t w = write(fd, ev, sizeof ev);
if (w != 16) fprintf(stderr, " WB fail: %s\n", strerror(errno));
}
}
}
close(fd);
}
/* ---------- keys (EVIOCGKEY poll) ---------- */
static void cmd_keys(const char *dev, int dur_ms)
{
int fd = open_dev(dev, 0);
if (fd < 0) return;
unsigned long prev[KEY_WORDS], cur[KEY_WORDS];
memset(prev, 0, sizeof prev);
printf("EVIOCGKEY poll on %s (dur=%dms)\n", dev, dur_ms);
fflush(stdout);
unsigned long long t0 = now_ms();
for (;;) {
if (dur_ms > 0 && now_ms() - t0 >= (unsigned long long)dur_ms) break;
memset(cur, 0, sizeof cur);
if (ioctl(fd, EVIOCGKEY(sizeof cur), cur) < 0) { perror("EVIOCGKEY"); break; }
for (int w = 0; w < KEY_WORDS; w++) {
if (cur[w] != prev[w]) {
for (int b = 0; b < 32; b++) {
int cb = (cur[w] >> b) & 1;
int pb = (prev[w] >> b) & 1;
if (cb != pb)
printf("key %d %s\n", w * 32 + b, cb ? "DOWN" : "UP");
}
prev[w] = cur[w];
}
}
fflush(stdout);
usleep(10000); /* 10 ms */
}
close(fd);
}
int main(int argc, char **argv)
{
setvbuf(stderr, NULL, _IONBF, 0);
if (argc < 2) {
fprintf(stderr, "usage: evtool codes|dump|send|grab|fwd|keys|grabchk <args>\n");
return 1;
}
const char *cmd = argv[1];
if (!strcmp(cmd, "codes") && argc >= 3) { cmd_codes(argv[2]); return 0; }
if (!strcmp(cmd, "dump") && argc >= 3) { cmd_dump(argc - 2, argv + 2); return 0; }
if (!strcmp(cmd, "send") && argc >= 6) { cmd_send(argv[2], atoi(argv[3]), atoi(argv[4]), atoi(argv[5])); return 0; }
if (!strcmp(cmd, "grab") && argc >= 3) { loop_forward(argv[2], 0); return 0; }
if (!strcmp(cmd, "fwd") && argc >= 3) { loop_forward(argv[2], 1); return 0; }
if (!strcmp(cmd, "keys") && argc >= 3) { cmd_keys(argv[2], argc >= 4 ? atoi(argv[3]) : 0); return 0; }
if (!strcmp(cmd, "fwdt") && argc >= 4) { loop_fwdt(argv[2], atoi(argv[3]), argc >= 5 ? atoi(argv[4]) : 1000, argc >= 6 ? atoi(argv[5]) : 0); return 0; }
if (!strcmp(cmd, "grabchk") && argc >= 3) {
int fd = open_dev(argv[2], 1);
if (fd >= 0) { do_grab(fd, 1); do_grab(fd, 0); close(fd); }
return 0;
}
fprintf(stderr, "bad args\n");
return 1;
}