fix(quick-search): keep the open window visible during the fill (no minimize)

The minimize-then-SW_SHOWNOACTIVATE approach flickered and sometimes lost the
restore race (window stayed minimized). Root fix: when the window was open
before the hotkey (ARestoreAfter), skip the minimize entirely — being the
foreground process is exactly what allows handing focus to the target, so the
window simply stays in place beside it. Tray-origin flow keeps the old
minimize (the window is a temporary overlay, trayed after the fill anyway).

Safety: if the target refuses the foreground (elevated / UIPI) and our window
is still foreground, bail before typing — otherwise the password would be
typed into the vault's own visible UI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
r-zakarya
2026-07-11 20:01:05 +01:00
parent 3b32a621e8
commit 7103fbf703
+40 -39
View File
@@ -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.