diff --git a/COPYING b/COPYING index 17dfe47553..35cfc1b1ee 100644 --- a/COPYING +++ b/COPYING @@ -175,14 +175,12 @@ Files: share/icons/application/scalable/actions/chevron-double-down.svg share/icons/application/scalable/actions/hammer-wrench.svg share/icons/application/scalable/actions/health.svg share/icons/application/scalable/actions/help-about.svg - share/icons/application/scalable/actions/key-enter.svg share/icons/application/scalable/actions/lock-question.svg share/icons/application/scalable/actions/message-close.svg share/icons/application/scalable/actions/move-down.svg share/icons/application/scalable/actions/move-up.svg share/icons/application/scalable/actions/paperclip.svg share/icons/application/scalable/actions/password-copy.svg - share/icons/application/scalable/actions/password-generate.svg share/icons/application/scalable/actions/password-generator.svg share/icons/application/scalable/actions/password-show-off.svg share/icons/application/scalable/actions/password-show-on.svg diff --git a/docs/images/autotype_selection_dialog_type_menu.png b/docs/images/autotype_selection_dialog_type_menu.png index f0e83ee80f..08fb0f9ee2 100644 Binary files a/docs/images/autotype_selection_dialog_type_menu.png and b/docs/images/autotype_selection_dialog_type_menu.png differ diff --git a/docs/topics/AutoType.adoc b/docs/topics/AutoType.adoc index 6d54e34e30..8b60830d9c 100644 --- a/docs/topics/AutoType.adoc +++ b/docs/topics/AutoType.adoc @@ -60,6 +60,7 @@ image::autotype_entry_sequences.png[] |{DELAY X} |Pause typing for X milliseconds |{CLEARFIELD} |Clear the input field |{PICKCHARS} |Pick specific password characters from a dialog +|{MODE=VIRTUAL} |(Experimental) Use virtual key presses on Windows, useful for virtual machines |=== === Performing Global Auto-Type diff --git a/share/icons/application/scalable/actions/key-enter.svg b/share/icons/application/scalable/actions/key-enter.svg deleted file mode 100644 index 05126f2a36..0000000000 --- a/share/icons/application/scalable/actions/key-enter.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/share/icons/application/scalable/actions/password-generate.svg b/share/icons/application/scalable/actions/password-generate.svg deleted file mode 100644 index 7192714859..0000000000 --- a/share/icons/application/scalable/actions/password-generate.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/share/icons/icons.qrc b/share/icons/icons.qrc index 61cbc91033..209a1d35cc 100644 --- a/share/icons/icons.qrc +++ b/share/icons/icons.qrc @@ -50,7 +50,6 @@ application/scalable/actions/health.svg application/scalable/actions/help-about.svg application/scalable/actions/hibp.svg - application/scalable/actions/key-enter.svg application/scalable/actions/lock-question.svg application/scalable/actions/keyboard-shortcuts.svg application/scalable/actions/message-close.svg @@ -60,7 +59,6 @@ application/scalable/actions/object-unlocked.svg application/scalable/actions/paperclip.svg application/scalable/actions/password-copy.svg - application/scalable/actions/password-generate.svg application/scalable/actions/password-generator.svg application/scalable/actions/password-show-off.svg application/scalable/actions/password-show-on.svg diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts index 92d8de75de..155dfa2ff8 100644 --- a/share/translations/keepassxc_en.ts +++ b/share/translations/keepassxc_en.ts @@ -705,14 +705,6 @@ Double click a row to perform Auto-Type or find an entry using the search: - - <p>You can use advanced search queries to find any entry in your open databases. The following shortcuts are useful:<br/> -Ctrl+F - Toggle database search<br/> -Ctrl+1 - Type username<br/> -Ctrl+2 - Type password<br/> -Ctrl+3 - Type TOTP</p> - - Search all open databases @@ -753,6 +745,19 @@ Ctrl+3 - Type TOTP</p> Copy TOTP + + <p>You can use advanced search queries to find any entry in your open databases. The following shortcuts are useful:<br/> +Ctrl+F - Toggle database search<br/> +Ctrl+1 - Type username<br/> +Ctrl+2 - Type password<br/> +Ctrl+3 - Type TOTP<br/> +Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> + + + + Use Virtual Keyboard + + BrowserAccessControlDialog diff --git a/src/autotype/AutoType.cpp b/src/autotype/AutoType.cpp index 6038960044..850863e916 100644 --- a/src/autotype/AutoType.cpp +++ b/src/autotype/AutoType.cpp @@ -254,7 +254,10 @@ void AutoType::unregisterGlobalShortcut() /** * Core Autotype function that will execute actions */ -void AutoType::executeAutoTypeActions(const Entry* entry, QWidget* hideWindow, const QString& sequence, WId window) +void AutoType::executeAutoTypeActions(const Entry* entry, + const QString& sequence, + WId window, + AutoTypeExecutor::Mode mode) { QString error; auto actions = parseSequence(sequence, entry, error); @@ -274,7 +277,8 @@ void AutoType::executeAutoTypeActions(const Entry* entry, QWidget* hideWindow, c return; } - if (hideWindow) { + // Explicitly hide the main window if no target window is specified + if (window == 0) { #if defined(Q_OS_MACOS) // Check for accessibility permission if (!macUtils()->enableAccessibility()) { @@ -289,20 +293,22 @@ void AutoType::executeAutoTypeActions(const Entry* entry, QWidget* hideWindow, c macUtils()->raiseLastActiveWindow(); m_plugin->hideOwnWindow(); #else - getMainWindow()->minimizeOrHide(); + if (getMainWindow()) { + getMainWindow()->minimizeOrHide(); + } #endif - } - - // Restore window state in case app stole focus - restoreWindowState(); - QCoreApplication::processEvents(); - m_plugin->raiseWindow(m_windowForGlobal); - - // Used only for selected entry auto-type - if (!window) { + QCoreApplication::processEvents(); window = m_plugin->activeWindow(); + } else { + // Restore window state (macOS only) then raise the target window + restoreWindowState(); + QCoreApplication::processEvents(); + m_plugin->raiseWindow(window); } + // Restore executor mode + m_executor->mode = mode; + int delay = qMax(100, config()->get(Config::AutoTypeStartDelay).toInt()); Tools::wait(delay); @@ -346,7 +352,7 @@ void AutoType::executeAutoTypeActions(const Entry* entry, QWidget* hideWindow, c * Single Autotype entry-point function * Look up the Auto-Type sequence for the given entry then perfom Auto-Type in the active window */ -void AutoType::performAutoType(const Entry* entry, QWidget* hideWindow) +void AutoType::performAutoType(const Entry* entry) { if (!m_plugin) { return; @@ -354,7 +360,7 @@ void AutoType::performAutoType(const Entry* entry, QWidget* hideWindow) auto sequences = entry->autoTypeSequences(); if (!sequences.isEmpty()) { - executeAutoTypeActions(entry, hideWindow, sequences.first()); + executeAutoTypeActions(entry, sequences.first()); } } @@ -362,13 +368,13 @@ void AutoType::performAutoType(const Entry* entry, QWidget* hideWindow) * Extra Autotype entry-point function * Perfom Auto-Type of the directly specified sequence in the active window */ -void AutoType::performAutoTypeWithSequence(const Entry* entry, const QString& sequence, QWidget* hideWindow) +void AutoType::performAutoTypeWithSequence(const Entry* entry, const QString& sequence) { if (!m_plugin) { return; } - executeAutoTypeActions(entry, hideWindow, sequence); + executeAutoTypeActions(entry, sequence); } void AutoType::startGlobalAutoType(const QString& search) @@ -467,12 +473,19 @@ void AutoType::performGlobalAutoType(const QList>& dbLi } connect(getMainWindow(), &MainWindow::databaseLocked, selectDialog, &AutoTypeSelectDialog::reject); - connect(selectDialog, &AutoTypeSelectDialog::matchActivated, this, [this](const AutoTypeMatch& match) { - m_lastMatch = match; - m_lastMatchRetypeTimer.start(config()->get(Config::GlobalAutoTypeRetypeTime).toInt() * 1000); - executeAutoTypeActions(match.first, nullptr, match.second, m_windowForGlobal); - resetAutoTypeState(); - }); + connect(selectDialog, + &AutoTypeSelectDialog::matchActivated, + this, + [this](const AutoTypeMatch& match, bool virtualMode) { + m_lastMatch = match; + m_lastMatchRetypeTimer.start(config()->get(Config::GlobalAutoTypeRetypeTime).toInt() * 1000); + executeAutoTypeActions(match.first, + match.second, + m_windowForGlobal, + virtualMode ? AutoTypeExecutor::Mode::VIRTUAL + : AutoTypeExecutor::Mode::NORMAL); + resetAutoTypeState(); + }); connect(selectDialog, &QDialog::rejected, this, [this] { restoreWindowState(); resetAutoTypeState(); @@ -488,7 +501,7 @@ void AutoType::performGlobalAutoType(const QList>& dbLi selectDialog->activateWindow(); } else if (!matchList.isEmpty()) { // Only one match and not asking, do it! - executeAutoTypeActions(matchList.first().first, nullptr, matchList.first().second, m_windowForGlobal); + executeAutoTypeActions(matchList.first().first, matchList.first().second, m_windowForGlobal); resetAutoTypeState(); } else { // We should never get here @@ -717,6 +730,12 @@ AutoType::parseSequence(const QString& entrySequence, const Entry* entry, QStrin error = tr("Invalid conversion syntax: %1").arg(fullPlaceholder); return {}; } + } else if (placeholder.startsWith("mode=")) { + auto mode = AutoTypeExecutor::Mode::NORMAL; + if (placeholder.endsWith("virtual")) { + mode = AutoTypeExecutor::Mode::VIRTUAL; + } + actions << QSharedPointer::create(mode); } else if (placeholder == "beep" || placeholder.startsWith("vkey") || placeholder.startsWith("appactivate") || placeholder.startsWith("c:")) { // Ignore these commands diff --git a/src/autotype/AutoType.h b/src/autotype/AutoType.h index 1e09adaf36..5fc07adab2 100644 --- a/src/autotype/AutoType.h +++ b/src/autotype/AutoType.h @@ -19,15 +19,15 @@ #ifndef KEEPASSX_AUTOTYPE_H #define KEEPASSX_AUTOTYPE_H +#include "AutoTypeAction.h" + #include -#include #include #include +#include "AutoTypeAction.h" #include "AutoTypeMatch.h" -class AutoTypeAction; -class AutoTypeExecutor; class AutoTypePlatformInterface; class Database; class Entry; @@ -41,8 +41,8 @@ class AutoType : public QObject QStringList windowTitles(); bool registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers, QString* error = nullptr); void unregisterGlobalShortcut(); - void performAutoType(const Entry* entry, QWidget* hideWindow = nullptr); - void performAutoTypeWithSequence(const Entry* entry, const QString& sequence, QWidget* hideWindow = nullptr); + void performAutoType(const Entry* entry); + void performAutoTypeWithSequence(const Entry* entry, const QString& sequence); static bool verifyAutoTypeSyntax(const QString& sequence, const Entry* entry, QString& error); @@ -80,9 +80,9 @@ private slots: ~AutoType() override; void loadPlugin(const QString& pluginPath); void executeAutoTypeActions(const Entry* entry, - QWidget* hideWindow = nullptr, - const QString& customSequence = QString(), - WId window = 0); + const QString& sequence = QString(), + WId window = 0, + AutoTypeExecutor::Mode mode = AutoTypeExecutor::Mode::NORMAL); void restoreWindowState(); void resetAutoTypeState(); diff --git a/src/autotype/AutoTypeAction.cpp b/src/autotype/AutoTypeAction.cpp index d43ff70025..237d7743fe 100644 --- a/src/autotype/AutoTypeAction.cpp +++ b/src/autotype/AutoTypeAction.cpp @@ -65,3 +65,14 @@ AutoTypeAction::Result AutoTypeBegin::exec(AutoTypeExecutor* executor) const { return executor->execBegin(this); } + +AutoTypeMode::AutoTypeMode(AutoTypeExecutor::Mode mode) + : mode(mode) +{ +} + +AutoTypeAction::Result AutoTypeMode::exec(AutoTypeExecutor* executor) const +{ + executor->mode = mode; + return AutoTypeAction::Result::Ok(); +} diff --git a/src/autotype/AutoTypeAction.h b/src/autotype/AutoTypeAction.h index 48dd29cc9b..082d0aea7d 100644 --- a/src/autotype/AutoTypeAction.h +++ b/src/autotype/AutoTypeAction.h @@ -121,13 +121,29 @@ class KEEPASSXC_EXPORT AutoTypeBegin : public AutoTypeAction class KEEPASSXC_EXPORT AutoTypeExecutor { public: + enum class Mode + { + NORMAL, + VIRTUAL + }; + virtual ~AutoTypeExecutor() = default; virtual AutoTypeAction::Result execBegin(const AutoTypeBegin* action) = 0; virtual AutoTypeAction::Result execType(const AutoTypeKey* action) = 0; virtual AutoTypeAction::Result execClearField(const AutoTypeClearField* action) = 0; int execDelayMs = 25; + Mode mode = Mode::NORMAL; QString error; }; +class KEEPASSXC_EXPORT AutoTypeMode : public AutoTypeAction +{ +public: + AutoTypeMode(AutoTypeExecutor::Mode mode = AutoTypeExecutor::Mode::NORMAL); + Result exec(AutoTypeExecutor* executor) const override; + + const AutoTypeExecutor::Mode mode; +}; + #endif // KEEPASSX_AUTOTYPEACTION_H diff --git a/src/autotype/AutoTypeSelectDialog.cpp b/src/autotype/AutoTypeSelectDialog.cpp index d58e331510..0c8eefdc4a 100644 --- a/src/autotype/AutoTypeSelectDialog.cpp +++ b/src/autotype/AutoTypeSelectDialog.cpp @@ -58,6 +58,8 @@ AutoTypeSelectDialog::AutoTypeSelectDialog(QWidget* parent) } }); + m_ui->helpButton->setIcon(icons()->icon("system-help")); + m_ui->search->installEventFilter(this); m_searchTimer.setInterval(300); @@ -118,7 +120,7 @@ void AutoTypeSelectDialog::submitAutoTypeMatch(AutoTypeMatch match) if (match.first) { m_accepted = true; accept(); - emit matchActivated(std::move(match)); + emit matchActivated(std::move(match), m_virtualMode); } } @@ -274,34 +276,54 @@ void AutoTypeSelectDialog::buildActionMenu() m_actionMenu->addAction(typeUsernameAction); m_actionMenu->addAction(typePasswordAction); m_actionMenu->addAction(typeTotpAction); +#ifdef Q_OS_WIN + auto typeVirtualAction = new QAction(icons()->icon("auto-type"), tr("Use Virtual Keyboard")); + m_actionMenu->addAction(typeVirtualAction); +#endif m_actionMenu->addAction(copyUsernameAction); m_actionMenu->addAction(copyPasswordAction); m_actionMenu->addAction(copyTotpAction); - auto shortcut = new QShortcut(Qt::CTRL + Qt::Key_1, this); - connect(shortcut, &QShortcut::activated, typeUsernameAction, &QAction::trigger); + typeUsernameAction->setShortcut(Qt::CTRL + Qt::Key_1); connect(typeUsernameAction, &QAction::triggered, this, [&] { auto match = m_ui->view->currentMatch(); match.second = "{USERNAME}"; submitAutoTypeMatch(match); }); - shortcut = new QShortcut(Qt::CTRL + Qt::Key_2, this); - connect(shortcut, &QShortcut::activated, typePasswordAction, &QAction::trigger); + typePasswordAction->setShortcut(Qt::CTRL + Qt::Key_2); connect(typePasswordAction, &QAction::triggered, this, [&] { auto match = m_ui->view->currentMatch(); match.second = "{PASSWORD}"; submitAutoTypeMatch(match); }); - shortcut = new QShortcut(Qt::CTRL + Qt::Key_3, this); - connect(shortcut, &QShortcut::activated, typeTotpAction, &QAction::trigger); + typeTotpAction->setShortcut(Qt::CTRL + Qt::Key_3); connect(typeTotpAction, &QAction::triggered, this, [&] { auto match = m_ui->view->currentMatch(); match.second = "{TOTP}"; submitAutoTypeMatch(match); }); +#ifdef Q_OS_WIN + typeVirtualAction->setShortcut(Qt::CTRL + Qt::Key_4); + connect(typeVirtualAction, &QAction::triggered, this, [&] { + m_virtualMode = true; + activateCurrentMatch(); + }); +#endif + +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + // Qt 5.10 introduced a new "feature" to hide shortcuts in context menus + // Unfortunately, Qt::AA_DontShowShortcutsInContextMenus is broken, have to manually enable them + typeUsernameAction->setShortcutVisibleInContextMenu(true); + typePasswordAction->setShortcutVisibleInContextMenu(true); + typeTotpAction->setShortcutVisibleInContextMenu(true); +#ifdef Q_OS_WIN + typeVirtualAction->setShortcutVisibleInContextMenu(true); +#endif +#endif + connect(copyUsernameAction, &QAction::triggered, this, [&] { auto entry = m_ui->view->currentMatch().first; if (entry) { diff --git a/src/autotype/AutoTypeSelectDialog.h b/src/autotype/AutoTypeSelectDialog.h index fec596b344..9c05804106 100644 --- a/src/autotype/AutoTypeSelectDialog.h +++ b/src/autotype/AutoTypeSelectDialog.h @@ -45,7 +45,7 @@ class AutoTypeSelectDialog : public QDialog void setSearchString(const QString& search); signals: - void matchActivated(AutoTypeMatch match); + void matchActivated(AutoTypeMatch match, bool virtualMode = false); protected: bool eventFilter(QObject* obj, QEvent* event) override; @@ -69,6 +69,7 @@ private slots: QTimer m_searchTimer; QPointer m_actionMenu; + bool m_virtualMode = false; bool m_accepted = false; }; diff --git a/src/autotype/AutoTypeSelectDialog.ui b/src/autotype/AutoTypeSelectDialog.ui index cac656d608..0c5e3c8c28 100644 --- a/src/autotype/AutoTypeSelectDialog.ui +++ b/src/autotype/AutoTypeSelectDialog.ui @@ -43,34 +43,29 @@ - - - - 0 - 0 - + + + PointingHandCursor - - - 14 - 14 - + + Qt::NoFocus <p>You can use advanced search queries to find any entry in your open databases. The following shortcuts are useful:<br/> Ctrl+F - Toggle database search<br/> Ctrl+1 - Type username<br/> Ctrl+2 - Type password<br/> -Ctrl+3 - Type TOTP</p> +Ctrl+3 - Type TOTP<br/> +Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> - - + + QToolButton { + border: none; + background: none; +} - - :/icons/application/scalable/actions/system-help.svg - - - true + + ? diff --git a/src/autotype/windows/AutoTypeWindows.cpp b/src/autotype/windows/AutoTypeWindows.cpp index 894980f83c..9d0467b90a 100644 --- a/src/autotype/windows/AutoTypeWindows.cpp +++ b/src/autotype/windows/AutoTypeWindows.cpp @@ -81,67 +81,71 @@ bool AutoTypePlatformWin::raiseWindow(WId window) // // Send unicode character to foreground window // -void AutoTypePlatformWin::sendChar(const QChar& ch, bool isKeyDown) +void AutoTypePlatformWin::sendChar(const QChar& ch) { - auto vkey = VkKeyScanExW(ch.unicode(), GetKeyboardLayout(0)); - if (vkey == -1) { - // VKey not found, send as Unicode character - DWORD flags = KEYEVENTF_UNICODE; - if (!isKeyDown) { - flags |= KEYEVENTF_KEYUP; - } + DWORD nativeFlags = KEYEVENTF_UNICODE; + + INPUT in[2]; + in[0].type = INPUT_KEYBOARD; + in[0].ki.wVk = 0; + in[0].ki.wScan = ch.unicode(); + in[0].ki.dwFlags = KEYEVENTF_UNICODE; + in[0].ki.time = 0; + in[0].ki.dwExtraInfo = ::GetMessageExtraInfo(); + + in[1] = in[0]; + in[1].ki.dwFlags |= KEYEVENTF_KEYUP; - INPUT in; - in.type = INPUT_KEYBOARD; - in.ki.wVk = 0; - in.ki.wScan = ch.unicode(); - in.ki.dwFlags = flags; - in.ki.time = 0; - in.ki.dwExtraInfo = ::GetMessageExtraInfo(); - ::SendInput(1, &in, sizeof(INPUT)); + ::SendInput(2, &in[0], sizeof(INPUT)); +} + +void AutoTypePlatformWin::sendCharVirtual(const QChar& ch) +{ + auto vKey = VkKeyScanExW(ch.unicode(), GetKeyboardLayout(0)); + if (vKey == -1) { + // VKey not found, send as Unicode character + sendChar(ch); return; } - if (HIBYTE(vkey) & 0x6) { - sendKey(Qt::Key_AltGr, true); + if (HIBYTE(vKey) & 0x6) { + setKeyState(Qt::Key_AltGr, true); } else { - if (HIBYTE(vkey) & 0x1) { - sendKey(Qt::Key_Shift, true); + if (HIBYTE(vKey) & 0x1) { + setKeyState(Qt::Key_Shift, true); } - if (HIBYTE(vkey) & 0x2) { - sendKey(Qt::Key_Control, true); + if (HIBYTE(vKey) & 0x2) { + setKeyState(Qt::Key_Control, true); } - if (HIBYTE(vkey) & 0x4) { - sendKey(Qt::Key_Alt, true); + if (HIBYTE(vKey) & 0x4) { + setKeyState(Qt::Key_Alt, true); } } - DWORD flags = KEYEVENTF_SCANCODE; - if (!isKeyDown) { - flags |= KEYEVENTF_KEYUP; - } + INPUT in[2]; + in[0].type = INPUT_KEYBOARD; + in[0].ki.wVk = 0; + in[0].ki.wScan = MapVirtualKey(LOBYTE(vKey), MAPVK_VK_TO_VSC); + in[0].ki.dwFlags = KEYEVENTF_SCANCODE; + in[0].ki.time = 0; + in[0].ki.dwExtraInfo = ::GetMessageExtraInfo(); - INPUT in; - in.type = INPUT_KEYBOARD; - in.ki.wVk = 0; - in.ki.wScan = MapVirtualKey(LOBYTE(vkey), MAPVK_VK_TO_VSC); - in.ki.dwFlags = flags; - in.ki.time = 0; - in.ki.dwExtraInfo = ::GetMessageExtraInfo(); + in[1] = in[0]; + in[1].ki.dwFlags |= KEYEVENTF_KEYUP; - ::SendInput(1, &in, sizeof(INPUT)); + ::SendInput(2, &in[0], sizeof(INPUT)); - if (HIBYTE(vkey) & 0x6) { - sendKey(Qt::Key_AltGr, false); + if (HIBYTE(vKey) & 0x6) { + setKeyState(Qt::Key_AltGr, false); } else { - if (HIBYTE(vkey) & 0x1) { - sendKey(Qt::Key_Shift, false); + if (HIBYTE(vKey) & 0x1) { + setKeyState(Qt::Key_Shift, false); } - if (HIBYTE(vkey) & 0x2) { - sendKey(Qt::Key_Control, false); + if (HIBYTE(vKey) & 0x2) { + setKeyState(Qt::Key_Control, false); } - if (HIBYTE(vkey) & 0x4) { - sendKey(Qt::Key_Alt, false); + if (HIBYTE(vKey) & 0x4) { + setKeyState(Qt::Key_Alt, false); } } } @@ -149,14 +153,14 @@ void AutoTypePlatformWin::sendChar(const QChar& ch, bool isKeyDown) // // Send virtual key code to foreground window // -void AutoTypePlatformWin::sendKey(Qt::Key key, bool isKeyDown) +void AutoTypePlatformWin::setKeyState(Qt::Key key, bool down) { WORD nativeKeyCode = winUtils()->qtToNativeKeyCode(key); DWORD nativeFlags = KEYEVENTF_SCANCODE; if (isExtendedKey(nativeKeyCode)) { nativeFlags |= KEYEVENTF_EXTENDEDKEY; } - if (!isKeyDown) { + if (!down) { nativeFlags |= KEYEVENTF_KEYUP; } @@ -279,37 +283,40 @@ AutoTypeAction::Result AutoTypeExecutorWin::execBegin(const AutoTypeBegin* actio AutoTypeAction::Result AutoTypeExecutorWin::execType(const AutoTypeKey* action) { if (action->modifiers & Qt::ShiftModifier) { - m_platform->sendKey(Qt::Key_Shift, true); + m_platform->setKeyState(Qt::Key_Shift, true); } if (action->modifiers & Qt::ControlModifier) { - m_platform->sendKey(Qt::Key_Control, true); + m_platform->setKeyState(Qt::Key_Control, true); } if (action->modifiers & Qt::AltModifier) { - m_platform->sendKey(Qt::Key_Alt, true); + m_platform->setKeyState(Qt::Key_Alt, true); } if (action->modifiers & Qt::MetaModifier) { - m_platform->sendKey(Qt::Key_Meta, true); + m_platform->setKeyState(Qt::Key_Meta, true); } if (action->key != Qt::Key_unknown) { - m_platform->sendKey(action->key, true); - m_platform->sendKey(action->key, false); + m_platform->setKeyState(action->key, true); + m_platform->setKeyState(action->key, false); } else { - m_platform->sendChar(action->character, true); - m_platform->sendChar(action->character, false); + if (mode == Mode::VIRTUAL) { + m_platform->sendCharVirtual(action->character); + } else { + m_platform->sendChar(action->character); + } } if (action->modifiers & Qt::ShiftModifier) { - m_platform->sendKey(Qt::Key_Shift, false); + m_platform->setKeyState(Qt::Key_Shift, false); } if (action->modifiers & Qt::ControlModifier) { - m_platform->sendKey(Qt::Key_Control, false); + m_platform->setKeyState(Qt::Key_Control, false); } if (action->modifiers & Qt::AltModifier) { - m_platform->sendKey(Qt::Key_Alt, false); + m_platform->setKeyState(Qt::Key_Alt, false); } if (action->modifiers & Qt::MetaModifier) { - m_platform->sendKey(Qt::Key_Meta, false); + m_platform->setKeyState(Qt::Key_Meta, false); } Tools::sleep(execDelayMs); diff --git a/src/autotype/windows/AutoTypeWindows.h b/src/autotype/windows/AutoTypeWindows.h index 7b3d577d02..29e98ab353 100644 --- a/src/autotype/windows/AutoTypeWindows.h +++ b/src/autotype/windows/AutoTypeWindows.h @@ -43,8 +43,9 @@ class AutoTypePlatformWin : public QObject, public AutoTypePlatformInterface bool raiseWindow(WId window) override; AutoTypeExecutor* createExecutor() override; - void sendChar(const QChar& ch, bool isKeyDown); - void sendKey(Qt::Key key, bool isKeyDown); + void sendCharVirtual(const QChar& ch); + void sendChar(const QChar& ch); + void setKeyState(Qt::Key key, bool down); private: static bool isExtendedKey(DWORD nativeKeyCode); diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 1187138728..864b78c6ed 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -782,9 +782,9 @@ void DatabaseWidget::performAutoType(const QString& sequence) } if (sequence.isEmpty()) { - autoType()->performAutoType(currentEntry, window()); + autoType()->performAutoType(currentEntry); } else { - autoType()->performAutoTypeWithSequence(currentEntry, sequence, window()); + autoType()->performAutoTypeWithSequence(currentEntry, sequence); } } } diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index 32d0b82253..58ebdea6c8 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -220,7 +220,7 @@ void EditEntryWidget::openAutotypeHelp() void EditEntryWidget::setupAutoType() { m_autoTypeUi->setupUi(m_autoTypeWidget); - addPage(tr("Auto-Type"), icons()->icon("key-enter"), m_autoTypeWidget); + addPage(tr("Auto-Type"), icons()->icon("auto-type"), m_autoTypeWidget); m_autoTypeUi->openHelpButton->setIcon(icons()->icon("system-help")); diff --git a/tests/TestAutoType.cpp b/tests/TestAutoType.cpp index 32b4b1e499..235ba5a861 100644 --- a/tests/TestAutoType.cpp +++ b/tests/TestAutoType.cpp @@ -140,7 +140,7 @@ void TestAutoType::testInternal() void TestAutoType::testSingleAutoType() { - m_autoType->performAutoType(m_entry1, nullptr); + m_autoType->performAutoType(m_entry1); QCOMPARE(m_test->actionCount(), 14); QCOMPARE(m_test->actionChars(),