#include #include #include static void default_ldisc_write(struct device *, const struct input_event *); static kern_status_t default_ldisc_read(struct device *tty, void *buf, size_t max, size_t *nr_read, socks_flags_t flags); static char keycode_chars[] = { [KEY_UNKNOWN] = ' ', [KEY_A] = 'a', [KEY_B] = 'b', [KEY_C] = 'c', [KEY_D] = 'd', [KEY_E] = 'e', [KEY_F] = 'f', [KEY_G] = 'g', [KEY_H] = 'h', [KEY_I] = 'i', [KEY_J] = 'j', [KEY_K] = 'k', [KEY_L] = 'l', [KEY_M] = 'm', [KEY_N] = 'n', [KEY_O] = 'o', [KEY_P] = 'p', [KEY_Q] = 'q', [KEY_R] = 'r', [KEY_S] = 's', [KEY_T] = 't', [KEY_U] = 'u', [KEY_V] = 'v', [KEY_W] = 'w', [KEY_X] = 'x', [KEY_Y] = 'y', [KEY_Z] = 'z', [KEY_KEY_1] = '1', [KEY_KEY_2] = '2', [KEY_KEY_3] = '3', [KEY_KEY_4] = '4', [KEY_KEY_5] = '5', [KEY_KEY_6] = '6', [KEY_KEY_7] = '7', [KEY_KEY_8] = '8', [KEY_KEY_9] = '9', [KEY_KEY_0] = '0', [KEY_ENTER] = '\n', [KEY_ESCAPE] = 0, [KEY_BACKSPACE] = '\b', [KEY_TAB] = ' ', [KEY_SPACE] = ' ', [KEY_MINUS] = '-', [KEY_EQUALS] = '=', [KEY_LEFT_BRACE] = '[', [KEY_RIGHT_BRACE] = ']', [KEY_BACKSLASH] = '\\', [KEY_NON_US_HASH] = 0, [KEY_SEMICOLON] = ';', [KEY_APOSTROPHE] = '\'', [KEY_GRAVE_ACCENT] = 0, [KEY_COMMA] = ',', [KEY_DOT] = '.', [KEY_SLASH] = '/', [KEY_CAPS_LOCK] = 0, [KEY_F1] = 0, [KEY_F2] = 0, [KEY_F3] = 0, [KEY_F4] = 0, [KEY_F5] = 0, [KEY_F6] = 0, [KEY_F7] = 0, [KEY_F8] = 0, [KEY_F9] = 0, [KEY_F10] = 0, [KEY_F11] = 0, [KEY_F12] = 0, [KEY_PRINT_SCREEN] = 0, [KEY_SCROLL_LOCK] = 0, [KEY_PAUSE] = 0, [KEY_INSERT] = 0, [KEY_HOME] = 0, [KEY_PAGE_UP] = 0, [KEY_DELETE] = 0, [KEY_END] = 0, [KEY_PAGE_DOWN] = 0, [KEY_RIGHT] = 0, [KEY_LEFT] = 0, [KEY_DOWN] = 0, [KEY_UP] = 0, [KEY_NUM_LOCK] = 0, [KEY_KEYPAD_SLASH] = '/', [KEY_KEYPAD_ASTERISK] = '*', [KEY_KEYPAD_MINUS] = '-', [KEY_KEYPAD_PLUS] = '+', [KEY_KEYPAD_ENTER] = '\n', [KEY_KEYPAD_1] = '1', [KEY_KEYPAD_2] = '2', [KEY_KEYPAD_3] = '3', [KEY_KEYPAD_4] = '4', [KEY_KEYPAD_5] = '5', [KEY_KEYPAD_6] = '6', [KEY_KEYPAD_7] = '7', [KEY_KEYPAD_8] = '8', [KEY_KEYPAD_9] = '9', [KEY_KEYPAD_0] = '0', [KEY_KEYPAD_DOT] = '.', [KEY_NON_US_BACKSLASH] = 0, [KEY_KEYPAD_EQUALS] = '=', [KEY_MENU] = 0, [KEY_LEFT_CTRL] = 0, [KEY_LEFT_SHIFT] = 0, [KEY_LEFT_ALT] = 0, [KEY_LEFT_META] = 0, [KEY_RIGHT_CTRL] = 0, [KEY_RIGHT_SHIFT] = 0, [KEY_RIGHT_ALT] = 0, [KEY_RIGHT_META] = 0, [KEY_MEDIA_MUTE] = 0, [KEY_MEDIA_VOLUME_INCREMENT] = 0, [KEY_MEDIA_VOLUME_DECREMENT] = 0, }; static char keycode_chars_shift[] = { [KEY_UNKNOWN] = ' ', [KEY_A] = 'A', [KEY_B] = 'B', [KEY_C] = 'C', [KEY_D] = 'D', [KEY_E] = 'E', [KEY_F] = 'F', [KEY_G] = 'G', [KEY_H] = 'H', [KEY_I] = 'I', [KEY_J] = 'J', [KEY_K] = 'K', [KEY_L] = 'L', [KEY_M] = 'M', [KEY_N] = 'N', [KEY_O] = 'O', [KEY_P] = 'P', [KEY_Q] = 'Q', [KEY_R] = 'R', [KEY_S] = 'S', [KEY_T] = 'T', [KEY_U] = 'U', [KEY_V] = 'V', [KEY_W] = 'W', [KEY_X] = 'X', [KEY_Y] = 'Y', [KEY_Z] = 'Z', [KEY_KEY_1] = '!', [KEY_KEY_2] = '"', [KEY_KEY_3] = 0, [KEY_KEY_4] = '$', [KEY_KEY_5] = '%', [KEY_KEY_6] = '^', [KEY_KEY_7] = '&', [KEY_KEY_8] = '*', [KEY_KEY_9] = '(', [KEY_KEY_0] = ')', [KEY_ENTER] = '\n', [KEY_ESCAPE] = 0, [KEY_BACKSPACE] = '\b', [KEY_TAB] = ' ', [KEY_SPACE] = ' ', [KEY_MINUS] = '_', [KEY_EQUALS] = '+', [KEY_LEFT_BRACE] = '{', [KEY_RIGHT_BRACE] = '}', [KEY_BACKSLASH] = '|', [KEY_NON_US_HASH] = 0, [KEY_SEMICOLON] = ':', [KEY_APOSTROPHE] = '@', [KEY_GRAVE_ACCENT] = 0, [KEY_COMMA] = '<', [KEY_DOT] = '>', [KEY_SLASH] = '?', [KEY_CAPS_LOCK] = 0, [KEY_F1] = 0, [KEY_F2] = 0, [KEY_F3] = 0, [KEY_F4] = 0, [KEY_F5] = 0, [KEY_F6] = 0, [KEY_F7] = 0, [KEY_F8] = 0, [KEY_F9] = 0, [KEY_F10] = 0, [KEY_F11] = 0, [KEY_F12] = 0, [KEY_PRINT_SCREEN] = 0, [KEY_SCROLL_LOCK] = 0, [KEY_PAUSE] = 0, [KEY_INSERT] = 0, [KEY_HOME] = 0, [KEY_PAGE_UP] = 0, [KEY_DELETE] = 0, [KEY_END] = 0, [KEY_PAGE_DOWN] = 0, [KEY_RIGHT] = 0, [KEY_LEFT] = 0, [KEY_DOWN] = 0, [KEY_UP] = 0, [KEY_NUM_LOCK] = 0, [KEY_KEYPAD_SLASH] = '/', [KEY_KEYPAD_ASTERISK] = '*', [KEY_KEYPAD_MINUS] = '-', [KEY_KEYPAD_PLUS] = '+', [KEY_KEYPAD_ENTER] = '\n', [KEY_KEYPAD_1] = '1', [KEY_KEYPAD_2] = '2', [KEY_KEYPAD_3] = '3', [KEY_KEYPAD_4] = '4', [KEY_KEYPAD_5] = '5', [KEY_KEYPAD_6] = '6', [KEY_KEYPAD_7] = '7', [KEY_KEYPAD_8] = '8', [KEY_KEYPAD_9] = '9', [KEY_KEYPAD_0] = '0', [KEY_KEYPAD_DOT] = '.', [KEY_NON_US_BACKSLASH] = 0, [KEY_KEYPAD_EQUALS] = '=', [KEY_MENU] = 0, [KEY_LEFT_CTRL] = 0, [KEY_LEFT_SHIFT] = 0, [KEY_LEFT_ALT] = 0, [KEY_LEFT_META] = 0, [KEY_RIGHT_CTRL] = 0, [KEY_RIGHT_SHIFT] = 0, [KEY_RIGHT_ALT] = 0, [KEY_RIGHT_META] = 0, [KEY_MEDIA_MUTE] = 0, [KEY_MEDIA_VOLUME_INCREMENT] = 0, [KEY_MEDIA_VOLUME_DECREMENT] = 0, }; static struct tty_ldisc default_ldisc = { .name = "n_tty", .read = default_ldisc_read, .write = default_ldisc_write, }; static enum tty_modifier_key get_modifier_key(const struct input_event *ev) { switch (ev->ev_key.key) { case KEY_LEFT_CTRL: case KEY_RIGHT_CTRL: return TTY_KEY_CTRL; case KEY_LEFT_ALT: case KEY_RIGHT_ALT: return TTY_KEY_ALT; case KEY_LEFT_SHIFT: case KEY_RIGHT_SHIFT: return TTY_KEY_SHIFT; default: return TTY_KEY_OTHER; } } static bool is_arrow_key(const struct input_event *ev, char *ch) { bool ret = false; switch (ev->ev_key.key) { case KEY_UP: ret = true; *ch = 'A'; break; case KEY_DOWN: ret = true; *ch = 'B'; break; case KEY_RIGHT: ret = true; *ch = 'C'; break; case KEY_LEFT: ret = true; *ch = 'D'; break; default: ret = false; break; } return ret; } static void handle_modifier_keys(struct device *tty, enum tty_modifier_key modkey, const struct input_event *ev) { struct tty_device *ttydev = TTY_DEVICE(tty); if (ev->ev_key.state == INPUT_KEYSTATE_DOWN) { ttydev->tty_modstate |= modkey; } else { ttydev->tty_modstate &= ~modkey; } } static void convert_ev_to_chars(struct device *tty, const struct input_event *ev) { if (ev->ev_key.state == INPUT_KEYSTATE_UP) { return; } struct tty_device *ttydev = TTY_DEVICE(tty); char echo[4]; int echo_len = 0; char data[4]; int data_len = 0; char c = keycode_chars[ev->ev_key.key]; if (ttydev->tty_modstate & TTY_KEY_CTRL) { if (!isalpha(c)) { return; } echo[0] = '^'; echo[1] = toupper(c); echo_len = 2; c = tolower(c); c -= 97; c++; data[0] = c; data_len = 1; } else if (ttydev->tty_modstate & TTY_KEY_SHIFT) { c = keycode_chars_shift[ev->ev_key.key]; echo[0] = c; echo_len = 1; data[0] = c; data_len = 1; } else if (is_arrow_key(ev, &c)) { echo[0] = '^'; echo[1] = '['; echo[2] = '['; echo[3] = c; echo_len = 4; data[0] = 0x1b; data[1] = '['; data[2] = c; data_len = 3; } else if (c != 0) { echo[0] = c; echo_len = 1; data[0] = c; data_len = 1; } if (data_len == 0) { return; } ringbuffer_write(&ttydev->tty_input, data_len, data, S_NOBLOCK); size_t nr_written; tty_write(tty, echo, 0, echo_len, &nr_written, S_NOBLOCK); } static kern_status_t canonical_read(struct device *tty, void *buf, size_t max, size_t *nr_read, socks_flags_t flags) { //struct tty_device *ttydev = TTY_DEVICE(tty); //struct termios backup = ttydev //char *linebuf = ttydev->tty_linebuf; //unsigned int pos = 0, len = 0; return KERN_OK; } static kern_status_t non_canonical_read(struct device *tty, void *buf, size_t max, size_t *nr_read, socks_flags_t flags) { return KERN_OK; } static kern_status_t default_ldisc_read(struct device *tty, void *buf, size_t max, size_t *nr_read, socks_flags_t flags) { struct tty_device *ttydev = TTY_DEVICE(tty); if (ttydev->tty_config.c_lflag & ICANON) { return canonical_read(tty, buf, max, nr_read, flags); } else { return non_canonical_read(tty, buf, max, nr_read, flags); } return KERN_OK; } static void default_ldisc_write(struct device *tty, const struct input_event *ev) { enum tty_modifier_key modkeys = get_modifier_key(ev); if (modkeys != TTY_KEY_OTHER) { handle_modifier_keys(tty, modkeys, ev); } else { convert_ev_to_chars(tty, ev); } } struct tty_ldisc *tty_default_line_discipline(void) { return &default_ldisc; }