From ccb7a4c96d6372bc12bb2513531ad44469979b86 Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Tue, 24 Feb 2015 21:59:47 +0100 Subject: [PATCH 1/9] Blacklist the KDE 5 root window. --- src/autotype/x11/AutoTypeX11.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/autotype/x11/AutoTypeX11.cpp b/src/autotype/x11/AutoTypeX11.cpp index 843fbfa40..078821ad9 100644 --- a/src/autotype/x11/AutoTypeX11.cpp +++ b/src/autotype/x11/AutoTypeX11.cpp @@ -39,6 +39,7 @@ AutoTypePlatformX11::AutoTypePlatformX11() m_classBlacklist << "desktop_window" << "gnome-panel"; // Gnome m_classBlacklist << "kdesktop" << "kicker"; // KDE 3 m_classBlacklist << "Plasma"; // KDE 4 + m_classBlacklist << "plasmashell"; // KDE 5 m_classBlacklist << "xfdesktop" << "xfce4-panel"; // Xfce 4 m_currentGlobalKey = static_cast(0); From 778f01bcf12874167211f2c0cf8f061fd4e4c9f7 Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Tue, 24 Feb 2015 22:00:44 +0100 Subject: [PATCH 2/9] Increase sleep time after remapping a keycode. --- src/autotype/x11/AutoTypeX11.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/autotype/x11/AutoTypeX11.cpp b/src/autotype/x11/AutoTypeX11.cpp index 078821ad9..d2d3acf0e 100644 --- a/src/autotype/x11/AutoTypeX11.cpp +++ b/src/autotype/x11/AutoTypeX11.cpp @@ -540,7 +540,7 @@ int AutoTypePlatformX11::AddKeysym(KeySym keysym) all clients */ timespec ts; ts.tv_sec = 0; - ts.tv_nsec = 10 * 1000 * 1000; + ts.tv_nsec = 30 * 1000 * 1000; nanosleep(&ts, Q_NULLPTR); return m_remapKeycode; From 22f579a59e3ff94078217dff9259fc9a830b4316 Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Fri, 13 Mar 2015 19:40:52 +0100 Subject: [PATCH 3/9] Restore keyboard mapping only if we actually changed it. --- src/autotype/x11/AutoTypeX11.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/autotype/x11/AutoTypeX11.cpp b/src/autotype/x11/AutoTypeX11.cpp index d2d3acf0e..80a9d523f 100644 --- a/src/autotype/x11/AutoTypeX11.cpp +++ b/src/autotype/x11/AutoTypeX11.cpp @@ -59,7 +59,9 @@ AutoTypePlatformX11::AutoTypePlatformX11() void AutoTypePlatformX11::unload() { // Restore the KeyboardMapping to its original state. - AddKeysym(NoSymbol); + if (m_currentRemapKeysym != NoSymbol) { + AddKeysym(NoSymbol); + } if (m_keysymTable) { XFree(m_keysymTable); From e4985f4ff7d7592e52e5ccd9a96eadb6e475e5f0 Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Fri, 13 Mar 2015 19:41:49 +0100 Subject: [PATCH 4/9] Get the xtest keyboard instead of the core keyboard. If we don't find it fall back to the core keyboard. --- src/autotype/x11/AutoTypeX11.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/autotype/x11/AutoTypeX11.cpp b/src/autotype/x11/AutoTypeX11.cpp index 80a9d523f..2ac2504a1 100644 --- a/src/autotype/x11/AutoTypeX11.cpp +++ b/src/autotype/x11/AutoTypeX11.cpp @@ -436,9 +436,21 @@ void AutoTypePlatformX11::updateKeymap() int mod_index, mod_key; XModifierKeymap *modifiers; - /* read keyboard map */ if (m_xkb != NULL) XkbFreeKeyboard(m_xkb, XkbAllComponentsMask, True); - m_xkb = XkbGetKeyboard (m_dpy, XkbCompatMapMask | XkbGeometryMask, XkbUseCoreKbd); + + XDeviceInfo* devices; + int num_devices; + XID keyboard_id = XkbUseCoreKbd; + devices = XListInputDevices(m_dpy, &num_devices); + + for (int i = 0; i < num_devices; i++) { + if (QString(devices[i].name) == "Virtual core XTEST keyboard") { + keyboard_id = devices[i].id; + break; + } + } + + m_xkb = XkbGetKeyboard(m_dpy, XkbCompatMapMask | XkbGeometryMask, keyboard_id); XDisplayKeycodes(m_dpy, &m_minKeycode, &m_maxKeycode); if (m_keysymTable != NULL) XFree(m_keysymTable); From 2dfc740782ba256350c6b97503a955212b3d77bf Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Fri, 13 Mar 2015 19:43:52 +0100 Subject: [PATCH 5/9] Rework handling of modifiers in auto-type. Release all modifiers that are pressed and change the result. --- src/autotype/x11/AutoTypeX11.cpp | 53 ++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/src/autotype/x11/AutoTypeX11.cpp b/src/autotype/x11/AutoTypeX11.cpp index 2ac2504a1..e2d877bae 100644 --- a/src/autotype/x11/AutoTypeX11.cpp +++ b/src/autotype/x11/AutoTypeX11.cpp @@ -673,23 +673,56 @@ void AutoTypePlatformX11::SendKeyPressedEvent(KeySym keysym) Window root, child; int root_x, root_y, x, y; - unsigned int mask; - unsigned int saved_mask; + unsigned int wanted_mask = 0; + unsigned int original_mask; - XQueryPointer(m_dpy, event.root, &root, &child, &root_x, &root_y, &x, &y, &mask); - saved_mask = mask; + XQueryPointer(m_dpy, event.root, &root, &child, &root_x, &root_y, &x, &y, &original_mask); /* determine keycode and mask for the given keysym */ - keycode = GetKeycode(keysym, &mask); + keycode = GetKeycode(keysym, &wanted_mask); if (keycode < 8 || keycode > 255) { qWarning("Unable to get valid keycode for key: keysym=0x%lX", static_cast(keysym)); return; } - /* release all modifiers */ - SendModifier(&event, mask, KeyRelease); + event.state = original_mask; - SendModifier(&event, mask, KeyPress); + // modifiers that need to be pressed but aren't + unsigned int press_mask = wanted_mask & ~original_mask; + + // modifiers that are pressed but maybe shouldn't + unsigned int release_check_mask = original_mask & ~wanted_mask; + + // modifiers we need to release before sending the keycode + unsigned int release_mask = 0; + + // check every release_check_mask individually if it affects the keysym we would generate + // if it doesn't we probably don't need to release it + for (int mod_index = ShiftMapIndex; mod_index <= Mod5MapIndex; mod_index ++) { + if (release_check_mask & (1 << mod_index)) { + unsigned int mods_rtrn; + KeySym keysym_rtrn; + XkbTranslateKeyCode(m_xkb, keycode, wanted_mask | (1 << mod_index), &mods_rtrn, &keysym_rtrn); + + if (keysym_rtrn != keysym) { + release_mask |= (1 << mod_index); + } + } + } + + // finally check if the combination of pressed modifiers that we chose to ignore affects the keysym + unsigned int mods_rtrn; + KeySym keysym_rtrn; + XkbTranslateKeyCode(m_xkb, keycode, wanted_mask | (release_check_mask & ~release_mask), &mods_rtrn, &keysym_rtrn); + if (keysym_rtrn != keysym) { + // oh well, release all the modifiers we don't want + release_mask = release_check_mask; + } + + /* release all modifiers */ + SendModifier(&event, release_mask, KeyRelease); + + SendModifier(&event, press_mask, KeyPress); /* press and release key */ event.keycode = keycode; @@ -697,10 +730,10 @@ void AutoTypePlatformX11::SendKeyPressedEvent(KeySym keysym) SendEvent(&event, KeyRelease); /* release the modifiers */ - SendModifier(&event, mask, KeyRelease); + SendModifier(&event, press_mask, KeyRelease); /* restore the old keyboard mask */ - SendModifier(&event, saved_mask, KeyPress); + SendModifier(&event, release_mask, KeyPress); } int AutoTypePlatformX11::MyErrorHandler(Display* my_dpy, XErrorEvent* event) From b86b64086008fadb5c7fb88e6d87130af123cc33 Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Fri, 13 Mar 2015 19:45:57 +0100 Subject: [PATCH 6/9] Process events from the event loop before typing the first char. --- src/autotype/AutoType.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/autotype/AutoType.cpp b/src/autotype/AutoType.cpp index aac0c0cf8..2143eca76 100644 --- a/src/autotype/AutoType.cpp +++ b/src/autotype/AutoType.cpp @@ -148,6 +148,8 @@ void AutoType::performAutoType(const Entry* entry, QWidget* hideWindow, const QS window = m_plugin->activeWindow(); } + QCoreApplication::processEvents(QEventLoop::AllEvents, 10); + Q_FOREACH (AutoTypeAction* action, actions) { if (m_plugin->activeWindow() != window) { qWarning("Active window changed, interrupting auto-type."); From 2631277184f53f2d9a01b2ee179d874749476c34 Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Fri, 13 Mar 2015 19:48:18 +0100 Subject: [PATCH 7/9] Always sleep some time after the keymap has changed. This works around a problem where sometimes chars are typed as if some random modifiers are pressed. --- src/autotype/x11/AutoTypeX11.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/autotype/x11/AutoTypeX11.cpp b/src/autotype/x11/AutoTypeX11.cpp index e2d877bae..47ab9127a 100644 --- a/src/autotype/x11/AutoTypeX11.cpp +++ b/src/autotype/x11/AutoTypeX11.cpp @@ -484,6 +484,14 @@ void AutoTypePlatformX11::updateKeymap() } } XFreeModifiermap(modifiers); + + /* Xlib needs some time until the mapping is distributed to + all clients */ + // TODO: we should probably only sleep while in the middle of typing something + timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 30 * 1000 * 1000; + nanosleep(&ts, Q_NULLPTR); } bool AutoTypePlatformX11::isRemapKeycodeValid() @@ -550,13 +558,6 @@ int AutoTypePlatformX11::AddKeysym(KeySym keysym) XFlush(m_dpy); updateKeymap(); - /* Xlib needs some time until the mapping is distributed to - all clients */ - timespec ts; - ts.tv_sec = 0; - ts.tv_nsec = 30 * 1000 * 1000; - nanosleep(&ts, Q_NULLPTR); - return m_remapKeycode; } From 940a5026c1d86c092f9ebabc795891f3e68bd613 Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Fri, 13 Mar 2015 22:24:29 +0100 Subject: [PATCH 8/9] Properly auto-type line breaks and tabs in text. --- src/autotype/AutoType.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/autotype/AutoType.cpp b/src/autotype/AutoType.cpp index 2143eca76..ce68ae471 100644 --- a/src/autotype/AutoType.cpp +++ b/src/autotype/AutoType.cpp @@ -477,7 +477,15 @@ QList AutoType::createActionFromTemplate(const QString& tmpl, c QString resolved = entry->resolvePlaceholders(placeholder); if (placeholder != resolved) { Q_FOREACH (const QChar& ch, resolved) { - list.append(new AutoTypeChar(ch)); + if (ch == '\n') { + list.append(new AutoTypeKey(Qt::Key_Enter)); + } + else if (ch == '\t') { + list.append(new AutoTypeKey(Qt::Key_Tab)); + } + else { + list.append(new AutoTypeChar(ch)); + } } } From 3ab1072e9ef35e539d152a71cd6f1ad76bc75b00 Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Tue, 31 Mar 2015 22:31:04 +0200 Subject: [PATCH 9/9] Scale new custom icons down to 64x64 if they are larger. --- src/core/Metadata.cpp | 16 ++++++++++++++++ src/core/Metadata.h | 1 + src/gui/EditWidgetIcons.cpp | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/core/Metadata.cpp b/src/core/Metadata.cpp index 074291c73..402734c7b 100644 --- a/src/core/Metadata.cpp +++ b/src/core/Metadata.cpp @@ -343,6 +343,22 @@ void Metadata::addCustomIcon(const Uuid& uuid, const QImage& icon) Q_EMIT modified(); } +void Metadata::addCustomIconScaled(const Uuid& uuid, const QImage& icon) +{ + QImage iconScaled; + + // scale down to 64x64 if icon is larger + if (icon.width() > 64 || icon.height() > 64) { + iconScaled = icon.scaled(QSize(64, 64), Qt::KeepAspectRatio, + Qt::SmoothTransformation); + } + else { + iconScaled = icon; + } + + addCustomIcon(uuid, iconScaled); +} + void Metadata::removeCustomIcon(const Uuid& uuid) { Q_ASSERT(!uuid.isNull()); diff --git a/src/core/Metadata.h b/src/core/Metadata.h index cde7e26ae..4164fb63e 100644 --- a/src/core/Metadata.h +++ b/src/core/Metadata.h @@ -115,6 +115,7 @@ public: void setProtectNotes(bool value); // void setAutoEnableVisualHiding(bool value); void addCustomIcon(const Uuid& uuid, const QImage& icon); + void addCustomIconScaled(const Uuid& uuid, const QImage& icon); void removeCustomIcon(const Uuid& uuid); void copyCustomIcons(const QSet& iconList, const Metadata* otherMetadata); void setRecycleBinEnabled(bool value); diff --git a/src/gui/EditWidgetIcons.cpp b/src/gui/EditWidgetIcons.cpp index 9e8574535..bcc36077f 100644 --- a/src/gui/EditWidgetIcons.cpp +++ b/src/gui/EditWidgetIcons.cpp @@ -132,7 +132,7 @@ void EditWidgetIcons::addCustomIcon() QImage image(filename); if (!image.isNull()) { Uuid uuid = Uuid::random(); - m_database->metadata()->addCustomIcon(uuid, image.scaled(16, 16)); + m_database->metadata()->addCustomIconScaled(uuid, image); m_customIconModel->setIcons(m_database->metadata()->customIcons(), m_database->metadata()->customIconsOrder()); QModelIndex index = m_customIconModel->indexFromUuid(uuid);