329 lines
9.9 KiB
C
329 lines
9.9 KiB
C
#include <socks/tty.h>
|
|
#include <socks/input.h>
|
|
#include <socks/libc/ctype.h>
|
|
|
|
static void default_ldisc_write(struct device *, const struct input_event *);
|
|
|
|
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",
|
|
.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 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[2];
|
|
int echo_len = 0;
|
|
|
|
char c = keycode_chars[ev->ev_key.key];
|
|
if (c == 0) {
|
|
return;
|
|
}
|
|
|
|
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++;
|
|
} else if (ttydev->tty_modstate & TTY_KEY_SHIFT) {
|
|
c = keycode_chars_shift[ev->ev_key.key];
|
|
echo[0] = c;
|
|
echo_len = 1;
|
|
} else {
|
|
echo[0] = c;
|
|
echo_len = 1;
|
|
}
|
|
|
|
if (c == 0) {
|
|
return;
|
|
}
|
|
|
|
ringbuffer_write(&ttydev->tty_input, sizeof c, &c, S_NOBLOCK);
|
|
size_t nr_written;
|
|
tty_write(tty, echo, echo_len, &nr_written, S_NOBLOCK);
|
|
}
|
|
|
|
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;
|
|
}
|