fix(hotkeys): never touch the window while a native modal owns it

Ctrl+Shift+Q and Ctrl+Shift+A call RestoreWindowFromTray before JS can refuse, so a JS guard is too late by construction. Restoring the owner of a Save As dialog stranded it behind everything and the app looked frozen while it was only disabled.

NativeModalActive tests IsWindowEnabled - Windows disables the owner for the lifetime of the modal - and brings the dialog back to front via GetLastActivePopup instead of merely refusing.
This commit is contained in:
r-zakarya
2026-08-01 18:40:45 +01:00
parent 42d2d6fda5
commit 1c0423680d
2 changed files with 31 additions and 0 deletions
+3
View File
@@ -182,6 +182,9 @@ plus bas.
- **ATTENDU** : le dialogue est toujours là, au premier plan de l'application, et répond. L'app n'est cliquable qu'à travers lui — c'est normal, une boîte native modale désactive sa fenêtre propriétaire tant qu'on n'a pas répondu.
- **Historique** : le refus « busy » appelait `cancelAutofill()`, dont le chemin Delphi fait un `SetForegroundWindow` vers la fenêtre capturée. Le dialogue passait **derrière** l'autre application, et l'app paraissait figée : bloquée par une modale devenue introuvable. `refocus=0` distingue désormais **refuser** une demande (ne rien déplacer) de **terminer** une interaction utilisateur (rendre le focus à la cible).
- **Généralisation** : un refus ne doit jamais déplacer une fenêtre. Tout nouveau garde qui annule une action doit passer par ce chemin.
- **Deuxième cause, côté Delphi** : `Ctrl+Shift+Q` et `Ctrl+Shift+A` appellent `RestoreWindowFromTray` **avant** que JS ne puisse refuser — un garde JS arrive trop tard par construction. Restaurer la fenêtre propriétaire d'une modale native laisse le dialogue en rade derrière tout le reste : l'app semble gelée alors qu'elle est simplement *désactivée* par une boîte devenue introuvable (au point qu'il fallait un utilitaire de capture d'écran pour la faire réapparaître).
- **Garde** : `NativeModalActive` teste `IsWindowEnabled` sur notre fenêtre — Windows la désactive tant qu'une modale native lui appartient. Posé en tête des **quatre** points d'entrée hotkey (quick search hotkey + menu tray, new entry, autofill). Il ne se contente pas de refuser : il **ramène le dialogue au premier plan** via `GetLastActivePopup`, ce qui est précisément ce dont l'utilisateur a besoin.
- **ATTENDU après correctif** : pendant l'« Enregistrer sous », n'importe quel hotkey **fait réapparaître le dialogue** au lieu de l'enterrer.
### B14 · dialogues natifs ouverts par un clic programmatique
- **ACTION** : `A` ouverte + **dirty** → (a) Settings → *Import vault* ; (b) télécharger une pièce jointe (fallback web) ; (c) *Upload icon* ; (d) joindre un fichier.