Skip to content

Instantly share code, notes, and snippets.

@cnmoro
Created October 17, 2025 21:17
Show Gist options
  • Select an option

  • Save cnmoro/d31dde5a37506211dd02b7d2158cc9fc to your computer and use it in GitHub Desktop.

Select an option

Save cnmoro/d31dde5a37506211dd02b7d2158cc9fc to your computer and use it in GitHub Desktop.
Chromebook Linux Remap F-keys to Algr+1,2,3,etc
1 - Identificar o device
cat /proc/bus/input/devices
Look for something that says "keyboard" in the N: Name= line. In this example, it's "AT Translated Set 2 keyboard". The important part is the Handlers= line—it shows event1, which means the device is /dev/input/event1.
2 - Validar o dispositivo
sudo evtest
3 - Atualizar o código C com o device
Linha "input_fd = open("/dev/input/event0", O_RDONLY);" - trocar o eventX
4 - Build
sudo apt update
sudo apt install build-essential
gcc -o remapper remapper.c
sudo ./remapper # executa
---------------
Código:
```remapper.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <sys/ioctl.h>
int main() {
int input_fd, uinput_fd;
struct input_event ie;
struct uinput_setup usetup;
// Open uinput for creating virtual keyboard
uinput_fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if (uinput_fd < 0) {
perror("open /dev/uinput");
return 1;
}
// Set up virtual device
memset(&usetup, 0, sizeof(usetup));
usetup.id.bustype = BUS_USB;
usetup.id.vendor = 0x1234;
usetup.id.product = 0x5678;
strcpy(usetup.name, "Keyboard Remapper");
// Enable key events
ioctl(uinput_fd, UI_SET_EVBIT, EV_KEY);
ioctl(uinput_fd, UI_SET_EVBIT, EV_SYN);
for (int i = 0; i < 256; i++) {
ioctl(uinput_fd, UI_SET_KEYBIT, i);
}
ioctl(uinput_fd, UI_DEV_SETUP, &usetup);
ioctl(uinput_fd, UI_DEV_CREATE);
sleep(1);
// Open input device
input_fd = open("/dev/input/event4", O_RDONLY);
if (input_fd < 0) {
perror("open /dev/input/event4");
close(uinput_fd);
return 1;
}
printf("Listening for keyboard input. Press Ctrl+C to exit.\n");
printf("Remapping:\n");
printf(" AltGr+1 -> F1\n");
printf(" AltGr+2 -> F2\n");
printf(" ... (3-9 for F3-F9)\n");
printf(" AltGr+0 -> F10\n");
printf(" AltGr+- -> F11\n");
printf(" AltGr+= -> F12\n");
int altgr_pressed = 0;
int remapping_active = 0; // Flag to block modifier forwarding
// Mapping table for number keys to F-keys
struct {
int keycode;
int fkey;
} keymap[] = {
{KEY_1, KEY_F1},
{KEY_2, KEY_F2},
{KEY_3, KEY_F3},
{KEY_4, KEY_F4},
{KEY_5, KEY_F5},
{KEY_6, KEY_F6},
{KEY_7, KEY_F7},
{KEY_8, KEY_F8},
{KEY_9, KEY_F9},
{KEY_0, KEY_F10},
{KEY_MINUS, KEY_F11},
{KEY_EQUAL, KEY_F12},
{0, 0} // Sentinel
};
// Try to grab the device exclusively to prevent key events from propagating
ioctl(input_fd, EVIOCGRAB, 1);
while (1) {
if (read(input_fd, &ie, sizeof(ie)) != sizeof(ie)) {
perror("read");
break;
}
// Track Right Alt (AltGr) state
if (ie.type == EV_KEY && ie.code == KEY_RIGHTALT) {
altgr_pressed = ie.value;
}
// Check if this is a remappable key combination
if (ie.type == EV_KEY && altgr_pressed) {
int remapped_key = 0;
for (int i = 0; keymap[i].keycode != 0; i++) {
if (ie.code == keymap[i].keycode) {
remapped_key = keymap[i].fkey;
break;
}
}
if (remapped_key) {
if (ie.value == 1) { // Key press
remapping_active = 1; // Block modifier forwarding
// Calculate correct F-key number for display
int fkey_num = 0;
if (remapped_key >= KEY_F1 && remapped_key <= KEY_F12) {
fkey_num = remapped_key - KEY_F1 + 1;
}
printf("Detected AltGr+key, sending F%d\n", fkey_num);
// Send ONLY the F-key press (no modifiers)
struct input_event fkey_ev;
memset(&fkey_ev, 0, sizeof(fkey_ev));
fkey_ev.type = EV_KEY;
fkey_ev.code = remapped_key;
fkey_ev.value = 1;
write(uinput_fd, &fkey_ev, sizeof(fkey_ev));
// Sync
fkey_ev.type = EV_SYN;
fkey_ev.code = SYN_REPORT;
fkey_ev.value = 0;
write(uinput_fd, &fkey_ev, sizeof(fkey_ev));
} else if (ie.value == 2) { // Key repeat
// Forward repeat events as F-key repeats
struct input_event fkey_ev;
memset(&fkey_ev, 0, sizeof(fkey_ev));
fkey_ev.type = EV_KEY;
fkey_ev.code = remapped_key;
fkey_ev.value = 2; // repeat
write(uinput_fd, &fkey_ev, sizeof(fkey_ev));
// Sync
fkey_ev.type = EV_SYN;
fkey_ev.code = SYN_REPORT;
fkey_ev.value = 0;
write(uinput_fd, &fkey_ev, sizeof(fkey_ev));
} else if (ie.value == 0) { // Key release
// Send F-key release
struct input_event fkey_ev;
memset(&fkey_ev, 0, sizeof(fkey_ev));
fkey_ev.type = EV_KEY;
fkey_ev.code = remapped_key;
fkey_ev.value = 0;
write(uinput_fd, &fkey_ev, sizeof(fkey_ev));
// Sync
fkey_ev.type = EV_SYN;
fkey_ev.code = SYN_REPORT;
fkey_ev.value = 0;
write(uinput_fd, &fkey_ev, sizeof(fkey_ev));
remapping_active = 0; // Re-enable normal forwarding
}
continue; // Don't forward the original key
}
}
// Block AltGr events during remapping
if (remapping_active && ie.type == EV_KEY && ie.code == KEY_RIGHTALT) {
continue; // Don't forward AltGr during remapping
}
// Forward all other events
write(uinput_fd, &ie, sizeof(ie));
}
ioctl(input_fd, EVIOCGRAB, 0);
ioctl(uinput_fd, UI_DEV_DESTROY);
close(input_fd);
close(uinput_fd);
return 0;
}
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment