From 772122831998f8330ea2399cf35ea1356d37e380 Mon Sep 17 00:00:00 2001 From: Rushi chaganti <71964737+RushiChaganti@users.noreply.github.com> Date: Mon, 20 Jul 2026 06:19:16 +0530 Subject: [PATCH] shell: handle CTRL+BACKSPACE to clear filter (#6307) * emoji panel: handle CTRL+BACKSPACE to clear filter * shell: handle CTRL+BACKSPACE to clear filter in all search overlays * Indentation fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * menu filters: align keyboard editing with Qt standard shortcuts * menu filters: extract shared filter-editing helpers * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * potential fix for pull request findings * Only treat filter edit keys as edits when they change the text Backspace/Ctrl+U on an empty filter no longer calls setFilter(""), which was resetting the list selection back to the top. This also lets the menu's empty-filter Backspace fall through to goBack() with any modifier held, as it did before the Util extraction. Co-Authored-By: Claude Fable 5 --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: David Heinemeier Hansson Co-authored-by: Claude Fable 5 --- shell/Commons/Util.qml | 24 ++++++++++++++++++++++ shell/plugins/clipboard/Clipboard.qml | 4 ++-- shell/plugins/emojis/Emojis.qml | 4 ++-- shell/plugins/image-picker/ImagePicker.qml | 5 ++--- shell/plugins/launcher/Launcher.qml | 4 ++-- shell/plugins/menu/Menu.qml | 8 +++++--- shell/plugins/reminders/ReminderFlow.qml | 4 ++-- 7 files changed, 39 insertions(+), 14 deletions(-) diff --git a/shell/Commons/Util.qml b/shell/Commons/Util.qml index d92091ee..70ba0c58 100644 --- a/shell/Commons/Util.qml +++ b/shell/Commons/Util.qml @@ -77,6 +77,30 @@ QtObject { } } + // Standard Qt text-editing keys shared by every searchable panel's filter: + // Backspace delete previous character + // Ctrl+Backspace delete previous word (Qt DeleteStartOfWord) + // Ctrl+U clear the whole field + // True only when the event would actually change the text, so an empty + // filter never swallows the key — panels keep their own empty-filter + // fallbacks (e.g. menu back-navigation) in later branches. + function editsFilter(event, text) { + if (!text) return false + // Alt/Meta-modified sequences belong to other shortcuts — never edit here. + if (event.modifiers & (Qt.AltModifier | Qt.MetaModifier)) return false + if (event.key === Qt.Key_U) // Ctrl+U only (not Ctrl+Shift+U → Unicode input) + return event.modifiers === Qt.ControlModifier + return event.key === Qt.Key_Backspace // plain, Shift, or Ctrl Backspace + } + + // New filter text after applying an edit key. Assumes editsFilter(event, text). + function editedFilter(event, text) { + if (event.key === Qt.Key_U) return "" // Ctrl+U: clear + if (event.modifiers & Qt.ControlModifier) // Ctrl+Backspace: word + return text.replace(/\s+$/, "").replace(/\S+$/, "") + return text.slice(0, -1) // Backspace: char + } + // Layout normalization shared by bar config consumers // so the two never drift. Entries are deep-cloned to decouple from the // input config; consumers can mutate without leaking back to shell.json. diff --git a/shell/plugins/clipboard/Clipboard.qml b/shell/plugins/clipboard/Clipboard.qml index 6fc216f4..95a04f7f 100644 --- a/shell/plugins/clipboard/Clipboard.qml +++ b/shell/plugins/clipboard/Clipboard.qml @@ -345,8 +345,8 @@ Item { if (root.filterText) root.setFilter("") else root.close() event.accepted = true - } else if (event.key === Qt.Key_Backspace) { - if (root.filterText.length > 0) root.setFilter(root.filterText.slice(0, -1)) + } else if (Util.editsFilter(event, root.filterText)) { + root.setFilter(Util.editedFilter(event, root.filterText)) event.accepted = true } else if (event.key === Qt.Key_Delete) { if (event.modifiers & Qt.ShiftModifier) root.requestClearHistory() diff --git a/shell/plugins/emojis/Emojis.qml b/shell/plugins/emojis/Emojis.qml index b2b7bf4b..cbdf541d 100644 --- a/shell/plugins/emojis/Emojis.qml +++ b/shell/plugins/emojis/Emojis.qml @@ -200,8 +200,8 @@ Item { if (root.filterText) root.setFilter("") else root.dismiss() event.accepted = true - } else if (event.key === Qt.Key_Backspace) { - if (root.filterText.length > 0) root.setFilter(root.filterText.slice(0, -1)) + } else if (Util.editsFilter(event, root.filterText)) { + root.setFilter(Util.editedFilter(event, root.filterText)) event.accepted = true } else if (event.key === Qt.Key_Left) { root.select(-1) diff --git a/shell/plugins/image-picker/ImagePicker.qml b/shell/plugins/image-picker/ImagePicker.qml index f85f32c0..47c5eb53 100644 --- a/shell/plugins/image-picker/ImagePicker.qml +++ b/shell/plugins/image-picker/ImagePicker.qml @@ -417,9 +417,8 @@ Item { } else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { root.applySelected() event.accepted = true - } else if (event.key === Qt.Key_Backspace && root.filterable) { - if (root.filterText.length > 0) - root.updateFilter(root.filterText.slice(0, -1)) + } else if (root.filterable && Util.editsFilter(event, root.filterText)) { + root.updateFilter(Util.editedFilter(event, root.filterText)) event.accepted = true } else if (event.key === Qt.Key_Left || (event.key === Qt.Key_Tab && event.modifiers & Qt.ShiftModifier) || event.key === Qt.Key_Backtab) { root.selectAdjacent(-1) diff --git a/shell/plugins/launcher/Launcher.qml b/shell/plugins/launcher/Launcher.qml index 00b1f9e5..1cf1022b 100644 --- a/shell/plugins/launcher/Launcher.qml +++ b/shell/plugins/launcher/Launcher.qml @@ -464,8 +464,8 @@ Item { if (root.filterText.length > 0) root.setFilter("") else root.dismiss() event.accepted = true - } else if (event.key === Qt.Key_Backspace) { - if (root.filterText.length > 0) root.setFilter(root.filterText.slice(0, -1)) + } else if (Util.editsFilter(event, root.filterText)) { + root.setFilter(Util.editedFilter(event, root.filterText)) event.accepted = true } else if (event.key === Qt.Key_Up) { root.select(-1) diff --git a/shell/plugins/menu/Menu.qml b/shell/plugins/menu/Menu.qml index 1cf5d36d..b31f21bc 100644 --- a/shell/plugins/menu/Menu.qml +++ b/shell/plugins/menu/Menu.qml @@ -837,9 +837,11 @@ Item { if (root.filterText) root.setFilter("") else root.cancel() event.accepted = true - } else if (event.key === Qt.Key_Backspace) { - if (root.filterText.length > 0) root.setFilter(root.filterText.slice(0, -1)) - else root.goBack() + } else if (Util.editsFilter(event, root.filterText)) { + root.setFilter(Util.editedFilter(event, root.filterText)) + event.accepted = true + } else if (event.key === Qt.Key_Backspace && !root.filterText) { + root.goBack() event.accepted = true } else if (event.key === Qt.Key_Up) { root.select(-1) diff --git a/shell/plugins/reminders/ReminderFlow.qml b/shell/plugins/reminders/ReminderFlow.qml index f8d009ad..bc6616db 100644 --- a/shell/plugins/reminders/ReminderFlow.qml +++ b/shell/plugins/reminders/ReminderFlow.qml @@ -135,8 +135,8 @@ Item { if (root.filterText) root.setFilter("") else root.dismiss() event.accepted = true - } else if (event.key === Qt.Key_Backspace) { - if (root.filterText.length > 0) root.setFilter(root.filterText.slice(0, -1)) + } else if (Util.editsFilter(event, root.filterText)) { + root.setFilter(Util.editedFilter(event, root.filterText)) event.accepted = true } else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { root.submit()