Make mouse playback work.

This only includes left mouse button clicks, not right mouse button
clicks or scrollwheels.
This commit is contained in:
Eli Ribble 2021-08-30 10:11:10 -06:00
parent 61843f23c3
commit 829432d443
1 changed files with 100 additions and 60 deletions

View File

@ -10,7 +10,13 @@
#include <linux/uinput.h> #include <linux/uinput.h>
#include <sys/stat.h> #include <sys/stat.h>
int read_file(char* filename); int handle_keyboard(char* details, int keyboard_fd);
int handle_line(char* line, int keyboard_fd, int mouse_fd);
int handle_mouse(char* details, int mouse_fd);
int read_file(char* filename, int keyboard_fd, int mouse_fd);
int setup_mouse();
void teardown_keyboard(int fd);
void teardown_mouse(int fd);
void emit(int fd, int type, int code, int val) { void emit(int fd, int type, int code, int val) {
struct input_event ie; struct input_event ie;
@ -23,7 +29,19 @@ void emit(int fd, int type, int code, int val) {
write(fd, &ie, sizeof(ie)); write(fd, &ie, sizeof(ie));
} }
int handle_line(char* line) { int handle_keyboard(char* details, int keyboard_fd) {
int code, event_type, value;
int matched = sscanf(details, "%d,%d,%d", &event_type, &code, &value);
if(matched != 3) {
printf("Didn't match enough values for a keyboard event.\n");
return 1;
}
printf("Event type: %d, Code: %d, Value: %d\n",
event_type, code, value);
return 0;
}
int handle_line(char* line, int keyboard_fd, int mouse_fd) {
static time_t timer_seconds = 0; static time_t timer_seconds = 0;
static long timer_nanos = 0; static long timer_nanos = 0;
@ -49,7 +67,6 @@ int handle_line(char* line) {
--to_sleep.tv_nsec; --to_sleep.tv_nsec;
to_sleep.tv_nsec += 1000000000L; to_sleep.tv_nsec += 1000000000L;
} }
printf("%s", line);
// printf("Timer %ld %ld\n", timer_seconds, timer_nanos); // printf("Timer %ld %ld\n", timer_seconds, timer_nanos);
// printf("Read %ld %ld\n", seconds, nanos); // printf("Read %ld %ld\n", seconds, nanos);
// printf("Sleep %ld %ld\n", to_sleep.tv_sec, to_sleep.tv_nsec); // printf("Sleep %ld %ld\n", to_sleep.tv_sec, to_sleep.tv_nsec);
@ -60,6 +77,47 @@ int handle_line(char* line) {
} }
timer_seconds = seconds; timer_seconds = seconds;
timer_nanos = nanos; timer_nanos = nanos;
if(type == 'k') {
return handle_keyboard(details, keyboard_fd);
} else if(type == 'm') {
return handle_mouse(details, mouse_fd);
} else {
printf("Unexpected type %c/n", type);
return 1;
}
}
int handle_mouse(char* details, int mouse_fd) {
static int current_left = 0;
static int current_middle = 0;
static int current_right = 0;
int left, middle, right, x, y;
int matched = sscanf(details, "l%d,m%d,r%d,x%d,y%d",
&left, &middle, &right, &x, &y);
if(matched != 5) {
printf("Failed to match enough data for a mouse event.\n");
return 1;
}
printf("L: %d M: %d, R: %d, X: %d, Y: %d\n",
left, middle, right, x, y);
/* Move the mouse diagonally, 5 units per axis */
if(x != 0) {
emit(mouse_fd, EV_REL, REL_X, x);
}
if(y != 0) {
emit(mouse_fd, EV_REL, REL_Y, y);
}
if(left != current_left) {
emit(mouse_fd, EV_KEY, BTN_MOUSE, left);
current_left = left;
}
emit(mouse_fd, EV_SYN, SYN_REPORT, 0);
return 0; return 0;
} }
@ -69,13 +127,18 @@ int main(int argc, char* argv[]) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if(read_file(argv[1])) { int result = 0;
exit(EXIT_FAILURE); int mouse_fd = setup_mouse();
int keyboard_fd = 0;
if(read_file(argv[1], keyboard_fd, mouse_fd)) {
result = EXIT_FAILURE;
} }
return 0; teardown_keyboard(keyboard_fd);
teardown_mouse(mouse_fd);
return result;
} }
int read_file(char* filename) { int read_file(char* filename, int keyboard_fd, int mouse_fd) {
FILE* fp; FILE* fp;
char* line = NULL; char* line = NULL;
size_t len = 0; size_t len = 0;
@ -88,7 +151,7 @@ int read_file(char* filename) {
} }
while((read = getline(&line, &len, fp)) != -1) { while((read = getline(&line, &len, fp)) != -1) {
if(handle_line(line)) { if(handle_line(line, keyboard_fd, mouse_fd)) {
return 1; return 1;
} }
} }
@ -96,16 +159,9 @@ int read_file(char* filename) {
int setup_mouse() { int setup_mouse() {
struct uinput_setup usetup; struct uinput_setup usetup;
// int i = 50;
int i = 0;
int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
/* enable mouse button left and relative events */ /* enable mouse button left and relative events */
printf("EV_KEY 0x%08x\n", EV_KEY);
printf("UI_SET_EVBIT 0x%08lx\n", UI_SET_EVBIT);
printf("UI_SET_KEYBIT 0x%08lx\n", UI_SET_KEYBIT);
printf("BTN_LEFT 0x%08x\n", BTN_LEFT);
printf("EV_REL 0x%08x\n", EV_REL);
ioctl(fd, UI_SET_EVBIT, EV_KEY); ioctl(fd, UI_SET_EVBIT, EV_KEY);
@ -119,7 +175,7 @@ int setup_mouse() {
usetup.id.bustype = BUS_USB; usetup.id.bustype = BUS_USB;
usetup.id.vendor = 0x1234; /* sample vendor */ usetup.id.vendor = 0x1234; /* sample vendor */
usetup.id.product = 0x5678; /* sample product */ usetup.id.product = 0x5678; /* sample product */
strcpy(usetup.name, "Example device"); strcpy(usetup.name, "Playback mouses");
ioctl(fd, UI_DEV_SETUP, &usetup); ioctl(fd, UI_DEV_SETUP, &usetup);
ioctl(fd, UI_DEV_CREATE); ioctl(fd, UI_DEV_CREATE);
@ -131,30 +187,14 @@ int setup_mouse() {
* the event, otherwise it will not notice the event we are about * the event, otherwise it will not notice the event we are about
* to send. This pause is only needed in our example code! * to send. This pause is only needed in our example code!
*/ */
sleep(1); // sleep(1);
printf("Setup mouse to fd %d", fd);
/* Move the mouse diagonally, 5 units per axis */ return fd;
while (i--) { }
emit(fd, EV_REL, REL_X, 5);
emit(fd, EV_REL, REL_Y, 5);
emit(fd, EV_SYN, SYN_REPORT, 0);
usleep(15000);
}
// Click left mouse button.
emit(fd, EV_KEY, BTN_MOUSE, 1);
emit(fd, EV_SYN, SYN_REPORT, 0);
emit(fd, EV_KEY, BTN_MOUSE, 0);
emit(fd, EV_SYN, SYN_REPORT, 0);
/*
* Give userspace some time to read the events before we destroy the
* device with UI_DEV_DESTOY.
*/
sleep(1);
void teardown_mouse(int fd) {
ioctl(fd, UI_DEV_DESTROY); ioctl(fd, UI_DEV_DESTROY);
close(fd); close(fd);
return 0;
} }
void teardown_keyboard(int fd) {}