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
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:
@@ -23,6 +23,43 @@ from . import api_v3_bp
|
|||||||
logger = logging.getLogger(__name__)
|
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):
|
def safe_type_text(text):
|
||||||
"""Saisie de texte compatible VM/Citrix et claviers AZERTY/QWERTY.
|
"""Saisie de texte compatible VM/Citrix et claviers AZERTY/QWERTY.
|
||||||
|
|
||||||
@@ -34,20 +71,17 @@ def safe_type_text(text):
|
|||||||
import shutil
|
import shutil
|
||||||
import pyautogui
|
import pyautogui
|
||||||
|
|
||||||
# Méthode 1 : xdotool type (frappes clavier réelles)
|
# Méthode 1 : xdotool key par caractère (frappes clavier réelles)
|
||||||
# Envoie des événements X11 que QEMU/Citrix/RDP capturent et transmettent.
|
# xdotool type envoie des scancodes QWERTY que les VM AZERTY interprètent
|
||||||
# Le presse-papier ne traverse PAS les VM — xdotool si.
|
# 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'):
|
if shutil.which('xdotool'):
|
||||||
try:
|
try:
|
||||||
subprocess.run(
|
_xdotool_type_by_keysym(text)
|
||||||
['xdotool', 'type', '--delay', '20', '--clearmodifiers', '--', text],
|
print(f" ✅ Saisie via xdotool key ({len(text)} car.)")
|
||||||
timeout=max(30, len(text) * 0.05),
|
|
||||||
check=True
|
|
||||||
)
|
|
||||||
print(f" ✅ Saisie via xdotool type ({len(text)} car.)")
|
|
||||||
return
|
return
|
||||||
except Exception as e:
|
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)
|
# Méthode 2 : Presse-papier (fonctionne seulement en local, pas en VM)
|
||||||
xclip = shutil.which('xclip')
|
xclip = shutil.which('xclip')
|
||||||
|
|||||||
Reference in New Issue
Block a user