Skip to content

Instantly share code, notes, and snippets.

@imawizard
Created July 12, 2022 21:44
Show Gist options
  • Save imawizard/388fda54cad2c09ff4736c675202d40e to your computer and use it in GitHub Desktop.
Save imawizard/388fda54cad2c09ff4736c675202d40e to your computer and use it in GitHub Desktop.
/*
* based on dvorak.c and resources linked by Thomas Bocek
* compile with `gcc qw2mydv.c -o qw2mydv -std=c99 -pedantic -Wall -O3 -D_BSD_SOURCE`
* execute with `sudo ./qw2mydv /dev/input/event0`
*/
/* TODO:
* change keystate.shift to .lshift and .rshift
* add RSHIFT keymapping
* add MOD_CUSTOM, doesn't emit a key but sets custom_mod
* check on arrow keys through caps for custom_mod and change accordingly
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>
#include <linux/uinput.h>
#define die(str) \
do { \
perror(str); \
exit(EXIT_FAILURE); \
} while(0)
#define MOD_DEAD (1 << 1)
#define MOD_LCTRL (1 << 2)
#define MOD_RCTRL (1 << 3)
#define MOD_LSHIFT (1 << 4)
#define MOD_RSHIFT (1 << 5)
#define MOD_LALT (1 << 6)
#define MOD_RALT (1 << 7)
#define MOD_CAPS (1 << 8)
#define MOD_NUM (1 << 9)
#define MOD_SCROLL (1 << 10)
#define MOD_CTRL (MOD_LCTRL | MOD_RCTRL)
#define MOD_SHIFT (MOD_LSHIFT | MOD_RSHIFT)
#define MOD_ALT (MOD_LALT | MOD_RALT)
struct key {
int code;
int mods;
};
struct keystate {
struct key nomod;
struct key shift;
struct key caps;
};
enum evval_t {
RELEASED,
PRESSED,
REPEATED
};
static void adjust_mods(int fd, int mods, int newmods);
#define emitsyn(fd) emit((fd), EV_SYN, 0, SYN_REPORT)
#define emitkd(fd, key) emit((fd), EV_KEY, (key), PRESSED)
#define emitku(fd, key) emit((fd), EV_KEY, (key), RELEASED)
#define emitkp(fd, key) \
do { \
emitkd((fd), (key)); \
emitku((fd), (key)); \
} while (0)
static int emit(int fd, int type, int code, int value)
{
struct input_event ev;
ev.type = type;
ev.code = code;
ev.value = value;
/* timestamp values below are ignored */
ev.time.tv_sec = 0;
ev.time.tv_usec = 0;
return write(fd, &ev, sizeof(ev));
}
static void emitcp(int fd, int codepoint)
{
static int hexkeys[] = {
KEY_0, KEY_1, KEY_2, KEY_3,
KEY_4, KEY_5, KEY_6, KEY_7,
KEY_8, KEY_9, KEY_A, KEY_B,
KEY_C, KEY_D, KEY_E, KEY_F
};
int buf[4];
int n = 0;
emitkd(fd, KEY_LEFTCTRL);
emitkd(fd, KEY_LEFTSHIFT);
emitkp(fd, KEY_U);
emitku(fd, KEY_LEFTCTRL);
emitku(fd, KEY_LEFTSHIFT);
for (int rest = codepoint; rest; rest /= 16)
buf[n++] = rest % 16;
for (int i = n; i--;)
emitkp(fd, hexkeys[buf[i]]);
emitkp(fd, KEY_ENTER);
}
static void emitkey(int fd, int key, int keymods, int mods)
{
adjust_mods(fd, mods, keymods);
if (key > 0) {
/* generate single key presses */
emitkp(fd, key);
} else {
/* generate unicode codepoints */
emitcp(fd, abs(key));
}
adjust_mods(fd, keymods, mods);
}
static void print_event(struct input_event *ev) {
if (ev->type != EV_KEY) {
char *type;
switch (ev->type) {
case EV_SYN: type = "EV_SYN"; break;
case EV_REL: type = "EV_REL"; break;
case EV_ABS: type = "EV_ABS"; break;
case EV_MSC: type = "EV_MSC"; break;
case EV_SW: type = "EV_SW"; break;
case EV_LED: type = "EV_LED"; break;
case EV_SND: type = "EV_SND"; break;
case EV_REP: type = "EV_REP"; break;
case EV_FF: type = "EV_FF"; break;
case EV_PWR: type = "EV_PWR"; break;
case EV_FF_STATUS: type = "EV_FF_STATUS"; break;
default: type = "EV_???"; break;
}
printf("%s: %d 0x%02x (%d)\n", type, ev->value, (int)ev->code, (int)ev->code);
} else {
static char *evval[] = {
"RELEASED",
"PRESSED",
"REPEATED"
};
printf("EV_KEY: %s 0x%02x (%d)\n", evval[ev->value], (int)ev->code, (int)ev->code);
}
}
static int mod_bit(int key)
{
switch (key) {
case KEY_LEFTCTRL:
return MOD_LCTRL;
case KEY_RIGHTCTRL:
return MOD_RCTRL;
case KEY_LEFTSHIFT:
return MOD_LSHIFT;
case KEY_RIGHTSHIFT:
return MOD_RSHIFT;
case KEY_LEFTALT:
return MOD_LALT;
case KEY_RIGHTALT:
return MOD_RALT;
case KEY_CAPSLOCK:
return MOD_CAPS;
case KEY_NUMLOCK:
return MOD_NUM;
case KEY_SCROLLLOCK:
return MOD_SCROLL;
}
return 0;
}
static void adjust_mods(int fd, int mods, int newmods)
{
static struct {
int mod;
int key;
} modifiers[] = {
{MOD_LCTRL, KEY_LEFTCTRL},
{MOD_RCTRL, KEY_RIGHTCTRL},
{MOD_LSHIFT, KEY_LEFTSHIFT},
{MOD_RSHIFT, KEY_RIGHTSHIFT},
{MOD_LALT, KEY_LEFTALT},
{MOD_RALT, KEY_RIGHTALT}
/* TODO: add the rest? */
};
static int mods_len = sizeof(modifiers) / sizeof(modifiers[0]);
if (mods == newmods)
return;
for (int i = 0; i < mods_len; i++) {
if (mods & modifiers[i].mod && !(newmods & modifiers[i].mod)) {
emitku(fd, modifiers[i].key);
} else if (!(mods & modifiers[i].mod) && newmods & modifiers[i].mod) {
emitkd(fd, modifiers[i].key);
}
}
}
static struct keystate mapping[] = {
/* | NORMAL | | SHIFT | | CAPS | */
/* KEY_RESERVED */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_ESC */ {{-1, 0 }, {-1, 0 }, {KEY_SCREENLOCK, 0}},
/* KEY_1 */ {{0, 0 }, {0, 0 }, {0, 0}},
/* KEY_2 */ {{0, 0 }, {0, 0 }, {0, 0}},
/* KEY_3 */ {{KEY_9, MOD_LSHIFT}, /* => ) */ {0, 0 }, {0, 0}},
/* KEY_4 */ {{KEY_8, MOD_LSHIFT}, /* => ( */ {0, 0 }, {KEY_VOLUMEDOWN, 0}}, /* => 🔉 */
/* KEY_5 */ {{KEY_102ND, MOD_RALT }, /* => | */ {0, 0 }, {KEY_PREVIOUSSONG, 0}}, /* => « */
/* KEY_6 */ {{0, 0 }, {0, 0 }, {0, 0}},
/* KEY_7 */ {{0, 0 }, {0, 0 }, {0, 0}},
/* KEY_8 */ {{KEY_RIGHTBRACE, 0 }, /* => + */ {0, 0 }, {0, 0}},
/* KEY_9 */ {{KEY_RIGHTBRACE, MOD_LSHIFT}, /* => * */ {0, 0 }, {0, 0}},
/* KEY_0 */ {{KEY_6, MOD_LSHIFT}, /* => & */ {0, 0 }, {0, 0}},
/* KEY_MINUS */ {{0, 0 }, {0, 0 }, {0, 0}},
/* KEY_EQUAL */ {{0, 0 }, {0, 0 }, {0, 0}},
/* KEY_BACKSPACE */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_TAB */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_Q */ {{KEY_DOT, 0 }, /* => . */ {KEY_MINUS, MOD_LSHIFT}, /* => ? */ {0, 0}},
/* KEY_W */ {{KEY_COMMA, MOD_LSHIFT}, /* => ; */ {-0x00b4, MOD_DEAD }, /* => ´ */ {0, 0}},
/* KEY_E */ {{KEY_COMMA, MOD_DEAD }, /* => , */ {-0x0060, MOD_DEAD }, /* => ` */ {KEY_UP, 0}}, /* => ↑ */
/* KEY_R */ {{KEY_P, 0 }, /* => p */ {KEY_P, MOD_LSHIFT}, /* => P */ {KEY_VOLUMEUP, 0}}, /* => 🔊 */
/* KEY_T */ {{KEY_Z, 0 }, /* => y */ {KEY_Z, MOD_LSHIFT}, /* => Y */ {KEY_NEXTSONG, 0}}, /* => » */
/* KEY_Y */ {{KEY_F, 0 }, /* => f */ {KEY_F, MOD_LSHIFT}, /* => F */ {0, 0}},
/* KEY_U */ {{KEY_G, 0 }, /* => g */ {KEY_G, MOD_LSHIFT}, /* => G */ {KEY_KP7, 0}}, /* => 7 */
/* KEY_I */ {{KEY_C, 0 }, /* => c */ {KEY_C, MOD_LSHIFT}, /* => C */ {KEY_KP8, 0}}, /* => 8 */
/* KEY_O */ {{KEY_R, 0 }, /* => r */ {KEY_R, MOD_LSHIFT}, /* => R */ {KEY_KP9, 0}}, /* => 9 */
/* KEY_P */ {{KEY_L, 0 }, /* => l */ {KEY_L, MOD_LSHIFT}, /* => L */ {0, 0}},
/* KEY_LEFTBRACE */ {{0, 0 }, {0, 0 }, {0, 0}},
/* KEY_RIGHTBRACE */ {{0, 0 }, {0, 0 }, {0, 0}},
/* KEY_ENTER */ {{-1, 0 }, {-1, 0 }, {KEY_MUTE, 0}}, /* => 🔇 */
/* KEY_LEFTCTRL */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_A */ {{KEY_A, 0 }, /* => a */ {KEY_A, MOD_LSHIFT}, /* => A */ {0, 0}},
/* KEY_S */ {{KEY_O, 0 }, /* => o */ {KEY_O, MOD_LSHIFT}, /* => O */ {KEY_LEFT, 0}}, /* => ← */
/* KEY_D */ {{KEY_E, 0 }, /* => e */ {KEY_E, MOD_LSHIFT}, /* => E */ {KEY_DOWN, 0}}, /* => ↓ */
/* KEY_F */ {{KEY_I, 0 }, /* => i */ {KEY_I, MOD_LSHIFT}, /* => I */ {KEY_RIGHT, 0}}, /* => → */
/* KEY_G */ {{KEY_U, 0 }, /* => u */ {KEY_U, MOD_LSHIFT}, /* => U */ {0, 0}},
/* KEY_H */ {{KEY_D, 0 }, /* => d */ {KEY_D, MOD_LSHIFT}, /* => D */ {0, 0}},
/* KEY_J */ {{KEY_H, 0 }, /* => h */ {KEY_H, MOD_LSHIFT}, /* => H */ {KEY_KP4, 0}}, /* => 4 */
/* KEY_K */ {{KEY_T, 0 }, /* => t */ {KEY_T, MOD_LSHIFT}, /* => T */ {KEY_KP5, 0}}, /* => 5 */
/* KEY_L */ {{KEY_N, 0 }, /* => n */ {KEY_N, MOD_LSHIFT}, /* => N */ {KEY_KP6, 0}}, /* => 6 */
/* KEY_SEMICOLON */ {{KEY_S, 0 }, /* => s */ {KEY_S, MOD_LSHIFT}, /* => S */ {KEY_DELETE, 0}},
/* KEY_APOSTROPHE */ {{KEY_1, MOD_LSHIFT}, /* => ! */ {KEY_MINUS, 0 }, /* => ß */ {0, 0}},
/* KEY_GRAVE */ {{0, 0 }, {0, 0 }, {0, 0}},
/* KEY_LEFTSHIFT */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_BACKSLASH */ {{0, 0 }, {0, 0 }, {0, 0}},
/* KEY_Z */ {{-0x005e, MOD_DEAD }, /* => ^ */ {0, 0 }, {0, 0}},
/* KEY_X */ {{KEY_Q, 0 }, /* => q */ {KEY_Q, MOD_LSHIFT}, /* => Q */ {0, 0}},
/* KEY_C */ {{KEY_J, 0 }, /* => j */ {KEY_J, MOD_LSHIFT}, /* => J */ {0, 0}},
/* KEY_V */ {{KEY_K, 0 }, /* => k */ {KEY_K, MOD_LSHIFT}, /* => K */ {0, 0}},
/* KEY_B */ {{KEY_X, 0 }, /* => x */ {KEY_X, MOD_LSHIFT}, /* => X */ {0, 0}},
/* KEY_N */ {{KEY_B, 0 }, /* => b */ {KEY_B, MOD_LSHIFT}, /* => B */ {0, 0}},
/* KEY_M */ {{KEY_M, 0 }, /* => m */ {KEY_M, MOD_LSHIFT}, /* => M */ {KEY_KP1, 0}}, /* => 1 */
/* KEY_COMMA */ {{KEY_W, 0 }, /* => w */ {KEY_W, MOD_LSHIFT}, /* => W */ {KEY_KP2, 0}}, /* => 2 */
/* KEY_DOT */ {{KEY_V, 0 }, /* => v */ {KEY_V, MOD_LSHIFT}, /* => V */ {KEY_KP3, 0}}, /* => 3 */
/* KEY_SLASH */ {{KEY_Y, 0 }, /* => z */ {KEY_Y, MOD_LSHIFT}, /* => Z */ {KEY_KP0, 0}}, /* => 0 */
/* KEY_RIGHTSHIFT */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_KPASTERISK */ {{0, 0 }, {0, 0 }, {0, 0}},
/* KEY_LEFTALT */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_SPACE */ {{KEY_SPACE, 0 }, /* => */ {KEY_SPACE, 0 }, /* => */ {KEY_PLAYPAUSE, 0}}, /* => ⏸ */
/* KEY_CAPSLOCK */ {{0, 0 }, {0, 0 }, {0, 0}},
/* KEY_F1 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_F2 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_F3 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_F4 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_F5 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_F6 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_F7 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_F8 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_F9 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_F10 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_NUMLOCK */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_SCROLLLOCK */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_KP7 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_KP8 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_KP9 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_KPMINUS */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_KP4 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_KP5 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_KP6 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_KPPLUS */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_KP1 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_KP2 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_KP3 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_KP0 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_KPDOT */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_ZENKAKUHANKAKU */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_102ND */ {{0, 0 }, {0, 0 }, {0, 0}},
/* KEY_F11 */ {{-1, 0 }, {-1, 0 }, {-1, 0}},
/* KEY_F12 */ {{-1, 0 }, {-1, 0 }, {-1, 0}}
};
int main(int argc, char* argv[])
{
struct uinput_user_dev usetup = {0};
struct input_event ev;
int fdi, fdo;
ssize_t n;
char *input_device = "/dev/input/event0";
if (setuid(0) < 0)
perror("setuid failed");
if (argc > 1)
input_device = argv[1];
sleep(1);
if ((fdi = open(input_device, O_RDONLY)) < 0)
die("Cannot open input device");
/* consume events through reading */
if (ioctl(fdi, EVIOCGRAB, 1) < 0)
die("Cannot grab input device");
if ((fdo = open("/dev/uinput", O_WRONLY | O_NONBLOCK)) < 0)
die("Cannot open /dev/uinput");
/*
* The ioctls below will enable the device that is about to be
* created, to pass key events it reads from the input device.
*/
if (ioctl(fdo, UI_SET_EVBIT, EV_KEY) < 0)
die("Cannot set ev bits, key");
if (ioctl(fdo, UI_SET_EVBIT, EV_SYN) < 0)
die("Cannot set ev bits, syn");
if (ioctl(fdo, UI_SET_EVBIT, EV_MSC) < 0)
die("Cannot set ev bits, msc");
for (int i = 0; i < KEY_CNT; i++) {
if (ioctl(fdo, UI_SET_KEYBIT, i) < 0)
die("Cannot set key bit");
}
/* set up input driver */
usetup.id.bustype = BUS_USB;
usetup.id.vendor = 0x1488;
usetup.id.product = 0x1488;
usetup.id.version = 1;
snprintf(usetup.name, UINPUT_MAX_NAME_SIZE, "qwertz2mydvorak");
if (write(fdo, &usetup, sizeof(usetup)) < 0) /* ioctl(fdo, UI_DEV_SETUP, &usetup) fails */
die("Cannot set device data");
if (ioctl(fdo, UI_DEV_CREATE) < 0)
die("Cannot create device");
/* main loop */
for (;;) {
n = read(fdi, &ev, sizeof(ev));
if (n < 0) {
if (errno == EINTR)
continue;
else
break;
} else if (n != sizeof(ev)) {
errno = EIO;
break;
}
if (ev.type == EV_KEY) {
/* handle key events */
static int mapping_len = sizeof(mapping) / sizeof(mapping[0]);
static int mods = 0;
static int gotany = 0;
static struct key gotdead;
int keycode = -1;
int keymods = 0;
int mod;
if (mod = mod_bit(ev.code)) {
switch (ev.value) {
case PRESSED:
mods |= mod;
gotany = 0;
break;
case RELEASED:
mods &= ~mod;
/* bare capslock generates escape */
/*
if (mod == MOD_CAPS && !gotany)
emitkp(fdo, KEY_ESC);
*/
break;
}
if (ev.code < mapping_len)
keycode = mapping[ev.code].nomod.code;
} else if (mods & MOD_CTRL) {
/* don't transform when ctrl is pressed */
keycode = ev.code;
keymods = mods;
} else {
for (;;) {
struct key *key;
if (ev.code >= mapping_len)
break;
if (mods & MOD_CAPS) {
key = &mapping[ev.code].caps;
/* FIXME: shift check needed? */
if (mods & MOD_SHIFT)
keymods |= MOD_LSHIFT;
} else if (mods & MOD_SHIFT) {
key = &mapping[ev.code].shift;
} else {
key = &mapping[ev.code].nomod;
}
keycode = key->code;
keymods |= key->mods;
break;
}
}
if (keycode == -1) {
/* forward the event */
emit(fdo, ev.type, ev.code, ev.value);
} else if (keycode < -1 || keycode > 0) {
/* remap it if keycode != 0 */
if (keymods & MOD_DEAD || gotdead.code) {
keymods &= ~MOD_DEAD;
if (!gotdead.code) {
/* dead key got pressed */
if (ev.value != RELEASED) {
gotdead.code = keycode;
gotdead.mods = keymods;
}
continue;
} else if (ev.value != RELEASED) {
/* transform the follow-up key */
switch (gotdead.code) {
case KEY_COMMA:
switch (ev.code) {
case KEY_W: /* ; => ' */
keycode = KEY_BACKSLASH;
keymods = MOD_LSHIFT;
break;
case KEY_E: /* , => , */
keycode = KEY_COMMA;
keymods = 0;
break;
case KEY_R: /* p => " */
keycode = KEY_2;
keymods = MOD_LSHIFT;
break;
case KEY_T: /* y => # */
keycode = KEY_BACKSLASH;
keymods = 0;
break;
case KEY_U: /* g => _ */
keycode = KEY_SLASH;
keymods = MOD_LSHIFT;
break;
case KEY_I: /* c => > */
keycode = KEY_102ND;
keymods = MOD_LSHIFT;
break;
case KEY_O: /* r => < */
keycode = KEY_102ND;
keymods = 0;
break;
case KEY_P: /* l => ~ */
keycode = KEY_RIGHTBRACE;
keymods = MOD_RALT;
break;
case KEY_A: /* a => ä */
keycode = KEY_APOSTROPHE;
break;
case KEY_S: /* o => ö */
keycode = KEY_SEMICOLON;
break;
case KEY_D: /* e => ü */
keycode = KEY_LEFTBRACE;
break;
case KEY_F: /* i => = */
keycode = KEY_0;
keymods = MOD_LSHIFT;
break;
case KEY_G: /* u => \ */
keycode = KEY_MINUS;
keymods = MOD_RALT;
break;
case KEY_H: /* d => $ */
keycode = KEY_4;
keymods = MOD_LSHIFT;
break;
case KEY_J: /* h => - */
keycode = KEY_SLASH;
keymods = 0;
break;
case KEY_K: /* t => } */
keycode = KEY_0;
keymods = MOD_RALT;
break;
case KEY_L: /* n => { */
keycode = KEY_7;
keymods = MOD_RALT;
break;
case KEY_SEMICOLON: /* s => / */
keycode = KEY_7;
keymods = MOD_LSHIFT;
break;
case KEY_X: /* q => ¥ */
keycode = -0x00a5;
keymods = 0;
break;
case KEY_C: /* j => £ */
keycode = -0x00a3;
keymods = 0;
break;
case KEY_V: /* k => € */
keycode = KEY_E;
keymods = MOD_RALT;
break;
case KEY_N: /* b => : */
keycode = KEY_DOT;
keymods = MOD_LSHIFT;
break;
case KEY_M: /* m => @ */
keycode = KEY_Q;
keymods = MOD_RALT;
break;
case KEY_COMMA: /* w => ] */
keycode = KEY_9;
keymods = MOD_RALT;
break;
case KEY_DOT: /* v => [ */
keycode = KEY_8;
keymods = MOD_RALT;
break;
case KEY_SLASH: /* z => % */
keycode = KEY_5;
keymods = MOD_LSHIFT;
break;
default:
emitkey(fdo, gotdead.code, gotdead.mods, mods);
break;
}
break;
case -0x005e:
switch (ev.code) {
case KEY_A: /* a => â */
keycode = -0x00e2;
if (keymods & MOD_LSHIFT)
keycode += 32;
keymods = 0;
break;
case KEY_D: /* e => ê */
keycode = -0x00ea;
if (keymods & MOD_LSHIFT)
keycode += 32;
keymods = 0;
break;
case KEY_G: /* u => û */
keycode = -0x00fb;
if (keymods & MOD_LSHIFT)
keycode += 32;
keymods = 0;
break;
case KEY_F: /* i => î */
keycode = -0x00ee;
if (keymods & MOD_LSHIFT)
keycode += 32;
keymods = 0;
break;
case KEY_S: /* o => ô */
keycode = -0x00f4;
if (keymods & MOD_LSHIFT)
keycode += 32;
keymods = 0;
break;
case KEY_SPACE: /* => ^ */
keycode = gotdead.code;
keymods = 0;
break;
default:
emitkey(fdo, gotdead.code, gotdead.mods, mods);
break;
}
break;
case -0x0060:
switch (ev.code) {
case KEY_A: /* a => à */
keycode = -0x00e0;
if (keymods & MOD_LSHIFT)
keycode += 32;
keymods = 0;
break;
case KEY_D: /* e => è */
keycode = -0x00e8;
if (keymods & MOD_LSHIFT)
keycode += 32;
keymods = 0;
break;
case KEY_G: /* u => ù */
keycode = -0x00f9;
if (keymods & MOD_LSHIFT)
keycode += 32;
keymods = 0;
break;
case KEY_F: /* i => ì */
keycode = -0x00ec;
if (keymods & MOD_LSHIFT)
keycode += 32;
keymods = 0;
break;
case KEY_S: /* o => ò */
keycode = -0x00f2;
if (keymods & MOD_LSHIFT)
keycode += 32;
keymods = 0;
break;
case KEY_SPACE: /* => ` */
keycode = gotdead.code;
keymods = 0;
break;
default:
emitkey(fdo, gotdead.code, gotdead.mods, mods);
break;
}
break;
case -0x00b4:
switch (ev.code) {
case KEY_T: /* y => ý */
keycode = -0x00fd;
if (keymods & MOD_LSHIFT)
keycode += 32;
keymods = 0;
break;
case KEY_A: /* a => á */
keycode = -0x00e1;
if (keymods & MOD_LSHIFT)
keycode += 32;
keymods = 0;
break;
case KEY_D: /* e => é */
keycode = -0x00e9;
if (keymods & MOD_LSHIFT)
keycode += 32;
keymods = 0;
break;
case KEY_G: /* u => ú */
keycode = -0x00fa;
if (keymods & MOD_LSHIFT)
keycode += 32;
keymods = 0;
break;
case KEY_F: /* i => í */
keycode = -0x00ed;
if (keymods & MOD_LSHIFT)
keycode += 32;
keymods = 0;
break;
case KEY_S: /* o => ó */
keycode = -0x00f3;
if (keymods & MOD_LSHIFT)
keycode += 32;
keymods = 0;
break;
case KEY_SPACE: /* => ´ */
keycode = gotdead.code;
keymods = 0;
break;
default:
emitkey(fdo, gotdead.code, gotdead.mods, mods);
break;
}
break;
}
gotdead.code = 0;
}
}
if (ev.value == RELEASED)
continue;
emitkey(fdo, keycode, keymods, mods);
gotany = 1;
}
} else {
/* forward everything else */
emit(fdo, ev.type, ev.code, ev.value);
}
}
close(fdi);
ioctl(fdo, UI_DEV_DESTROY);
close(fdo);
die("read failed");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment