aboutsummaryrefslogtreecommitdiffstats
path: root/tests/manual/x11vkbwrapper/handlekeyevents.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/manual/x11vkbwrapper/handlekeyevents.cpp')
-rw-r--r--tests/manual/x11vkbwrapper/handlekeyevents.cpp171
1 files changed, 152 insertions, 19 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;
+}
+