/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file COPYING that should have accompanied this file. * * This package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "CKeyState.h" #include "IEventQueue.h" #include "CLog.h" #include #include #include #include static const KeyButton kButtonMask = (KeyButton)(IKeyState::kNumButtons - 1); static const KeyID s_decomposeTable[] = { // spacing version of dead keys 0x0060, 0x0300, 0x0020, 0, // grave, dead_grave, space 0x00b4, 0x0301, 0x0020, 0, // acute, dead_acute, space 0x005e, 0x0302, 0x0020, 0, // asciicircum, dead_circumflex, space 0x007e, 0x0303, 0x0020, 0, // asciitilde, dead_tilde, space 0x00a8, 0x0308, 0x0020, 0, // diaeresis, dead_diaeresis, space 0x00b0, 0x030a, 0x0020, 0, // degree, dead_abovering, space 0x00b8, 0x0327, 0x0020, 0, // cedilla, dead_cedilla, space 0x02db, 0x0328, 0x0020, 0, // ogonek, dead_ogonek, space 0x02c7, 0x030c, 0x0020, 0, // caron, dead_caron, space 0x02d9, 0x0307, 0x0020, 0, // abovedot, dead_abovedot, space 0x02dd, 0x030b, 0x0020, 0, // doubleacute, dead_doubleacute, space 0x02d8, 0x0306, 0x0020, 0, // breve, dead_breve, space 0x00af, 0x0304, 0x0020, 0, // macron, dead_macron, space // Latin-1 (ISO 8859-1) 0x00c0, 0x0300, 0x0041, 0, // Agrave, dead_grave, A 0x00c1, 0x0301, 0x0041, 0, // Aacute, dead_acute, A 0x00c2, 0x0302, 0x0041, 0, // Acircumflex, dead_circumflex, A 0x00c3, 0x0303, 0x0041, 0, // Atilde, dead_tilde, A 0x00c4, 0x0308, 0x0041, 0, // Adiaeresis, dead_diaeresis, A 0x00c5, 0x030a, 0x0041, 0, // Aring, dead_abovering, A 0x00c7, 0x0327, 0x0043, 0, // Ccedilla, dead_cedilla, C 0x00c8, 0x0300, 0x0045, 0, // Egrave, dead_grave, E 0x00c9, 0x0301, 0x0045, 0, // Eacute, dead_acute, E 0x00ca, 0x0302, 0x0045, 0, // Ecircumflex, dead_circumflex, E 0x00cb, 0x0308, 0x0045, 0, // Ediaeresis, dead_diaeresis, E 0x00cc, 0x0300, 0x0049, 0, // Igrave, dead_grave, I 0x00cd, 0x0301, 0x0049, 0, // Iacute, dead_acute, I 0x00ce, 0x0302, 0x0049, 0, // Icircumflex, dead_circumflex, I 0x00cf, 0x0308, 0x0049, 0, // Idiaeresis, dead_diaeresis, I 0x00d1, 0x0303, 0x004e, 0, // Ntilde, dead_tilde, N 0x00d2, 0x0300, 0x004f, 0, // Ograve, dead_grave, O 0x00d3, 0x0301, 0x004f, 0, // Oacute, dead_acute, O 0x00d4, 0x0302, 0x004f, 0, // Ocircumflex, dead_circumflex, O 0x00d5, 0x0303, 0x004f, 0, // Otilde, dead_tilde, O 0x00d6, 0x0308, 0x004f, 0, // Odiaeresis, dead_diaeresis, O 0x00d9, 0x0300, 0x0055, 0, // Ugrave, dead_grave, U 0x00da, 0x0301, 0x0055, 0, // Uacute, dead_acute, U 0x00db, 0x0302, 0x0055, 0, // Ucircumflex, dead_circumflex, U 0x00dc, 0x0308, 0x0055, 0, // Udiaeresis, dead_diaeresis, U 0x00dd, 0x0301, 0x0059, 0, // Yacute, dead_acute, Y 0x00e0, 0x0300, 0x0061, 0, // agrave, dead_grave, a 0x00e1, 0x0301, 0x0061, 0, // aacute, dead_acute, a 0x00e2, 0x0302, 0x0061, 0, // acircumflex, dead_circumflex, a 0x00e3, 0x0303, 0x0061, 0, // atilde, dead_tilde, a 0x00e4, 0x0308, 0x0061, 0, // adiaeresis, dead_diaeresis, a 0x00e5, 0x030a, 0x0061, 0, // aring, dead_abovering, a 0x00e7, 0x0327, 0x0063, 0, // ccedilla, dead_cedilla, c 0x00e8, 0x0300, 0x0065, 0, // egrave, dead_grave, e 0x00e9, 0x0301, 0x0065, 0, // eacute, dead_acute, e 0x00ea, 0x0302, 0x0065, 0, // ecircumflex, dead_circumflex, e 0x00eb, 0x0308, 0x0065, 0, // ediaeresis, dead_diaeresis, e 0x00ec, 0x0300, 0x0069, 0, // igrave, dead_grave, i 0x00ed, 0x0301, 0x0069, 0, // iacute, dead_acute, i 0x00ee, 0x0302, 0x0069, 0, // icircumflex, dead_circumflex, i 0x00ef, 0x0308, 0x0069, 0, // idiaeresis, dead_diaeresis, i 0x00f1, 0x0303, 0x006e, 0, // ntilde, dead_tilde, n 0x00f2, 0x0300, 0x006f, 0, // ograve, dead_grave, o 0x00f3, 0x0301, 0x006f, 0, // oacute, dead_acute, o 0x00f4, 0x0302, 0x006f, 0, // ocircumflex, dead_circumflex, o 0x00f5, 0x0303, 0x006f, 0, // otilde, dead_tilde, o 0x00f6, 0x0308, 0x006f, 0, // odiaeresis, dead_diaeresis, o 0x00f9, 0x0300, 0x0075, 0, // ugrave, dead_grave, u 0x00fa, 0x0301, 0x0075, 0, // uacute, dead_acute, u 0x00fb, 0x0302, 0x0075, 0, // ucircumflex, dead_circumflex, u 0x00fc, 0x0308, 0x0075, 0, // udiaeresis, dead_diaeresis, u 0x00fd, 0x0301, 0x0079, 0, // yacute, dead_acute, y 0x00ff, 0x0308, 0x0079, 0, // ydiaeresis, dead_diaeresis, y // Latin-2 (ISO 8859-2) 0x0104, 0x0328, 0x0041, 0, // Aogonek, dead_ogonek, A 0x013d, 0x030c, 0x004c, 0, // Lcaron, dead_caron, L 0x015a, 0x0301, 0x0053, 0, // Sacute, dead_acute, S 0x0160, 0x030c, 0x0053, 0, // Scaron, dead_caron, S 0x015e, 0x0327, 0x0053, 0, // Scedilla, dead_cedilla, S 0x0164, 0x030c, 0x0054, 0, // Tcaron, dead_caron, T 0x0179, 0x0301, 0x005a, 0, // Zacute, dead_acute, Z 0x017d, 0x030c, 0x005a, 0, // Zcaron, dead_caron, Z 0x017b, 0x0307, 0x005a, 0, // Zabovedot, dead_abovedot, Z 0x0105, 0x0328, 0x0061, 0, // aogonek, dead_ogonek, a 0x013e, 0x030c, 0x006c, 0, // lcaron, dead_caron, l 0x015b, 0x0301, 0x0073, 0, // sacute, dead_acute, s 0x0161, 0x030c, 0x0073, 0, // scaron, dead_caron, s 0x015f, 0x0327, 0x0073, 0, // scedilla, dead_cedilla, s 0x0165, 0x030c, 0x0074, 0, // tcaron, dead_caron, t 0x017a, 0x0301, 0x007a, 0, // zacute, dead_acute, z 0x017e, 0x030c, 0x007a, 0, // zcaron, dead_caron, z 0x017c, 0x0307, 0x007a, 0, // zabovedot, dead_abovedot, z 0x0154, 0x0301, 0x0052, 0, // Racute, dead_acute, R 0x0102, 0x0306, 0x0041, 0, // Abreve, dead_breve, A 0x0139, 0x0301, 0x004c, 0, // Lacute, dead_acute, L 0x0106, 0x0301, 0x0043, 0, // Cacute, dead_acute, C 0x010c, 0x030c, 0x0043, 0, // Ccaron, dead_caron, C 0x0118, 0x0328, 0x0045, 0, // Eogonek, dead_ogonek, E 0x011a, 0x030c, 0x0045, 0, // Ecaron, dead_caron, E 0x010e, 0x030c, 0x0044, 0, // Dcaron, dead_caron, D 0x0143, 0x0301, 0x004e, 0, // Nacute, dead_acute, N 0x0147, 0x030c, 0x004e, 0, // Ncaron, dead_caron, N 0x0150, 0x030b, 0x004f, 0, // Odoubleacute, dead_doubleacute, O 0x0158, 0x030c, 0x0052, 0, // Rcaron, dead_caron, R 0x016e, 0x030a, 0x0055, 0, // Uring, dead_abovering, U 0x0170, 0x030b, 0x0055, 0, // Udoubleacute, dead_doubleacute, U 0x0162, 0x0327, 0x0054, 0, // Tcedilla, dead_cedilla, T 0x0155, 0x0301, 0x0072, 0, // racute, dead_acute, r 0x0103, 0x0306, 0x0061, 0, // abreve, dead_breve, a 0x013a, 0x0301, 0x006c, 0, // lacute, dead_acute, l 0x0107, 0x0301, 0x0063, 0, // cacute, dead_acute, c 0x010d, 0x030c, 0x0063, 0, // ccaron, dead_caron, c 0x0119, 0x0328, 0x0065, 0, // eogonek, dead_ogonek, e 0x011b, 0x030c, 0x0065, 0, // ecaron, dead_caron, e 0x010f, 0x030c, 0x0064, 0, // dcaron, dead_caron, d 0x0144, 0x0301, 0x006e, 0, // nacute, dead_acute, n 0x0148, 0x030c, 0x006e, 0, // ncaron, dead_caron, n 0x0151, 0x030b, 0x006f, 0, // odoubleacute, dead_doubleacute, o 0x0159, 0x030c, 0x0072, 0, // rcaron, dead_caron, r 0x016f, 0x030a, 0x0075, 0, // uring, dead_abovering, u 0x0171, 0x030b, 0x0075, 0, // udoubleacute, dead_doubleacute, u 0x0163, 0x0327, 0x0074, 0, // tcedilla, dead_cedilla, t // Latin-3 (ISO 8859-3) 0x0124, 0x0302, 0x0048, 0, // Hcircumflex, dead_circumflex, H 0x0130, 0x0307, 0x0049, 0, // Iabovedot, dead_abovedot, I 0x011e, 0x0306, 0x0047, 0, // Gbreve, dead_breve, G 0x0134, 0x0302, 0x004a, 0, // Jcircumflex, dead_circumflex, J 0x0125, 0x0302, 0x0068, 0, // hcircumflex, dead_circumflex, h 0x011f, 0x0306, 0x0067, 0, // gbreve, dead_breve, g 0x0135, 0x0302, 0x006a, 0, // jcircumflex, dead_circumflex, j 0x010a, 0x0307, 0x0043, 0, // Cabovedot, dead_abovedot, C 0x0108, 0x0302, 0x0043, 0, // Ccircumflex, dead_circumflex, C 0x0120, 0x0307, 0x0047, 0, // Gabovedot, dead_abovedot, G 0x011c, 0x0302, 0x0047, 0, // Gcircumflex, dead_circumflex, G 0x016c, 0x0306, 0x0055, 0, // Ubreve, dead_breve, U 0x015c, 0x0302, 0x0053, 0, // Scircumflex, dead_circumflex, S 0x010b, 0x0307, 0x0063, 0, // cabovedot, dead_abovedot, c 0x0109, 0x0302, 0x0063, 0, // ccircumflex, dead_circumflex, c 0x0121, 0x0307, 0x0067, 0, // gabovedot, dead_abovedot, g 0x011d, 0x0302, 0x0067, 0, // gcircumflex, dead_circumflex, g 0x016d, 0x0306, 0x0075, 0, // ubreve, dead_breve, u 0x015d, 0x0302, 0x0073, 0, // scircumflex, dead_circumflex, s // Latin-4 (ISO 8859-4) 0x0156, 0x0327, 0x0052, 0, // Rcedilla, dead_cedilla, R 0x0128, 0x0303, 0x0049, 0, // Itilde, dead_tilde, I 0x013b, 0x0327, 0x004c, 0, // Lcedilla, dead_cedilla, L 0x0112, 0x0304, 0x0045, 0, // Emacron, dead_macron, E 0x0122, 0x0327, 0x0047, 0, // Gcedilla, dead_cedilla, G 0x0157, 0x0327, 0x0072, 0, // rcedilla, dead_cedilla, r 0x0129, 0x0303, 0x0069, 0, // itilde, dead_tilde, i 0x013c, 0x0327, 0x006c, 0, // lcedilla, dead_cedilla, l 0x0113, 0x0304, 0x0065, 0, // emacron, dead_macron, e 0x0123, 0x0327, 0x0067, 0, // gcedilla, dead_cedilla, g 0x0100, 0x0304, 0x0041, 0, // Amacron, dead_macron, A 0x012e, 0x0328, 0x0049, 0, // Iogonek, dead_ogonek, I 0x0116, 0x0307, 0x0045, 0, // Eabovedot, dead_abovedot, E 0x012a, 0x0304, 0x0049, 0, // Imacron, dead_macron, I 0x0145, 0x0327, 0x004e, 0, // Ncedilla, dead_cedilla, N 0x014c, 0x0304, 0x004f, 0, // Omacron, dead_macron, O 0x0136, 0x0327, 0x004b, 0, // Kcedilla, dead_cedilla, K 0x0172, 0x0328, 0x0055, 0, // Uogonek, dead_ogonek, U 0x0168, 0x0303, 0x0055, 0, // Utilde, dead_tilde, U 0x016a, 0x0304, 0x0055, 0, // Umacron, dead_macron, U 0x0101, 0x0304, 0x0061, 0, // amacron, dead_macron, a 0x012f, 0x0328, 0x0069, 0, // iogonek, dead_ogonek, i 0x0117, 0x0307, 0x0065, 0, // eabovedot, dead_abovedot, e 0x012b, 0x0304, 0x0069, 0, // imacron, dead_macron, i 0x0146, 0x0327, 0x006e, 0, // ncedilla, dead_cedilla, n 0x014d, 0x0304, 0x006f, 0, // omacron, dead_macron, o 0x0137, 0x0327, 0x006b, 0, // kcedilla, dead_cedilla, k 0x0173, 0x0328, 0x0075, 0, // uogonek, dead_ogonek, u 0x0169, 0x0303, 0x0075, 0, // utilde, dead_tilde, u 0x016b, 0x0304, 0x0075, 0, // umacron, dead_macron, u // Latin-8 (ISO 8859-14) 0x1e02, 0x0307, 0x0042, 0, // Babovedot, dead_abovedot, B 0x1e03, 0x0307, 0x0062, 0, // babovedot, dead_abovedot, b 0x1e0a, 0x0307, 0x0044, 0, // Dabovedot, dead_abovedot, D 0x1e80, 0x0300, 0x0057, 0, // Wgrave, dead_grave, W 0x1e82, 0x0301, 0x0057, 0, // Wacute, dead_acute, W 0x1e0b, 0x0307, 0x0064, 0, // dabovedot, dead_abovedot, d 0x1ef2, 0x0300, 0x0059, 0, // Ygrave, dead_grave, Y 0x1e1e, 0x0307, 0x0046, 0, // Fabovedot, dead_abovedot, F 0x1e1f, 0x0307, 0x0066, 0, // fabovedot, dead_abovedot, f 0x1e40, 0x0307, 0x004d, 0, // Mabovedot, dead_abovedot, M 0x1e41, 0x0307, 0x006d, 0, // mabovedot, dead_abovedot, m 0x1e56, 0x0307, 0x0050, 0, // Pabovedot, dead_abovedot, P 0x1e81, 0x0300, 0x0077, 0, // wgrave, dead_grave, w 0x1e57, 0x0307, 0x0070, 0, // pabovedot, dead_abovedot, p 0x1e83, 0x0301, 0x0077, 0, // wacute, dead_acute, w 0x1e60, 0x0307, 0x0053, 0, // Sabovedot, dead_abovedot, S 0x1ef3, 0x0300, 0x0079, 0, // ygrave, dead_grave, y 0x1e84, 0x0308, 0x0057, 0, // Wdiaeresis, dead_diaeresis, W 0x1e85, 0x0308, 0x0077, 0, // wdiaeresis, dead_diaeresis, w 0x1e61, 0x0307, 0x0073, 0, // sabovedot, dead_abovedot, s 0x0174, 0x0302, 0x0057, 0, // Wcircumflex, dead_circumflex, W 0x1e6a, 0x0307, 0x0054, 0, // Tabovedot, dead_abovedot, T 0x0176, 0x0302, 0x0059, 0, // Ycircumflex, dead_circumflex, Y 0x0175, 0x0302, 0x0077, 0, // wcircumflex, dead_circumflex, w 0x1e6b, 0x0307, 0x0074, 0, // tabovedot, dead_abovedot, t 0x0177, 0x0302, 0x0079, 0, // ycircumflex, dead_circumflex, y // Latin-9 (ISO 8859-15) 0x0178, 0x0308, 0x0059, 0, // Ydiaeresis, dead_diaeresis, Y // Compose key sequences 0x00c6, kKeyCompose, 0x0041, 0x0045, 0, // AE, A, E 0x00c1, kKeyCompose, 0x0041, 0x0027, 0, // Aacute, A, apostrophe 0x00c2, kKeyCompose, 0x0041, 0x0053, 0, // Acircumflex, A, asciicircum 0x00c3, kKeyCompose, 0x0041, 0x0022, 0, // Adiaeresis, A, quotedbl 0x00c0, kKeyCompose, 0x0041, 0x0060, 0, // Agrave, A, grave 0x00c5, kKeyCompose, 0x0041, 0x002a, 0, // Aring, A, asterisk 0x00c3, kKeyCompose, 0x0041, 0x007e, 0, // Atilde, A, asciitilde 0x00c7, kKeyCompose, 0x0043, 0x002c, 0, // Ccedilla, C, comma 0x00d0, kKeyCompose, 0x0044, 0x002d, 0, // ETH, D, minus 0x00c9, kKeyCompose, 0x0045, 0x0027, 0, // Eacute, E, apostrophe 0x00ca, kKeyCompose, 0x0045, 0x0053, 0, // Ecircumflex, E, asciicircum 0x00cb, kKeyCompose, 0x0045, 0x0022, 0, // Ediaeresis, E, quotedbl 0x00c8, kKeyCompose, 0x0045, 0x0060, 0, // Egrave, E, grave 0x00cd, kKeyCompose, 0x0049, 0x0027, 0, // Iacute, I, apostrophe 0x00ce, kKeyCompose, 0x0049, 0x0053, 0, // Icircumflex, I, asciicircum 0x00cf, kKeyCompose, 0x0049, 0x0022, 0, // Idiaeresis, I, quotedbl 0x00cc, kKeyCompose, 0x0049, 0x0060, 0, // Igrave, I, grave 0x00d1, kKeyCompose, 0x004e, 0x007e, 0, // Ntilde, N, asciitilde 0x00d3, kKeyCompose, 0x004f, 0x0027, 0, // Oacute, O, apostrophe 0x00d4, kKeyCompose, 0x004f, 0x0053, 0, // Ocircumflex, O, asciicircum 0x00d6, kKeyCompose, 0x004f, 0x0022, 0, // Odiaeresis, O, quotedbl 0x00d2, kKeyCompose, 0x004f, 0x0060, 0, // Ograve, O, grave 0x00d8, kKeyCompose, 0x004f, 0x002f, 0, // Ooblique, O, slash 0x00d5, kKeyCompose, 0x004f, 0x007e, 0, // Otilde, O, asciitilde 0x00de, kKeyCompose, 0x0054, 0x0048, 0, // THORN, T, H 0x00da, kKeyCompose, 0x0055, 0x0027, 0, // Uacute, U, apostrophe 0x00db, kKeyCompose, 0x0055, 0x0053, 0, // Ucircumflex, U, asciicircum 0x00dc, kKeyCompose, 0x0055, 0x0022, 0, // Udiaeresis, U, quotedbl 0x00d9, kKeyCompose, 0x0055, 0x0060, 0, // Ugrave, U, grave 0x00dd, kKeyCompose, 0x0059, 0x0027, 0, // Yacute, Y, apostrophe 0x00e1, kKeyCompose, 0x0061, 0x0027, 0, // aacute, a, apostrophe 0x00e2, kKeyCompose, 0x0061, 0x0053, 0, // acircumflex, a, asciicircum 0x00b4, kKeyCompose, 0x0027, 0x0027, 0, // acute, apostrophe, apostrophe 0x00e4, kKeyCompose, 0x0061, 0x0022, 0, // adiaeresis, a, quotedbl 0x00e6, kKeyCompose, 0x0061, 0x0065, 0, // ae, a, e 0x00e0, kKeyCompose, 0x0061, 0x0060, 0, // agrave, a, grave 0x00e5, kKeyCompose, 0x0061, 0x002a, 0, // aring, a, asterisk 0x0040, kKeyCompose, 0x0041, 0x0054, 0, // at, A, T 0x00e3, kKeyCompose, 0x0061, 0x007e, 0, // atilde, a, asciitilde 0x005c, kKeyCompose, 0x002f, 0x002f, 0, // backslash, slash, slash 0x007c, kKeyCompose, 0x004c, 0x0056, 0, // bar, L, V 0x007b, kKeyCompose, 0x0028, 0x002d, 0, // braceleft, parenleft, minus 0x007d, kKeyCompose, 0x0029, 0x002d, 0, // braceright, parenright, minus 0x005b, kKeyCompose, 0x0028, 0x0028, 0, // bracketleft, parenleft, parenleft 0x005d, kKeyCompose, 0x0029, 0x0029, 0, // bracketright, parenright, parenright 0x00a6, kKeyCompose, 0x0042, 0x0056, 0, // brokenbar, B, V 0x00e7, kKeyCompose, 0x0063, 0x002c, 0, // ccedilla, c, comma 0x00b8, kKeyCompose, 0x002c, 0x002c, 0, // cedilla, comma, comma 0x00a2, kKeyCompose, 0x0063, 0x002f, 0, // cent, c, slash 0x00a9, kKeyCompose, 0x0028, 0x0063, 0, // copyright, parenleft, c 0x00a4, kKeyCompose, 0x006f, 0x0078, 0, // currency, o, x 0x00b0, kKeyCompose, 0x0030, 0x0053, 0, // degree, 0, asciicircum 0x00a8, kKeyCompose, 0x0022, 0x0022, 0, // diaeresis, quotedbl, quotedbl 0x00f7, kKeyCompose, 0x003a, 0x002d, 0, // division, colon, minus 0x00e9, kKeyCompose, 0x0065, 0x0027, 0, // eacute, e, apostrophe 0x00ea, kKeyCompose, 0x0065, 0x0053, 0, // ecircumflex, e, asciicircum 0x00eb, kKeyCompose, 0x0065, 0x0022, 0, // ediaeresis, e, quotedbl 0x00e8, kKeyCompose, 0x0065, 0x0060, 0, // egrave, e, grave 0x00f0, kKeyCompose, 0x0064, 0x002d, 0, // eth, d, minus 0x00a1, kKeyCompose, 0x0021, 0x0021, 0, // exclamdown, exclam, exclam 0x00ab, kKeyCompose, 0x003c, 0x003c, 0, // guillemotleft, less, less 0x00bb, kKeyCompose, 0x003e, 0x003e, 0, // guillemotright, greater, greater 0x0023, kKeyCompose, 0x002b, 0x002b, 0, // numbersign, plus, plus 0x00ad, kKeyCompose, 0x002d, 0x002d, 0, // hyphen, minus, minus 0x00ed, kKeyCompose, 0x0069, 0x0027, 0, // iacute, i, apostrophe 0x00ee, kKeyCompose, 0x0069, 0x0053, 0, // icircumflex, i, asciicircum 0x00ef, kKeyCompose, 0x0069, 0x0022, 0, // idiaeresis, i, quotedbl 0x00ec, kKeyCompose, 0x0069, 0x0060, 0, // igrave, i, grave 0x00af, kKeyCompose, 0x002d, 0x0053, 0, // macron, minus, asciicircum 0x00ba, kKeyCompose, 0x006f, 0x005f, 0, // masculine, o, underscore 0x00b5, kKeyCompose, 0x0075, 0x002f, 0, // mu, u, slash 0x00d7, kKeyCompose, 0x0078, 0x0078, 0, // multiply, x, x 0x00a0, kKeyCompose, 0x0020, 0x0020, 0, // nobreakspace, space, space 0x00ac, kKeyCompose, 0x002c, 0x002d, 0, // notsign, comma, minus 0x00f1, kKeyCompose, 0x006e, 0x007e, 0, // ntilde, n, asciitilde 0x00f3, kKeyCompose, 0x006f, 0x0027, 0, // oacute, o, apostrophe 0x00f4, kKeyCompose, 0x006f, 0x0053, 0, // ocircumflex, o, asciicircum 0x00f6, kKeyCompose, 0x006f, 0x0022, 0, // odiaeresis, o, quotedbl 0x00f2, kKeyCompose, 0x006f, 0x0060, 0, // ograve, o, grave 0x00bd, kKeyCompose, 0x0031, 0x0032, 0, // onehalf, 1, 2 0x00bc, kKeyCompose, 0x0031, 0x0034, 0, // onequarter, 1, 4 0x00b9, kKeyCompose, 0x0031, 0x0053, 0, // onesuperior, 1, asciicircum 0x00aa, kKeyCompose, 0x0061, 0x005f, 0, // ordfeminine, a, underscore 0x00f8, kKeyCompose, 0x006f, 0x002f, 0, // oslash, o, slash 0x00f5, kKeyCompose, 0x006f, 0x007e, 0, // otilde, o, asciitilde 0x00b6, kKeyCompose, 0x0070, 0x0021, 0, // paragraph, p, exclam 0x00b7, kKeyCompose, 0x002e, 0x002e, 0, // periodcentered, period, period 0x00b1, kKeyCompose, 0x002b, 0x002d, 0, // plusminus, plus, minus 0x00bf, kKeyCompose, 0x003f, 0x003f, 0, // questiondown, question, question 0x00ae, kKeyCompose, 0x0028, 0x0072, 0, // registered, parenleft, r 0x00a7, kKeyCompose, 0x0073, 0x006f, 0, // section, s, o 0x00df, kKeyCompose, 0x0073, 0x0073, 0, // ssharp, s, s 0x00a3, kKeyCompose, 0x004c, 0x002d, 0, // sterling, L, minus 0x00fe, kKeyCompose, 0x0074, 0x0068, 0, // thorn, t, h 0x00be, kKeyCompose, 0x0033, 0x0034, 0, // threequarters, 3, 4 0x00b3, kKeyCompose, 0x0033, 0x0053, 0, // threesuperior, 3, asciicircum 0x00b2, kKeyCompose, 0x0032, 0x0053, 0, // twosuperior, 2, asciicircum 0x00fa, kKeyCompose, 0x0075, 0x0027, 0, // uacute, u, apostrophe 0x00fb, kKeyCompose, 0x0075, 0x0053, 0, // ucircumflex, u, asciicircum 0x00fc, kKeyCompose, 0x0075, 0x0022, 0, // udiaeresis, u, quotedbl 0x00f9, kKeyCompose, 0x0075, 0x0060, 0, // ugrave, u, grave 0x00fd, kKeyCompose, 0x0079, 0x0027, 0, // yacute, y, apostrophe 0x00ff, kKeyCompose, 0x0079, 0x0022, 0, // ydiaeresis, y, quotedbl 0x00a5, kKeyCompose, 0x0079, 0x003d, 0, // yen, y, equal // end of table 0 }; static const KeyID s_numpadTable[] = { kKeyKP_Space, 0x0020, kKeyKP_Tab, kKeyTab, kKeyKP_Enter, kKeyReturn, kKeyKP_F1, kKeyF1, kKeyKP_F2, kKeyF2, kKeyKP_F3, kKeyF3, kKeyKP_F4, kKeyF4, kKeyKP_Home, kKeyHome, kKeyKP_Left, kKeyLeft, kKeyKP_Up, kKeyUp, kKeyKP_Right, kKeyRight, kKeyKP_Down, kKeyDown, kKeyKP_PageUp, kKeyPageUp, kKeyKP_PageDown, kKeyPageDown, kKeyKP_End, kKeyEnd, kKeyKP_Begin, kKeyBegin, kKeyKP_Insert, kKeyInsert, kKeyKP_Delete, kKeyDelete, kKeyKP_Equal, 0x003d, kKeyKP_Multiply, 0x002a, kKeyKP_Add, 0x002b, kKeyKP_Separator, 0x002c, kKeyKP_Subtract, 0x002d, kKeyKP_Decimal, 0x002e, kKeyKP_Divide, 0x002f, kKeyKP_0, 0x0030, kKeyKP_1, 0x0031, kKeyKP_2, 0x0032, kKeyKP_3, 0x0033, kKeyKP_4, 0x0034, kKeyKP_5, 0x0035, kKeyKP_6, 0x0036, kKeyKP_7, 0x0037, kKeyKP_8, 0x0038, kKeyKP_9, 0x0039 }; // // CKeyState // CKeyState::CKeyState() : m_mask(0) { memset(&m_keys, 0, sizeof(m_keys)); memset(&m_syntheticKeys, 0, sizeof(m_syntheticKeys)); memset(&m_keyClientData, 0, sizeof(m_keyClientData)); memset(&m_serverKeys, 0, sizeof(m_serverKeys)); } CKeyState::~CKeyState() { // do nothing } void CKeyState::onKey(KeyButton button, bool down, KeyModifierMask newState) { // update modifier state m_mask = newState; LOG((CLOG_DEBUG1 "new mask: 0x%04x", m_mask)); // ignore bogus buttons button &= kButtonMask; if (button == 0) { return; } // update key state if (down) { m_keys[button] = 1; m_syntheticKeys[button] = 1; } else { m_keys[button] = 0; m_syntheticKeys[button] = 0; } } void CKeyState::sendKeyEvent( void* target, bool press, bool isAutoRepeat, KeyID key, KeyModifierMask mask, SInt32 count, KeyButton button) { if (m_keyMap.isHalfDuplex(key, button)) { if (isAutoRepeat) { // ignore auto-repeat on half-duplex keys } else { EVENTQUEUE->addEvent(CEvent(getKeyDownEvent(), target, CKeyInfo::alloc(key, mask, button, 1))); EVENTQUEUE->addEvent(CEvent(getKeyUpEvent(), target, CKeyInfo::alloc(key, mask, button, 1))); } } else { if (isAutoRepeat) { EVENTQUEUE->addEvent(CEvent(getKeyRepeatEvent(), target, CKeyInfo::alloc(key, mask, button, count))); } else if (press) { EVENTQUEUE->addEvent(CEvent(getKeyDownEvent(), target, CKeyInfo::alloc(key, mask, button, 1))); } else { EVENTQUEUE->addEvent(CEvent(getKeyUpEvent(), target, CKeyInfo::alloc(key, mask, button, 1))); } } } void CKeyState::updateKeyMap() { // get the current keyboard map CKeyMap keyMap; getKeyMap(keyMap); m_keyMap.swap(keyMap); m_keyMap.finish(); // add special keys addCombinationEntries(); addKeypadEntries(); addAliasEntries(); } void CKeyState::updateKeyState() { // reset our state memset(&m_keys, 0, sizeof(m_keys)); memset(&m_syntheticKeys, 0, sizeof(m_syntheticKeys)); memset(&m_keyClientData, 0, sizeof(m_keyClientData)); memset(&m_serverKeys, 0, sizeof(m_serverKeys)); m_activeModifiers.clear(); // get the current keyboard state KeyButtonSet keysDown; pollPressedKeys(keysDown); for (KeyButtonSet::const_iterator i = keysDown.begin(); i != keysDown.end(); ++i) { m_keys[*i] = 1; } // get the current modifier state m_mask = pollActiveModifiers(); // set active modifiers CAddActiveModifierContext addModifierContext(pollActiveGroup(), m_mask, m_activeModifiers); m_keyMap.foreachKey(&CKeyState::addActiveModifierCB, &addModifierContext); LOG((CLOG_DEBUG1 "modifiers on update: 0x%04x", m_mask)); } void CKeyState::addActiveModifierCB(KeyID, SInt32 group, CKeyMap::KeyItem& keyItem, void* vcontext) { CAddActiveModifierContext* context = reinterpret_cast(vcontext); if (group == context->m_activeGroup && (keyItem.m_generates & context->m_mask) != 0) { context->m_activeModifiers.insert(std::make_pair( keyItem.m_generates, keyItem)); } } void CKeyState::setHalfDuplexMask(KeyModifierMask mask) { m_keyMap.clearHalfDuplexModifiers(); if ((mask & KeyModifierCapsLock) != 0) { m_keyMap.addHalfDuplexModifier(kKeyCapsLock); } if ((mask & KeyModifierNumLock) != 0) { m_keyMap.addHalfDuplexModifier(kKeyNumLock); } if ((mask & KeyModifierScrollLock) != 0) { m_keyMap.addHalfDuplexModifier(kKeyScrollLock); } } void CKeyState::fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton serverID) { // if this server key is already down then this is probably a // mis-reported autorepeat. serverID &= kButtonMask; if (m_serverKeys[serverID] != 0) { fakeKeyRepeat(id, mask, 1, serverID); return; } // ignore certain keys if (isIgnoredKey(id, mask)) { LOG((CLOG_DEBUG1 "ignored key %04x %04x", id, mask)); return; } // get keys for key press Keystrokes keys; ModifierToKeys oldActiveModifiers = m_activeModifiers; const CKeyMap::KeyItem* keyItem = m_keyMap.mapKey(keys, id, pollActiveGroup(), m_activeModifiers, getActiveModifiersRValue(), mask, false); if (keyItem == NULL) { return; } KeyButton localID = (KeyButton)(keyItem->m_button & kButtonMask); updateModifierKeyState(localID, oldActiveModifiers, m_activeModifiers); if (localID != 0) { // note keys down ++m_keys[localID]; ++m_syntheticKeys[localID]; m_keyClientData[localID] = keyItem->m_client; m_serverKeys[serverID] = localID; } // generate key events fakeKeys(keys, 1); } void CKeyState::fakeKeyRepeat( KeyID id, KeyModifierMask mask, SInt32 count, KeyButton serverID) { serverID &= kButtonMask; // if we haven't seen this button go down then ignore it KeyButton oldLocalID = m_serverKeys[serverID]; if (oldLocalID == 0) { return; } // get keys for key repeat Keystrokes keys; ModifierToKeys oldActiveModifiers = m_activeModifiers; const CKeyMap::KeyItem* keyItem = m_keyMap.mapKey(keys, id, pollActiveGroup(), m_activeModifiers, getActiveModifiersRValue(), mask, true); if (keyItem == NULL) { return; } KeyButton localID = (KeyButton)(keyItem->m_button & kButtonMask); if (localID == 0) { return; } // if the KeyButton for the auto-repeat is not the same as for the // initial press then mark the initial key as released and the new // key as pressed. this can happen when we auto-repeat after a // dead key. for example, a dead accent followed by 'a' will // generate an 'a with accent' followed by a repeating 'a'. the // KeyButtons for the two KeyIDs might be different. if (localID != oldLocalID) { // replace key up with previous KeyButton but leave key down // alone so it uses the new KeyButton. for (Keystrokes::iterator index = keys.begin(); index != keys.end(); ++index) { if (index->m_type == Keystroke::kButton && index->m_data.m_button.m_button == localID) { index->m_data.m_button.m_button = oldLocalID; break; } } // note that old key is now up --m_keys[oldLocalID]; --m_syntheticKeys[oldLocalID]; // note keys down updateModifierKeyState(localID, oldActiveModifiers, m_activeModifiers); ++m_keys[localID]; ++m_syntheticKeys[localID]; m_keyClientData[localID] = keyItem->m_client; m_serverKeys[serverID] = localID; } // generate key events fakeKeys(keys, count); } void CKeyState::fakeKeyUp(KeyButton serverID) { // if we haven't seen this button go down then ignore it KeyButton localID = m_serverKeys[serverID & kButtonMask]; if (localID == 0) { return; } // get the sequence of keys to simulate key release Keystrokes keys; keys.push_back(Keystroke(localID, false, false, m_keyClientData[localID])); // note keys down --m_keys[localID]; --m_syntheticKeys[localID]; m_serverKeys[serverID] = 0; // check if this is a modifier for (ModifierToKeys::iterator i = m_activeModifiers.begin(); i != m_activeModifiers.end(); ++i) { if (i->second.m_button == localID && !i->second.m_lock) { // modifier is no longer down KeyModifierMask mask = i->first; m_activeModifiers.erase(i); if (m_activeModifiers.count(mask) == 0) { // no key for modifier is down so deactivate modifier m_mask &= ~mask; LOG((CLOG_DEBUG1 "new state %04x", m_mask)); } break; } } // generate key events fakeKeys(keys, 1); } void CKeyState::fakeAllKeysUp() { Keystrokes keys; for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) { if (m_syntheticKeys[i] > 0) { keys.push_back(Keystroke(i, false, false, m_keyClientData[i])); m_keys[i] = 0; m_syntheticKeys[i] = 0; } } fakeKeys(keys, 1); memset(&m_serverKeys, 0, sizeof(m_serverKeys)); m_activeModifiers.clear(); m_mask = pollActiveModifiers(); } bool CKeyState::isKeyDown(KeyButton button) const { return (m_keys[button & kButtonMask] > 0); } KeyModifierMask CKeyState::getActiveModifiers() const { return m_mask; } KeyModifierMask& CKeyState::getActiveModifiersRValue() { return m_mask; } SInt32 CKeyState::getEffectiveGroup(SInt32 group, SInt32 offset) const { return m_keyMap.getEffectiveGroup(group, offset); } bool CKeyState::isIgnoredKey(KeyID key, KeyModifierMask) const { switch (key) { case kKeyCapsLock: case kKeyNumLock: case kKeyScrollLock: return true; default: return false; } } KeyButton CKeyState::getButton(KeyID id, SInt32 group) const { const CKeyMap::KeyItemList* items = m_keyMap.findCompatibleKey(id, group, 0, 0); if (items == NULL) { return 0; } else { return items->back().m_button; } } void CKeyState::addAliasEntries() { for (SInt32 g = 0, n = m_keyMap.getNumGroups(); g < n; ++g) { // if we can't shift any kKeyTab key in a particular group but we can // shift kKeyLeftTab then add a shifted kKeyTab entry that matches a // shifted kKeyLeftTab entry. m_keyMap.addKeyAliasEntry(kKeyTab, g, KeyModifierShift, KeyModifierShift, kKeyLeftTab, KeyModifierShift, KeyModifierShift); // if we have no kKeyLeftTab but we do have a kKeyTab that can be // shifted then add kKeyLeftTab that matches a kKeyTab. m_keyMap.addKeyAliasEntry(kKeyLeftTab, g, KeyModifierShift, KeyModifierShift, kKeyTab, 0, KeyModifierShift); // map non-breaking space to space m_keyMap.addKeyAliasEntry(0x20, g, 0, 0, 0xa0, 0, 0); } } void CKeyState::addKeypadEntries() { // map every numpad key to its equivalent non-numpad key if it's not // on the keyboard. for (SInt32 g = 0, n = m_keyMap.getNumGroups(); g < n; ++g) { for (size_t i = 0; i < sizeof(s_numpadTable) / sizeof(s_numpadTable[0]); i += 2) { m_keyMap.addKeyCombinationEntry(s_numpadTable[i], g, s_numpadTable + i + 1, 1); } } } void CKeyState::addCombinationEntries() { for (SInt32 g = 0, n = m_keyMap.getNumGroups(); g < n; ++g) { // add dead and compose key composition sequences for (const KeyID* i = s_decomposeTable; *i != 0; ++i) { // count the decomposed keys for this key UInt32 numKeys = 0; for (const KeyID* j = i; *++j != 0; ) { ++numKeys; } // add an entry for this key m_keyMap.addKeyCombinationEntry(*i, g, i + 1, numKeys); // next key i += numKeys + 1; } } } void CKeyState::fakeKeys(const Keystrokes& keys, UInt32 count) { // do nothing if no keys or no repeats if (count == 0 || keys.empty()) { return; } // generate key events LOG((CLOG_DEBUG1 "keystrokes:")); for (Keystrokes::const_iterator k = keys.begin(); k != keys.end(); ) { if (k->m_type == Keystroke::kButton && k->m_data.m_button.m_repeat) { // repeat from here up to but not including the next key // with m_repeat == false count times. Keystrokes::const_iterator start = k; while (count-- > 0) { // send repeating events for (k = start; k != keys.end() && k->m_type == Keystroke::kButton && k->m_data.m_button.m_repeat; ++k) { fakeKey(*k); } } // note -- k is now on the first non-repeat key after the // repeat keys, exactly where we'd like to continue from. } else { // send event fakeKey(*k); // next key ++k; } } } void CKeyState::updateModifierKeyState(KeyButton button, const ModifierToKeys& oldModifiers, const ModifierToKeys& newModifiers) { // get the pressed modifier buttons before and after CKeyMap::ButtonToKeyMap oldKeys, newKeys; for (ModifierToKeys::const_iterator i = oldModifiers.begin(); i != oldModifiers.end(); ++i) { oldKeys.insert(std::make_pair(i->second.m_button, &i->second)); } for (ModifierToKeys::const_iterator i = newModifiers.begin(); i != newModifiers.end(); ++i) { newKeys.insert(std::make_pair(i->second.m_button, &i->second)); } // get the modifier buttons that were pressed or released CKeyMap::ButtonToKeyMap pressed, released; std::set_difference(oldKeys.begin(), oldKeys.end(), newKeys.begin(), newKeys.end(), std::inserter(released, released.end()), ButtonToKeyLess()); std::set_difference(newKeys.begin(), newKeys.end(), oldKeys.begin(), oldKeys.end(), std::inserter(pressed, pressed.end()), ButtonToKeyLess()); // update state for (CKeyMap::ButtonToKeyMap::const_iterator i = released.begin(); i != released.end(); ++i) { if (i->first != button) { m_keys[i->first] = 0; m_syntheticKeys[i->first] = 0; } } for (CKeyMap::ButtonToKeyMap::const_iterator i = pressed.begin(); i != pressed.end(); ++i) { if (i->first != button) { m_keys[i->first] = 1; m_syntheticKeys[i->first] = 1; m_keyClientData[i->first] = i->second->m_client; } } } // // CKeyState::CAddActiveModifierContext // CKeyState::CAddActiveModifierContext::CAddActiveModifierContext( SInt32 group, KeyModifierMask mask, ModifierToKeys& activeModifiers) : m_activeGroup(group), m_mask(mask), m_activeModifiers(activeModifiers) { // do nothing }