blob: 6295253918cf95ae46ab4e4f77467a0c8603c8b4 [file] [log] [blame] [edit]
/*
* 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-2023 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 <dave@mielke.cc>.
*/
#include "prologue.h"
#include <string.h>
#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;
}