From 38ba208455f39107dc4d98d7089adb4cafc19029 Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Tue, 28 Jul 2026 15:32:25 +0100 Subject: [PATCH] fix(autofill): stop sending Ctrl+A after the Tab in a full fill Tabbing into an input already selects its whole content, so the second clear was redundant. Where Tab lands on something that is not editable - a link, a reveal button, the document, as on the Reddit login form - Ctrl+A selected the entire page instead and the password went nowhere. Co-Authored-By: Claude Opus 5 --- TEST_SCENARIOS.md | 12 +++++++++--- delphi-backend/Source/PM.Bridge.pas | 6 +++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/TEST_SCENARIOS.md b/TEST_SCENARIOS.md index 33b3895..3560f46 100644 --- a/TEST_SCENARIOS.md +++ b/TEST_SCENARIOS.md @@ -328,6 +328,12 @@ garde refusait, à raison, de pré-remplir avec « Password Manager »). - **Non-régression** : après un autofill (pick ou Esc), le focus reste sur la fenêtre **remplie** — ces deux chemins passent `AReturnForeground = False`, ayant déjà placé le premier plan eux-mêmes. - **Historique — quatre tentatives, toutes tranchées par le log** : (1) rendre le focus *après* avoir caché la fenêtre — Windows n'autorise que le propriétaire courant du premier plan à le céder, l'appel était silencieusement refusé ; (2) échantillonner le premier plan au moment du besoin — il vaut alors *notre* fenêtre, la capture se rejetait elle-même et n'apprenait jamais rien (`prev=` à chaque fois) ; (3) capturer au clic sur l'icône du tray — on obtient une fenêtre du **shell** (`NotifyIconOverflowWindow`, « Fenêtre de dépassement de capacité de la barre d'état système ») ; (4) consommer la valeur après usage — le premier masquage marchait, les suivants plus. **Solution** : un hook `EVENT_SYSTEM_FOREGROUND` (`WINEVENT_OUTOFCONTEXT`, aucune injection) note *chaque* changement et garde le dernier qui n'est ni à nous ni au shell ; la restitution se fait **avant** de cacher. +### H13 · pas de `Ctrl+A` après le Tab (formulaires type Reddit) +- **ACTION** : `Ctrl+Shift+L` sur un formulaire où **Tab depuis le username ne mène pas au champ mot de passe** (page de connexion Reddit : le Tab tombe à côté). +- **ATTENDU** : plus de **sélection de toute la page**. Le mot de passe peut malgré tout ne pas être saisi si le focus n'a pas atterri dans un champ éditable — c'est la limite du Tab, pas un bug de plus. +- **Contournement pour ces formulaires** : cliquer le champ mot de passe puis `Ctrl+Shift+P` (remplissage password seul, aucun Tab). +- **Historique** : la séquence envoyait `Ctrl+A + Del` avant **chaque** champ. Après le Tab c'était doublement mauvais : redondant (arriver par Tab sélectionne déjà tout le contenu du champ, cf. K1) et destructeur quand le Tab tombe sur un lien, un bouton ou le document — `Ctrl+A` sélectionne alors la page entière et la frappe se perd. Retiré ; celui d'avant le username reste (l'utilisateur y a placé le curseur par un clic, rien n'est sélectionné). + ### H11 · l'application précédente réduite reste réduite - **ACTION** : depuis X, **réduire X** dans la barre des tâches → ouvrir le coffre (icône du tray) → le fermer par la croix. - **ATTENDU** : X **reste réduite**. Le focus part où Windows décide ; on ne rouvre pas une fenêtre que l'utilisateur a rangée. @@ -455,9 +461,9 @@ est précisément le piège de coalescence documenté dans CLAUDE.md. - **OBSERVÉ** : le **username** n'est pas effacé (la frappe s'insère), mais l'ancien **password** disparaît et est remplacé. - **C'EST NORMAL** — vérifié de bout en bout : le JS envoie `&clear=0`, Delphi - met `FAutofillPendingClear := False`, et les **deux** `ClearFieldIfWanted` - (avant username et avant password) sortent immédiatement. Notre code - n'efface rien. + met `FAutofillPendingClear := False`. Notre code n'efface rien. (Depuis le + correctif H13 il n'y a de toute façon **plus qu'un seul** `ClearFieldIfWanted`, + avant le username : celui d'avant le password a été retiré.) La cause est le **Tab** du pipeline `username → Tab → password` : arriver dans un champ par Tab **sélectionne tout son contenu** (comportement standard Windows / navigateur), et la frappe remplace la sélection. Le username, lui, diff --git a/delphi-backend/Source/PM.Bridge.pas b/delphi-backend/Source/PM.Bridge.pas index 55d72f5..c707b56 100644 --- a/delphi-backend/Source/PM.Bridge.pas +++ b/delphi-backend/Source/PM.Bridge.pas @@ -1586,7 +1586,11 @@ begin ForceReleaseModifiers; SendVKey(VK_TAB); Sleep(200); - ClearFieldIfWanted; + // No clear here: tabbing INTO an input already selects its whole content, + // so typing replaces it. Sending Ctrl+A as well is not just redundant — when + // Tab lands somewhere that is not an editable field (a link, a reveal + // button, the document itself, as on the Reddit login form) it selects the + // ENTIRE PAGE, and the password is then typed into nothing. SendUnicodeString(APassword); finally // Re-register with the LIVE combo (user may have rebound it), not the