aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPekka Gehör <pekka.gehor@siili.com>2019-11-12 11:52:31 +0200
committerRisto Avila <risto.avila@qt.io>2019-11-18 11:22:48 +0000
commit1f064bf6de8412af2644c2ca14d146b17ffc695b (patch)
treebf2c5b8ea964529110a029cee4835a5432b63f79
parent6547842b5ec6f3f13dc0d9fec6c8e4d167bfb2ce (diff)
Fix for a special character issue
Some of a characters need change of keyboard mapping, that they appear correctly. In the previous implementation there was no change of keyboard mapping, which caused the wrong character to appear or no character at all. Change-Id: I5670d37efba5b1a3aa4dd93e5309efea14fa0f53 Reviewed-by: Mitch Curtis <mitch.curtis@qt.io> (cherry picked from commit 4b9a5746581494ebf9e9847b829d2810e4469a53) Reviewed-by: Jani Heikkinen <jani.heikkinen@qt.io>
-rw-r--r--tests/manual/x11vkbwrapper/handlekeyevents.cpp171
-rw-r--r--tests/manual/x11vkbwrapper/handlekeyevents.h13
-rw-r--r--tests/manual/x11vkbwrapper/keysymmapsforfakeinput.h40
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),