From 0604cca148c8b67d2b2b6bd93d75b90f44f586be Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Wed, 26 Aug 2026 17:35:36 +0100 Subject: [PATCH] feat(autofill): un bouton Open, et le menu ne passe plus sous la barrette Quand la barrette est allumee, elle est souvent la seule chose de l'application a l'ecran : revenir au coffre ne doit pas demander de retrouver l'icone du tray. Le menu d'opacite passait derriere : le battement qui repose la barrette en tete de la bande TOPMOST cinq fois par seconde recouvrait le menu que la barrette venait d'ouvrir - lui aussi dans cette bande. TrackPopupMenu est modal, donc le minuteur battait pendant tout ce temps. Il s'arrete maintenant le temps du menu. Co-Authored-By: Claude Opus 5 --- CLAUDE.md | 13 +++++++++---- delphi-backend/Source/PM.Bridge.pas | 18 ++++++++++++++++-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 6512be2..2a02db6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -164,9 +164,10 @@ via `settings_json`). Menu du tray → **Lazy mode (fill with the mouse)** : une barrette de trois boutons *Full* / *Password* / *2FA* qui flotte au-dessus de tout et fait -exactement ce que font `Ctrl+Shift+L` / `Ctrl+Shift+P` / `Ctrl+Shift+T`. Un -quatrième bouton `X` la referme — elle flotte au-dessus de tout, s'en -débarrasser doit pouvoir se faire là où elle est, pas seulement depuis le tray. +exactement ce que font `Ctrl+Shift+L` / `Ctrl+Shift+P` / `Ctrl+Shift+T`. Deux +boutons de plus, *Open* et `X` : quand la barrette est allumée, elle est souvent +la seule chose de l'application à l'écran — revenir au coffre ou s'en +débarrasser ne doit pas obliger à retrouver l'icône du tray. **`WS_EX_NOACTIVATE` est toute l'astuce.** Une fenêtre ordinaire prendrait le premier plan au clic — le champ que l'utilisateur vient de cliquer perdrait son @@ -210,7 +211,11 @@ Détails : aussi, et cliquer son fond vide la remonte en tête de cette bande — une barrette posée dessus passe **derrière** et semble avoir disparu. Le même battement de 200 ms la repose (`SetWindowPos … SWP_NOMOVE or SWP_NOSIZE`) ; - sans mouvement ni taille à changer, l'appel ne repeint rien. + sans mouvement ni taille à changer, l'appel ne repeint rien. **Ce battement + s'arrête pendant le menu d'opacité** (`KillTimer` / `SetTimer` autour de + `TrackPopupMenu`, qui est modal) : le menu déroulant est lui aussi dans la + bande `TOPMOST`, et se faisait donc recouvrir par la barrette qui venait de + l'ouvrir. - **Traîner depuis un bouton** : les boutons sont subclassés (`GWLP_WNDPROC`, une seule proc d'origine — même classe). Sur `WM_LBUTTONDOWN`, **`DragDetect`** tranche entre clic et glissement en respectant le seuil réglé par diff --git a/delphi-backend/Source/PM.Bridge.pas b/delphi-backend/Source/PM.Bridge.pas index 63b2b90..7b2bad0 100644 --- a/delphi-backend/Source/PM.Bridge.pas +++ b/delphi-backend/Source/PM.Bridge.pas @@ -403,6 +403,7 @@ const LAZY_ID_PWD = 102; LAZY_ID_TOTP = 103; LAZY_ID_CLOSE = 104; + LAZY_ID_OPEN = 105; // LE SONDAGE PLUTOT QUE TrackMouseEvent. La barrette a quatre fenetres // enfants : passer d'elle a un bouton envoie deja un WM_MOUSELEAVE au parent, // et il faudrait donc suivre la souris sur les cinq fenetres pour recoller @@ -417,7 +418,7 @@ const // Coin haut-gauche retenu, 'x,y'. Meme raison que l'opacite d'etre une pref // DPAPI : la barrette s'allume parfois coffre ferme. LAZY_POS_KEY = 'lazyPos'; - LAZY_W = 236; + LAZY_W = 298; LAZY_H = 40; // Palette de la barrette, en COLORREF ($00BBGGRR - les octets sont INVERSES @@ -1169,6 +1170,12 @@ begin MF_STRING or IfThen(FLazyAlphaPct = CHOICES[I], MF_CHECKED, MF_UNCHECKED), CHOICES[I], PChar(Format('%d%% when the mouse leaves', [CHOICES[I]]))); + // LE BATTEMENT DOIT S'ARRETER PENDANT LE MENU. Il repose la barrette en + // tete de la bande TOPMOST cinq fois par seconde - or le menu deroulant est + // lui aussi dans cette bande, et se retrouvait donc recouvert par la + // barrette qui venait de l'ouvrir. TrackPopupMenu est modal : le minuteur + // continuerait de battre pendant tout ce temps. + KillTimer(FLazyWnd, LAZY_TIMER_ID); GetCursorPos(LPt); // Le proprietaire du menu est la fenetre message-only, JAMAIS la barrette : // TrackPopupMenu exige un SetForegroundWindow pour se refermer tout seul, et @@ -1187,6 +1194,8 @@ begin end; finally DestroyMenu(LMenu); + if FLazyWnd <> 0 then + SetTimer(FLazyWnd, LAZY_TIMER_ID, LAZY_POLL_MS, nil); end; end; @@ -1277,6 +1286,7 @@ begin LAZY_ID_FULL: FireAutofillRequest(akFull); LAZY_ID_PWD: FireAutofillRequest(akPasswordOnly); LAZY_ID_TOTP: FireAutofillRequest(akTotp); + LAZY_ID_OPEN: if Assigned(FOnTrayRestore) then FOnTrayRestore(); LAZY_ID_CLOSE: PostMessage(FMsgWindow, WM_LAZY_CLOSE, 0, 0); end; AMsg.Result := 0; @@ -1333,9 +1343,13 @@ begin MakeButton(LAZY_ID_FULL, 'Full', 5, 56); MakeButton(LAZY_ID_PWD, 'Password', 67, 76); MakeButton(LAZY_ID_TOTP, '2FA', 149, 52); + // Meme raison que le X : quand la barrette est allumee, elle est souvent la + // seule chose de l'application a l'ecran. Revenir au coffre ne doit pas + // demander de retrouver l'icone du tray. + MakeButton(LAZY_ID_OPEN, 'Open', 207, 56); // Fermer la barrette sans passer par le menu du tray : elle flotte au-dessus // de tout, donc s'en debarrasser doit se faire la ou elle est. - MakeButton(LAZY_ID_CLOSE, 'X', 207, 24); + MakeButton(LAZY_ID_CLOSE, 'X', 269, 24); // Bottom right of the WORK area, so it does not start life under the // taskbar. From there the user drags it wherever the login form is.