fix(typing): xdotool key par keysym au lieu de type (fix AZERTY dans VM)
Some checks failed
security-audit / Bandit (scan statique) (push) Successful in 11s
security-audit / pip-audit (CVE dépendances) (push) Successful in 11s
security-audit / Scan secrets (grep) (push) Successful in 9s
tests / Lint (ruff + black) (push) Successful in 13s
tests / Tests unitaires (sans GPU) (push) Failing after 14s
tests / Tests sécurité (critique) (push) Has been skipped

xdotool type envoie des scancodes QWERTY — dans une VM AZERTY,
':' devient 'M', '/' devient '!', etc.

Nouvelle approche : xdotool key avec les noms de keysym X11
(colon, slash, period, etc.) qui sont indépendants du layout.
Chaque caractère est envoyé individuellement — plus lent mais
100% fiable en AZERTY/QWERTY, local ou VM.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dom
2026-04-18 23:15:44 +02:00
parent 3d243d731d
commit 588c8f22c1

View File

@@ -23,6 +23,43 @@ from . import api_v3_bp
logger = logging.getLogger(__name__)
_CHAR_TO_KEYSYM = {
' ': 'space', '\t': 'Tab', '\n': 'Return',
'!': 'exclam', '"': 'quotedbl', '#': 'numbersign', '$': 'dollar',
'%': 'percent', '&': 'ampersand', "'": 'apostrophe',
'(': 'parenleft', ')': 'parenright', '*': 'asterisk', '+': 'plus',
',': 'comma', '-': 'minus', '.': 'period', '/': 'slash',
':': 'colon', ';': 'semicolon', '<': 'less', '=': 'equal',
'>': 'greater', '?': 'question', '@': 'at',
'[': 'bracketleft', '\\': 'backslash', ']': 'bracketright',
'^': 'asciicircum', '_': 'underscore', '`': 'grave',
'{': 'braceleft', '|': 'bar', '}': 'braceright', '~': 'asciitilde',
}
def _xdotool_type_by_keysym(text):
"""Tape du texte via xdotool key, caractère par caractère avec keysyms.
Indépendant du layout clavier — fonctionne en AZERTY dans une VM QWERTY
et inversement. Plus lent que xdotool type mais 100% fiable.
"""
keys = []
for ch in text:
if ch in _CHAR_TO_KEYSYM:
keys.append(_CHAR_TO_KEYSYM[ch])
elif ch.isalnum():
keys.append(ch)
else:
keys.append(ch)
for key in keys:
subprocess.run(
['xdotool', 'key', '--clearmodifiers', key],
timeout=2, check=True
)
time.sleep(0.02)
def safe_type_text(text):
"""Saisie de texte compatible VM/Citrix et claviers AZERTY/QWERTY.
@@ -34,20 +71,17 @@ def safe_type_text(text):
import shutil
import pyautogui
# Méthode 1 : xdotool type (frappes clavier réelles)
# Envoie des événements X11 que QEMU/Citrix/RDP capturent et transmettent.
# Le presse-papier ne traverse PAS les VM — xdotool si.
# Méthode 1 : xdotool key par caractère (frappes clavier réelles)
# xdotool type envoie des scancodes QWERTY que les VM AZERTY interprètent
# mal (: → M, / → !, etc.). xdotool key avec les noms de keysym est
# indépendant du layout et traverse QEMU/Citrix/RDP correctement.
if shutil.which('xdotool'):
try:
subprocess.run(
['xdotool', 'type', '--delay', '20', '--clearmodifiers', '--', text],
timeout=max(30, len(text) * 0.05),
check=True
)
print(f" ✅ Saisie via xdotool type ({len(text)} car.)")
_xdotool_type_by_keysym(text)
print(f" ✅ Saisie via xdotool key ({len(text)} car.)")
return
except Exception as e:
print(f" ⚠️ xdotool type échoué: {e}")
print(f" ⚠️ xdotool key échoué: {e}")
# Méthode 2 : Presse-papier (fonctionne seulement en local, pas en VM)
xclip = shutil.which('xclip')