Skip to content

Instantly share code, notes, and snippets.

@ryan-mcclue
Created October 26, 2021 09:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ryan-mcclue/c662df5d5272d3409c00d0f0942aa3dd to your computer and use it in GitHub Desktop.
Save ryan-mcclue/c662df5d5272d3409c00d0f0942aa3dd to your computer and use it in GitHub Desktop.
Simulate Key Presses
// 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