/* * BRLTTY - A background process providing access to the console screen (when in * text mode) for a blind person using a refreshable braille display. * * Copyright (C) 1995-2021 by The BRLTTY Developers. * * BRLTTY comes with ABSOLUTELY NO WARRANTY. * * This is free software, placed under the terms of the * GNU Lesser General Public License, as published by the Free Software * Foundation; either version 2.1 of the License, or (at your option) any * later version. Please see the file LICENSE-LGPL for details. * * Web Page: http://brltty.app/ * * This software is maintained by Dave Mielke . */ #include "prologue.h" #include #include "log.h" #include "report.h" #include "cmd_queue.h" #include "cmd_keycodes.h" #include "kbd_keycodes.h" #include "brl_cmds.h" #include "alert.h" typedef enum { MOD_RELEASE = 0, /* must be first */ MOD_GUI_LEFT, MOD_GUI_RIGHT, MOD_CONTEXT, MOD_LOCK_CAPS, MOD_LOCK_SCROLL, MOD_LOCK_NUMBER, MOD_SHIFT_LEFT, MOD_SHIFT_RIGHT, MOD_CONTROL_LEFT, MOD_CONTROL_RIGHT, MOD_ALT_LEFT, MOD_ALT_RIGHT } Modifier; #define MOD_BIT(number) (1 << (number)) #define MOD_SET(number, bits) ((bits) |= MOD_BIT((number))) #define MOD_CLR(number, bits) ((bits) &= ~MOD_BIT((number))) #define MOD_TST(number, bits) ((bits) & MOD_BIT((number))) typedef struct { int command; int alternate; } KeyEntry; static const KeyEntry keyEntry_Escape = {BRL_CMD_KEY(ESCAPE)}; static const KeyEntry keyEntry_F1 = {BRL_CMD_KFN(1)}; static const KeyEntry keyEntry_F2 = {BRL_CMD_KFN(2)}; static const KeyEntry keyEntry_F3 = {BRL_CMD_KFN(3)}; static const KeyEntry keyEntry_F4 = {BRL_CMD_KFN(4)}; static const KeyEntry keyEntry_F5 = {BRL_CMD_KFN(5)}; static const KeyEntry keyEntry_F6 = {BRL_CMD_KFN(6)}; static const KeyEntry keyEntry_F7 = {BRL_CMD_KFN(7)}; static const KeyEntry keyEntry_F8 = {BRL_CMD_KFN(8)}; static const KeyEntry keyEntry_F9 = {BRL_CMD_KFN(9)}; static const KeyEntry keyEntry_F10 = {BRL_CMD_KFN(10)}; static const KeyEntry keyEntry_F11 = {BRL_CMD_KFN(11)}; static const KeyEntry keyEntry_F12 = {BRL_CMD_KFN(12)}; static const KeyEntry keyEntry_ScrollLock = {MOD_LOCK_SCROLL}; static const KeyEntry keyEntry_F13 = {BRL_CMD_KFN(13)}; static const KeyEntry keyEntry_F14 = {BRL_CMD_KFN(14)}; static const KeyEntry keyEntry_F15 = {BRL_CMD_KFN(15)}; static const KeyEntry keyEntry_F16 = {BRL_CMD_KFN(16)}; static const KeyEntry keyEntry_F17 = {BRL_CMD_KFN(17)}; static const KeyEntry keyEntry_F18 = {BRL_CMD_KFN(18)}; static const KeyEntry keyEntry_F19 = {BRL_CMD_KFN(19)}; static const KeyEntry keyEntry_F20 = {BRL_CMD_KFN(20)}; static const KeyEntry keyEntry_F21 = {BRL_CMD_KFN(21)}; static const KeyEntry keyEntry_F22 = {BRL_CMD_KFN(22)}; static const KeyEntry keyEntry_F23 = {BRL_CMD_KFN(23)}; static const KeyEntry keyEntry_F24 = {BRL_CMD_KFN(24)}; static const KeyEntry keyEntry_Grave = {BRL_CMD_CHAR(WC_C('`')), BRL_CMD_CHAR(WC_C('~'))}; static const KeyEntry keyEntry_1 = {BRL_CMD_CHAR(WC_C('1')), BRL_CMD_CHAR(WC_C('!'))}; static const KeyEntry keyEntry_2 = {BRL_CMD_CHAR(WC_C('2')), BRL_CMD_CHAR(WC_C('@'))}; static const KeyEntry keyEntry_3 = {BRL_CMD_CHAR(WC_C('3')), BRL_CMD_CHAR(WC_C('#'))}; static const KeyEntry keyEntry_4 = {BRL_CMD_CHAR(WC_C('4')), BRL_CMD_CHAR(WC_C('$'))}; static const KeyEntry keyEntry_5 = {BRL_CMD_CHAR(WC_C('5')), BRL_CMD_CHAR(WC_C('%'))}; static const KeyEntry keyEntry_6 = {BRL_CMD_CHAR(WC_C('6')), BRL_CMD_CHAR(WC_C('^'))}; static const KeyEntry keyEntry_7 = {BRL_CMD_CHAR(WC_C('7')), BRL_CMD_CHAR(WC_C('&'))}; static const KeyEntry keyEntry_8 = {BRL_CMD_CHAR(WC_C('8')), BRL_CMD_CHAR(WC_C('*'))}; static const KeyEntry keyEntry_9 = {BRL_CMD_CHAR(WC_C('9')), BRL_CMD_CHAR(WC_C('('))}; static const KeyEntry keyEntry_0 = {BRL_CMD_CHAR(WC_C('0')), BRL_CMD_CHAR(WC_C(')'))}; static const KeyEntry keyEntry_Minus = {BRL_CMD_CHAR(WC_C('-')), BRL_CMD_CHAR(WC_C('_'))}; static const KeyEntry keyEntry_Equal = {BRL_CMD_CHAR(WC_C('=')), BRL_CMD_CHAR(WC_C('+'))}; static const KeyEntry keyEntry_Backspace = {BRL_CMD_KEY(BACKSPACE)}; static const KeyEntry keyEntry_Tab = {BRL_CMD_KEY(TAB)}; static const KeyEntry keyEntry_Q = {BRL_CMD_CHAR(WC_C('q')), BRL_CMD_CHAR(WC_C('Q'))}; static const KeyEntry keyEntry_W = {BRL_CMD_CHAR(WC_C('w')), BRL_CMD_CHAR(WC_C('W'))}; static const KeyEntry keyEntry_E = {BRL_CMD_CHAR(WC_C('e')), BRL_CMD_CHAR(WC_C('E'))}; static const KeyEntry keyEntry_R = {BRL_CMD_CHAR(WC_C('r')), BRL_CMD_CHAR(WC_C('R'))}; static const KeyEntry keyEntry_T = {BRL_CMD_CHAR(WC_C('t')), BRL_CMD_CHAR(WC_C('T'))}; static const KeyEntry keyEntry_Y = {BRL_CMD_CHAR(WC_C('y')), BRL_CMD_CHAR(WC_C('Y'))}; static const KeyEntry keyEntry_U = {BRL_CMD_CHAR(WC_C('u')), BRL_CMD_CHAR(WC_C('U'))}; static const KeyEntry keyEntry_I = {BRL_CMD_CHAR(WC_C('i')), BRL_CMD_CHAR(WC_C('I'))}; static const KeyEntry keyEntry_O = {BRL_CMD_CHAR(WC_C('o')), BRL_CMD_CHAR(WC_C('O'))}; static const KeyEntry keyEntry_P = {BRL_CMD_CHAR(WC_C('p')), BRL_CMD_CHAR(WC_C('P'))}; static const KeyEntry keyEntry_LeftBracket = {BRL_CMD_CHAR(WC_C('[')), BRL_CMD_CHAR(WC_C('{'))}; static const KeyEntry keyEntry_RightBracket = {BRL_CMD_CHAR(WC_C(']')), BRL_CMD_CHAR(WC_C('}'))}; static const KeyEntry keyEntry_Backslash = {BRL_CMD_CHAR('\\'), BRL_CMD_CHAR(WC_C('|'))}; static const KeyEntry keyEntry_CapsLock = {MOD_LOCK_CAPS}; static const KeyEntry keyEntry_A = {BRL_CMD_CHAR(WC_C('a')), BRL_CMD_CHAR(WC_C('A'))}; static const KeyEntry keyEntry_S = {BRL_CMD_CHAR(WC_C('s')), BRL_CMD_CHAR(WC_C('S'))}; static const KeyEntry keyEntry_D = {BRL_CMD_CHAR(WC_C('d')), BRL_CMD_CHAR(WC_C('D'))}; static const KeyEntry keyEntry_F = {BRL_CMD_CHAR(WC_C('f')), BRL_CMD_CHAR(WC_C('F'))}; static const KeyEntry keyEntry_G = {BRL_CMD_CHAR(WC_C('g')), BRL_CMD_CHAR(WC_C('G'))}; static const KeyEntry keyEntry_H = {BRL_CMD_CHAR(WC_C('h')), BRL_CMD_CHAR(WC_C('H'))}; static const KeyEntry keyEntry_J = {BRL_CMD_CHAR(WC_C('j')), BRL_CMD_CHAR(WC_C('J'))}; static const KeyEntry keyEntry_K = {BRL_CMD_CHAR(WC_C('k')), BRL_CMD_CHAR(WC_C('K'))}; static const KeyEntry keyEntry_L = {BRL_CMD_CHAR(WC_C('l')), BRL_CMD_CHAR(WC_C('L'))}; static const KeyEntry keyEntry_Semicolon = {BRL_CMD_CHAR(WC_C(';')), BRL_CMD_CHAR(WC_C(':'))}; static const KeyEntry keyEntry_Apostrophe = {BRL_CMD_CHAR(WC_C('\'')), BRL_CMD_CHAR(WC_C('"'))}; static const KeyEntry keyEntry_Enter = {BRL_CMD_KEY(ENTER)}; static const KeyEntry keyEntry_LeftShift = {MOD_SHIFT_LEFT}; static const KeyEntry keyEntry_Europe2 = {BRL_CMD_CHAR(WC_C('<')), BRL_CMD_CHAR(WC_C('>'))}; static const KeyEntry keyEntry_Z = {BRL_CMD_CHAR(WC_C('z')), BRL_CMD_CHAR(WC_C('Z'))}; static const KeyEntry keyEntry_X = {BRL_CMD_CHAR(WC_C('x')), BRL_CMD_CHAR(WC_C('X'))}; static const KeyEntry keyEntry_C = {BRL_CMD_CHAR(WC_C('c')), BRL_CMD_CHAR(WC_C('C'))}; static const KeyEntry keyEntry_V = {BRL_CMD_CHAR(WC_C('v')), BRL_CMD_CHAR(WC_C('V'))}; static const KeyEntry keyEntry_B = {BRL_CMD_CHAR(WC_C('b')), BRL_CMD_CHAR(WC_C('B'))}; static const KeyEntry keyEntry_N = {BRL_CMD_CHAR(WC_C('n')), BRL_CMD_CHAR(WC_C('N'))}; static const KeyEntry keyEntry_M = {BRL_CMD_CHAR(WC_C('m')), BRL_CMD_CHAR(WC_C('M'))}; static const KeyEntry keyEntry_Comma = {BRL_CMD_CHAR(WC_C(',')), BRL_CMD_CHAR(WC_C('<'))}; static const KeyEntry keyEntry_Period = {BRL_CMD_CHAR(WC_C('.')), BRL_CMD_CHAR(WC_C('>'))}; static const KeyEntry keyEntry_Slash = {BRL_CMD_CHAR(WC_C('/')), BRL_CMD_CHAR(WC_C('?'))}; static const KeyEntry keyEntry_RightShift = {MOD_SHIFT_RIGHT}; static const KeyEntry keyEntry_LeftControl = {MOD_CONTROL_LEFT}; static const KeyEntry keyEntry_LeftGUI = {MOD_GUI_LEFT}; static const KeyEntry keyEntry_LeftAlt = {MOD_ALT_LEFT}; static const KeyEntry keyEntry_Space = {BRL_CMD_CHAR(WC_C(' '))}; static const KeyEntry keyEntry_RightAlt = {MOD_ALT_RIGHT}; static const KeyEntry keyEntry_RightGUI = {MOD_GUI_RIGHT}; static const KeyEntry keyEntry_Context = {MOD_CONTEXT}; static const KeyEntry keyEntry_RightControl = {MOD_CONTROL_RIGHT}; static const KeyEntry keyEntry_Insert = {BRL_CMD_KEY(INSERT)}; static const KeyEntry keyEntry_Delete = {BRL_CMD_KEY(DELETE)}; static const KeyEntry keyEntry_Home = {BRL_CMD_KEY(HOME)}; static const KeyEntry keyEntry_End = {BRL_CMD_KEY(END)}; static const KeyEntry keyEntry_PageUp = {BRL_CMD_KEY(PAGE_UP)}; static const KeyEntry keyEntry_PageDown = {BRL_CMD_KEY(PAGE_DOWN)}; static const KeyEntry keyEntry_ArrowUp = {BRL_CMD_KEY(CURSOR_UP)}; static const KeyEntry keyEntry_ArrowLeft = {BRL_CMD_KEY(CURSOR_LEFT)}; static const KeyEntry keyEntry_ArrowDown = {BRL_CMD_KEY(CURSOR_DOWN)}; static const KeyEntry keyEntry_ArrowRight = {BRL_CMD_KEY(CURSOR_RIGHT)}; static const KeyEntry keyEntry_NumLock = {MOD_LOCK_NUMBER}; static const KeyEntry keyEntry_KPSlash = {BRL_CMD_CHAR(WC_C('/'))}; static const KeyEntry keyEntry_KPAsterisk = {BRL_CMD_CHAR(WC_C('*'))}; static const KeyEntry keyEntry_KPMinus = {BRL_CMD_CHAR(WC_C('-'))}; static const KeyEntry keyEntry_KPPlus = {BRL_CMD_CHAR(WC_C('+'))}; static const KeyEntry keyEntry_KPEnter = {BRL_CMD_KEY(ENTER)}; static const KeyEntry keyEntry_KPPeriod = {BRL_CMD_KEY(DELETE), BRL_CMD_CHAR(WC_C('.'))}; static const KeyEntry keyEntry_KP0 = {BRL_CMD_KEY(INSERT), BRL_CMD_CHAR(WC_C('0'))}; static const KeyEntry keyEntry_KP1 = {BRL_CMD_KEY(END), BRL_CMD_CHAR(WC_C('1'))}; static const KeyEntry keyEntry_KP2 = {BRL_CMD_KEY(CURSOR_DOWN), BRL_CMD_CHAR(WC_C('2'))}; static const KeyEntry keyEntry_KP3 = {BRL_CMD_KEY(PAGE_DOWN), BRL_CMD_CHAR(WC_C('3'))}; static const KeyEntry keyEntry_KP4 = {BRL_CMD_KEY(CURSOR_LEFT), BRL_CMD_CHAR(WC_C('4'))}; static const KeyEntry keyEntry_KP5 = {BRL_CMD_CHAR(WC_C('5'))}; static const KeyEntry keyEntry_KP6 = {BRL_CMD_KEY(CURSOR_RIGHT), BRL_CMD_CHAR(WC_C('6'))}; static const KeyEntry keyEntry_KP7 = {BRL_CMD_KEY(HOME), BRL_CMD_CHAR(WC_C('7'))}; static const KeyEntry keyEntry_KP8 = {BRL_CMD_KEY(CURSOR_UP), BRL_CMD_CHAR(WC_C('8'))}; static const KeyEntry keyEntry_KP9 = {BRL_CMD_KEY(PAGE_UP), BRL_CMD_CHAR(WC_C('9'))}; static const KeyEntry keyEntry_KPComma = {BRL_CMD_CHAR(WC_C(','))}; typedef struct { ReportListenerInstance *resetListener; struct { const KeyEntry *const *keyMap; size_t keyCount; unsigned int modifiers; } xt; struct { const KeyEntry *const *keyMap; size_t keyCount; unsigned int modifiers; } at; struct { unsigned int modifiers; } ps2; } KeycodeCommandData; #define USE_KEY_MAP(set,escape) \ (kcd->set.keyCount = (kcd->set.keyMap = set##KeyMap##escape)? \ (sizeof(set##KeyMap##escape) / sizeof(*kcd->set.keyMap)): 0) static void handleKey (const KeyEntry *key, int release, unsigned int *modifiers) { if (key) { int cmd = key->command; int blk = cmd & BRL_MSK_BLK; if (key->alternate) { int alternate = 0; if (blk == BRL_CMD_BLK(PASSCHAR)) { if (MOD_TST(MOD_SHIFT_LEFT, *modifiers) || MOD_TST(MOD_SHIFT_RIGHT, *modifiers)) alternate = 1; } else { if (MOD_TST(MOD_LOCK_NUMBER, *modifiers)) alternate = 1; } if (alternate) { cmd = key->alternate; blk = cmd & BRL_MSK_BLK; } } if (cmd) { if (blk) { if (!release) { if (blk == BRL_CMD_BLK(PASSCHAR)) { if (MOD_TST(MOD_LOCK_CAPS, *modifiers)) cmd |= BRL_FLG_INPUT_UPPER; if (MOD_TST(MOD_ALT_LEFT, *modifiers)) cmd |= BRL_FLG_INPUT_META; if (MOD_TST(MOD_ALT_RIGHT, *modifiers)) cmd |= BRL_FLG_INPUT_ALTGR; if (MOD_TST(MOD_GUI_LEFT, *modifiers) || MOD_TST(MOD_GUI_RIGHT, *modifiers)) cmd |= BRL_FLG_INPUT_GUI; if (MOD_TST(MOD_CONTROL_LEFT, *modifiers) || MOD_TST(MOD_CONTROL_RIGHT, *modifiers)) cmd |= BRL_FLG_INPUT_CONTROL; } else if ((blk == BRL_CMD_BLK(PASSKEY)) && MOD_TST(MOD_ALT_LEFT, *modifiers)) { int arg = cmd & BRL_MSK_ARG; switch (arg) { case BRL_KEY_CURSOR_LEFT: cmd = BRL_CMD_SWITCHVT_PREV; break; case BRL_KEY_CURSOR_RIGHT: cmd = BRL_CMD_SWITCHVT_NEXT; break; default: if (arg >= BRL_KEY_FUNCTION) { cmd = BRL_CMD_BLK(SWITCHVT) + (arg - BRL_KEY_FUNCTION); } break; } } handleCommand(cmd); } } else { switch (cmd) { case MOD_LOCK_SCROLL: case MOD_LOCK_NUMBER: case MOD_LOCK_CAPS: if (!release) { if (MOD_TST(cmd, *modifiers)) { MOD_CLR(cmd, *modifiers); } else { MOD_SET(cmd, *modifiers); } } break; case MOD_SHIFT_LEFT: case MOD_SHIFT_RIGHT: case MOD_CONTROL_LEFT: case MOD_CONTROL_RIGHT: case MOD_ALT_LEFT: case MOD_ALT_RIGHT: if (release) { MOD_CLR(cmd, *modifiers); } else { MOD_SET(cmd, *modifiers); } break; } } } } } static const KeyEntry *const xtKeyMap00[] = { [XT_KEY_00_Escape] = &keyEntry_Escape, [XT_KEY_00_F1] = &keyEntry_F1, [XT_KEY_00_F2] = &keyEntry_F2, [XT_KEY_00_F3] = &keyEntry_F3, [XT_KEY_00_F4] = &keyEntry_F4, [XT_KEY_00_F5] = &keyEntry_F5, [XT_KEY_00_F6] = &keyEntry_F6, [XT_KEY_00_F7] = &keyEntry_F7, [XT_KEY_00_F8] = &keyEntry_F8, [XT_KEY_00_F9] = &keyEntry_F9, [XT_KEY_00_F10] = &keyEntry_F10, [XT_KEY_00_F11] = &keyEntry_F11, [XT_KEY_00_F12] = &keyEntry_F12, [XT_KEY_00_ScrollLock] = &keyEntry_ScrollLock, [XT_KEY_00_F13] = &keyEntry_F13, [XT_KEY_00_F14] = &keyEntry_F14, [XT_KEY_00_F15] = &keyEntry_F15, [XT_KEY_00_F16] = &keyEntry_F16, [XT_KEY_00_F17] = &keyEntry_F17, [XT_KEY_00_F18] = &keyEntry_F18, [XT_KEY_00_F19] = &keyEntry_F19, [XT_KEY_00_F20] = &keyEntry_F20, [XT_KEY_00_F21] = &keyEntry_F21, [XT_KEY_00_F22] = &keyEntry_F22, [XT_KEY_00_F23] = &keyEntry_F23, [XT_KEY_00_F24] = &keyEntry_F24, [XT_KEY_00_Grave] = &keyEntry_Grave, [XT_KEY_00_1] = &keyEntry_1, [XT_KEY_00_2] = &keyEntry_2, [XT_KEY_00_3] = &keyEntry_3, [XT_KEY_00_4] = &keyEntry_4, [XT_KEY_00_5] = &keyEntry_5, [XT_KEY_00_6] = &keyEntry_6, [XT_KEY_00_7] = &keyEntry_7, [XT_KEY_00_8] = &keyEntry_8, [XT_KEY_00_9] = &keyEntry_9, [XT_KEY_00_0] = &keyEntry_0, [XT_KEY_00_Minus] = &keyEntry_Minus, [XT_KEY_00_Equal] = &keyEntry_Equal, [XT_KEY_00_Backspace] = &keyEntry_Backspace, [XT_KEY_00_Tab] = &keyEntry_Tab, [XT_KEY_00_Q] = &keyEntry_Q, [XT_KEY_00_W] = &keyEntry_W, [XT_KEY_00_E] = &keyEntry_E, [XT_KEY_00_R] = &keyEntry_R, [XT_KEY_00_T] = &keyEntry_T, [XT_KEY_00_Y] = &keyEntry_Y, [XT_KEY_00_U] = &keyEntry_U, [XT_KEY_00_I] = &keyEntry_I, [XT_KEY_00_O] = &keyEntry_O, [XT_KEY_00_P] = &keyEntry_P, [XT_KEY_00_LeftBracket] = &keyEntry_LeftBracket, [XT_KEY_00_RightBracket] = &keyEntry_RightBracket, [XT_KEY_00_Backslash] = &keyEntry_Backslash, [XT_KEY_00_CapsLock] = &keyEntry_CapsLock, [XT_KEY_00_A] = &keyEntry_A, [XT_KEY_00_S] = &keyEntry_S, [XT_KEY_00_D] = &keyEntry_D, [XT_KEY_00_F] = &keyEntry_F, [XT_KEY_00_G] = &keyEntry_G, [XT_KEY_00_H] = &keyEntry_H, [XT_KEY_00_J] = &keyEntry_J, [XT_KEY_00_K] = &keyEntry_K, [XT_KEY_00_L] = &keyEntry_L, [XT_KEY_00_Semicolon] = &keyEntry_Semicolon, [XT_KEY_00_Apostrophe] = &keyEntry_Apostrophe, [XT_KEY_00_Enter] = &keyEntry_Enter, [XT_KEY_00_LeftShift] = &keyEntry_LeftShift, [XT_KEY_00_Europe2] = &keyEntry_Europe2, [XT_KEY_00_Z] = &keyEntry_Z, [XT_KEY_00_X] = &keyEntry_X, [XT_KEY_00_C] = &keyEntry_C, [XT_KEY_00_V] = &keyEntry_V, [XT_KEY_00_B] = &keyEntry_B, [XT_KEY_00_N] = &keyEntry_N, [XT_KEY_00_M] = &keyEntry_M, [XT_KEY_00_Comma] = &keyEntry_Comma, [XT_KEY_00_Period] = &keyEntry_Period, [XT_KEY_00_Slash] = &keyEntry_Slash, [XT_KEY_00_RightShift] = &keyEntry_RightShift, [XT_KEY_00_LeftControl] = &keyEntry_LeftControl, [XT_KEY_00_LeftAlt] = &keyEntry_LeftAlt, [XT_KEY_00_Space] = &keyEntry_Space, [XT_KEY_00_NumLock] = &keyEntry_NumLock, [XT_KEY_00_KPAsterisk] = &keyEntry_KPAsterisk, [XT_KEY_00_KPMinus] = &keyEntry_KPMinus, [XT_KEY_00_KPPlus] = &keyEntry_KPPlus, [XT_KEY_00_KPPeriod] = &keyEntry_KPPeriod, [XT_KEY_00_KP0] = &keyEntry_KP0, [XT_KEY_00_KP1] = &keyEntry_KP1, [XT_KEY_00_KP2] = &keyEntry_KP2, [XT_KEY_00_KP3] = &keyEntry_KP3, [XT_KEY_00_KP4] = &keyEntry_KP4, [XT_KEY_00_KP5] = &keyEntry_KP5, [XT_KEY_00_KP6] = &keyEntry_KP6, [XT_KEY_00_KP7] = &keyEntry_KP7, [XT_KEY_00_KP8] = &keyEntry_KP8, [XT_KEY_00_KP9] = &keyEntry_KP9, }; static const KeyEntry *const xtKeyMapE0[] = { [XT_KEY_E0_LeftGUI] = &keyEntry_LeftGUI, [XT_KEY_E0_RightAlt] = &keyEntry_RightAlt, [XT_KEY_E0_RightGUI] = &keyEntry_RightGUI, [XT_KEY_E0_Context] = &keyEntry_Context, [XT_KEY_E0_RightControl] = &keyEntry_RightControl, [XT_KEY_E0_Insert] = &keyEntry_Insert, [XT_KEY_E0_Delete] = &keyEntry_Delete, [XT_KEY_E0_Home] = &keyEntry_Home, [XT_KEY_E0_End] = &keyEntry_End, [XT_KEY_E0_PageUp] = &keyEntry_PageUp, [XT_KEY_E0_PageDown] = &keyEntry_PageDown, [XT_KEY_E0_ArrowUp] = &keyEntry_ArrowUp, [XT_KEY_E0_ArrowLeft] = &keyEntry_ArrowLeft, [XT_KEY_E0_ArrowDown] = &keyEntry_ArrowDown, [XT_KEY_E0_ArrowRight] = &keyEntry_ArrowRight, [XT_KEY_E0_KPSlash] = &keyEntry_KPSlash, [XT_KEY_E0_KPEnter] = &keyEntry_KPEnter, }; #define xtKeyMapE1 NULL static void xtHandleScanCode (KeycodeCommandData *kcd, unsigned char code) { if (code == XT_MOD_E0) { USE_KEY_MAP(xt, E0); } else if (code == XT_MOD_E1) { USE_KEY_MAP(xt, E1); } else { int release = (code & XT_BIT_RELEASE) != 0; code &= ~XT_BIT_RELEASE; if (code < kcd->xt.keyCount) { const KeyEntry *key = kcd->xt.keyMap[code]; USE_KEY_MAP(xt, 00); handleKey(key, release, &kcd->xt.modifiers); } } } static const KeyEntry *const atKeyMap00[] = { [AT_KEY_00_Escape] = &keyEntry_Escape, [AT_KEY_00_F1] = &keyEntry_F1, [AT_KEY_00_F2] = &keyEntry_F2, [AT_KEY_00_F3] = &keyEntry_F3, [AT_KEY_00_F4] = &keyEntry_F4, [AT_KEY_00_F5] = &keyEntry_F5, [AT_KEY_00_F6] = &keyEntry_F6, [AT_KEY_00_F7] = &keyEntry_F7, [AT_KEY_00_F8] = &keyEntry_F8, [AT_KEY_00_F9] = &keyEntry_F9, [AT_KEY_00_F10] = &keyEntry_F10, [AT_KEY_00_F11] = &keyEntry_F11, [AT_KEY_00_F12] = &keyEntry_F12, [AT_KEY_00_ScrollLock] = &keyEntry_ScrollLock, [AT_KEY_00_F13] = &keyEntry_F13, [AT_KEY_00_F14] = &keyEntry_F14, [AT_KEY_00_F15] = &keyEntry_F15, [AT_KEY_00_F16] = &keyEntry_F16, [AT_KEY_00_F17] = &keyEntry_F17, [AT_KEY_00_F18] = &keyEntry_F18, [AT_KEY_00_F19] = &keyEntry_F19, [AT_KEY_00_F20] = &keyEntry_F20, [AT_KEY_00_F21] = &keyEntry_F21, [AT_KEY_00_F22] = &keyEntry_F22, [AT_KEY_00_F23] = &keyEntry_F23, [AT_KEY_00_F24] = &keyEntry_F24, [AT_KEY_00_Grave] = &keyEntry_Grave, [AT_KEY_00_1] = &keyEntry_1, [AT_KEY_00_2] = &keyEntry_2, [AT_KEY_00_3] = &keyEntry_3, [AT_KEY_00_4] = &keyEntry_4, [AT_KEY_00_5] = &keyEntry_5, [AT_KEY_00_6] = &keyEntry_6, [AT_KEY_00_7] = &keyEntry_7, [AT_KEY_00_8] = &keyEntry_8, [AT_KEY_00_9] = &keyEntry_9, [AT_KEY_00_0] = &keyEntry_0, [AT_KEY_00_Minus] = &keyEntry_Minus, [AT_KEY_00_Equal] = &keyEntry_Equal, [AT_KEY_00_Backspace] = &keyEntry_Backspace, [AT_KEY_00_Tab] = &keyEntry_Tab, [AT_KEY_00_Q] = &keyEntry_Q, [AT_KEY_00_W] = &keyEntry_W, [AT_KEY_00_E] = &keyEntry_E, [AT_KEY_00_R] = &keyEntry_R, [AT_KEY_00_T] = &keyEntry_T, [AT_KEY_00_Y] = &keyEntry_Y, [AT_KEY_00_U] = &keyEntry_U, [AT_KEY_00_I] = &keyEntry_I, [AT_KEY_00_O] = &keyEntry_O, [AT_KEY_00_P] = &keyEntry_P, [AT_KEY_00_LeftBracket] = &keyEntry_LeftBracket, [AT_KEY_00_RightBracket] = &keyEntry_RightBracket, [AT_KEY_00_Backslash] = &keyEntry_Backslash, [AT_KEY_00_CapsLock] = &keyEntry_CapsLock, [AT_KEY_00_A] = &keyEntry_A, [AT_KEY_00_S] = &keyEntry_S, [AT_KEY_00_D] = &keyEntry_D, [AT_KEY_00_F] = &keyEntry_F, [AT_KEY_00_G] = &keyEntry_G, [AT_KEY_00_H] = &keyEntry_H, [AT_KEY_00_J] = &keyEntry_J, [AT_KEY_00_K] = &keyEntry_K, [AT_KEY_00_L] = &keyEntry_L, [AT_KEY_00_Semicolon] = &keyEntry_Semicolon, [AT_KEY_00_Apostrophe] = &keyEntry_Apostrophe, [AT_KEY_00_Enter] = &keyEntry_Enter, [AT_KEY_00_LeftShift] = &keyEntry_LeftShift, [AT_KEY_00_Europe2] = &keyEntry_Europe2, [AT_KEY_00_Z] = &keyEntry_Z, [AT_KEY_00_X] = &keyEntry_X, [AT_KEY_00_C] = &keyEntry_C, [AT_KEY_00_V] = &keyEntry_V, [AT_KEY_00_B] = &keyEntry_B, [AT_KEY_00_N] = &keyEntry_N, [AT_KEY_00_M] = &keyEntry_M, [AT_KEY_00_Comma] = &keyEntry_Comma, [AT_KEY_00_Period] = &keyEntry_Period, [AT_KEY_00_Slash] = &keyEntry_Slash, [AT_KEY_00_RightShift] = &keyEntry_RightShift, [AT_KEY_00_LeftControl] = &keyEntry_LeftControl, [AT_KEY_00_LeftAlt] = &keyEntry_LeftAlt, [AT_KEY_00_Space] = &keyEntry_Space, [AT_KEY_00_NumLock] = &keyEntry_NumLock, [AT_KEY_00_KPAsterisk] = &keyEntry_KPAsterisk, [AT_KEY_00_KPMinus] = &keyEntry_KPMinus, [AT_KEY_00_KPPlus] = &keyEntry_KPPlus, [AT_KEY_00_KPPeriod] = &keyEntry_KPPeriod, [AT_KEY_00_KP0] = &keyEntry_KP0, [AT_KEY_00_KP1] = &keyEntry_KP1, [AT_KEY_00_KP2] = &keyEntry_KP2, [AT_KEY_00_KP3] = &keyEntry_KP3, [AT_KEY_00_KP4] = &keyEntry_KP4, [AT_KEY_00_KP5] = &keyEntry_KP5, [AT_KEY_00_KP6] = &keyEntry_KP6, [AT_KEY_00_KP7] = &keyEntry_KP7, [AT_KEY_00_KP8] = &keyEntry_KP8, [AT_KEY_00_KP9] = &keyEntry_KP9, }; static const KeyEntry *const atKeyMapE0[] = { [AT_KEY_E0_LeftGUI] = &keyEntry_LeftGUI, [AT_KEY_E0_RightAlt] = &keyEntry_RightAlt, [AT_KEY_E0_RightGUI] = &keyEntry_RightGUI, [AT_KEY_E0_Context] = &keyEntry_Context, [AT_KEY_E0_RightControl] = &keyEntry_RightControl, [AT_KEY_E0_Insert] = &keyEntry_Insert, [AT_KEY_E0_Delete] = &keyEntry_Delete, [AT_KEY_E0_Home] = &keyEntry_Home, [AT_KEY_E0_End] = &keyEntry_End, [AT_KEY_E0_PageUp] = &keyEntry_PageUp, [AT_KEY_E0_PageDown] = &keyEntry_PageDown, [AT_KEY_E0_ArrowUp] = &keyEntry_ArrowUp, [AT_KEY_E0_ArrowLeft] = &keyEntry_ArrowLeft, [AT_KEY_E0_ArrowDown] = &keyEntry_ArrowDown, [AT_KEY_E0_ArrowRight] = &keyEntry_ArrowRight, [AT_KEY_E0_KPSlash] = &keyEntry_KPSlash, [AT_KEY_E0_KPEnter] = &keyEntry_KPEnter, }; #define atKeyMapE1 NULL static void atHandleScanCode (KeycodeCommandData *kcd, unsigned char code) { if (code == AT_MOD_RELEASE) { MOD_SET(MOD_RELEASE, kcd->at.modifiers); } else if (code == AT_MOD_E0) { USE_KEY_MAP(at, E0); } else if (code == AT_MOD_E1) { USE_KEY_MAP(at, E1); } else if (code < kcd->at.keyCount) { const KeyEntry *key = kcd->at.keyMap[code]; int release = MOD_TST(MOD_RELEASE, kcd->at.modifiers); MOD_CLR(MOD_RELEASE, kcd->at.modifiers); USE_KEY_MAP(at, 00); handleKey(key, release, &kcd->at.modifiers); } } static const KeyEntry *const ps2KeyMap[] = { [PS2_KEY_Escape] = &keyEntry_Escape, [PS2_KEY_F1] = &keyEntry_F1, [PS2_KEY_F2] = &keyEntry_F2, [PS2_KEY_F3] = &keyEntry_F3, [PS2_KEY_F4] = &keyEntry_F4, [PS2_KEY_F5] = &keyEntry_F5, [PS2_KEY_F6] = &keyEntry_F6, [PS2_KEY_F7] = &keyEntry_F7, [PS2_KEY_F8] = &keyEntry_F8, [PS2_KEY_F9] = &keyEntry_F9, [PS2_KEY_F10] = &keyEntry_F10, [PS2_KEY_F11] = &keyEntry_F11, [PS2_KEY_F12] = &keyEntry_F12, [PS2_KEY_ScrollLock] = &keyEntry_ScrollLock, [PS2_KEY_Grave] = &keyEntry_Grave, [PS2_KEY_1] = &keyEntry_1, [PS2_KEY_2] = &keyEntry_2, [PS2_KEY_3] = &keyEntry_3, [PS2_KEY_4] = &keyEntry_4, [PS2_KEY_5] = &keyEntry_5, [PS2_KEY_6] = &keyEntry_6, [PS2_KEY_7] = &keyEntry_7, [PS2_KEY_8] = &keyEntry_8, [PS2_KEY_9] = &keyEntry_9, [PS2_KEY_0] = &keyEntry_0, [PS2_KEY_Minus] = &keyEntry_Minus, [PS2_KEY_Equal] = &keyEntry_Equal, [PS2_KEY_Backspace] = &keyEntry_Backspace, [PS2_KEY_Tab] = &keyEntry_Tab, [PS2_KEY_Q] = &keyEntry_Q, [PS2_KEY_W] = &keyEntry_W, [PS2_KEY_E] = &keyEntry_E, [PS2_KEY_R] = &keyEntry_R, [PS2_KEY_T] = &keyEntry_T, [PS2_KEY_Y] = &keyEntry_Y, [PS2_KEY_U] = &keyEntry_U, [PS2_KEY_I] = &keyEntry_I, [PS2_KEY_O] = &keyEntry_O, [PS2_KEY_P] = &keyEntry_P, [PS2_KEY_LeftBracket] = &keyEntry_LeftBracket, [PS2_KEY_RightBracket] = &keyEntry_RightBracket, [PS2_KEY_Backslash] = &keyEntry_Backslash, [PS2_KEY_CapsLock] = &keyEntry_CapsLock, [PS2_KEY_A] = &keyEntry_A, [PS2_KEY_S] = &keyEntry_S, [PS2_KEY_D] = &keyEntry_D, [PS2_KEY_F] = &keyEntry_F, [PS2_KEY_G] = &keyEntry_G, [PS2_KEY_H] = &keyEntry_H, [PS2_KEY_J] = &keyEntry_J, [PS2_KEY_K] = &keyEntry_K, [PS2_KEY_L] = &keyEntry_L, [PS2_KEY_Semicolon] = &keyEntry_Semicolon, [PS2_KEY_Apostrophe] = &keyEntry_Apostrophe, [PS2_KEY_Enter] = &keyEntry_Enter, [PS2_KEY_LeftShift] = &keyEntry_LeftShift, [PS2_KEY_Europe2] = &keyEntry_Europe2, [PS2_KEY_Z] = &keyEntry_Z, [PS2_KEY_X] = &keyEntry_X, [PS2_KEY_C] = &keyEntry_C, [PS2_KEY_V] = &keyEntry_V, [PS2_KEY_B] = &keyEntry_B, [PS2_KEY_N] = &keyEntry_N, [PS2_KEY_M] = &keyEntry_M, [PS2_KEY_Comma] = &keyEntry_Comma, [PS2_KEY_Period] = &keyEntry_Period, [PS2_KEY_Slash] = &keyEntry_Slash, [PS2_KEY_RightShift] = &keyEntry_RightShift, [PS2_KEY_LeftControl] = &keyEntry_LeftControl, [PS2_KEY_LeftGUI] = &keyEntry_LeftGUI, [PS2_KEY_LeftAlt] = &keyEntry_LeftAlt, [PS2_KEY_Space] = &keyEntry_Space, [PS2_KEY_RightAlt] = &keyEntry_RightAlt, [PS2_KEY_RightGUI] = &keyEntry_RightGUI, [PS2_KEY_Context] = &keyEntry_Context, [PS2_KEY_RightControl] = &keyEntry_RightControl, [PS2_KEY_Insert] = &keyEntry_Insert, [PS2_KEY_Delete] = &keyEntry_Delete, [PS2_KEY_Home] = &keyEntry_Home, [PS2_KEY_End] = &keyEntry_End, [PS2_KEY_PageUp] = &keyEntry_PageUp, [PS2_KEY_PageDown] = &keyEntry_PageDown, [PS2_KEY_ArrowUp] = &keyEntry_ArrowUp, [PS2_KEY_ArrowLeft] = &keyEntry_ArrowLeft, [PS2_KEY_ArrowDown] = &keyEntry_ArrowDown, [PS2_KEY_ArrowRight] = &keyEntry_ArrowRight, [PS2_KEY_NumLock] = &keyEntry_NumLock, [PS2_KEY_KPSlash] = &keyEntry_KPSlash, [PS2_KEY_KPAsterisk] = &keyEntry_KPAsterisk, [PS2_KEY_KPMinus] = &keyEntry_KPMinus, [PS2_KEY_KPPlus] = &keyEntry_KPPlus, [PS2_KEY_KPEnter] = &keyEntry_KPEnter, [PS2_KEY_KPPeriod] = &keyEntry_KPPeriod, [PS2_KEY_KP0] = &keyEntry_KP0, [PS2_KEY_KP1] = &keyEntry_KP1, [PS2_KEY_KP2] = &keyEntry_KP2, [PS2_KEY_KP3] = &keyEntry_KP3, [PS2_KEY_KP4] = &keyEntry_KP4, [PS2_KEY_KP5] = &keyEntry_KP5, [PS2_KEY_KP6] = &keyEntry_KP6, [PS2_KEY_KP7] = &keyEntry_KP7, [PS2_KEY_KP8] = &keyEntry_KP8, [PS2_KEY_KP9] = &keyEntry_KP9, [PS2_KEY_KPComma] = &keyEntry_KPComma, }; static void ps2HandleScanCode (KeycodeCommandData *kcd, unsigned char code) { if (code == PS2_MOD_RELEASE) { MOD_SET(MOD_RELEASE, kcd->ps2.modifiers); } else if (code < ARRAY_COUNT(ps2KeyMap)) { const KeyEntry *key = ps2KeyMap[code]; int release = MOD_TST(MOD_RELEASE, kcd->ps2.modifiers); MOD_CLR(MOD_RELEASE, kcd->ps2.modifiers); handleKey(key, release, &kcd->ps2.modifiers); } } static int handleKeycodeCommands (int command, void *data) { KeycodeCommandData *kcd = data; int arg = command & BRL_MSK_ARG; switch (command & BRL_MSK_BLK) { case BRL_CMD_BLK(PASSXT): if (command & BRL_FLG_KBD_RELEASE) arg |= XT_BIT_RELEASE; if (command & BRL_FLG_KBD_EMUL0) xtHandleScanCode(kcd, XT_MOD_E0); if (command & BRL_FLG_KBD_EMUL1) xtHandleScanCode(kcd, XT_MOD_E1); xtHandleScanCode(kcd, arg); break; case BRL_CMD_BLK(PASSAT): if (command & BRL_FLG_KBD_RELEASE) atHandleScanCode(kcd, AT_MOD_RELEASE); if (command & BRL_FLG_KBD_EMUL0) atHandleScanCode(kcd, AT_MOD_E0); if (command & BRL_FLG_KBD_EMUL1) atHandleScanCode(kcd, AT_MOD_E1); atHandleScanCode(kcd, arg); break; case BRL_CMD_BLK(PASSPS2): if (command & BRL_FLG_KBD_RELEASE) ps2HandleScanCode(kcd, PS2_MOD_RELEASE); ps2HandleScanCode(kcd, arg); break; default: return 0; } return 1; } static void resetKeycodeCommandData (void *data) { KeycodeCommandData *kcd = data; USE_KEY_MAP(xt, 00); kcd->xt.modifiers = 0; USE_KEY_MAP(at, 00); kcd->at.modifiers = 0; kcd->ps2.modifiers = 0; } REPORT_LISTENER(keycodeCommandDataResetListener) { KeycodeCommandData *kcd = parameters->listenerData; resetKeycodeCommandData(kcd); } static void destroyKeycodeCommandData (void *data) { KeycodeCommandData *kcd = data; unregisterReportListener(kcd->resetListener); free(kcd); } int addKeycodeCommands (void) { KeycodeCommandData *kcd; if ((kcd = malloc(sizeof(*kcd)))) { memset(kcd, 0, sizeof(*kcd)); resetKeycodeCommandData(kcd); if ((kcd->resetListener = registerReportListener(REPORT_BRAILLE_DEVICE_ONLINE, keycodeCommandDataResetListener, kcd))) { if (pushCommandHandler("keycodes", KTB_CTX_DEFAULT, handleKeycodeCommands, destroyKeycodeCommandData, kcd)) { return 1; } unregisterReportListener(kcd->resetListener); } free(kcd); } else { logMallocError(); } return 0; }