Created
October 26, 2021 09:30
-
-
Save ryan-mcclue/c662df5d5272d3409c00d0f0942aa3dd to your computer and use it in GitHub Desktop.
Simulate Key Presses
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: zlib-acknowledgement | |
#include <linux/uinput.h> | |
#include <unistd.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <time.h> | |
#include <fcntl.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdio.h> | |
void | |
sleep_ms(int ms) | |
{ | |
struct timespec sleep_time = {0}; | |
sleep_time.tv_nsec = ms * 1000000; | |
struct timespec leftover_sleep_time = {0}; | |
nanosleep(&sleep_time, &leftover_sleep_time); | |
} | |
void | |
send_event(int fd, int type, int code, int val) | |
{ | |
struct input_event ev = {0}; | |
ev.type = type; | |
ev.code = code; | |
ev.value = val; | |
write(fd, &ev, sizeof(ev)); | |
} | |
void | |
send_keypress(int fd, int key_code) | |
{ | |
send_event(fd, EV_KEY, key_code, 1); | |
send_event(fd, EV_SYN, SYN_REPORT, 0); | |
send_event(fd, EV_KEY, key_code, 0); | |
send_event(fd, EV_SYN, SYN_REPORT, 0); | |
sleep_ms(100); | |
} | |
void | |
register_key(int fd, int key_code) | |
{ | |
ioctl(fd, UI_SET_EVBIT, EV_KEY); | |
ioctl(fd, UI_SET_KEYBIT, key_code); | |
} | |
int | |
main(int argc, char *argv[]) | |
{ | |
// IMPORTANT(Ryan): Normally require root priveleges to access uinput device. | |
// To work around this: | |
// $(sudo groupadd -f uinput) | |
// $(sudo usermod -a "$USER" -G uinput) | |
// /etc/udev/rules.d/99-input.rules: KERNEL=="uninput",GROUP="uinput",MODE:="0660" | |
int uinput_fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); | |
if (uinput_fd < 0) return EXIT_FAILURE; | |
register_key(uinput_fd, KEY_F12); | |
register_key(uinput_fd, KEY_TAB); | |
register_key(uinput_fd, KEY_ENTER); | |
struct uinput_setup usetup = {0}; | |
usetup.id.bustype = BUS_USB; | |
usetup.id.vendor = 0x1234; | |
usetup.id.product = 0x5678; | |
strcpy(usetup.name, "simulated-keyboard"); | |
ioctl(uinput_fd, UI_DEV_SETUP, &usetup); | |
ioctl(uinput_fd, UI_DEV_CREATE); | |
// IMPORTANT(Ryan): Give userspace time to register then listen to device | |
// Tweak per system | |
sleep_ms(120); | |
send_keypress(uinput_fd, KEY_F12); | |
send_keypress(uinput_fd, KEY_TAB); | |
send_keypress(uinput_fd, KEY_ENTER); | |
ioctl(uinput_fd, UI_DEV_DESTROY); | |
close(uinput_fd); | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment