Created
January 27, 2026 08:37
-
-
Save valignatev/e24a1ba8050f81464178e0695f041157 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| // 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; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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