123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566 |
- /* vim: tabstop=4 shiftwidth=4 noexpandtab
- * This file is part of ToaruOS and is released under the terms
- * of the NCSA / University of Illinois License - see LICENSE.md
- * Copyright (C) 2012-2018 K. Lange
- *
- * General-purpose keyboard conversion library.
- *
- * This provides similar functionality to xkb:
- * - It provides mappings for keyboards from locales
- * - It translates incoming key presses to key names
- * - It translates incoming keys to escape sequences
- */
- #include <stdio.h>
- #include <toaru/kbd.h>
- #define DEBUG_SCANCODES 0
- #define KEY_UP_MASK 0x80
- #define KEY_CODE_MASK 0x7F
- #define KEY_CTRL_MASK 0x40
- #define norm 0x01
- #define spec 0x02
- #define func 0x03
- #define SET_UNSET(a,b,c) (a) = (c) ? ((a) | (b)) : ((a) & ~(b))
- char key_method[] = {
- /* 00 */ 0, spec, norm, norm, norm, norm, norm, norm,
- /* 08 */ norm, norm, norm, norm, norm, norm, norm, norm,
- /* 10 */ norm, norm, norm, norm, norm, norm, norm, norm,
- /* 18 */ norm, norm, norm, norm, norm, spec, norm, norm,
- /* 20 */ norm, norm, norm, norm, norm, norm, norm, norm,
- /* 28 */ norm, norm, spec, norm, norm, norm, norm, norm,
- /* 30 */ norm, norm, norm, norm, norm, norm, spec, norm,
- /* 38 */ spec, norm, spec, func, func, func, func, func,
- /* 40 */ func, func, func, func, func, spec, spec, spec,
- /* 48 */ spec, spec, spec, spec, spec, spec, spec, spec,
- /* 50 */ spec, spec, spec, spec, spec, spec, spec, func,
- /* 58 */ func, spec, spec, spec, spec, spec, spec, spec,
- /* 60 */ spec, spec, spec, spec, spec, spec, spec, spec,
- /* 68 */ spec, spec, spec, spec, spec, spec, spec, spec,
- /* 70 */ spec, spec, spec, spec, spec, spec, spec, spec,
- /* 78 */ spec, spec, spec, spec, spec, spec, spec, spec,
- };
- char kbd_us[128] = {
- 0, 27,
- '1','2','3','4','5','6','7','8','9','0',
- '-','=','\b',
- '\t', /* tab */
- 'q','w','e','r','t','y','u','i','o','p','[',']','\n',
- 0, /* control */
- 'a','s','d','f','g','h','j','k','l',';','\'', '`',
- 0, /* left shift */
- '\\','z','x','c','v','b','n','m',',','.','/',
- 0, /* right shift */
- '*',
- 0, /* alt */
- ' ', /* space */
- 0, /* caps lock */
- 0, /* F1 [59] */
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, /* ... F10 */
- 0, /* 69 num lock */
- 0, /* scroll lock */
- 0, /* home */
- 0, /* up */
- 0, /* page up */
- '-',
- 0, /* left arrow */
- 0,
- 0, /* right arrow */
- '+',
- 0, /* 79 end */
- 0, /* down */
- 0, /* page down */
- 0, /* insert */
- 0, /* delete */
- 0, 0, 0,
- 0, /* F11 */
- 0, /* F12 */
- 0, /* everything else */
- };
- char kbd_us_l2[128] = {
- 0, 27,
- '!','@','#','$','%','^','&','*','(',')',
- '_','+','\b',
- '\t', /* tab */
- 'Q','W','E','R','T','Y','U','I','O','P','{','}','\n',
- 0, /* control */
- 'A','S','D','F','G','H','J','K','L',':','"', '~',
- 0, /* left shift */
- '|','Z','X','C','V','B','N','M','<','>','?',
- 0, /* right shift */
- '*',
- 0, /* alt */
- ' ', /* space */
- 0, /* caps lock */
- 0, /* F1 [59] */
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, /* ... F10 */
- 0, /* 69 num lock */
- 0, /* scroll lock */
- 0, /* home */
- 0, /* up */
- 0, /* page up */
- '-',
- 0, /* left arrow */
- 0,
- 0, /* right arrow */
- '+',
- 0, /* 79 end */
- 0, /* down */
- 0, /* page down */
- 0, /* insert */
- 0, /* delete */
- 0, 0, 0,
- 0, /* F11 */
- 0, /* F12 */
- 0, /* everything else */
- };
- /*
- * Converts from incoming terminal keys to kbd_keys
- */
- kbd_key_t kbd_key(key_event_state_t * state, unsigned char c) {
- switch (state->kbd_state) {
- case KBD_NORMAL:
- switch (c) {
- case 0x1b:
- state->kbd_state = KBD_ESC_A;
- return KEY_NONE;
- default:
- return c;
- }
- case KBD_ESC_A:
- switch (c) {
- case 0x5b:
- state->kbd_state = KBD_ESC_B;
- return KEY_NONE;
- case 'O':
- state->kbd_state = KBD_ESC_O;
- return KEY_NONE;
- default:
- state->kbd_state = KBD_NORMAL;
- return c;
- }
- case KBD_ESC_O:
- switch (c) {
- case 0x41:
- state->kbd_state = KBD_NORMAL;
- return KEY_ARROW_UP;
- case 0x42:
- state->kbd_state = KBD_NORMAL;
- return KEY_ARROW_DOWN;
- case 0x43:
- state->kbd_state = KBD_NORMAL;
- return KEY_ARROW_RIGHT;
- case 0x44:
- state->kbd_state = KBD_NORMAL;
- return KEY_ARROW_LEFT;
- case 'H':
- state->kbd_state = KBD_NORMAL;
- return KEY_HOME;
- case 'F':
- state->kbd_state = KBD_NORMAL;
- return KEY_END;
- default:
- state->kbd_state = KBD_NORMAL;
- return c;
- }
- case KBD_ESC_B:
- switch (c) {
- case 0x41:
- state->kbd_state = KBD_NORMAL;
- return KEY_ARROW_UP;
- case 0x42:
- state->kbd_state = KBD_NORMAL;
- return KEY_ARROW_DOWN;
- case 0x43:
- state->kbd_state = KBD_NORMAL;
- return KEY_ARROW_RIGHT;
- case 0x44:
- state->kbd_state = KBD_NORMAL;
- return KEY_ARROW_LEFT;
- case 'H':
- state->kbd_state = KBD_NORMAL;
- return KEY_HOME;
- case 'F':
- state->kbd_state = KBD_NORMAL;
- return KEY_END;
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- state->kbd_esc_buf = c;
- state->kbd_state = KBD_ESC_EXT;
- return KEY_NONE;
- default:
- state->kbd_state = KBD_NORMAL;
- return c;
- }
- case KBD_ESC_EXT:
- switch (c) {
- case '~':
- switch (state->kbd_esc_buf) {
- case '2':
- state->kbd_state = KBD_NORMAL;
- return KEY_INSERT;
- case '3':
- state->kbd_state = KBD_NORMAL;
- return KEY_DEL;
- case '5':
- state->kbd_state = KBD_NORMAL;
- return KEY_PAGE_UP;
- case '6':
- state->kbd_state = KBD_NORMAL;
- return KEY_PAGE_DOWN;
- default:
- return c;
- }
- case 'A':
- switch (state->kbd_esc_buf) {
- case '2':
- state->kbd_state = KBD_NORMAL;
- return KEY_SHIFT_ARROW_UP;
- case '5':
- state->kbd_state = KBD_NORMAL;
- return KEY_CTRL_ARROW_UP;
- /* Other modifier states? */
- default:
- return c;
- }
- case 'B':
- switch (state->kbd_esc_buf) {
- case '2':
- state->kbd_state = KBD_NORMAL;
- return KEY_SHIFT_ARROW_DOWN;
- case '5':
- state->kbd_state = KBD_NORMAL;
- return KEY_CTRL_ARROW_DOWN;
- /* Other modifier states? */
- default:
- return c;
- }
- case 'C':
- switch (state->kbd_esc_buf) {
- case '2':
- state->kbd_state = KBD_NORMAL;
- return KEY_SHIFT_ARROW_RIGHT;
- case '5':
- state->kbd_state = KBD_NORMAL;
- return KEY_CTRL_ARROW_RIGHT;
- /* Other modifier states? */
- default:
- return c;
- }
- case 'D':
- switch (state->kbd_esc_buf) {
- case '2':
- state->kbd_state = KBD_NORMAL;
- return KEY_SHIFT_ARROW_LEFT;
- case '5':
- state->kbd_state = KBD_NORMAL;
- return KEY_CTRL_ARROW_LEFT;
- /* Other modifier states? */
- default:
- return c;
- }
- case ';':
- /* We don't produce multiple-argument escapes ourself, but
- * we should handle them anyway because other terminals
- * definitely do make them... */
- state->kbd_state = KBD_ESC_B;
- return KEY_NONE;
- default:
- return c;
- }
- default:
- return KEY_BAD_STATE;
- }
- return KEY_BAD_STATE;
- }
- int kbd_scancode(key_event_state_t * state, unsigned char c, key_event_t * event) {
- /* Convert scancodes to a series of keys */
- event->keycode = 0;
- event->action = 0;
- event->modifiers = 0;
- event->key = 0;
- #if DEBUG_SCANCODES
- fprintf(stderr, "[%d] %d\n", state->kbd_s_state, (int)c);
- #endif
- event->modifiers |= state->kl_ctrl ? KEY_MOD_LEFT_CTRL : 0;
- event->modifiers |= state->kl_shift ? KEY_MOD_LEFT_SHIFT : 0;
- event->modifiers |= state->kl_alt ? KEY_MOD_LEFT_ALT : 0;
- event->modifiers |= state->kl_super ? KEY_MOD_LEFT_SUPER : 0;
- event->modifiers |= state->kr_ctrl ? KEY_MOD_RIGHT_CTRL : 0;
- event->modifiers |= state->kr_shift ? KEY_MOD_RIGHT_SHIFT : 0;
- event->modifiers |= state->kr_alt ? KEY_MOD_RIGHT_ALT : 0;
- event->modifiers |= state->kr_super ? KEY_MOD_RIGHT_SUPER : 0;
- if (!state->kbd_s_state) {
- if (c == 0xE0) {
- state->kbd_s_state = 1;
- /* Literally nothing */
- return 0;
- }
- if (c & KEY_UP_MASK) {
- c ^= KEY_UP_MASK;
- event->action = KEY_ACTION_UP;
- } else {
- event->action = KEY_ACTION_DOWN;
- }
- int down = (event->action == KEY_ACTION_DOWN);
- switch (key_method[c]) {
- case norm:
- {
- event->keycode = kbd_us[c];
- if (state->k_ctrl) {
- int s = kbd_us[c];
- if (s >= 'a' && s <= 'z') s -= 'a' - 'A';
- if (s == '-') s = '_';
- if (s == '`') s = '@';
- int out = (int)(s - KEY_CTRL_MASK);
- if (out < 0 || out > 0x1F) {
- event->key = kbd_us[c];
- } else {
- event->key = out;
- }
- } else {
- event->key = state->k_shift ? kbd_us_l2[c] : kbd_us[c];
- }
- }
- break;
- case spec:
- switch (c) {
- case 0x01:
- event->key = '\033';
- event->keycode = KEY_ESCAPE;
- break;
- case 0x1D:
- state->k_ctrl = down;
- state->kl_ctrl = down;
- event->keycode = KEY_LEFT_CTRL;
- SET_UNSET(event->modifiers, KEY_MOD_LEFT_CTRL, down);
- break;
- case 0x2A:
- state->k_shift = down;
- state->kl_shift = down;
- event->keycode = KEY_LEFT_SHIFT;
- SET_UNSET(event->modifiers, KEY_MOD_LEFT_SHIFT, down);
- break;
- case 0x36:
- state->k_shift = down;
- state->kr_shift = down;
- event->keycode = KEY_RIGHT_SHIFT;
- SET_UNSET(event->modifiers, KEY_MOD_RIGHT_SHIFT, down);
- break;
- case 0x38:
- state->k_alt = down;
- state->kl_alt = down;
- event->keycode = KEY_LEFT_ALT;
- SET_UNSET(event->modifiers, KEY_MOD_LEFT_ALT, down);
- break;
- case KEY_SCANCODE_NUM_0:
- event->keycode = KEY_NUM_0;
- event->key = '0';
- break;
- case KEY_SCANCODE_NUM_1:
- event->keycode = KEY_NUM_1;
- event->key = '1';
- break;
- case KEY_SCANCODE_NUM_2:
- event->keycode = KEY_NUM_2;
- event->key = '2';
- break;
- case KEY_SCANCODE_NUM_3:
- event->keycode = KEY_NUM_3;
- event->key = '3';
- break;
- case KEY_SCANCODE_NUM_4:
- event->keycode = KEY_NUM_4;
- event->key = '4';
- break;
- case KEY_SCANCODE_NUM_5:
- event->keycode = KEY_NUM_5;
- event->key = '5';
- break;
- case KEY_SCANCODE_NUM_6:
- event->keycode = KEY_NUM_6;
- event->key = '6';
- break;
- case KEY_SCANCODE_NUM_7:
- event->keycode = KEY_NUM_7;
- event->key = '7';
- break;
- case KEY_SCANCODE_NUM_8:
- event->keycode = KEY_NUM_8;
- event->key = '8';
- break;
- case KEY_SCANCODE_NUM_9:
- event->keycode = KEY_NUM_9;
- event->key = '9';
- break;
- case KEY_SCANCODE_NUM_DOT:
- event->keycode = KEY_NUM_DOT;
- event->key = '.';
- break;
- case KEY_SCANCODE_NUM_MIN:
- event->keycode = KEY_NUM_MINUS;
- event->key = '-';
- break;
- case KEY_SCANCODE_NUM_ADD:
- event->keycode = KEY_NUM_PLUS;
- event->key = '+';
- break;
- default:
- break;
- }
- break;
- case func:
- switch (c) {
- case KEY_SCANCODE_F1:
- event->keycode = KEY_F1;
- break;
- case KEY_SCANCODE_F2:
- event->keycode = KEY_F2;
- break;
- case KEY_SCANCODE_F3:
- event->keycode = KEY_F3;
- break;
- case KEY_SCANCODE_F4:
- event->keycode = KEY_F4;
- break;
- case KEY_SCANCODE_F5:
- event->keycode = KEY_F5;
- break;
- case KEY_SCANCODE_F6:
- event->keycode = KEY_F6;
- break;
- case KEY_SCANCODE_F7:
- event->keycode = KEY_F7;
- break;
- case KEY_SCANCODE_F8:
- event->keycode = KEY_F8;
- break;
- case KEY_SCANCODE_F9:
- event->keycode = KEY_F9;
- break;
- case KEY_SCANCODE_F10:
- event->keycode = KEY_F10;
- break;
- case KEY_SCANCODE_F11:
- event->keycode = KEY_F11;
- break;
- case KEY_SCANCODE_F12:
- event->keycode = KEY_F12;
- break;
- }
- break;
- default:
- break;
- }
- if (event->key) {
- return down;
- }
- return 0;
- } else if (state->kbd_s_state == 1) {
- if (c & KEY_UP_MASK) {
- c ^= KEY_UP_MASK;
- event->action = KEY_ACTION_UP;
- } else {
- event->action = KEY_ACTION_DOWN;
- }
- int down = (event->action == KEY_ACTION_DOWN);
- switch (c) {
- case 0x5B:
- state->k_super = down;
- state->kl_super = down;
- event->keycode = KEY_LEFT_SUPER;
- SET_UNSET(event->modifiers, KEY_MOD_LEFT_SUPER, down);
- break;
- case 0x5C:
- state->k_super = down;
- state->kr_super = down;
- event->keycode = KEY_RIGHT_SUPER;
- SET_UNSET(event->modifiers, KEY_MOD_RIGHT_SUPER, down);
- break;
- case 0x1D:
- state->kr_ctrl = down;
- state->k_ctrl = down;
- event->keycode = KEY_RIGHT_CTRL;
- SET_UNSET(event->modifiers, KEY_MOD_RIGHT_CTRL, down);
- break;
- case 0x38:
- state->kr_alt = down;
- state->k_alt = down;
- event->keycode = KEY_RIGHT_ALT;
- SET_UNSET(event->modifiers, KEY_MOD_RIGHT_ALT, down);
- break;
- case 0x48:
- event->keycode = KEY_ARROW_UP;
- break;
- case 0x4D:
- event->keycode = KEY_ARROW_RIGHT;
- break;
- case 0x47:
- event->keycode = KEY_HOME;
- break;
- case 0x49:
- event->keycode = KEY_PAGE_UP;
- break;
- case 0x4B:
- event->keycode = KEY_ARROW_LEFT;
- break;
- case 0x4F:
- event->keycode = KEY_END;
- break;
- case 0x50:
- event->keycode = KEY_ARROW_DOWN;
- break;
- case 0x51:
- event->keycode = KEY_PAGE_DOWN;
- break;
- case 0x52:
- event->keycode = KEY_INSERT;
- break;
- case 0x53:
- event->keycode = KEY_DEL;
- break;
- case 0x35:
- event->keycode = KEY_NUM_DIV;
- event->key = '/';
- break;
- case 0x1C:
- event->keycode = KEY_NUM_ENTER;
- event->key = '\n';
- break;
- default:
- break;
- }
- state->kbd_s_state = 0;
- return 0;
- }
- return 0;
- }
|