diff --git a/delphi-backend/Source/PM.Bridge.pas b/delphi-backend/Source/PM.Bridge.pas index 91be884..d166fa1 100644 --- a/delphi-backend/Source/PM.Bridge.pas +++ b/delphi-backend/Source/PM.Bridge.pas @@ -127,8 +127,8 @@ type procedure ShowFirstTimeBalloon; function FindFMXAppWindow: HWND; public - // Tray balloon (gated by the "Show tray notifications" setting). Used - // for messages the user must see while the window is hidden — e.g. an + // Tray balloon (caller applies its own gating setting). Used for + // messages the user must see while the window is hidden — e.g. an // autofill blocked by an elevated target. procedure ShowBalloon(const ATitle, AText: string; AWarning: Boolean = False); constructor Create(AMainForm: TForm); @@ -623,8 +623,8 @@ procedure TPMBridge.ShowBalloon(const ATitle, AText: string; var LBalloon: TNotifyIconData; begin - // Gated by the "Show tray notifications" user setting. - if not FShowNotifications then Exit; + // No gating here — each caller applies its own setting (first-time tray + // balloon → FShowNotifications; autofill-blocked → autofillFailBalloon). // Build a separate TNotifyIconData with NIF_INFO set, NIM_MODIFY on the // same uID. szInfo/szInfoTitle carry the balloon content. FillChar(LBalloon, SizeOf(LBalloon), 0); @@ -1091,6 +1091,12 @@ procedure SendSelectAllAndDelete; var LInputs: array[0..5] of TInput; begin + // This is the ONLY real-VK chord we inject (password chars go out as + // KEYEVENTF_UNICODE / VK_PACKET, which can't match a RegisterHotKey). + // If the user re-presses Ctrl+Shift mid-sequence, our VK_A below becomes + // a physical Ctrl+Shift+A = our own new-entry hotkey firing mid-fill. + // Force-release right here, at the risky instant — not just once up front. + ForceReleaseModifiers; FillChar(LInputs, SizeOf(LInputs), 0); LInputs[0].Itype := INPUT_KEYBOARD; LInputs[0].ki.wVk := VK_CONTROL; diff --git a/delphi-backend/UMainForm.pas b/delphi-backend/UMainForm.pas index 55f4e90..259d853 100644 --- a/delphi-backend/UMainForm.pas +++ b/delphi-backend/UMainForm.pas @@ -108,6 +108,9 @@ type // Send Ctrl+A + Del before typing each field (user setting, default ON; // OFF for targets where Ctrl+A isn't select-all — terminals, RDP). FAutofillPendingClear: Boolean; + // Tray balloon when the fill fails while the window is hidden (user + // setting "Tray alert when autofill is blocked", default ON). + FAutofillPendingNotify: Boolean; // Created dynamically in FormCreate so the directive can pick either // TTMSFNCWebBrowser or TTMSFNCEdgeWebBrowser at compile time without // needing two .fmx variants. Aligned to Client to fill the remaining @@ -900,7 +903,8 @@ begin FAutofillPendingHWND := FAutofillTargetHWND; FAutofillPendingHide := GetParam('hide_after') = '1'; FAutofillPendingUserOnly := GetParam('field') = 'user'; - FAutofillPendingClear := GetParam('clear') <> '0'; // absent = ON + FAutofillPendingClear := GetParam('clear') <> '0'; // absent = ON + FAutofillPendingNotify := GetParam('notify') <> '0'; // absent = ON FAutofillTargetHWND := 0; // Small timer so SetForegroundWindow has time to take effect before @@ -1453,7 +1457,7 @@ procedure TMainForm.AutofillTimerTick(Sender: TObject); var TargetHwnd: HWND; PendingUser, PendingPass: string; - HideAfter, UserOnly, ClearFirst: Boolean; + HideAfter, UserOnly, ClearFirst, NotifyFail: Boolean; ForegroundAfter: HWND; begin TargetHwnd := FAutofillPendingHWND; @@ -1462,12 +1466,14 @@ begin HideAfter := FAutofillPendingHide; UserOnly := FAutofillPendingUserOnly; ClearFirst := FAutofillPendingClear; + NotifyFail := FAutofillPendingNotify; FAutofillPendingHWND := 0; FAutofillPendingUser := ''; FAutofillPendingPass := ''; FAutofillPendingHide := False; FAutofillPendingUserOnly := False; FAutofillPendingClear := False; + FAutofillPendingNotify := False; TTimer(Sender).Enabled := False; TTimer(Sender).Free; @@ -1487,9 +1493,9 @@ begin 'if(window.Bridge&&typeof Bridge.onAutofillResult==="function")' + 'Bridge.onAutofillResult(' + BoolToStr(LFillOk, True).ToLower + ')'); // Window hidden (tray) → the in-app failure toast is invisible; surface - // the block via a tray balloon instead (gated by the tray-notifications - // setting inside ShowBalloon). - if (not LFillOk) and + // the block via a tray balloon instead (gated by the dedicated + // "Tray alert when autofill is blocked" setting, default ON). + if (not LFillOk) and NotifyFail and ((not Self.Visible) or IsIconic(WindowHandleToPlatform(Self.Handle).Wnd)) then FBridge.ShowBalloon('Autofill blocked', 'The target window runs as administrator — Windows silently blocks ' + diff --git a/index.html b/index.html index 4e3c214..b949def 100644 --- a/index.html +++ b/index.html @@ -642,6 +642,19 @@ +