barrier/lib/synergy/CKeyState.cpp

889 lines
34 KiB
C++

/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* 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.
*/
#include "CKeyState.h"
#include "IEventQueue.h"
#include "CLog.h"
#include <cstring>
#include <algorithm>
#include <iterator>
#include <list>
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<CAddActiveModifierContext*>(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
}