diff --git a/src/autotype/AutoType.cpp b/src/autotype/AutoType.cpp index 47efeb1ca..f3496849d 100644 --- a/src/autotype/AutoType.cpp +++ b/src/autotype/AutoType.cpp @@ -317,7 +317,7 @@ bool AutoType::parseActions(const QString& sequence, const Entry* entry, QListget("AutoTypeDelay").toInt(); for (const QChar& ch : sequence) { diff --git a/src/autotype/mac/AutoTypeMac.cpp b/src/autotype/mac/AutoTypeMac.cpp index 7056c7310..ffd3c227c 100644 --- a/src/autotype/mac/AutoTypeMac.cpp +++ b/src/autotype/mac/AutoTypeMac.cpp @@ -499,14 +499,12 @@ void AutoTypeExecutorMac::execChar(AutoTypeChar* action) { m_platform->sendChar(action->character, true); m_platform->sendChar(action->character, false); - usleep(25 * 1000); } void AutoTypeExecutorMac::execKey(AutoTypeKey* action) { m_platform->sendKey(action->key, true); m_platform->sendKey(action->key, false); - usleep(25 * 1000); } void AutoTypeExecutorMac::execClearField(AutoTypeClearField* action = nullptr) diff --git a/src/autotype/windows/AutoTypeWindows.cpp b/src/autotype/windows/AutoTypeWindows.cpp index 2dfc7a269..3ff2343b9 100644 --- a/src/autotype/windows/AutoTypeWindows.cpp +++ b/src/autotype/windows/AutoTypeWindows.cpp @@ -522,14 +522,12 @@ void AutoTypeExecutorWin::execChar(AutoTypeChar* action) { m_platform->sendChar(action->character, true); m_platform->sendChar(action->character, false); - ::Sleep(25); } void AutoTypeExecutorWin::execKey(AutoTypeKey* action) { m_platform->sendKey(action->key, true); m_platform->sendKey(action->key, false); - ::Sleep(25); } void AutoTypeExecutorWin::execClearField(AutoTypeClearField* action = nullptr) diff --git a/src/autotype/xcb/AutoTypeXCB.cpp b/src/autotype/xcb/AutoTypeXCB.cpp index 436cd5b59..1946c8883 100644 --- a/src/autotype/xcb/AutoTypeXCB.cpp +++ b/src/autotype/xcb/AutoTypeXCB.cpp @@ -641,21 +641,13 @@ int AutoTypePlatformX11::AddKeysym(KeySym keysym) * If input focus is specified explicitly, select the window * before send event to the window. */ -void AutoTypePlatformX11::SendEvent(XKeyEvent* event, int event_type) +void AutoTypePlatformX11::SendKeyEvent(unsigned keycode, bool press) { - XSync(event->display, False); + XSync(m_dpy, False); int (*oldHandler) (Display*, XErrorEvent*) = XSetErrorHandler(MyErrorHandler); - event->type = event_type; - Bool press; - if (event->type == KeyPress) { - press = True; - } - else { - press = False; - } - XTestFakeKeyEvent(event->display, event->keycode, press, 0); - XFlush(event->display); + XTestFakeKeyEvent(m_dpy, keycode, press, 0); + XFlush(m_dpy); XSetErrorHandler(oldHandler); } @@ -664,17 +656,12 @@ void AutoTypePlatformX11::SendEvent(XKeyEvent* event, int event_type) * Send a modifier press/release event for all modifiers * which are set in the mask variable. */ -void AutoTypePlatformX11::SendModifier(XKeyEvent *event, unsigned int mask, int event_type) +void AutoTypePlatformX11::SendModifiers(unsigned int mask, bool press) { int mod_index; for (mod_index = ShiftMapIndex; mod_index <= Mod5MapIndex; mod_index ++) { if (mask & (1 << mod_index)) { - event->keycode = m_modifier_keycode[mod_index]; - SendEvent(event, event_type); - if (event_type == KeyPress) - event->state |= (1 << mod_index); - else - event->state &= (1 << mod_index); + SendKeyEvent(m_modifier_keycode[mod_index], press); } } } @@ -729,43 +716,15 @@ bool AutoTypePlatformX11::keysymModifiers(KeySym keysym, int keycode, unsigned i * window to simulate keyboard. If modifiers (shift, control, etc) * are set ON, many events will be sent. */ -void AutoTypePlatformX11::SendKeyPressedEvent(KeySym keysym) +void AutoTypePlatformX11::SendKey(KeySym keysym, unsigned int modifiers) { - SendKey(keysym,true); - SendKey(keysym,false); -} - -void AutoTypePlatformX11::SendKey(KeySym keysym, bool isKeyDown) -{ - Window cur_focus; - int revert_to; - XKeyEvent event; - int keycode; - if (keysym == NoSymbol) { qWarning("No such key: keysym=0x%lX", keysym); return; } - XGetInputFocus(m_dpy, &cur_focus, &revert_to); - - event.display = m_dpy; - event.window = cur_focus; - event.root = m_rootWindow; - event.subwindow = None; - event.time = CurrentTime; - event.x = 1; - event.y = 1; - event.x_root = 1; - event.y_root = 1; - event.same_screen = True; - - Window root, child; - int root_x, root_y, x, y; - unsigned int wanted_mask = 0; - unsigned int original_mask; - - XQueryPointer(m_dpy, event.root, &root, &child, &root_x, &root_y, &x, &y, &original_mask); + int keycode; + unsigned int wanted_mask; /* determine keycode and mask for the given keysym */ keycode = GetKeycode(keysym, &wanted_mask); @@ -773,8 +732,14 @@ void AutoTypePlatformX11::SendKey(KeySym keysym, bool isKeyDown) qWarning("Unable to get valid keycode for key: keysym=0x%lX", keysym); return; } + wanted_mask |= modifiers; - event.state = original_mask; + Window root, child; + int root_x, root_y, x, y; + unsigned int original_mask; + + XSync(m_dpy, False); + XQueryPointer(m_dpy, m_rootWindow, &root, &child, &root_x, &root_y, &x, &y, &original_mask); // modifiers that need to be pressed but aren't unsigned int press_mask = wanted_mask & ~original_mask; @@ -785,47 +750,52 @@ void AutoTypePlatformX11::SendKey(KeySym keysym, bool isKeyDown) // 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 (!modifiers) { + // 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); + 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 + // 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; + } + } else { 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; - if (isKeyDown) { - SendEvent(&event, KeyPress); - } else { - SendEvent(&event, KeyRelease); + /* set modifiers mask */ + if ((release_mask | press_mask) & LockMask) { + SendModifiers(LockMask, true); + SendModifiers(LockMask, false); } + SendModifiers(release_mask & ~LockMask, false); + SendModifiers(press_mask & ~LockMask, true); - /* release the modifiers */ - SendModifier(&event, press_mask, KeyRelease); + /* press and release release key */ + SendKeyEvent(keycode, true); + SendKeyEvent(keycode, false); - /* restore the old keyboard mask */ - SendModifier(&event, release_mask, KeyPress); + /* restore previous modifiers mask */ + SendModifiers(press_mask & ~LockMask, false); + SendModifiers(release_mask & ~LockMask, true); + if ((release_mask | press_mask) & LockMask) { + SendModifiers(LockMask, true); + SendModifiers(LockMask, false); + } } int AutoTypePlatformX11::MyErrorHandler(Display* my_dpy, XErrorEvent* event) @@ -848,14 +818,12 @@ AutoTypeExecutorX11::AutoTypeExecutorX11(AutoTypePlatformX11* platform) void AutoTypeExecutorX11::execChar(AutoTypeChar* action) { - m_platform->SendKeyPressedEvent(m_platform->charToKeySym(action->character)); - Tools::wait(25); + m_platform->SendKey(m_platform->charToKeySym(action->character)); } void AutoTypeExecutorX11::execKey(AutoTypeKey* action) { - m_platform->SendKeyPressedEvent(m_platform->keyToKeySym(action->key)); - Tools::wait(25); + m_platform->SendKey(m_platform->keyToKeySym(action->key)); } void AutoTypeExecutorX11::execClearField(AutoTypeClearField* action = nullptr) @@ -866,19 +834,13 @@ void AutoTypeExecutorX11::execClearField(AutoTypeClearField* action = nullptr) ts.tv_sec = 0; ts.tv_nsec = 25 * 1000 * 1000; - m_platform->SendKey(m_platform->keyToKeySym(Qt::Key_Control), true); - m_platform->SendKeyPressedEvent(m_platform->keyToKeySym(Qt::Key_Home)); - m_platform->SendKey(m_platform->keyToKeySym(Qt::Key_Control), false); + m_platform->SendKey(m_platform->keyToKeySym(Qt::Key_Home), static_cast(ControlMask)); nanosleep(&ts, nullptr); - m_platform->SendKey(m_platform->keyToKeySym(Qt::Key_Control), true); - m_platform->SendKey(m_platform->keyToKeySym(Qt::Key_Shift), true); - m_platform->SendKeyPressedEvent(m_platform->keyToKeySym(Qt::Key_End)); - m_platform->SendKey(m_platform->keyToKeySym(Qt::Key_Shift), false); - m_platform->SendKey(m_platform->keyToKeySym(Qt::Key_Control), false); + m_platform->SendKey(m_platform->keyToKeySym(Qt::Key_End), static_cast(ControlMask | ShiftMask)); nanosleep(&ts, nullptr); - m_platform->SendKeyPressedEvent(m_platform->keyToKeySym(Qt::Key_Backspace)); + m_platform->SendKey(m_platform->keyToKeySym(Qt::Key_Backspace)); nanosleep(&ts, nullptr); } diff --git a/src/autotype/xcb/AutoTypeXCB.h b/src/autotype/xcb/AutoTypeXCB.h index 34e539cf9..600e001aa 100644 --- a/src/autotype/xcb/AutoTypeXCB.h +++ b/src/autotype/xcb/AutoTypeXCB.h @@ -58,8 +58,7 @@ public: KeySym charToKeySym(const QChar& ch); KeySym keyToKeySym(Qt::Key key); - void SendKeyPressedEvent(KeySym keysym); - void SendKey(KeySym keysym, bool isKeyDown); + void SendKey(KeySym keysym, unsigned int modifiers = 0); signals: void globalShortcutTriggered(); @@ -80,8 +79,8 @@ private: bool isRemapKeycodeValid(); int AddKeysym(KeySym keysym); void AddModifier(KeySym keysym); - void SendEvent(XKeyEvent* event, int event_type); - void SendModifier(XKeyEvent *event, unsigned int mask, int event_type); + void SendKeyEvent(unsigned keycode, bool press); + void SendModifiers(unsigned int mask, bool press); int GetKeycode(KeySym keysym, unsigned int *mask); bool keysymModifiers(KeySym keysym, int keycode, unsigned int *mask); diff --git a/src/core/Config.cpp b/src/core/Config.cpp index 675896d22..f5ec751ce 100644 --- a/src/core/Config.cpp +++ b/src/core/Config.cpp @@ -119,6 +119,7 @@ void Config::init(const QString& fileName) m_defaults.insert("UseGroupIconOnEntryCreation", false); m_defaults.insert("AutoTypeEntryTitleMatch", true); m_defaults.insert("AutoTypeEntryURLMatch", true); + m_defaults.insert("AutoTypeDelay", 25); m_defaults.insert("UseGroupIconOnEntryCreation", true); m_defaults.insert("IgnoreGroupExpansion", false); m_defaults.insert("security/clearclipboard", true); diff --git a/src/gui/AboutDialog.ui b/src/gui/AboutDialog.ui index 5bea301aa..132243664 100644 --- a/src/gui/AboutDialog.ui +++ b/src/gui/AboutDialog.ui @@ -2,30 +2,10 @@ AboutDialog - - - 0 - 0 - 450 - 450 - - - - - 0 - 0 - - - - - 450 - 450 - - About KeePassXC - + @@ -71,7 +51,7 @@ - <span style="font-size: 24pt"> KeePassXC v${VERSION}</span> + <span style="font-size: 20pt"> KeePassXC ${VERSION}</span> 0 @@ -102,7 +82,7 @@ - <html><head/><body><p>Website: <a href="https://keepassxc.org/"><span style="text-decoration: underline; color:#0000ff;">https://keepassxc.org</span></a></p></body></html> + Website: <a href="https://keepassxc.org/" style="text-decoration: underline">https://keepassxc.org</a> true @@ -112,7 +92,7 @@ - <html><head/><body><p>Report bugs at: <a href="https://github.com/keepassxreboot/keepassxc/issues"><span style="text-decoration: underline; color:#0000ff;">https://github.com</span></a></p></body></html> + Report bugs at: <a href="https://github.com/keepassxreboot/keepassxc/issues" style="text-decoration: underline;">https://github.com</a> true @@ -138,13 +118,13 @@ - + 0 0 - <html><head/><body><p>KeePassXC is distributed under the terms of the GNU General Public License (GPL) version 2 or (at your option) version 3.</p></body></html> + KeePassXC is distributed under the terms of the GNU General Public License (GPL) version 2 or (at your option) version 3. true @@ -167,6 +147,13 @@ + + + + Project Maintainers: + + + @@ -176,7 +163,14 @@ - <html><head><style>li {font-size: 10pt}</style></head><body><p><span style=" font-size:10pt;">Project Maintainers:</span></p><ul><li>droidmonkey</li><li>phoerious</li><li>TheZ3ro</li><li>louib</li><li>Weslly</li><li>debfx (KeePassX)</li></ul></body></html> + <ul> + <li>droidmonkey</li> + <li>phoerious</li> + <li>TheZ3ro</li> + <li>louib</li> + <li>Weslly</li> + <li>debfx (KeePassX)</li> +</ul> @@ -201,45 +195,81 @@ - - - <html><body> - <p style="font-size:x-large; font-weight:600;">Code:</p> - <ul> - <li style="font-size:10pt">debfx (KeePassX)</li> - <li style="font-size:10pt">BlueIce (KeePassX)</li> - <li style="font-size:10pt">droidmonkey</li> - <li style="font-size:10pt">phoerious</li> - <li style="font-size:10pt">TheZ3ro</li> - <li style="font-size:10pt">louib</li> - <li style="font-size:10pt">weslly</li> - <li style="font-size:10pt">keithbennett (KeePassHTTP)</li> - <li style="font-size:10pt">Typz (KeePassHTTP)</li> - <li style="font-size:10pt">denk-mal (KeePassHTTP)</li> - <li style="font-size:10pt">kylemanna (YubiKey)</li> - <li style="font-size:10pt">seatedscribe (CSV Importer)</li> - <li style="font-size:10pt">pgalves (Inline Messages)</li> - </ul> - <p style="font-size:x-large; font-weight:600;">Translations:</p> - <ul> - <li style="font-size:10pt"><span style="font-weight:600;">Chinese:</span> Biggulu, ligyxy, BestSteve</li> - <li style="font-size:10pt"><span style="font-weight:600;">Czech:</span> pavelb, JosefVitu</li> - <li style="font-size:10pt"><span style="font-weight:600;">Dutch:</span> Vistaus, KnooL, apie</li> - <li style="font-size:10pt"><span style="font-weight:600;">Finnish:</span> MawKKe</li> - <li style="font-size:10pt"><span style="font-weight:600;">French:</span> Scrat15, frgnca, gilbsgilbs, gtalbot, iannick, kyodev, logut</li> - <li style="font-size:10pt"><span style="font-weight:600;">German:</span> Calyrx, DavidHamburg, antsas, codejunky, jensrutschmann, montilo, omnisome4, origin_de, pcrcoding, phoerious, rgloor, vlenzer</li> - <li style="font-size:10pt"><span style="font-weight:600;">Greek:</span> nplatis</li> - <li style="font-size:10pt"><span style="font-weight:600;">Italian:</span> TheZ3ro, FranzMari, Mte90, tosky</li> - <li style="font-size:10pt"><span style="font-weight:600;">Kazakh:</span> sotrud_nik</li> - <li style="font-size:10pt"><span style="font-weight:600;">Lithuanian:</span> Moo</li> - <li style="font-size:10pt"><span style="font-weight:600;">Polish:</span> konradmb, mrerexx</li> - <li style="font-size:10pt"><span style="font-weight:600;">Portuguese: </span>vitor895, weslly, American_Jesus, mihai.ile</li> - <li style="font-size:10pt"><span style="font-weight:600;">Russian:</span> vsvyatski, KekcuHa, wkill95</li> - <li style="font-size:10pt"><span style="font-weight:600;">Spanish:</span> EdwardNavarro, antifaz, piegope, pquin, vsvyatski</li> - <li style="font-size:10pt"><span style="font-weight:600;">Swedish:</span> henziger</li> - </ul> - </body></html> + + + true + + + + 0 + 0 + 418 + 848 + + + + + + + + 0 + 0 + + + + IBeamCursor + + + <h2>Code:</h2> +<ul> +<li>debfx (KeePassX) </li> +<li>BlueIce (KeePassX) </li> +<li>droidmonkey </li> +<li>phoerious </li> +<li>TheZ3ro </li> +<li>louib </li> +<li >weslly </li> +<li>keithbennett (KeePassHTTP) </li> +<li>Typz (KeePassHTTP) </li> +<li>denk-mal (KeePassHTTP) </li> +<li>kylemanna (YubiKey) </li> +<li>seatedscribe (CSV Importer) </li> +<li>pgalves (Inline Messages) </li> +</ul> + +<h2>Translations:</h2> +<ul> +<li><b>Chinese:</b> Biggulu, ligyxy, BestSteve </li> +<li><b>Czech:</b> pavelb, JosefVitu </li> +<li><b>Dutch:</b> Vistaus, KnooL, apie </li> +<li><b>Finnish:</b> MawKKe </li> +<li><b>French:</b> Scrat15, frgnca, gilbsgilbs, gtalbot, iannick, kyodev, logut </li> +<li><b>German:</b> Calyrx, DavidHamburg, antsas, codejunky, jensrutschmann, montilo, omnisome4, origin_de, pcrcoding, phoerious, rgloor, vlenzer </li> +<li><b>Greek:</b> nplatis </li> +<li><b>Italian:</b> TheZ3ro, FranzMari, Mte90, tosky </li> +<li><b>Kazakh:</b> sotrud_nik </li> +<li><b>Lithuanian:</b> Moo </li> +<li><b>Polish:</b> konradmb, mrerexx </li> +<li><b>Portuguese: </b>vitor895, weslly, American_Jesus, mihai.ile </li> +<li><b>Russian:</b> vsvyatski, KekcuHa, wkill95 </li> +<li><b>Spanish:</b> EdwardNavarro, antifaz, piegope, pquin, vsvyatski </li> +<li><b>Swedish:</b> henziger </li> +</ul> + + + Qt::RichText + + + true + + + Qt::TextBrowserInteraction + + + + + @@ -268,21 +298,21 @@ - <html><head/><body><p>Include the following information whenever you report a bug:</p></body></html> + Include the following information whenever you report a bug: - - - 0 - 0 - - true + + + + + Qt::TextBrowserInteraction + diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 0d40e89e8..f1d5f866c 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -552,8 +552,14 @@ void MainWindow::updateWindowTitle() QString customWindowTitlePart; int stackedWidgetIndex = m_ui->stackedWidget->currentIndex(); int tabWidgetIndex = m_ui->tabWidget->currentIndex(); + bool isModified = m_ui->tabWidget->isModified(tabWidgetIndex); + if (stackedWidgetIndex == DatabaseTabScreen && tabWidgetIndex != -1) { customWindowTitlePart = m_ui->tabWidget->tabText(tabWidgetIndex); + if (isModified) { + // remove asterisk '*' from title + customWindowTitlePart.remove(customWindowTitlePart.size() - 1, 1); + } if (m_ui->tabWidget->readOnly(tabWidgetIndex)) { customWindowTitlePart.append(QString(" [%1]").arg(tr("read-only"))); } @@ -565,7 +571,7 @@ void MainWindow::updateWindowTitle() if (customWindowTitlePart.isEmpty()) { windowTitle = BaseWindowTitle; } else { - windowTitle = QString("%1 - %2").arg(customWindowTitlePart, BaseWindowTitle); + windowTitle = QString("%1[*] - %2").arg(customWindowTitlePart, BaseWindowTitle); } if (customWindowTitlePart.isEmpty() || stackedWidgetIndex == 1) { @@ -574,7 +580,7 @@ void MainWindow::updateWindowTitle() setWindowFilePath(m_ui->tabWidget->databasePath(tabWidgetIndex)); } - setWindowModified(m_ui->tabWidget->isModified(tabWidgetIndex)); + setWindowModified(isModified); setWindowTitle(windowTitle); } diff --git a/src/gui/SettingsWidget.cpp b/src/gui/SettingsWidget.cpp index 864a6365c..04d9e082f 100644 --- a/src/gui/SettingsWidget.cpp +++ b/src/gui/SettingsWidget.cpp @@ -142,6 +142,7 @@ void SettingsWidget::loadSettings() if (m_globalAutoTypeKey > 0 && m_globalAutoTypeModifiers > 0) { m_generalUi->autoTypeShortcutWidget->setShortcut(m_globalAutoTypeKey, m_globalAutoTypeModifiers); } + m_generalUi->autoTypeDelaySpinBox->setValue(config()->get("AutoTypeDelay").toInt()); } @@ -208,6 +209,7 @@ void SettingsWidget::saveSettings() config()->set("GlobalAutoTypeKey", m_generalUi->autoTypeShortcutWidget->key()); config()->set("GlobalAutoTypeModifiers", static_cast(m_generalUi->autoTypeShortcutWidget->modifiers())); + config()->set("AutoTypeDelay", m_generalUi->autoTypeDelaySpinBox->value()); } config()->set("security/clearclipboard", m_secUi->clearClipboardCheckBox->isChecked()); config()->set("security/clearclipboardtimeout", m_secUi->clearClipboardSpinBox->value()); diff --git a/src/gui/SettingsWidgetGeneral.ui b/src/gui/SettingsWidgetGeneral.ui index e75631995..2854b7560 100644 --- a/src/gui/SettingsWidgetGeneral.ui +++ b/src/gui/SettingsWidgetGeneral.ui @@ -325,27 +325,18 @@ - - - 15 + + + 10 - - - - - 0 - 0 - - + + Global Auto-Type shortcut - - Qt::AlignLeading - - + @@ -355,6 +346,35 @@ + + + + Auto-Type delay + + + + + + + + 0 + 0 + + + + ms + + + + + + 999 + + + 25 + + +