diff --git a/src/autotype/AutoType.cpp b/src/autotype/AutoType.cpp index aac0c0cf8..ce68ae471 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."); @@ -475,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)); + } } } diff --git a/src/autotype/x11/AutoTypeX11.cpp b/src/autotype/x11/AutoTypeX11.cpp index 843fbfa40..47ab9127a 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); @@ -58,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); @@ -433,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); @@ -469,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() @@ -535,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 = 10 * 1000 * 1000; - nanosleep(&ts, Q_NULLPTR); - return m_remapKeycode; } @@ -658,23 +674,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; @@ -682,10 +731,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) 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);