fix(autofill): texte arabe + latin tape en entier vers VNC
Un caractere sans touche dans la disposition courante est cherche dans les autres dispositions installees ; la fenetre VNC y bascule le temps de le taper, puis la disposition d'origine est rendue. Eprouve vers un Mac, clavier francais comme arabe actif. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1451,12 +1451,16 @@ d'accord.
|
|||||||
Ctrl+Alt). **AltGr = `VK_LCONTROL` + `VK_RMENU` etendu**, comme le vrai
|
Ctrl+Alt). **AltGr = `VK_LCONTROL` + `VK_RMENU` etendu**, comme le vrai
|
||||||
clavier : un Ctrl+Alt generique etait lu par TigerVNC comme deux
|
clavier : un Ctrl+Alt generique etait lu par TigerVNC comme deux
|
||||||
modificateurs, et `@` (AltGr+0 en AZERTY) arrivait en `a`. Chaque touche porte
|
modificateurs, et `@` (AltGr+0 en AZERTY) arrivait en `a`. Chaque touche porte
|
||||||
aussi son scancode (`MapVirtualKeyEx`). **Un caractere sans touche dans la
|
aussi son scancode (`MapVirtualKeyEx`). **Texte melange (arabe + latin)** :
|
||||||
disposition locale** (arabe sur clavier francais) ne peut pas passer : il
|
un caractere sans touche dans la disposition courante est cherche dans les
|
||||||
est **saute et compte** - journal `N character(s) have no key on this
|
autres dispositions installees (`GetKeyboardLayoutList`) ; la fenetre cible
|
||||||
keyboard and were NOT typed - copy instead` ; la copie, que TigerVNC
|
y est basculee (`WM_INPUTLANGCHANGEREQUEST`, attente que son fil l'ait
|
||||||
synchronise, reste le recours. Eprouve vers un Mac : lettres, espaces, `@`,
|
prise - TigerVNC traduit chaque touche avec la disposition de SON fil), et
|
||||||
`#` corrects, 19 caracteres arabes sautes et comptes.
|
la disposition d'origine est rendue a la fin. Seul un caractere qu'aucune
|
||||||
|
disposition installee ne sait taper est **saute et compte** - journal
|
||||||
|
`N character(s) have no key on this keyboard and were NOT typed - copy
|
||||||
|
instead`. Eprouve vers un Mac : `تاسيب... jhbs... @ #` complet, clavier
|
||||||
|
francais comme arabe actif.
|
||||||
|
|
||||||
- **UIPI** : SendInput vers process élevé bloqué. Notepad++ admin,
|
- **UIPI** : SendInput vers process élevé bloqué. Notepad++ admin,
|
||||||
regedit → autofill silencieusement no-op. Tester avec apps non-élevées.
|
regedit → autofill silencieusement no-op. Tester avec apps non-élevées.
|
||||||
|
|||||||
@@ -2116,10 +2116,42 @@ end;
|
|||||||
/// ALTGR = Ctrl GAUCHE + Alt DROIT (touche etendue), comme le clavier le
|
/// ALTGR = Ctrl GAUCHE + Alt DROIT (touche etendue), comme le clavier le
|
||||||
/// produit : un Ctrl+Alt generique etait lu par TigerVNC comme deux
|
/// produit : un Ctrl+Alt generique etait lu par TigerVNC comme deux
|
||||||
/// modificateurs ordinaires, et "@" (AltGr+0 en AZERTY) arrivait en "a".
|
/// modificateurs ordinaires, et "@" (AltGr+0 en AZERTY) arrivait en "a".
|
||||||
/// Un caractere sans touche dans cette disposition (de l'arabe sur un clavier
|
/// TEXTE MELANGE (arabe + latin) : un caractere sans touche dans la
|
||||||
/// francais) ne peut pas passer par VNC : il est saute et compte - la copie,
|
/// disposition courante est cherche dans les AUTRES dispositions installees
|
||||||
/// que TigerVNC synchronise, reste le recours. Rend le nombre de sautes.
|
/// sur le poste ; on y bascule la fenetre cible (TigerVNC traduit chaque touche
|
||||||
function SendKeyCodeString(const AText: string; ALayout: HKL): Integer;
|
/// avec la disposition de SON fil), on tape, et la disposition d'origine est
|
||||||
|
/// rendue a la fin. Seul un caractere qu'aucune disposition installee ne sait
|
||||||
|
/// taper est saute et compte - la copie, que TigerVNC synchronise, reste alors
|
||||||
|
/// le recours. Rend le nombre de sautes.
|
||||||
|
function SwitchTargetLayout(ATarget: HWND; ALayout: HKL): Boolean;
|
||||||
|
var
|
||||||
|
LThread: DWORD;
|
||||||
|
begin
|
||||||
|
LThread := GetWindowThreadProcessId(ATarget, nil);
|
||||||
|
PostMessage(ATarget, WM_INPUTLANGCHANGEREQUEST, 0, LPARAM(ALayout));
|
||||||
|
// La bascule est asynchrone : on attend qu'elle soit faite avant de taper,
|
||||||
|
// sinon les premieres touches partiraient encore dans l'ancienne.
|
||||||
|
for var I := 1 to 30 do
|
||||||
|
begin
|
||||||
|
if GetKeyboardLayout(LThread) = ALayout then Exit(True);
|
||||||
|
Sleep(10);
|
||||||
|
end;
|
||||||
|
Result := GetKeyboardLayout(LThread) = ALayout;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function LayoutForChar(ACh: WideChar; ACurrent: HKL): HKL;
|
||||||
|
var
|
||||||
|
LList: array[0..31] of HKL;
|
||||||
|
N, I: Integer;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
N := GetKeyboardLayoutList(Length(LList), LList);
|
||||||
|
for I := 0 to N - 1 do
|
||||||
|
if (LList[I] <> ACurrent) and (VkKeyScanEx(ACh, LList[I]) <> -1) then
|
||||||
|
Exit(LList[I]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function SendKeyCodeString(const AText: string; ATarget: HWND; ALayout: HKL): Integer;
|
||||||
var
|
var
|
||||||
LInputs: TArray<TInput>;
|
LInputs: TArray<TInput>;
|
||||||
LCount: Integer;
|
LCount: Integer;
|
||||||
@@ -2142,10 +2174,21 @@ var
|
|||||||
LShift, LCtrl, LAlt: Boolean;
|
LShift, LCtrl, LAlt: Boolean;
|
||||||
begin
|
begin
|
||||||
Result := 0;
|
Result := 0;
|
||||||
|
var LOriginal := ALayout;
|
||||||
|
try
|
||||||
for I := 1 to Length(AText) do
|
for I := 1 to Length(AText) do
|
||||||
begin
|
begin
|
||||||
LScan := VkKeyScanEx(AText[I], ALayout);
|
LScan := VkKeyScanEx(AText[I], ALayout);
|
||||||
if LScan = -1 then
|
if LScan = -1 then
|
||||||
|
begin
|
||||||
|
var LOther := LayoutForChar(AText[I], ALayout);
|
||||||
|
if (LOther <> 0) and SwitchTargetLayout(ATarget, LOther) then
|
||||||
|
begin
|
||||||
|
ALayout := LOther;
|
||||||
|
LScan := VkKeyScanEx(AText[I], ALayout);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if LScan = -1 then
|
||||||
begin
|
begin
|
||||||
Inc(Result);
|
Inc(Result);
|
||||||
Continue;
|
Continue;
|
||||||
@@ -2169,13 +2212,18 @@ begin
|
|||||||
if LShift then Key(VK_LSHIFT, True);
|
if LShift then Key(VK_LSHIFT, True);
|
||||||
SendInput(LCount, @LInputs[0], SizeOf(TInput));
|
SendInput(LCount, @LInputs[0], SizeOf(TInput));
|
||||||
end;
|
end;
|
||||||
|
finally
|
||||||
|
// Rendre a l'utilisateur la disposition qu'il avait choisie.
|
||||||
|
if ALayout <> LOriginal then SwitchTargetLayout(ATarget, LOriginal);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
/// Rend le nombre de caracteres qui n'ont pas pu etre tapes (VNC seulement).
|
/// Rend le nombre de caracteres qui n'ont pas pu etre tapes (VNC seulement).
|
||||||
function SendTextTo(const AText: string; AByKeys: Boolean; ALayout: HKL): Integer;
|
function SendTextTo(const AText: string; AByKeys: Boolean; ATarget: HWND;
|
||||||
|
ALayout: HKL): Integer;
|
||||||
begin
|
begin
|
||||||
Result := 0;
|
Result := 0;
|
||||||
if AByKeys then Result := SendKeyCodeString(AText, ALayout)
|
if AByKeys then Result := SendKeyCodeString(AText, ATarget, ALayout)
|
||||||
else SendUnicodeString(AText);
|
else SendUnicodeString(AText);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -2422,19 +2470,19 @@ begin
|
|||||||
if AUsernameOnly then
|
if AUsernameOnly then
|
||||||
begin
|
begin
|
||||||
ClearFieldIfWanted;
|
ClearFieldIfWanted;
|
||||||
Inc(LMissing, SendTextTo(AUsername, LByKeys, LLayout));
|
Inc(LMissing, SendTextTo(AUsername, LByKeys, ATargetHWND, LLayout));
|
||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if AUsername = '' then
|
if AUsername = '' then
|
||||||
begin
|
begin
|
||||||
ClearFieldIfWanted;
|
ClearFieldIfWanted;
|
||||||
Inc(LMissing, SendTextTo(APassword, LByKeys, LLayout));
|
Inc(LMissing, SendTextTo(APassword, LByKeys, ATargetHWND, LLayout));
|
||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
ClearFieldIfWanted;
|
ClearFieldIfWanted;
|
||||||
Inc(LMissing, SendTextTo(AUsername, LByKeys, LLayout));
|
Inc(LMissing, SendTextTo(AUsername, LByKeys, ATargetHWND, LLayout));
|
||||||
Sleep(200);
|
Sleep(200);
|
||||||
// Real-VK send: a physically held Shift here turns Tab into Shift+Tab —
|
// Real-VK send: a physically held Shift here turns Tab into Shift+Tab —
|
||||||
// focus moves BACKWARD and the password lands in the username field.
|
// focus moves BACKWARD and the password lands in the username field.
|
||||||
@@ -2446,7 +2494,7 @@ begin
|
|||||||
// Tab lands somewhere that is not an editable field (a link, a reveal
|
// Tab lands somewhere that is not an editable field (a link, a reveal
|
||||||
// button, the document itself, as on the Reddit login form) it selects the
|
// button, the document itself, as on the Reddit login form) it selects the
|
||||||
// ENTIRE PAGE, and the password is then typed into nothing.
|
// ENTIRE PAGE, and the password is then typed into nothing.
|
||||||
Inc(LMissing, SendTextTo(APassword, LByKeys, LLayout));
|
Inc(LMissing, SendTextTo(APassword, LByKeys, ATargetHWND, LLayout));
|
||||||
finally
|
finally
|
||||||
if LMissing > 0 then
|
if LMissing > 0 then
|
||||||
FLastFillWaits := FLastFillWaits + Format(
|
FLastFillWaits := FLastFillWaits + Format(
|
||||||
|
|||||||
Reference in New Issue
Block a user