From 3c84bdca490619d27d966f86401f5feca23d163d Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Mon, 27 Jul 2026 21:03:57 +0100 Subject: [PATCH] fix(autofill): return to the tray after picking in the multi-match picker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only the quick-search path captured whether the window was tray-hidden and fed it back as hide_after; JS never sends that parameter from the autofill picker, so Ctrl+Shift+L pulled the window out of the tray and left it on the desktop. Capture it in BridgeAutofillRequest instead, when the hotkey fires — by execute time the picker has already restored the window and the state is gone. Same rule as quick-search: tray-hidden only, a taskbar-minimised window is not sent to the tray it never came from. Co-Authored-By: Claude Opus 5 --- TEST_SCENARIOS.md | 6 ++++++ delphi-backend/UMainForm.pas | 14 +++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/TEST_SCENARIOS.md b/TEST_SCENARIOS.md index 772e934..8eeb6f4 100644 --- a/TEST_SCENARIOS.md +++ b/TEST_SCENARIOS.md @@ -310,6 +310,12 @@ l'éditeur slideover : créer + éditer une entrée, ajouter/retirer des tags, - **ACTION** : verrouiller → `Ctrl+Shift+T`. - **ATTENDU** : l'app revient au premier plan avec le focus sur le master password (même comportement que les autres hotkeys), pas de no-op silencieux. +### H9 · retour au tray après un pick dans le picker ✅ +- **ACTION** : app **au tray** → `Ctrl+Shift+L` depuis une autre app sur un titre à plusieurs candidats → le picker sort la fenêtre du tray → choisir une entrée. +- **ATTENDU** : le remplissage se fait puis l'app **repart au tray**, comme elle est venue. +- **Variantes** : match unique (pas de picker) → reste au tray ; app déjà visible → reste visible ; app **minimisée dans la barre des tâches** → n'est **pas** envoyée au tray (`not Self.Visible` est faux pour une fenêtre iconique) ; picker fermé sans choisir → l'app reste où elle est et le hotkey suivant n'hérite pas de l'état capturé. +- **Historique** : seul le chemin quick-search capturait « était cachée » (`LWasHidden`) et le faisait remonter via `hide_after` ; JS n'envoie jamais ce paramètre depuis le picker d'autofill, donc l'app restait sur le bureau. Capturé désormais côté Delphi dans `BridgeAutofillRequest`, au moment du hotkey — après, le picker a déjà détruit l'information. + ### H7 · combo déjà pris par une autre application ✅ - **ACTION** : assigner à un hotkey un combo qu'une autre app tient déjà en global (ex. `Ctrl+Shift+Q` si Quick Assist / un lanceur l'occupe ; sinon, tester en assignant le même combo dans deux apps). - **ATTENDU** : toast **nommant le combo refusé** — « Already used by another app: 2FA code — pick another combo » — **et** un ⚠ ambre persistant sur cette ligne de Settings, **et** une pastille ambre sur l'entrée *Settings* de la sidebar (seul indice hors du panneau). Le toast d'avertissement reste ~10 s et se ferme au clic. Les **autres** hotkeys restent fonctionnels (enregistrement best-effort, pas de tout-ou-rien). diff --git a/delphi-backend/UMainForm.pas b/delphi-backend/UMainForm.pas index fed16c0..8d2b0e0 100644 --- a/delphi-backend/UMainForm.pas +++ b/delphi-backend/UMainForm.pas @@ -120,6 +120,11 @@ type // SendInput because Win10/11 anti-focus-stealing rules then refuse to // hand focus to the target window. FAutofillPendingHide: Boolean; + // Same idea for the Ctrl+Shift+L/P/T hotkeys: captured when the hotkey + // fires, because the multi-match picker pulls the window out of the tray + // before the user picks, so by execute time the state is already lost. + // JS never sends hide_after on this path — only quick-search does. + FAutofillHotkeyWasHidden: Boolean; // True when the pending autofill should type ONLY the username (quick // search "autofill username" — right-click / Shift+Enter in fill mode). FAutofillPendingUserOnly: Boolean; @@ -1056,7 +1061,8 @@ begin FAutofillPendingUser := GetParam('username'); FAutofillPendingPass := GetParam('password'); FAutofillPendingHWND := FAutofillTargetHWND; - FAutofillPendingHide := GetParam('hide_after') = '1'; + FAutofillPendingHide := (GetParam('hide_after') = '1') or FAutofillHotkeyWasHidden; + FAutofillHotkeyWasHidden := False; FAutofillPendingUserOnly := GetParam('field') = 'user'; FAutofillPendingClear := GetParam('clear') <> '0'; // absent = ON FAutofillPendingNotify := GetParam('notify') <> '0'; // absent = ON @@ -1081,6 +1087,9 @@ begin if FAutofillTargetHWND <> 0 then SetForegroundWindow(FAutofillTargetHWND); FAutofillTargetHWND := 0; + // Cancelled: the window stays wherever the user left it, and the captured + // state must not leak into the next hotkey. + FAutofillHotkeyWasHidden := False; LogLine('Autofill cancelled (no match or dismissed)'); end @@ -1775,6 +1784,9 @@ var begin if not FServer.Active then Exit; FAutofillTargetHWND := ATargetHWND; + // Tray-hidden only, like the quick-search path: a window merely minimised to + // the taskbar must not come back as a tray icon it never was. + FAutofillHotkeyWasHidden := not Self.Visible; // Escape the title for safe injection into a JS string literal. LTitle := ATitle;