From 6b908e73a5fc8f50af2780a183f34ec781d27d7f Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Wed, 26 Aug 2026 17:27:38 +0100 Subject: [PATCH] fix(autofill): la barrette reste au-dessus, et se traine depuis ses boutons TOPMOST n'est pas un rang, c'est une bande. La barre des taches y est aussi, et cliquer son fond vide la remonte en tete de cette bande : une barrette posee dessus passe DERRIERE et semble avoir disparu. Le meme battement de 200 ms la repose. Traine depuis un bouton : les boutons sont subclasses, et DragDetect tranche entre clic et glissement en respectant le seuil regle par l'utilisateur. Sur un clic, on envoie BN_CLICKED a la place du bouton - DragDetect a avale le WM_LBUTTONUP, lui rendre la main le laisserait enfonce pour toujours. Co-Authored-By: Claude Opus 5 --- CLAUDE.md | 12 +++++++ delphi-backend/Source/PM.Bridge.pas | 53 +++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 42e7862..6512be2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -206,6 +206,18 @@ Détails : détruirait le `NOACTIVATE` qui la fait fonctionner. Deux portes vers ce menu — `WM_NCRBUTTONUP` (le fond est non-client à cause de `HTCAPTION`) et `WM_CONTEXTMENU` (remonté par les boutons). +- **`TOPMOST` n'est pas un rang, c'est une bande** : la barre des tâches y est + 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. +- **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 + l'utilisateur. Glissement → `ReleaseCapture` + `WM_SYSCOMMAND, SC_MOVE or + HTCAPTION`. Clic → on **envoie `BN_CLICKED` à la place du bouton** : DragDetect + a avalé le `WM_LBUTTONUP`, lui rendre la main le laisserait enfoncé pour + toujours. Le clic droit n'est pas intercepté, donc le menu d'opacité tient. - Le survol est **sondé** par un `SetTimer` de 200 ms, pas par `TrackMouseEvent` : avec quatre fenêtres enfants, passer de la barrette à un bouton envoie déjà un `WM_MOUSELEAVE` au parent. Comparer le curseur au rectangle ignore ce piège. diff --git a/delphi-backend/Source/PM.Bridge.pas b/delphi-backend/Source/PM.Bridge.pas index bb77be0..63b2b90 100644 --- a/delphi-backend/Source/PM.Bridge.pas +++ b/delphi-backend/Source/PM.Bridge.pas @@ -1066,6 +1066,45 @@ begin FOnAutofillRequest(AKind, LTarget, LTitle); end; +// Les quatre boutons sont de la meme classe, donc une seule procedure d'origine +// a retenir. +var + GLazyOldBtnProc: Pointer = nil; + +/// Un appui sur un bouton de la barrette : clic, ou debut de glissement ? +/// +/// C'EST DragDetect QUI TRANCHE, ET PERSONNE D'AUTRE. Il bloque jusqu'a ce que +/// la souris depasse le seuil de glissement du systeme - celui que +/// l'utilisateur a regle, et qui n'est pas le meme sur un ecran tactile - ou +/// jusqu'au relachement. Un seuil ecrit a la main serait un troisieme reglage +/// que personne n'a demande. +function LazyButtonProc(AWnd: HWND; AMsg: UINT; AWp: WPARAM; + ALp: LPARAM): LRESULT; stdcall; +var + LPt: TPoint; +begin + if AMsg = WM_LBUTTONDOWN then + begin + GetCursorPos(LPt); + if DragDetect(AWnd, LPt) then + begin + ReleaseCapture; // DragDetect a pris la souris, la boucle de deplacement la veut + // Exactement le geste "trainer par la barre de titre" : la barrette EST + // sa propre barre de titre (WM_NCHITTEST -> HTCAPTION). + SendMessage(GetParent(AWnd), WM_SYSCOMMAND, SC_MOVE or HTCAPTION, 0); + end + else + // Relache sans bouger. DragDetect a AVALE le WM_LBUTTONUP, que le bouton + // ne verra donc jamais : lui rendre la main le laisserait enfonce pour + // toujours. On annonce le clic a sa place - c'est le message qu'il aurait + // envoye lui-meme. + SendMessage(GetParent(AWnd), WM_COMMAND, + MAKEWPARAM(GetDlgCtrlID(AWnd), BN_CLICKED), LPARAM(AWnd)); + Exit(0); + end; + Result := CallWindowProc(GLazyOldBtnProc, AWnd, AMsg, AWp, ALp); +end; + procedure TPMBridge.DrawLazyButton(ADraw: PDrawItemStruct); var LRect: TRect; @@ -1174,6 +1213,14 @@ begin FLazyHover := LIn; ApplyLazyAlpha(LIn); end; + // TOPMOST N'EST PAS UN RANG, C'EST UNE BANDE. La barre des taches y est + // elle aussi, et cliquer son fond vide la remonte en tete de cette + // bande : une barrette posee dessus passe DERRIERE et semble avoir + // disparu, alors qu'elle est seulement recouverte. La reposer a chaque + // battement est ce que font tous les outils flottants ; sans mouvement + // ni taille a changer, l'appel ne repeint rien. + SetWindowPos(FLazyWnd, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE); Exit; end; // Fin du glissement (la boucle modale ouverte par HTCAPTION), donc une @@ -1252,9 +1299,11 @@ procedure TPMBridge.SetLazyBar(AOn: Boolean); LBtn := CreateWindow('BUTTON', PChar(ACaption), WS_CHILD or WS_VISIBLE or BS_OWNERDRAW, AX, 5, AWidth, 28, FLazyWnd, HMENU(AId), HInstance, nil); + if LBtn = 0 then Exit; // Without this the button wears the 1995 system font. - if LBtn <> 0 then - SendMessage(LBtn, WM_SETFONT, WPARAM(GetStockObject(DEFAULT_GUI_FONT)), 1); + SendMessage(LBtn, WM_SETFONT, WPARAM(GetStockObject(DEFAULT_GUI_FONT)), 1); + GLazyOldBtnProc := Pointer(SetWindowLongPtr(LBtn, GWLP_WNDPROC, + LONG_PTR(@LazyButtonProc))); end; var