From af753f003e842aa8db632e4bb04a1e9ee5ddb9b3 Mon Sep 17 00:00:00 2001 From: Juzu-O Date: Sun, 10 Aug 2025 06:10:04 +0300 Subject: [PATCH] Add URL auto-type and copy options to auto-type selection popup and menus (#12341) * Added "Type {URL}" option to the auto-type selection popup right-click context menu * Added "Copy {URL}" option to the auto-type selection popup right-click context menu * Added keyboard shortcuts: CTRL+4 for "Type {URL}" and CTRL+SHIFT+4 for "Copy {URL}" * Updated "Use Virtual Keyboard" shortcut from CTRL+4 to CTRL+5 to avoid inconsistency with order of shortcuts * Added URL auto-type options "{URL}" and "{URL}{ENTER}" to main window entry view right-click menu * Added URL auto-type options "{URL}" and "{URL}{ENTER}" to toolbar auto-type button dropdown menu * Added translation strings for "Type {URL}" and "Copy {URL}" to support internationalization --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: juzu-o <3142026+juzu-o@users.noreply.github.com> Co-authored-by: Jonathan White --- share/translations/keepassxc_en.ts | 27 +++++++++++++++-------- src/autotype/AutoTypeSelectDialog.cpp | 31 ++++++++++++++++++++++++++- src/autotype/AutoTypeSelectDialog.ui | 15 +++++++------ src/gui/DatabaseWidget.cpp | 10 +++++++++ src/gui/DatabaseWidget.h | 2 ++ src/gui/MainWindow.cpp | 9 ++++++++ src/gui/MainWindow.ui | 28 ++++++++++++++++++++++++ 7 files changed, 105 insertions(+), 17 deletions(-) diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts index e0007af7c..22864da6f 100644 --- a/share/translations/keepassxc_en.ts +++ b/share/translations/keepassxc_en.ts @@ -800,15 +800,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<br/> -Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> - - Search all open databases @@ -853,6 +844,24 @@ Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> Use Virtual Keyboard + + <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 - Type URL<br/> +Ctrl+5 - Use Virtual Keyboard (Windows Only)</p> + + + + Type {URL} + + + + Copy URL + + BrowserAccessControlDialog diff --git a/src/autotype/AutoTypeSelectDialog.cpp b/src/autotype/AutoTypeSelectDialog.cpp index eb4b10a47..826ee5e33 100644 --- a/src/autotype/AutoTypeSelectDialog.cpp +++ b/src/autotype/AutoTypeSelectDialog.cpp @@ -37,6 +37,7 @@ enum MENU_FIELD USERNAME = 1, PASSWORD, TOTP, + URL, }; AutoTypeSelectDialog::AutoTypeSelectDialog(QWidget* parent) @@ -267,6 +268,7 @@ void AutoTypeSelectDialog::updateActionMenu(const AutoTypeMatch& match) bool hasUsername = !match.first->username().isEmpty(); bool hasPassword = !match.first->password().isEmpty(); bool hasTotp = match.first->hasValidTotp(); + bool hasUrl = !match.first->url().isEmpty(); for (auto action : m_actionMenu->actions()) { auto prop = action->property(MENU_FIELD_PROP_NAME); @@ -281,6 +283,9 @@ void AutoTypeSelectDialog::updateActionMenu(const AutoTypeMatch& match) case MENU_FIELD::TOTP: action->setEnabled(hasTotp); break; + case MENU_FIELD::URL: + action->setEnabled(hasUrl); + break; } } } @@ -292,15 +297,19 @@ void AutoTypeSelectDialog::buildActionMenu() auto typeUsernameAction = new QAction(icons()->icon("auto-type"), tr("Type {USERNAME}"), this); auto typePasswordAction = new QAction(icons()->icon("auto-type"), tr("Type {PASSWORD}"), this); auto typeTotpAction = new QAction(icons()->icon("auto-type"), tr("Type {TOTP}"), this); + auto typeUrlAction = new QAction(icons()->icon("auto-type"), tr("Type {URL}"), this); auto copyUsernameAction = new QAction(icons()->icon("username-copy"), tr("Copy Username"), this); auto copyPasswordAction = new QAction(icons()->icon("password-copy"), tr("Copy Password"), this); auto copyTotpAction = new QAction(icons()->icon("totp"), tr("Copy TOTP"), this); + auto copyUrlAction = new QAction(icons()->icon("url-copy"), tr("Copy URL"), this); m_actionMenu->addAction(typeUsernameAction); m_actionMenu->addAction(typePasswordAction); m_actionMenu->addAction(typeTotpAction); + m_actionMenu->addAction(typeUrlAction); m_actionMenu->addAction(copyUsernameAction); m_actionMenu->addAction(copyPasswordAction); m_actionMenu->addAction(copyTotpAction); + m_actionMenu->addAction(copyUrlAction); typeUsernameAction->setShortcut(Qt::CTRL + Qt::Key_1); typeUsernameAction->setProperty(MENU_FIELD_PROP_NAME, MENU_FIELD::USERNAME); @@ -326,10 +335,18 @@ void AutoTypeSelectDialog::buildActionMenu() submitAutoTypeMatch(match); }); + typeUrlAction->setShortcut(Qt::CTRL + Qt::Key_4); + typeUrlAction->setProperty(MENU_FIELD_PROP_NAME, MENU_FIELD::URL); + connect(typeUrlAction, &QAction::triggered, this, [&] { + auto match = m_ui->view->currentMatch(); + match.second = "{URL}"; + submitAutoTypeMatch(match); + }); + #ifdef Q_OS_WIN auto typeVirtualAction = new QAction(icons()->icon("auto-type"), tr("Use Virtual Keyboard"), nullptr); m_actionMenu->insertAction(copyUsernameAction, typeVirtualAction); - typeVirtualAction->setShortcut(Qt::CTRL + Qt::Key_4); + typeVirtualAction->setShortcut(Qt::CTRL + Qt::Key_5); connect(typeVirtualAction, &QAction::triggered, this, [&] { m_virtualMode = true; activateCurrentMatch(); @@ -366,17 +383,29 @@ void AutoTypeSelectDialog::buildActionMenu() } }); + copyUrlAction->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_4); + copyUrlAction->setProperty(MENU_FIELD_PROP_NAME, MENU_FIELD::URL); + connect(copyUrlAction, &QAction::triggered, this, [&] { + auto entry = m_ui->view->currentMatch().first; + if (entry) { + clipboard()->setText(entry->resolvePlaceholder(entry->url())); + reject(); + } + }); + // 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); + typeUrlAction->setShortcutVisibleInContextMenu(true); #if defined(Q_OS_WIN) typeVirtualAction->setShortcutVisibleInContextMenu(true); #endif copyUsernameAction->setShortcutVisibleInContextMenu(true); copyPasswordAction->setShortcutVisibleInContextMenu(true); copyTotpAction->setShortcutVisibleInContextMenu(true); + copyUrlAction->setShortcutVisibleInContextMenu(true); } void AutoTypeSelectDialog::showEvent(QShowEvent* event) diff --git a/src/autotype/AutoTypeSelectDialog.ui b/src/autotype/AutoTypeSelectDialog.ui index 0c5e3c8c2..0c0f6561e 100644 --- a/src/autotype/AutoTypeSelectDialog.ui +++ b/src/autotype/AutoTypeSelectDialog.ui @@ -50,13 +50,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<br/> -Ctrl+4 - Use Virtual Keyboard (Windows Only)</p> + + <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 - Type URL<br/> +Ctrl+5 - Use Virtual Keyboard (Windows Only)</p> QToolButton { diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index cc6757da8..2edbfe839 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -919,6 +919,16 @@ void DatabaseWidget::performAutoTypeTOTP() performAutoType(QStringLiteral("{TOTP}")); } +void DatabaseWidget::performAutoTypeURL() +{ + performAutoType(QStringLiteral("{URL}")); +} + +void DatabaseWidget::performAutoTypeURLEnter() +{ + performAutoType(QStringLiteral("{URL}{ENTER}")); +} + void DatabaseWidget::openUrl() { auto currentEntry = currentSelectedEntry(); diff --git a/src/gui/DatabaseWidget.h b/src/gui/DatabaseWidget.h index 7f74e9e4e..d990419a2 100644 --- a/src/gui/DatabaseWidget.h +++ b/src/gui/DatabaseWidget.h @@ -202,6 +202,8 @@ public slots: void performAutoTypePassword(); void performAutoTypePasswordEnter(); void performAutoTypeTOTP(); + void performAutoTypeURL(); + void performAutoTypeURLEnter(); void setClipboardTextAndMinimize(const QString& text); void openUrl(); void downloadSelectedFavicons(); diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index f154824d9..3bba30f04 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -167,6 +167,8 @@ MainWindow::MainWindow() autotypeMenu->addAction(m_ui->actionEntryAutoTypePassword); autotypeMenu->addAction(m_ui->actionEntryAutoTypePasswordEnter); autotypeMenu->addAction(m_ui->actionEntryAutoTypeTOTP); + autotypeMenu->addAction(m_ui->actionEntryAutoTypeURL); + autotypeMenu->addAction(m_ui->actionEntryAutoTypeURLEnter); m_ui->actionEntryAutoType->setMenu(autotypeMenu); auto autoTypeButton = qobject_cast(m_ui->toolBar->widgetForAction(m_ui->actionEntryAutoType)); if (autoTypeButton) { @@ -417,6 +419,8 @@ MainWindow::MainWindow() m_ui->actionEntryAutoTypePassword->setIcon(icons()->icon("auto-type")); m_ui->actionEntryAutoTypePasswordEnter->setIcon(icons()->icon("auto-type")); m_ui->actionEntryAutoTypeTOTP->setIcon(icons()->icon("auto-type")); + m_ui->actionEntryAutoTypeURL->setIcon(icons()->icon("auto-type")); + m_ui->actionEntryAutoTypeURLEnter->setIcon(icons()->icon("auto-type")); m_ui->actionEntryMoveUp->setIcon(icons()->icon("move-up")); m_ui->actionEntryMoveDown->setIcon(icons()->icon("move-down")); m_ui->actionEntryCopyUsername->setIcon(icons()->icon("username-copy")); @@ -556,6 +560,9 @@ MainWindow::MainWindow() m_actionMultiplexer.connect( m_ui->actionEntryAutoTypePasswordEnter, SIGNAL(triggered()), SLOT(performAutoTypePasswordEnter())); m_actionMultiplexer.connect(m_ui->actionEntryAutoTypeTOTP, SIGNAL(triggered()), SLOT(performAutoTypeTOTP())); + m_actionMultiplexer.connect(m_ui->actionEntryAutoTypeURL, SIGNAL(triggered()), SLOT(performAutoTypeURL())); + m_actionMultiplexer.connect( + m_ui->actionEntryAutoTypeURLEnter, SIGNAL(triggered()), SLOT(performAutoTypeURLEnter())); m_actionMultiplexer.connect(m_ui->actionEntryOpenUrl, SIGNAL(triggered()), SLOT(openUrl())); m_actionMultiplexer.connect(m_ui->actionEntryDownloadIcon, SIGNAL(triggered()), SLOT(downloadSelectedFavicons())); #ifdef WITH_XC_SSHAGENT @@ -1003,6 +1010,8 @@ void MainWindow::updateMenuActionState() m_ui->actionEntryAutoTypePassword->setEnabled(singleEntrySelected && dbWidget->currentEntryHasPassword()); m_ui->actionEntryAutoTypePasswordEnter->setEnabled(singleEntrySelected && dbWidget->currentEntryHasPassword()); m_ui->actionEntryAutoTypeTOTP->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp()); + m_ui->actionEntryAutoTypeURL->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUrl()); + m_ui->actionEntryAutoTypeURLEnter->setEnabled(singleEntrySelected && dbWidget->currentEntryHasUrl()); m_ui->actionEntryAutoTypeTOTP->setVisible(singleEntrySelected && dbWidget->currentEntryHasTotp()); m_ui->actionEntryOpenUrl->setEnabled(singleEntryOrEditing && dbWidget->currentEntryHasUrl()); m_ui->actionEntryTotp->setEnabled(singleEntrySelected && dbWidget->currentEntryHasTotp()); diff --git a/src/gui/MainWindow.ui b/src/gui/MainWindow.ui index 99f109612..bc0f0535b 100644 --- a/src/gui/MainWindow.ui +++ b/src/gui/MainWindow.ui @@ -759,6 +759,34 @@ {TOTP} + + + false + + + {URL} + + + {URL} + + + {URL} + + + + + false + + + {URL}{ENTER} + + + {URL}{ENTER} + + + {URL}{ENTER} + + Download &Favicon