diff options
Diffstat (limited to 'tests/manual/x11vkbwrapper')
-rw-r--r-- | tests/manual/x11vkbwrapper/handlekeyevents.cpp | 171 | ||||
-rw-r--r-- | tests/manual/x11vkbwrapper/handlekeyevents.h | 13 | ||||
-rw-r--r-- | tests/manual/x11vkbwrapper/keysymmapsforfakeinput.h | 40 |
3 files changed, 182 insertions, 42 deletions
diff --git a/tests/manual/x11vkbwrapper/handlekeyevents.cpp b/tests/manual/x11vkbwrapper/handlekeyevents.cpp index 0c3c85a4..c6b5c9f3 100644 --- a/tests/manual/x11vkbwrapper/handlekeyevents.cpp +++ b/tests/manual/x11vkbwrapper/handlekeyevents.cpp @@ -39,11 +39,13 @@ extern "C" { #include <xdo.h> #include <X11/extensions/XTest.h> +#include "atspi/atspi.h" } namespace { const bool KKeyPress = true; const bool KKeyRelease = false; +const int NoKeySymFound = 63; // Undefine define KeyRelease from X.h. // Enables using QEvent::KeyRelease type in eventFilter. @@ -104,6 +106,7 @@ HandleKeyEvents::~HandleKeyEvents() bool HandleKeyEvents::init() { + m_temporaryKeyCodes = QHash<Qt::Key, int>(); m_xdo = xdo_new(nullptr); return m_xdo != nullptr; } @@ -117,7 +120,7 @@ bool HandleKeyEvents::init() */ bool HandleKeyEvents::eventFilter(QObject *watched, QEvent *event) { - Q_UNUSED( watched ); + Q_UNUSED( watched ) const auto type = event->type(); if (type == QEvent::MouseButtonRelease && !QGuiApplication::inputMethod()->isVisible()) { @@ -153,12 +156,12 @@ bool HandleKeyEvents::eventFilter(QObject *watched, QEvent *event) 2000); /** a Key strings as Emojis ":-), <3". */ } else if (str.length() > 1) { - xdo_enter_text_window(m_xdo, CURRENTWINDOW, - str.toLatin1(), - 2000); + for (auto sKey : str) { + sendKeyWithAtspi(nullptr, sKey); + } /** a Normal Keys. */ - } else if (!str.isEmpty()) { - keyTap(str); + } else if (key != Qt::Key_Shift) { + sendKeyWithAtspi(keyEvent, QString("")); } } return false; @@ -166,24 +169,67 @@ bool HandleKeyEvents::eventFilter(QObject *watched, QEvent *event) /** * @brief HandleKeyEvents::keyTap + * @param keyEvent a QKeyEvent pointer * @param key a Key as a string */ -void HandleKeyEvents::keyTap(const QString &key) const +void HandleKeyEvents::keyTap(const QKeyEvent *keyEvent, const QString &key) +{ + qCDebug(lcHandleKeyEvents) << Q_FUNC_INFO; + + /** Scratch space for temporary keycode bindings */ + int scratchKeyCode = 0; + KeyCode keyCode = 0x0; + + if (keyEvent) { + auto qtKey = static_cast<Qt::Key>(keyEvent->key()); + if (m_temporaryKeyCodes.contains(qtKey)) { + scratchKeyCode = m_temporaryKeyCodes.value(qtKey); + } else { + scratchKeyCode = getTemporaryKeyCode(); + m_temporaryKeyCodes.insert(qtKey, scratchKeyCode); + } + + /** find the keysym for the given unicode char */ + const QString str = qtKeyCodes2.indexOf(qtKey) >= 0 ? "U"+ QString::number(keyEvent->key(), 16 ) : + "U"+ keyEvent->text().toLatin1().toHex(); + const KeySym sym = XStringToKeysym(str.toUtf8().data()); + if (sym && sym != NoKeySymFound) { + remapScratchKeyCode(sym, scratchKeyCode); + keyCode = static_cast<KeyCode>(scratchKeyCode); + } else { + keyCode = getUnicodeKeyCode(keyEvent->text(), scratchKeyCode); + } + keyClick(keyCode, keyEvent->text()); + } else { + keyCode = getUnicodeKeyCode(key, getTemporaryKeyCode()); + keyClick(keyCode, key); + } + + /** Revert Keymapping */ + remapScratchKeyCode(NoSymbol, scratchKeyCode); +} + +/** + * @brief HandleKeyEvents::keyClick + * @param key + * @param keyText Key as a string + */ +void HandleKeyEvents::keyClick(const KeyCode key, const QString &keyText) const { qCDebug(lcHandleKeyEvents) << Q_FUNC_INFO; - bool shiftDown = false; - KeyCode keyCode = getUnicodeKeycode(key); KeyCode shift = XKeysymToKeycode(m_xdo->xdpy, XK_Shift_L); + bool shiftDown = false; + /** Press a Shift button down if capital letter. */ - if (key.length() == 1 && (key.toLower() != key || xUpKeyCodes.count(key))) { + if (keyText.length() == 1 && (keyText.toLower() != keyText || xUpKeyCodes.count(keyText))) { keyPressRelease(shift, KKeyPress); shiftDown = true; } /** A Key press */ - keyPressRelease(keyCode, KKeyPress); + keyPressRelease(key, KKeyPress); /** A Key release */ - keyPressRelease(keyCode, KKeyRelease); + keyPressRelease(key, KKeyRelease); /** Release a Shift button if capital letter. */ if (shiftDown) { @@ -205,12 +251,12 @@ void HandleKeyEvents::keyPressRelease(const KeyCode key, const bool eventType) c } /** - * @brief HandleKeyEvents::getUnicodeKeycode + * @brief HandleKeyEvents::getUnicodeKeyCode * Get a correct key mapping for a key. * @param key a Key as a string * @return Keycode */ -KeyCode HandleKeyEvents::getUnicodeKeycode(const QString &key) const +KeyCode HandleKeyEvents::getUnicodeKeyCode(const QString &key, int scratchKeyCode) const { qCDebug(lcHandleKeyEvents) << Q_FUNC_INFO; KeyCode code = 0; @@ -221,12 +267,99 @@ KeyCode HandleKeyEvents::getUnicodeKeycode(const QString &key) const auto xUpKeyIter = xKeyCodes.find(key); code = XKeysymToKeycode(m_xdo->xdpy, xUpKeyIter->second); } else { - auto unicodeIter = unicodeKeySymbols.find(key); - quint32 unicodeKey = unicodeIter != unicodeKeySymbols.end() ? unicodeIter->second : 0; - KeySym keysyms[] = {unicodeKey}; - XChangeKeyboardMapping(m_xdo->xdpy, 999, 1, static_cast<KeySym*>(keysyms), 1); - code = static_cast<KeyCode>(999); + const KeySym sym = unicodeKeySymbols.find(key)->second; + remapScratchKeyCode(sym, scratchKeyCode); + code = static_cast<KeyCode>(scratchKeyCode); } return code; } +/** + * @brief HandleKeyEvents::remapScratchKeyCode + * Remap the requested KeySym + * @param sym KeySymbol + * @param scratchKeyCode unused keycode to use for remapping + */ +void HandleKeyEvents::remapScratchKeyCode(const KeySym sym, int scratchKeyCode) const +{ + qCDebug(lcHandleKeyEvents) << Q_FUNC_INFO; + KeySym keysyms[] = {sym, sym}; + /** Remap */ + XChangeKeyboardMapping(m_xdo->xdpy, scratchKeyCode, 2, keysyms, 1); +} + +/** + * @brief HandleKeyEvents::sendKeyWithAtspi + * To send a ordinary keys via atspi(D-Bus). It is faster than a XTestFakeKeyEvent + * @param keyEvent KeyEvent + * @param key Key as string + */ +void HandleKeyEvents::sendKeyWithAtspi(const QKeyEvent *keyEvent, const QString key) +{ + qCDebug(lcHandleKeyEvents) << Q_FUNC_INFO; + const QString str = keyEvent != nullptr ? keyEvent->text() : key; + if (str.isEmpty()) { + return; + } + + const KeySym sym = unicodeKeySymbolsForAtspi.find(str)->second; + if (sym == 0) { + keyTap(keyEvent, QString("")); + } else { + GError *error = nullptr; + if (!atspi_generate_keyboard_event(static_cast<long>(sym), nullptr, ATSPI_KEY_SYM, &error)) { + qCDebug(lcHandleKeyEvents) << "Error message: " << error->message; + } + } +} + +/** + * @brief HandleKeyEvents::getTemporaryKeyCode + * @return + */ +int HandleKeyEvents::getTemporaryKeyCode() +{ + qCDebug(lcHandleKeyEvents) << Q_FUNC_INFO; + KeySym *keySyms = nullptr; + int keySymsPerKeyCode = 0; + + /** Scratch space for temporary keycode bindings */ + int scratchKeyCode = 0; + int keyCodeLow = 0; + int keyCodeHigh = 0; + + /** get the range of keycodes usually from 8 - 255 */ + XDisplayKeycodes(m_xdo->xdpy, &keyCodeLow, &keyCodeHigh); + /** get all the mapped keysyms availabl */ + const KeyCode keyCodeL = static_cast<KeyCode>(keyCodeLow); + keySyms = XGetKeyboardMapping( + m_xdo->xdpy, + keyCodeL, + keyCodeHigh - keyCodeLow, + &keySymsPerKeyCode); + + /** find unused keycode for unmapped keysyms so we can + hook up our own keycode and map every keysym on it + so we just need to 'click' our once unmapped keycode */ + int i; + for (i = keyCodeLow; i <= keyCodeHigh; i++) { + int keyIsEmpty = 1; + for (int j = 0; j < keySymsPerKeyCode; j++) { + const int symindex = (i - keyCodeLow) * keySymsPerKeyCode + j; + if (keySyms[symindex] != 0) { + keyIsEmpty = 0; + } else { + break; + } + } + if (keyIsEmpty) { + scratchKeyCode = i; + break; + } + } + XFree(keySyms); + XFlush(m_xdo->xdpy); + + return scratchKeyCode; +} + diff --git a/tests/manual/x11vkbwrapper/handlekeyevents.h b/tests/manual/x11vkbwrapper/handlekeyevents.h index 760ba757..72fc44f2 100644 --- a/tests/manual/x11vkbwrapper/handlekeyevents.h +++ b/tests/manual/x11vkbwrapper/handlekeyevents.h @@ -31,9 +31,9 @@ #define HANDLEKEYEVENTS_H #include <QObject> +#include <QHash> class QKeyEvent; - extern "C" { #include <xdo.h> } @@ -52,9 +52,14 @@ public: bool init(); private: - void keyTap(const QString &key) const; + void keyTap(const QKeyEvent *keyEvent, const QString &key); + void keyClick(const KeyCode key, const QString &keyText) const; void keyPressRelease(const KeyCode key, const bool eventType) const; - KeyCode getUnicodeKeycode(const QString &key) const; + KeyCode getUnicodeKeyCode(const QString &key, int scratchKeyCode) const; + void remapScratchKeyCode(const KeySym sym, int scratchKeyCode) const; + void sendKeyWithAtspi(const QKeyEvent *keyEvent, const QString key); + int getTemporaryKeyCode(); + protected: /** Deliver events from a another object(s). */ @@ -63,6 +68,8 @@ protected: private: /** Libxdo context. */ xdo_t *m_xdo; + /** Store temporary keycodes. */ + QHash<Qt::Key, int> m_temporaryKeyCodes; }; #endif // HANDLEKEYEVENTS_H diff --git a/tests/manual/x11vkbwrapper/keysymmapsforfakeinput.h b/tests/manual/x11vkbwrapper/keysymmapsforfakeinput.h index 7dc404ba..b36a4221 100644 --- a/tests/manual/x11vkbwrapper/keysymmapsforfakeinput.h +++ b/tests/manual/x11vkbwrapper/keysymmapsforfakeinput.h @@ -39,25 +39,24 @@ extern "C" { #include <ctime> } +static const std::map<QString, quint32> unicodeKeySymbolsForAtspi { + {"!",0x0021}, {"#",0x0023}, {"%",0x0025}, {"&",0x0026}, {"'",0x0027}, + {"(",0x0028}, {")",0x0029}, {"*",0x002A}, {"+",0x002B}, {",",0x002C}, {"-",0x002D}, {".",0x002E}, + {"0",0x0030}, {"1",0x0031}, {"2",0x0032}, {"3",0x0033}, {"4",0x0034}, {"5",0x0035}, {"6",0x0036}, + {"7",0x0037}, {"8",0x0038}, {"9",0x0039}, {":",0x003A}, {";",0x003B}, {"<",0x003C}, {"/",0x002F}, + {"=",0x003D}, {">",0x003E}, {"?",0x003F}, {"A",0x0041}, {"B",0x0042}, {"C",0x0043}, + {"D",0x0044}, {"E",0x0045}, {"F",0x0046}, {"G",0x0047}, {"H",0x0048}, {"I",0x0049}, {"J",0x004A}, + {"K",0x004B}, {"L",0x004C}, {"M",0x004D}, {"N",0x004E}, {"O",0x004F}, {"P",0x0050}, {"Q",0x0051}, + {"R",0x0052}, {"S",0x0053}, {"T",0x0054}, {"U",0x0055}, {"V",0x0056}, {"W",0x0057}, {"X",0x0058}, + {"Y",0x0059}, {"Z",0x005A}, {"_",0x005F}, + {"a",0x0061}, {"b",0x0062}, {"c",0x0063}, {"d",0x0064}, {"e",0x0065}, {"f",0x0066}, + {"g",0x0067}, {"h",0x0068}, {"i",0x0069}, {"j",0x006A}, {"k",0x006B}, {"l",0x006C}, {"m",0x006D}, + {"n",0x006E}, {"o",0x006F}, {"p",0x0070}, {"q",0x0071}, {"r",0x0072}, {"s",0x0073}, {"t",0x0074}, + {"u",0x0075}, {"v",0x0076}, {"w",0x0077}, {"x",0x0078}, {"y",0x0079}, {"z",0x007A}, +}; + static const std::map<QString, quint32> unicodeKeySymbols { - {"!",0x0021}, {"\"",0x0022}, {"#",0x0023}, {"$",0x0024}, {"%",0x0025}, {"&",0x0026}, {"'",0x0027}, - {"(",0x0028}, {")",0x0029}, {"*",0x002A}, {"+",0x002B}, {",",0x002C}, {"-",0x002D}, {".",0x002E}, - {"/",0x002F}, - {"0",0x0030}, {"1",0x0031}, {"2",0x0032}, {"3",0x0033}, {"4",0x0034}, {"5",0x0035}, - {"6",0x0036}, {"7",0x0037}, {"8",0x0038}, {"9",0x0039}, - {":",0x003A}, {";",0x003B}, {"<",0x003C}, - {"=",0x003D}, {">",0x003E}, {"?",0x003F}, {"@",0x0040}, - {"A",0x0041}, {"B",0x0042}, {"C",0x0043}, - {"D",0x0044}, {"E",0x0045}, {"F",0x0046}, {"G",0x0047}, {"H",0x0048}, {"I",0x0049}, {"J",0x004A}, - {"K",0x004B}, {"L",0x004C}, {"M",0x004D}, {"N",0x004E}, {"O",0x004F}, {"P",0x0050}, {"Q",0x0051}, - {"R",0x0052}, {"S",0x0053}, {"T",0x0054}, {"U",0x0055}, {"V",0x0056}, {"W",0x0057}, {"X",0x0058}, - {"Y",0x0059}, {"Z",0x005A}, - {"[",0x005B}, {"\\",0x005C}, {"]",0x005D}, {"^",0x005E}, {"_",0x005F}, - {"`",0x0060}, - {"a",0x0061}, {"b",0x0062}, {"c",0x0063}, {"d",0x0064}, {"e",0x0065}, {"f",0x0066}, - {"g",0x0067}, {"h",0x0068}, {"i",0x0069}, {"j",0x006A}, {"k",0x006B}, {"l",0x006C}, {"m",0x006D}, - {"n",0x006E}, {"o",0x006F}, {"p",0x0070}, {"q",0x0071}, {"r",0x0072}, {"s",0x0073}, {"t",0x0074}, - {"u",0x0075}, {"v",0x0076}, {"w",0x0077}, {"x",0x0078}, {"y",0x0079}, {"z",0x007A}, {"{",0x007B}, + {"=",0x003D}, {">",0x003E}, {"?",0x003F}, {"@",0x0040}, {"^",0x005E}, {"|",0x007C}, {"}",0x007D}, {"~",0x007E}, {" ",0x00A0}, {"¡",0x00A1}, {"¢",0x00A2}, {"£",0x00A3}, {"¤",0x00A4}, {"¥",0x00A5}, {"¦",0x00A6}, {"§",0x00A7}, {"¨",0x00A8}, {"©",0x00A9}, {"ª",0x00AA}, {"«",0x00AB}, {"¬",0x00AC}, {"",0x00AD}, {"®",0x00AE}, {"¯",0x00AF}, {"°",0x00B0}, {"±",0x00B1}, @@ -279,15 +278,16 @@ static const std::map<QString, quint32> xUpKeyCodes { {"%", XK_percent}, {"&", XK_ampersand}, {"(", XK_parenleft}, {")", XK_parenright}, {"*", XK_asterisk}, {"+", XK_plus}, {":", XK_colon}, {">", XK_greater}, {"~", XK_asciitilde}, - {"?", XK_question}, {"@", XK_at}, {"^", XK_asciicircum}, {"_", XK_underscore}, + {"?", XK_question}, {"@", XK_at}, {"_", XK_underscore}, {":-D", 0}, }; static const QList<Qt::Key> qtKeyCodes { {Qt::Key_Backspace, Qt:: Key_Enter, Qt::Key_Return, Qt::Key_Plus, - Qt::Key_Slash, Qt::Key_AsciiCircum, Qt::Key_AsciiTilde, Qt::Key_Equal + Qt::Key_Slash, Qt::Key_Equal } }; + static const QList<Qt::Key> qtKeyCodes2 { // √ € ™ “ {Qt::Key(8730), Qt::Key(8364), Qt::Key(8482), Qt::Key(8220), |