diff --git a/delphi-backend/Source/PM.Bridge.pas b/delphi-backend/Source/PM.Bridge.pas index 31d1ee1..288d0e1 100644 --- a/delphi-backend/Source/PM.Bridge.pas +++ b/delphi-backend/Source/PM.Bridge.pas @@ -165,9 +165,10 @@ type // without a stored username. // AUsernameOnly = True → type ONLY the username (no Tab, no password); // used by the quick-search "autofill username" action. - // ARestoreAfter = True → if the fill had to minimise our own window (it - // was foreground, e.g. quick-search pick), show it again afterwards - // WITHOUT activating it, so an app the user had open doesn't vanish. + // ARestoreAfter = True → the window was open before the hotkey: keep it + // visible (no minimize at all — the foreground process is allowed to hand + // focus to the target). False (tray-origin) → minimize out of the way, + // the caller trays it after the fill. procedure ExecuteAutofill(ATargetHWND: HWND; const AUsername, APassword: string; AUsernameOnly: Boolean = False; ARestoreAfter: Boolean = False); @@ -1145,59 +1146,59 @@ const FocusSettleDelayMs = 120; var OwnFormHwnd: HWND; - LMinimizedSelf: Boolean; begin OwnFormHwnd := MainFormHWND(FMainForm); - LMinimizedSelf := False; - if GetForegroundWindow = OwnFormHwnd then + // ARestoreAfter (window was open before the hotkey): DON'T minimize at all. + // Being the foreground process is precisely what lets us hand the focus to + // the target via ForceForegroundWindow — the window just stays where it is, + // beside the target. (The old minimize-then-restore flickered and sometimes + // lost the restore race.) Without ARestoreAfter (tray-origin flow), the + // restored window is a temporary overlay: shove it out of the way as before + // — the caller trays it after the fill anyway. + if (GetForegroundWindow = OwnFormHwnd) and (not ARestoreAfter) then begin ShowWindow(OwnFormHwnd, SW_MINIMIZE); - LMinimizedSelf := True; Sleep(MinimizeSettleMs); end; - try - if ATargetHWND <> 0 then - ForceForegroundWindow(ATargetHWND); + if ATargetHWND <> 0 then + ForceForegroundWindow(ATargetHWND); - WaitForModifierRelease(1000); - Sleep(FocusSettleDelayMs); + WaitForModifierRelease(1000); + Sleep(FocusSettleDelayMs); - // Username-only: type just the username into the focused field, no Tab, - // no password. Used by the quick-search right-click / Shift+Enter path. - if AUsernameOnly then - begin - SendSelectAllAndDelete; - Sleep(60); - SendUnicodeString(AUsername); - Exit; - end; - - if AUsername = '' then - begin - SendSelectAllAndDelete; - Sleep(60); - SendUnicodeString(APassword); - Exit; - end; + // Never type into our own window: if the target refused the foreground + // (elevated process / UIPI), the keystrokes would land in the vault UI + // itself — a password typed into a visible search box. Bail instead. + if GetForegroundWindow = OwnFormHwnd then Exit; + // Username-only: type just the username into the focused field, no Tab, + // no password. Used by the quick-search right-click / Shift+Enter path. + if AUsernameOnly then + begin SendSelectAllAndDelete; Sleep(60); SendUnicodeString(AUsername); - Sleep(200); - SendVKey(VK_TAB); - Sleep(200); + Exit; + end; + + if AUsername = '' then + begin SendSelectAllAndDelete; Sleep(60); SendUnicodeString(APassword); - finally - // We shoved our own window out of the way to give the target the - // foreground. If it was open before the fill (quick-search pick while - // the app sits next to the target), bring it back at its old position - // — SW_SHOWNOACTIVATE so the freshly-filled app keeps the focus. - if LMinimizedSelf and ARestoreAfter then - ShowWindow(OwnFormHwnd, SW_SHOWNOACTIVATE); + Exit; end; + + SendSelectAllAndDelete; + Sleep(60); + SendUnicodeString(AUsername); + Sleep(200); + SendVKey(VK_TAB); + Sleep(200); + SendSelectAllAndDelete; + Sleep(60); + SendUnicodeString(APassword); end; end.