fix(quick-search): stop teleporting + hiding an already-open window

Two bugs when Ctrl+Shift+Q fires while the app window is open beside the
target app:
- RestoreFromTray re-applied FSavedPlacement (captured at the LAST
  MinimizeToTray) to an already-visible window -> it jumped to a stale
  position. Now: visible and not iconic -> just SetForegroundWindow.
- ExecuteAutofill minimizes our window when it is foreground (the user just
  clicked the entry) and never brought it back when hide_after was false.
  New ARestoreAfter param (= not HideAfter): restore with SW_SHOWNOACTIVATE
  after the fill, so the window returns to its position without stealing
  focus from the freshly-filled target.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
r-zakarya
2026-07-11 19:52:26 +01:00
parent 01426a48b1
commit 3b32a621e8
2 changed files with 58 additions and 27 deletions
+29 -2
View File
@@ -165,8 +165,12 @@ 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.
procedure ExecuteAutofill(ATargetHWND: HWND;
const AUsername, APassword: string; AUsernameOnly: Boolean = False);
const AUsername, APassword: string; AUsernameOnly: Boolean = False;
ARestoreAfter: Boolean = False);
property SecureClipboard: TSecureClipboard read FSecureClipboard;
property TrayAdded: Boolean read FTrayAdded;
property AutofillRegistered: Boolean read FAutofillRegistered;
@@ -638,6 +642,16 @@ begin
LFormHwnd := MainFormHWND(FMainForm);
LAppHwnd := FindFMXAppWindow;
// Already visible and not minimised (quick-search / focus hotkey while the
// window is open): just bring it to front. Re-applying FSavedPlacement —
// captured at the LAST MinimizeToTray — would teleport the window to a
// stale position the user has since moved away from.
if FMainForm.Visible and (not IsIconic(LFormHwnd)) then
begin
SetForegroundWindow(LFormHwnd);
Exit;
end;
// Reverse order: show the app proxy first so the taskbar entry comes back,
// then show and foreground the form.
if LAppHwnd <> 0 then
@@ -1124,20 +1138,25 @@ begin
end;
procedure TPMBridge.ExecuteAutofill(ATargetHWND: HWND;
const AUsername, APassword: string; AUsernameOnly: Boolean = False);
const AUsername, APassword: string; AUsernameOnly: Boolean = False;
ARestoreAfter: Boolean = False);
const
MinimizeSettleMs = 80;
FocusSettleDelayMs = 120;
var
OwnFormHwnd: HWND;
LMinimizedSelf: Boolean;
begin
OwnFormHwnd := MainFormHWND(FMainForm);
LMinimizedSelf := False;
if GetForegroundWindow = OwnFormHwnd then
begin
ShowWindow(OwnFormHwnd, SW_MINIMIZE);
LMinimizedSelf := True;
Sleep(MinimizeSettleMs);
end;
try
if ATargetHWND <> 0 then
ForceForegroundWindow(ATargetHWND);
@@ -1171,6 +1190,14 @@ 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);
end;
end;
end.
+5 -1
View File
@@ -1466,7 +1466,11 @@ begin
TTimer(Sender).Enabled := False;
TTimer(Sender).Free;
FBridge.ExecuteAutofill(TargetHwnd, PendingUser, PendingPass, UserOnly);
// ARestoreAfter = not HideAfter: if the app was open before the hotkey
// (quick-search beside the target), it comes back after the fill; if it
// started hidden, the MinimizeToTray below re-hides it anyway.
FBridge.ExecuteAutofill(TargetHwnd, PendingUser, PendingPass, UserOnly,
not HideAfter);
ForegroundAfter := GetForegroundWindow;
LogLine(Format('Autofill executed — target=%s, foreground_after=%s, match=%s',
[IntToHex(TargetHwnd, 8), IntToHex(ForegroundAfter, 8),