#include #include #include #include #include #include #include #include #include #include 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) { struct input_event ie; ie.type = type; ie.code = code; ie.value = val; ie.time.tv_sec = 0; ie.time.tv_usec = 0; write(fd, &ie, sizeof(ie)); } 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 long timer_nanos = 0; time_t seconds; long nanos; char type; char details[32]; struct timespec to_sleep; struct timespec remaining; int matched = sscanf(line, "%ld %ld,%c,%s\n", &seconds, &nanos, &type, details); if(matched == 0) { printf("Line '%s' appears incorrect. Exiting", line); return 1; } else if(matched < 4) { printf("Only matched %d", matched); return 1; } to_sleep.tv_sec = seconds - timer_seconds; to_sleep.tv_nsec = nanos - timer_nanos; if(to_sleep.tv_nsec < 0) { --to_sleep.tv_nsec; to_sleep.tv_nsec += 1000000000L; } // printf("Timer %ld %ld\n", timer_seconds, timer_nanos); // printf("Read %ld %ld\n", seconds, nanos); // printf("Sleep %ld %ld\n", to_sleep.tv_sec, to_sleep.tv_nsec); int result = nanosleep(&to_sleep, &remaining); while(nanosleep(&to_sleep, &remaining) == -1) { to_sleep.tv_sec = remaining.tv_sec; to_sleep.tv_nsec = remaining.tv_nsec; } timer_seconds = seconds; 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; } int main(int argc, char* argv[]) { if(argc < 2) { printf("Please provide a capture file."); exit(EXIT_FAILURE); } int result = 0; int mouse_fd = setup_mouse(); int keyboard_fd = 0; if(read_file(argv[1], keyboard_fd, mouse_fd)) { result = EXIT_FAILURE; } teardown_keyboard(keyboard_fd); teardown_mouse(mouse_fd); return result; } int read_file(char* filename, int keyboard_fd, int mouse_fd) { FILE* fp; char* line = NULL; size_t len = 0; ssize_t read; fp = fopen(filename, "r"); if (fp == NULL) { printf("Failed to open file %s: %d\n", filename, errno); return 1; } while((read = getline(&line, &len, fp)) != -1) { if(handle_line(line, keyboard_fd, mouse_fd)) { return 1; } } } int setup_mouse() { struct uinput_setup usetup; int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); /* enable mouse button left and relative events */ ioctl(fd, UI_SET_EVBIT, EV_KEY); ioctl(fd, UI_SET_KEYBIT, BTN_LEFT); ioctl(fd, UI_SET_EVBIT, EV_REL); ioctl(fd, UI_SET_RELBIT, REL_X); ioctl(fd, UI_SET_RELBIT, REL_Y); memset(&usetup, 0, sizeof(usetup)); usetup.id.bustype = BUS_USB; usetup.id.vendor = 0x1234; /* sample vendor */ usetup.id.product = 0x5678; /* sample product */ strcpy(usetup.name, "Playback mouses"); ioctl(fd, UI_DEV_SETUP, &usetup); ioctl(fd, UI_DEV_CREATE); /* * On UI_DEV_CREATE the kernel will create the device node for this * device. We are inserting a pause here so that userspace has time * to detect, initialize the new device, and can start listening to * the event, otherwise it will not notice the event we are about * to send. This pause is only needed in our example code! */ // sleep(1); printf("Setup mouse to fd %d", fd); return fd; } void teardown_mouse(int fd) { ioctl(fd, UI_DEV_DESTROY); close(fd); } void teardown_keyboard(int fd) {}