Skip to content

Instantly share code, notes, and snippets.

@valignatev
Created January 27, 2026 08:37
Show Gist options
  • Select an option

  • Save valignatev/e24a1ba8050f81464178e0695f041157 to your computer and use it in GitHub Desktop.

Select an option

Save valignatev/e24a1ba8050f81464178e0695f041157 to your computer and use it in GitHub Desktop.
// gcc main.c -o kb && ./kb
#include <linux/uinput.h>
#include <linux/input.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
void send_key(int fd, int key_code, int use_shift, int sleep_ms) {
struct input_event ev;
if (use_shift) {
memset(&ev, 0, sizeof(ev));
ev.type = EV_KEY;
ev.code = KEY_LEFTSHIFT;
ev.value = 1;
if (write(fd, &ev, sizeof(ev)) < 0) {
perror("Failed to write event");
exit(1);
}
memset(&ev, 0, sizeof(ev));
ev.type = EV_SYN;
ev.code = SYN_REPORT;
ev.value = 0;
if (write(fd, &ev, sizeof(ev)) < 0) {
perror("Failed to write event");
exit(1);
}
}
memset(&ev, 0, sizeof(ev));
ev.type = EV_KEY;
ev.code = key_code;
ev.value = 1;
if (write(fd, &ev, sizeof(ev)) < 0) {
perror("Failed to write event");
exit(1);
}
memset(&ev, 0, sizeof(ev));
ev.type = EV_SYN;
ev.code = SYN_REPORT;
ev.value = 0;
if (write(fd, &ev, sizeof(ev)) < 0) {
perror("Failed to write event");
exit(1);
}
memset(&ev, 0, sizeof(ev));
ev.type = EV_KEY;
ev.code = key_code;
ev.value = 0;
if (write(fd, &ev, sizeof(ev)) < 0) {
perror("Failed to write event");
exit(1);
}
memset(&ev, 0, sizeof(ev));
ev.type = EV_SYN;
ev.code = SYN_REPORT;
ev.value = 0;
if (write(fd, &ev, sizeof(ev)) < 0) {
perror("Failed to write event");
exit(1);
}
if (use_shift) {
memset(&ev, 0, sizeof(ev));
ev.type = EV_KEY;
ev.code = KEY_LEFTSHIFT;
ev.value = 0;
if (write(fd, &ev, sizeof(ev)) < 0) {
perror("Failed to write event");
exit(1);
}
memset(&ev, 0, sizeof(ev));
ev.type = EV_SYN;
ev.code = SYN_REPORT;
ev.value = 0;
if (write(fd, &ev, sizeof(ev)) < 0) {
perror("Failed to write event");
exit(1);
}
}
usleep(sleep_ms * 1000);
}
int main() {
int fd;
struct uinput_setup usetup;
struct input_event ev;
fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if (fd < 0) {
perror("Failed to open /dev/uinput");
exit(1);
}
int keys[] = {KEY_LEFTSHIFT, KEY_H, KEY_E, KEY_L, KEY_O};
if (ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0) {
perror("Failed to set EV_KEY");
exit(1);
}
if (ioctl(fd, UI_SET_EVBIT, EV_SYN) < 0) {
perror("Failed to set EV_SYN");
exit(1);
}
for (int i = 0; i < 5; i++) {
if (ioctl(fd, UI_SET_KEYBIT, keys[i]) < 0) {
perror("Failed to set key");
exit(1);
}
}
memset(&usetup, 0, sizeof(usetup));
snprintf(usetup.name, UINPUT_MAX_NAME_SIZE, "virtual-kb");
usetup.id.bustype = BUS_VIRTUAL;
usetup.id.vendor = 0x1;
usetup.id.product = 0x1;
usetup.id.version = 1;
if (ioctl(fd, UI_DEV_SETUP, &usetup) < 0) {
perror("Failed to setup device");
exit(1);
}
if (ioctl(fd, UI_DEV_CREATE) < 0) {
perror("Failed to create device");
exit(1);
}
sleep(2);
send_key(fd, KEY_H, 0, 200);
send_key(fd, KEY_E, 1, 200);
send_key(fd, KEY_L, 0, 200);
send_key(fd, KEY_L, 1, 200);
send_key(fd, KEY_L, 0, 200);
send_key(fd, KEY_O, 1, 0);
if (ioctl(fd, UI_DEV_DESTROY) < 0) {
perror("Failed to destroy device");
exit(1);
}
close(fd);
return 0;
}
@Gchipunov
Copy link

I wrote a game prototype to use terminal input for raspberry pi zero, since I don't have a keyboard connected to it, and usually when coding, use notepadnpp SFTP/SSH to send files to it, and terminal to run it, so its fast reiternation,

this example runs the input on thread and has a timer, for basic input, I'm making a 2D platformer that I'm porting from Android to Raspberry Pi zero, and before that porting from PC to Android with a InputDevice.cpp class for GlobalCallback for movement key data

https://github.com/Gchipunov/Colos_Android_Game/blob/main/raspberrypi_zero_prototypes/android_colo_game_v_0.6_rpi_zero1/raw_quads2.cpp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment