gui-control
Управление GUI 1С через X11. Навык учит агента обнаруживать окна 1С (включая диалоги ошибок), делать скриншоты и симулировать ввод (Enter, Escape) для управления интерфейсом без участия человека.
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
Управление GUI 1С через X11
Назначение
Навык учит агента управлять графическим интерфейсом 1С в окружениях с виртуальным X11-дисплеем (Xvfb). Используется когда стандартные инструменты (ЖР, ТЖ) недоступны или недостаточны — например, база «зависла» на диалоге ошибки и не завершается корректно.
Стек:
Xvfb :99 (виртуальный фреймбуфер)
├── python-xlib → читает метаданные окон (заголовки, геометрия), симулирует ввод
└── PIL ImageGrab → читает пиксели фреймбуфера → скриншот
Принцип: X11-управление — это action, не диагностика. Использовать только когда детектирован GUI-диалог, блокирующий нормальное завершение базы. Диагностику причин — через ЖР (event-log-analysis).
Когда применять
| Триггер | Действие |
|---|---|
База запущена, но в ЖР нет событий после test_start_time |
Проверить — не завис ли GUI-диалог |
| Заголовок окна содержит «Ошибка» / «Предупреждение» | Сделать скриншот → закрыть диалог → анализировать ЖР |
| База не завершается после прогона тестов | Закрыть базу естественным путём через Escape + Enter |
| Нужно зафиксировать состояние экрана для лога | Снять скриншот окна 1С |
Настройка окружения
import os
os.environ['DISPLAY'] = ':99'
Переменная должна быть установлена до импорта Xlib и PIL.
Сценарии использования
Сценарий 1: Детектировать диалог ошибки 1С
Цель: проверить, не завис ли GUI на диалоге ошибки, не читая ЖР.
import os
os.environ['DISPLAY'] = ':99'
from Xlib import display
d = display.Display()
root = d.screen().root
error_windows = []
for win in root.query_tree().children:
name = win.get_wm_name()
wm_class = win.get_wm_class()
if wm_class and '1cv8' in wm_class:
if name and any(kw in name for kw in ['Ошибка', 'Предупреждение', 'Error']):
error_windows.append({'id': win.id, 'name': name})
print(error_windows)
Интерпретация:
| Результат | Вывод |
|---|---|
error_windows пустой, есть другие окна 1С |
База работает нормально |
error_windows пустой, нет окон 1С вообще |
База завершилась (успешно или упала до GUI) |
error_windows не пустой |
Диалог ошибки заблокировал выполнение → перейти к сценарию 2 |
Сценарий 2: Закрыть диалог ошибки и завершить базу
Цель: закрыть базу «естественным путём» после обнаруженного диалога ошибки, чтобы затем анализировать ЖР.
Последовательность клавиш:
-
Enter— закрыть диалог ошибки. -
Escape— инициировать закрытие приложения. -
Enter— подтвердить закрытие.
import os, time
os.environ['DISPLAY'] = ':99'
from Xlib import display, X
from Xlib.ext.xtest import fake_input
def send_key(d, keycode, delay=0.3):
fake_input(d, X.KeyPress, keycode)
d.flush()
time.sleep(delay)
fake_input(d, X.KeyRelease, keycode)
d.flush()
time.sleep(delay)
d = display.Display()
ENTER = d.keysym_to_keycode(0xFF0D)
ESCAPE = d.keysym_to_keycode(0xFF1B)
send_key(d, ENTER) # закрыть диалог ошибки
time.sleep(1)
send_key(d, ESCAPE) # инициировать закрытие
time.sleep(1)
send_key(d, ENTER) # подтвердить закрытие
Важно: после выполнения подождать 2–3 секунды и проверить через сценарий 1, что окон 1С больше нет.
Сценарий 3: Скриншот для лога
Цель: зафиксировать состояние экрана перед закрытием диалога ошибки.
Когда нужен: только для лога или ручной отладки. В автоматическом пайплайне — опционально, перед шагом 2.
import os
os.environ['DISPLAY'] = ':99'
from PIL import ImageGrab
from Xlib import display
d = display.Display()
root = d.screen().root
for win in root.query_tree().children:
name = win.get_wm_name()
wm_class = win.get_wm_class()
if wm_class and '1cv8' in wm_class:
geom = win.get_geometry()
img = ImageGrab.grab(bbox=(
geom.x, geom.y,
geom.x + geom.width,
geom.y + geom.height
))
path = f'/tmp/onec_{win.id}.png'
img.save(path)
print(f'Скриншот сохранён: {path}')
Типичный пайплайн: тесты завершились, база не закрылась
1. search_event_log(from=test_start_time, limit=20)
│
├── есть события, нет Error → база работает, ждать
├── есть Error → скриншот (сценарий 3) → закрыть (сценарий 2) → анализ ЖР
└── нет событий → детектировать окна (сценарий 1)
│
├── окно с ошибкой → скриншот → закрыть
└── нет окон → база не запустилась
Безопасность
| Правило | Описание |
|---|---|
| Только локально | X11-управление работает только в окружении с Xvfb. Не применять на продуктивных серверах с реальным дисплеем. |
| Enter/Escape — не произвольный ввод | Симулировать только навигационные клавиши. Не вводить данные в поля формы. |
| Скриншоты — в /tmp/ | Не сохранять в репозиторий. Скриншоты могут содержать персональные данные из форм 1С. |
Типичные ошибки
| Ошибка | Обходной путь |
|---|---|
DISPLAY не установлен |
os.environ['DISPLAY'] = ':99' до импортов |
python-xlib не установлен |
pip install python-xlib |
PIL.ImageGrab не работает на Linux |
Использовать Pillow + python3-xlib: pip install Pillow |
| Окна 1С не найдены, но процесс есть | Процесс запустился, но GUI ещё не отрисован — подождать 2–3 сек и повторить |
| XTEST extension недоступна | Проверить что Xvfb запущен с флагом -extensions XTEST |
Capabilities
| Capability | Назначение |
|---|---|
python-xlib |
Чтение метаданных окон, симуляция ввода |
PIL ImageGrab |
Скриншот фреймбуфера или отдельного окна |
Связанные навыки
| Навык | Когда использовать |
|---|---|
event-log-analysis |
Анализ причин ошибки после закрытия диалога |
tech-log-analysis |
Технические детали (СУБД, блокировки) если ЖР не даёт ответа |
depends_on: []
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-03-11
- Index updated
- 2026-03-11
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!