chore(autofill): mesurer ou passe le temps d'un remplissage

Un autofill lent apres une periode d'inactivite peut l'etre pour des
raisons sans rapport qui se ressemblent parfaitement de l'exterieur : le
moteur WebView2 qui se reveille, la prise du premier plan, ou l'attente
de la relache des modificateurs. Elles se corrigent a des endroits
opposes, donc on les separe au lieu de deviner laquelle accuser.

Trois marques : le temps que met la PAGE a repondre au raccourci, le
total, et le detail des deux attentes internes.

Premiere mesure : 13 ms de reponse apres 23 minutes en tray, total
635 ms. Le renderer ne dormait donc pas - l'hypothese la plus evidente
etait fausse - et 635 ms est le cout nominal de la sequence, faite de
pauses fixes (80 + 120 + 60 + 200 + 200). Le cas lent reste a attraper.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
r-zakarya
2026-09-02 19:31:03 +01:00
parent f8b7ffe379
commit da74a675be
2 changed files with 54 additions and 2 deletions
+35 -2
View File
@@ -18,6 +18,7 @@ interface
uses
System.SysUtils, System.Classes, System.UITypes, System.NetEncoding,
System.StrUtils, System.Generics.Collections, System.IOUtils, System.JSON,
System.Diagnostics,
System.Net.HttpClient, System.Net.URLClient,
Winapi.Windows, Winapi.ShellAPI,
FMX.Forms, FMX.Controls, FMX.Controls.Presentation, FMX.StdCtrls,
@@ -109,6 +110,16 @@ type
FQuitting: Boolean; // set when user picks "Quit" in tray menu — bypasses
// FormCloseQuery's minimize-to-tray intercept.
FAutofillTargetHWND: HWND; // saved at hotkey time, consumed on /execute
// CHRONOMETRE DU RACCOURCI, arme au moment ou l'on appelle la page.
//
// Un autofill lent apres une periode d'inactivite peut l'etre pour deux
// raisons sans rapport : le moteur WebView2 qui se reveille et met des
// secondes a repondre, ou la sequence de frappe elle-meme (prise du premier
// plan, attente des modificateurs). Les deux se ressemblent parfaitement de
// l'exterieur - l'utilisateur voit "ca a mis trois secondes" - et se
// corrigent a des endroits opposes. On mesure donc les deux segments
// separement plutot que de deviner lequel accuser.
FAutofillClock: TStopwatch;
// Pending payload for the 60ms delay timer (focus settle before SendInput).
// Cleared inside AutofillTimerTick.
FAutofillPendingHWND: HWND;
@@ -1153,6 +1164,16 @@ begin
FAutofillPendingNotify := GetParam('notify') <> '0'; // absent = ON
FAutofillTargetHWND := 0;
// PREMIER SEGMENT : combien la PAGE a mis a repondre.
//
// Tout ce qui precede est du JavaScript - reveil du moteur, appariement du
// titre, dechiffrement du mot de passe. Si le chiffre est gros ici et petit
// plus bas, c'est le renderer qu'il faut regarder, pas la sequence de
// frappe. Le contraire designe SendInput et la prise du premier plan.
if FAutofillClock.IsRunning then
LogLine(Format('Autofill: page answered in %d ms',
[FAutofillClock.ElapsedMilliseconds]));
// Small timer so SetForegroundWindow has time to take effect before
// SendInput fires — avoids the first keystrokes going to our window.
// TTimer.OnTimer is a TNotifyEvent (method, not anon proc) → we use a
@@ -1891,9 +1912,18 @@ begin
var LFillOk := FBridge.ExecuteAutofill(TargetHwnd, PendingUser, PendingPass,
UserOnly, not HideAfter, ClearFirst);
ForegroundAfter := GetForegroundWindow;
LogLine(Format('Autofill executed — target=%s, foreground_after=%s, ok=%s',
// SECOND SEGMENT, et le total. La difference entre les deux chiffres est le
// cout de la frappe : minimisation, prise du premier plan, attente de la
// relache des modificateurs, puis SendInput.
LogLine(Format('Autofill executed — target=%s, foreground_after=%s, ok=%s, ' +
'total=%d ms',
[IntToHex(TargetHwnd, 8), IntToHex(ForegroundAfter, 8),
BoolToStr(LFillOk, True)]));
BoolToStr(LFillOk, True), FAutofillClock.ElapsedMilliseconds]));
FAutofillClock.Stop;
// Le detail des deux attentes internes : sans lui, un total de trois secondes
// ne dit pas LAQUELLE a enfle, et les deux se corrigent differemment.
if FBridge.LastFillWaits <> '' then
LogLine('Autofill waits — ' + FBridge.LastFillWaits);
// Tell JS whether the keystrokes were actually sent — the success toast
// must not lie when the target runs elevated (UIPI drops our input).
WebBrowser.ExecuteJavaScript(
@@ -1942,6 +1972,9 @@ begin
else LKind := 'full';
end;
// Arme AVANT l'appel : ce qui suit se passe dans le moteur, et c'est
// justement ce temps-la qu'on cherche a voir.
FAutofillClock := TStopwatch.StartNew;
WebBrowser.ExecuteJavaScript(
'if(window.Bridge&&typeof Bridge.onAutofillRequest==="function")' +
'Bridge.onAutofillRequest("' + LTitle + '","' + LKind + '")');