fix(hotkeys): a locked vault must not hand the foreground back

Both locked-vault paths cancelled the autofill with the default refocus, which returns the foreground to the captured target - right after Delphi had raised our window. Ctrl+Shift+Q flashed for a frame then Notepad took over; Ctrl+Shift+L moved the window twice because focusApp had to take it back.
This commit is contained in:
r-zakarya
2026-08-07 14:48:12 +01:00
parent d242f09c53
commit 476d6660ad
3 changed files with 13 additions and 5 deletions
+3 -2
View File
@@ -459,8 +459,9 @@ l'éditeur slideover : créer + éditer une entrée, ajouter/retirer des tags,
- **ATTENDU** : accepté et actif immédiatement ; **refusé** s'il duplique un des 4 autres hotkeys ; *Reset to defaults* le remet à `Ctrl+Shift+T` ; le réglage survit à un redémarrage (synced via `settings_json`). - **ATTENDU** : accepté et actif immédiatement ; **refusé** s'il duplique un des 4 autres hotkeys ; *Reset to defaults* le remet à `Ctrl+Shift+T` ; le réglage survit à un redémarrage (synced via `settings_json`).
### H5 · coffre verrouillé ✅ ### H5 · coffre verrouillé ✅
- **ACTION** : verrouiller → `Ctrl+Shift+T`. - **ACTION** : verrouiller → `Ctrl+Shift+T`, puis **`Ctrl+Shift+Q`**, depuis une autre application (Notepad).
- **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. - **ATTENDU** : l'app revient au premier plan **et y reste**, focus sur le master password. Pas de no-op silencieux, et **aucun clignotement** : elle ne doit pas apparaître puis rendre la main à l'application de départ.
- **Historique** : les deux chemins « coffre verrouillé » annulaient l'autofill avec le refocus **par défaut**, qui rend volontairement le premier plan à la fenêtre cible — juste après que Delphi ait affiché notre fenêtre. Sur `Ctrl+Shift+Q` ça se voyait comme un flash d'une frame avant le retour à Notepad ; sur `Ctrl+Shift+L` le `focusApp()` qui suit reprenait le focus, donc deux déplacements de fenêtre pour finir là où un seul suffit. Les deux passent maintenant `refocus=false` (cf. B17 : **un refus ne doit jamais déplacer une fenêtre**).
### H9 · retour au tray après un pick dans le picker ✅ ### 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. - **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.
+4 -1
View File
@@ -253,7 +253,10 @@ async function autofillHandleRequest(windowTitle, kind) {
if (!state.cryptoKey || state.locked || !state.token) { if (!state.cryptoKey || state.locked || !state.token) {
// Vault is locked — bring the app to the front so the user can // Vault is locked — bring the app to the front so the user can
// unlock immediately, rather than silently no-op'ing the hotkey. // unlock immediately, rather than silently no-op'ing the hotkey.
Bridge.cancelAutofill(); // refocus=false: the default hands the foreground back to the target,
// which focusApp would then have to take away again — two window moves
// to end where one gets us, and the round trip is visible.
Bridge.cancelAutofill(false);
Bridge.focusApp(); Bridge.focusApp();
setTimeout(() => { setTimeout(() => {
const pwd = document.getElementById('loginPassword'); const pwd = document.getElementById('loginPassword');
+6 -2
View File
@@ -550,8 +550,12 @@ const Bridge = (() => {
if (typeof toast === 'function') if (typeof toast === 'function')
toast('Vault is locked — unlock to search', 'warning'); toast('Vault is locked — unlock to search', 'warning');
// Tell Delphi we cancelled so the captured HWND doesn't // Tell Delphi we cancelled so the captured HWND doesn't
// linger waiting for a never-coming /execute. // linger waiting for a never-coming /execute. refocus=false:
if (forFill && Bridge.cancelAutofill) Bridge.cancelAutofill(); // Delphi has just brought our window up and we put the cursor
// in the master-password field — handing the foreground back
// to the target would undo that, which read as a 1-frame flash
// before the other application took over again.
if (forFill && Bridge.cancelAutofill) Bridge.cancelAutofill(false);
return; return;
} }
if (typeof openQuickSearchModal === 'function') if (typeof openQuickSearchModal === 'function')