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:
@@ -30,6 +30,7 @@ interface
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
System.SysUtils, System.Classes, System.Math, System.Types,
|
System.SysUtils, System.Classes, System.Math, System.Types,
|
||||||
|
System.Diagnostics,
|
||||||
FMX.Types, FMX.Forms,
|
FMX.Types, FMX.Forms,
|
||||||
Winapi.Windows, Winapi.ShellAPI, Winapi.Messages, Winapi.MultiMon,
|
Winapi.Windows, Winapi.ShellAPI, Winapi.Messages, Winapi.MultiMon,
|
||||||
PM.SingleInstance, PM.UserPrefs;
|
PM.SingleInstance, PM.UserPrefs;
|
||||||
@@ -162,6 +163,8 @@ type
|
|||||||
// settings_json : elle peut etre allumee coffre ferme, quand aucune session
|
// settings_json : elle peut etre allumee coffre ferme, quand aucune session
|
||||||
// n'existe pour lire les reglages du serveur.
|
// n'existe pour lire les reglages du serveur.
|
||||||
FLazyAlphaPct: Integer;
|
FLazyAlphaPct: Integer;
|
||||||
|
// Voir la propriete LastFillWaits.
|
||||||
|
FLastFillWaits: string;
|
||||||
// Dernier etat connu du survol, pour ne reposer l'opacite que sur un
|
// Dernier etat connu du survol, pour ne reposer l'opacite que sur un
|
||||||
// changement - SetLayeredWindowAttributes force un repaint a chaque appel.
|
// changement - SetLayeredWindowAttributes force un repaint a chaque appel.
|
||||||
FLazyHover: Boolean;
|
FLazyHover: Boolean;
|
||||||
@@ -250,6 +253,10 @@ type
|
|||||||
function ExecuteAutofill(ATargetHWND: HWND;
|
function ExecuteAutofill(ATargetHWND: HWND;
|
||||||
const AUsername, APassword: string; AUsernameOnly: Boolean = False;
|
const AUsername, APassword: string; AUsernameOnly: Boolean = False;
|
||||||
ARestoreAfter: Boolean = False; AClearFirst: Boolean = True): Boolean;
|
ARestoreAfter: Boolean = False; AClearFirst: Boolean = True): Boolean;
|
||||||
|
/// Le detail des deux attentes du dernier remplissage, pour le journal de
|
||||||
|
/// l'hote. Une chaine plutot qu'un evenement : ExecuteAutofill s'execute
|
||||||
|
/// sur le thread principal, juste avant que l'hote journalise.
|
||||||
|
property LastFillWaits: string read FLastFillWaits;
|
||||||
property SecureClipboard: TSecureClipboard read FSecureClipboard;
|
property SecureClipboard: TSecureClipboard read FSecureClipboard;
|
||||||
property TrayAdded: Boolean read FTrayAdded;
|
property TrayAdded: Boolean read FTrayAdded;
|
||||||
// Show or hide the lazy strip. Idempotent, and remembered across launches.
|
// Show or hide the lazy strip. Idempotent, and remembered across launches.
|
||||||
@@ -1989,11 +1996,23 @@ begin
|
|||||||
Sleep(MinimizeSettleMs);
|
Sleep(MinimizeSettleMs);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// LES DEUX SEULES ATTENTES QUI PEUVENT ENFLER, mesurees separement.
|
||||||
|
//
|
||||||
|
// Le total d'un remplissage est d'environ 660 ms par construction - des
|
||||||
|
// Sleep fixes. Quand il depasse plusieurs secondes, c'est forcement l'une de
|
||||||
|
// ces deux-la : la prise du premier plan, qui sonde jusqu'a 600 ms, ou
|
||||||
|
// l'attente de la relache des modificateurs, jusqu'a 1000 ms. Les confondre
|
||||||
|
// ferait chercher du cote du moteur web, qui n'y est pour rien.
|
||||||
|
var LSw := TStopwatch.StartNew;
|
||||||
if ATargetHWND <> 0 then
|
if ATargetHWND <> 0 then
|
||||||
ForceForegroundWindow(ATargetHWND);
|
ForceForegroundWindow(ATargetHWND);
|
||||||
|
var LFgMs := LSw.ElapsedMilliseconds;
|
||||||
|
|
||||||
|
LSw := TStopwatch.StartNew;
|
||||||
WaitForModifierRelease(1000);
|
WaitForModifierRelease(1000);
|
||||||
ForceReleaseModifiers; // timeout hit with keys still down → clean state
|
ForceReleaseModifiers; // timeout hit with keys still down → clean state
|
||||||
|
FLastFillWaits := Format('foreground=%d ms, modifiers=%d ms',
|
||||||
|
[LFgMs, LSw.ElapsedMilliseconds]);
|
||||||
Sleep(FocusSettleDelayMs);
|
Sleep(FocusSettleDelayMs);
|
||||||
|
|
||||||
// Never type into our own window: if the target refused the foreground,
|
// Never type into our own window: if the target refused the foreground,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ interface
|
|||||||
uses
|
uses
|
||||||
System.SysUtils, System.Classes, System.UITypes, System.NetEncoding,
|
System.SysUtils, System.Classes, System.UITypes, System.NetEncoding,
|
||||||
System.StrUtils, System.Generics.Collections, System.IOUtils, System.JSON,
|
System.StrUtils, System.Generics.Collections, System.IOUtils, System.JSON,
|
||||||
|
System.Diagnostics,
|
||||||
System.Net.HttpClient, System.Net.URLClient,
|
System.Net.HttpClient, System.Net.URLClient,
|
||||||
Winapi.Windows, Winapi.ShellAPI,
|
Winapi.Windows, Winapi.ShellAPI,
|
||||||
FMX.Forms, FMX.Controls, FMX.Controls.Presentation, FMX.StdCtrls,
|
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
|
FQuitting: Boolean; // set when user picks "Quit" in tray menu — bypasses
|
||||||
// FormCloseQuery's minimize-to-tray intercept.
|
// FormCloseQuery's minimize-to-tray intercept.
|
||||||
FAutofillTargetHWND: HWND; // saved at hotkey time, consumed on /execute
|
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).
|
// Pending payload for the 60ms delay timer (focus settle before SendInput).
|
||||||
// Cleared inside AutofillTimerTick.
|
// Cleared inside AutofillTimerTick.
|
||||||
FAutofillPendingHWND: HWND;
|
FAutofillPendingHWND: HWND;
|
||||||
@@ -1153,6 +1164,16 @@ begin
|
|||||||
FAutofillPendingNotify := GetParam('notify') <> '0'; // absent = ON
|
FAutofillPendingNotify := GetParam('notify') <> '0'; // absent = ON
|
||||||
FAutofillTargetHWND := 0;
|
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
|
// Small timer so SetForegroundWindow has time to take effect before
|
||||||
// SendInput fires — avoids the first keystrokes going to our window.
|
// SendInput fires — avoids the first keystrokes going to our window.
|
||||||
// TTimer.OnTimer is a TNotifyEvent (method, not anon proc) → we use a
|
// TTimer.OnTimer is a TNotifyEvent (method, not anon proc) → we use a
|
||||||
@@ -1891,9 +1912,18 @@ begin
|
|||||||
var LFillOk := FBridge.ExecuteAutofill(TargetHwnd, PendingUser, PendingPass,
|
var LFillOk := FBridge.ExecuteAutofill(TargetHwnd, PendingUser, PendingPass,
|
||||||
UserOnly, not HideAfter, ClearFirst);
|
UserOnly, not HideAfter, ClearFirst);
|
||||||
ForegroundAfter := GetForegroundWindow;
|
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),
|
[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
|
// Tell JS whether the keystrokes were actually sent — the success toast
|
||||||
// must not lie when the target runs elevated (UIPI drops our input).
|
// must not lie when the target runs elevated (UIPI drops our input).
|
||||||
WebBrowser.ExecuteJavaScript(
|
WebBrowser.ExecuteJavaScript(
|
||||||
@@ -1942,6 +1972,9 @@ begin
|
|||||||
else LKind := 'full';
|
else LKind := 'full';
|
||||||
end;
|
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(
|
WebBrowser.ExecuteJavaScript(
|
||||||
'if(window.Bridge&&typeof Bridge.onAutofillRequest==="function")' +
|
'if(window.Bridge&&typeof Bridge.onAutofillRequest==="function")' +
|
||||||
'Bridge.onAutofillRequest("' + LTitle + '","' + LKind + '")');
|
'Bridge.onAutofillRequest("' + LTitle + '","' + LKind + '")');
|
||||||
|
|||||||
Reference in New Issue
Block a user