* (WIP)-all issues corrected, tests started * first test passing alternative solution for SonarCloud check fixed for to while translation added changelog item adding tests and fixes more tests; avoid compiling BSD Tests on Windows attempting a BSD compile patch more tests borrowing symbol detection from another test more ambitious testing changed the order of assertions for better info more tests fixed clear errors before executing expanding transformation to use string comparison including terminator on translation count a different flag for testing MS Windows differente Windows flag more tests fixing platform encoding match Windows compiler difference on #ifdef Google Test macro usage fix test added added keymap test test and initialisation fixed ms cl issue with named init test for keymap exercising keystate more configuration exercises one more test for config added Unicode test an IPv6 test more portable networking code using our own platform switching code avoiding strcpy * Fixed typo in Changelog. * +appropriate memory handling * one more test for coverage * a tad more coverage * expanded test on Config Co-authored-by: Max <maxmommersteeg@hotmail.com> Co-authored-by: SerhiiGadzhilov <71632867+SerhiiGadzhilov@users.noreply.github.com>
944 lines
40 KiB
C++
944 lines
40 KiB
C++
/*
|
|
* synergy -- mouse and keyboard sharing utility
|
|
* Copyright (C) 2012-2016 Symless Ltd.
|
|
* 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 LICENSE 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "synergy/KeyState.h"
|
|
#include "base/Log.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
|
|
};
|
|
|
|
//
|
|
// KeyState
|
|
//
|
|
|
|
KeyState::KeyState(IEventQueue* events) :
|
|
IKeyState(events),
|
|
m_keyMapPtr(new synergy::KeyMap()),
|
|
m_keyMap(*m_keyMapPtr),
|
|
m_mask(0),
|
|
m_events(events)
|
|
{
|
|
init();
|
|
}
|
|
|
|
KeyState::KeyState(IEventQueue* events, synergy::KeyMap& keyMap) :
|
|
IKeyState(events),
|
|
m_keyMapPtr(0),
|
|
m_keyMap(keyMap),
|
|
m_mask(0),
|
|
m_events(events)
|
|
{
|
|
init();
|
|
}
|
|
|
|
KeyState::~KeyState()
|
|
{
|
|
if (m_keyMapPtr)
|
|
delete m_keyMapPtr;
|
|
}
|
|
|
|
void
|
|
KeyState::init()
|
|
{
|
|
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));
|
|
}
|
|
|
|
void
|
|
KeyState::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
|
|
KeyState::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 {
|
|
m_events->addEvent(Event(m_events->forIKeyState().keyDown(), target,
|
|
KeyInfo::alloc(key, mask, button, 1)));
|
|
m_events->addEvent(Event(m_events->forIKeyState().keyUp(), target,
|
|
KeyInfo::alloc(key, mask, button, 1)));
|
|
}
|
|
}
|
|
else {
|
|
if (isAutoRepeat) {
|
|
m_events->addEvent(Event(m_events->forIKeyState().keyRepeat(), target,
|
|
KeyInfo::alloc(key, mask, button, count)));
|
|
}
|
|
else if (press) {
|
|
m_events->addEvent(Event(m_events->forIKeyState().keyDown(), target,
|
|
KeyInfo::alloc(key, mask, button, 1)));
|
|
}
|
|
else {
|
|
m_events->addEvent(Event(m_events->forIKeyState().keyUp(), target,
|
|
KeyInfo::alloc(key, mask, button, 1)));
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
KeyState::updateKeyMap(synergy::KeyMap* existing)
|
|
{
|
|
if (existing) {
|
|
m_keyMap.swap(*existing);
|
|
}
|
|
else {
|
|
// get the current keyboard map
|
|
synergy::KeyMap keyMap;
|
|
getKeyMap(keyMap);
|
|
m_keyMap.swap(keyMap);
|
|
m_keyMap.finish();
|
|
}
|
|
|
|
// add special keys
|
|
addCombinationEntries();
|
|
addKeypadEntries();
|
|
addAliasEntries();
|
|
}
|
|
|
|
void
|
|
KeyState::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
|
|
AddActiveModifierContext addModifierContext(pollActiveGroup(), m_mask,
|
|
m_activeModifiers);
|
|
m_keyMap.foreachKey(&KeyState::addActiveModifierCB, &addModifierContext);
|
|
|
|
LOG((CLOG_DEBUG1 "modifiers on update: 0x%04x", m_mask));
|
|
}
|
|
|
|
void
|
|
KeyState::addActiveModifierCB(KeyID, SInt32 group,
|
|
synergy::KeyMap::KeyItem& keyItem, void* vcontext)
|
|
{
|
|
AddActiveModifierContext* context =
|
|
static_cast<AddActiveModifierContext*>(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
|
|
KeyState::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
|
|
KeyState::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 synergy::KeyMap::KeyItem* keyItem =
|
|
m_keyMap.mapKey(keys, id, pollActiveGroup(), m_activeModifiers,
|
|
getActiveModifiersRValue(), mask, false);
|
|
if (keyItem == NULL) {
|
|
// a media key won't be mapped on mac, so we need to fake it in a
|
|
// special way
|
|
if (id == kKeyAudioDown || id == kKeyAudioUp ||
|
|
id == kKeyAudioMute || id == kKeyAudioPlay ||
|
|
id == kKeyAudioPrev || id == kKeyAudioNext ||
|
|
id == kKeyBrightnessDown || id == kKeyBrightnessUp
|
|
) {
|
|
LOG((CLOG_DEBUG1 "emulating media key"));
|
|
fakeMediaKey(id);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
bool
|
|
KeyState::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 false;
|
|
}
|
|
|
|
// get keys for key repeat
|
|
Keystrokes keys;
|
|
ModifierToKeys oldActiveModifiers = m_activeModifiers;
|
|
const synergy::KeyMap::KeyItem* keyItem =
|
|
m_keyMap.mapKey(keys, id, pollActiveGroup(), m_activeModifiers,
|
|
getActiveModifiersRValue(), mask, true);
|
|
if (keyItem == NULL) {
|
|
return false;
|
|
}
|
|
KeyButton localID = (KeyButton)(keyItem->m_button & kButtonMask);
|
|
if (localID == 0) {
|
|
return false;
|
|
}
|
|
|
|
// 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);
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
KeyState::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 false;
|
|
}
|
|
|
|
// 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
|
|
ModifierToKeys::iterator i = m_activeModifiers.begin();
|
|
while (i != m_activeModifiers.end()) {
|
|
if (i->second.m_button == localID && !i->second.m_lock) {
|
|
// modifier is no longer down
|
|
KeyModifierMask mask = i->first;
|
|
|
|
ModifierToKeys::iterator tmp = i;
|
|
++i;
|
|
m_activeModifiers.erase(tmp);
|
|
|
|
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));
|
|
}
|
|
}
|
|
else {
|
|
++i;
|
|
}
|
|
}
|
|
|
|
// generate key events
|
|
fakeKeys(keys, 1);
|
|
return true;
|
|
}
|
|
|
|
void
|
|
KeyState::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
|
|
KeyState::fakeMediaKey(KeyID id)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
KeyState::isKeyDown(KeyButton button) const
|
|
{
|
|
return (m_keys[button & kButtonMask] > 0);
|
|
}
|
|
|
|
KeyModifierMask
|
|
KeyState::getActiveModifiers() const
|
|
{
|
|
return m_mask;
|
|
}
|
|
|
|
KeyModifierMask&
|
|
KeyState::getActiveModifiersRValue()
|
|
{
|
|
return m_mask;
|
|
}
|
|
|
|
SInt32
|
|
KeyState::getEffectiveGroup(SInt32 group, SInt32 offset) const
|
|
{
|
|
return m_keyMap.getEffectiveGroup(group, offset);
|
|
}
|
|
|
|
bool
|
|
KeyState::isIgnoredKey(KeyID key, KeyModifierMask) const
|
|
{
|
|
switch (key) {
|
|
case kKeyCapsLock:
|
|
case kKeyNumLock:
|
|
case kKeyScrollLock:
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
KeyButton
|
|
KeyState::getButton(KeyID id, SInt32 group) const
|
|
{
|
|
const synergy::KeyMap::KeyItemList* items =
|
|
m_keyMap.findCompatibleKey(id, group, 0, 0);
|
|
if (items == NULL) {
|
|
return 0;
|
|
}
|
|
else {
|
|
return items->back().m_button;
|
|
}
|
|
}
|
|
|
|
void
|
|
KeyState::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
|
|
KeyState::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
|
|
KeyState::addCombinationEntries()
|
|
{
|
|
for (SInt32 g = 0, n = m_keyMap.getNumGroups(); g < n; ++g) {
|
|
// add dead and compose key composition sequences
|
|
const KeyID* i = s_decomposeTable;
|
|
while (*i != 0) {
|
|
// count the decomposed keys for this key
|
|
UInt32 numKeys = 0;
|
|
const KeyID* j = i;
|
|
while (*++j != 0) {
|
|
++numKeys;
|
|
}
|
|
|
|
// add an entry for this key
|
|
m_keyMap.addKeyCombinationEntry(*i, g, i + 1, numKeys);
|
|
|
|
// next key
|
|
i += numKeys + 1;
|
|
++i;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
KeyState::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
|
|
KeyState::updateModifierKeyState(KeyButton button,
|
|
const ModifierToKeys& oldModifiers,
|
|
const ModifierToKeys& newModifiers)
|
|
{
|
|
// get the pressed modifier buttons before and after
|
|
synergy::KeyMap::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
|
|
synergy::KeyMap::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 (synergy::KeyMap::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 (synergy::KeyMap::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;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// KeyState::AddActiveModifierContext
|
|
//
|
|
|
|
KeyState::AddActiveModifierContext::AddActiveModifierContext(
|
|
SInt32 group, KeyModifierMask mask,
|
|
ModifierToKeys& activeModifiers) :
|
|
m_activeGroup(group),
|
|
m_mask(mask),
|
|
m_activeModifiers(activeModifiers)
|
|
{
|
|
// do nothing
|
|
}
|