fix(tray): give the foreground back to the application we took it from

Hiding a window hands the foreground to nobody, so we stayed foreground while
invisible. The next hotkey then captured our own window as its target and typed
the password into it, and Ctrl+Shift+A opened a New entry with an empty title —
the guard correctly refusing to prefill with "Password Manager".

Track foreground changes with an EVENT_SYSTEM_FOREGROUND hook and keep the last
window that is neither ours nor a shell one, then reactivate it just before
hiding. Sampling on demand cannot work: by then the user's application is two
foreground changes behind (their app, the taskbar they clicked, us), and
reactivating after the hide is silently refused since only the current
foreground owner may give focus away.

Autofill paths pass AReturnForeground=False — they already placed the
foreground on the window they filled.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
r-zakarya
2026-07-27 23:10:22 +01:00
parent a9e56c52b5
commit 33d8df3dee
3 changed files with 177 additions and 12 deletions
+9 -4
View File
@@ -477,10 +477,13 @@ begin
// focus has to be on the browser control first.
WebBrowser.SetFocus;
LWasHiddenJs := BoolToStr(LWasHidden, True).ToLower;
// Second arg forFill=true tells JS to SendInput on pick instead of copy.
// Second arg forFill tells JS to SendInput on pick instead of copy. The bridge
// reports HWND 0 when the foreground was our own hidden window: there is
// nothing to type into, so offer copy instead of a fill that goes nowhere.
WebBrowser.ExecuteJavaScript(
'if(window.Bridge&&typeof Bridge.openQuickSearch==="function")' +
'Bridge.openQuickSearch(' + LWasHiddenJs + ',true)');
'Bridge.openQuickSearch(' + LWasHiddenJs + ',' +
BoolToStr(ATargetHWND <> 0, True).ToLower + ')');
LogLine(Format('Quick-search hotkey — target=%s, title="%s"',
[IntToHex(ATargetHWND, 8), ATitle]));
end;
@@ -1093,7 +1096,8 @@ begin
if FAutofillHotkeyWasHidden then
begin
FAutofillHotkeyWasHidden := False;
FBridge.MinimizeToTray;
// Foreground already handed to the target above.
FBridge.MinimizeToTray(True, False);
end;
LogLine('Autofill cancelled (no match or dismissed)');
end
@@ -1777,7 +1781,8 @@ begin
// confusing the Win10/11 foreground-stealing watchdog.
if HideAfter then
begin
FBridge.MinimizeToTray;
// The filled window must keep the foreground we just handed it.
FBridge.MinimizeToTray(True, False);
LogLine('Hidden back to tray (post-autofill).');
end;
end;