X11 / Xlib: проблема синхронизации ввода виртуальной клавиатуры и сопоставления клавиатуры - PullRequest
1 голос
/ 18 марта 2019

Для автоматизированного тестового приложения мне нужно смоделировать большое количество ввода с клавиатуры в юникоде в старое приложение X11 (из которого у меня нет доступа к источнику).Моя программа берет ввод из кодированного входного потока UCS-2 LE через stdin, и основные операции выполняются следующим образом:

  1. Сохранение текущей раскладки клавиатуры и модификаторов блокировки (XDisplayKeycodes, XGetKeyboardMapping, XkbGetState)
  2. Разблокировать активные модификаторы (XkbLockModifiers)
  3. Отключить все подчиненные устройства клавиатуры X11 через расширение Xinput2
  4. Считывать ввод в очередь нажатия клавиш до тех пор, пока n не станет уникальнымвстречаются символы, где n - количество возможных кодов клавиш, возвращаемых XDisplayKeycodes.
  5. Сопоставьте эти n уникальные X11 KeySyms с помощью XChangeKeyboardMapping на n доступных KeyCodes
  6. Введите правильные коды клавиш для всех перечисленных ключей KeySyms через XTestFakeKeyEvent
  7. Очистите очередь и продолжайте в 4.), пока не будет доступен ввод
  8. Повторно активируйте клавиатуры и восстановите начальные модификаторы и сопоставления

По сути, эта система работает лучше и намного более производительно, чем любой инструмент ввода виртуальных клавиш X11, который я видел до сих пор.

Однако есть проблема, которую я могу пока только исправитьиспользуя ужасные задержки:

Как и любое другое приложение X11, целевое приложение получает событие X 1036 * (request == Keyboard) от X-сервера после того, как моему приложению удалось изменить таблицу сопоставления клавиатуры.Обычный ответ клиента X11 - вызвать XRefreshKeyboardMapping, чтобы обновить знания Xlib о новой раскладке клавиатуры.

Теперь, если у клиента есть некоторая задержка при обработке его очереди событий X11, вызов XRefreshKeyboardMapping может вернутьслишком недавнее картирование, которое уже на несколько поколений слишком далеко в будущем.Например, мой генератор ввода уже выполнил четвертый XChangeKeyboardMapping, когда целевое приложение только что обработало второе событие MappingNotify в своем обработчике очереди XEvent.На самом деле он должен получить второе поколение карты, которая больше не доступна на X-сервере в то время.

К сожалению, в событии клавиатуры MappingNotify нет идентификатора карты или какой-либо версии, поэтомучто XRefreshKeyboardMapping может ссылаться на конкретную карту ... и сервер X, похоже, также не ведет историю.

В результате преобразование KeyCode в KeySym приложения X11 работает сневерный макет и генерирует неправильные KeySyms.

Поэтому в основном мне приходится ждать, пока все клиенты (или, по крайней мере, один с фокусом ввода) запросят и получат мою последнюю карту XChangeKeyboardMapping, прежде чем мне разрешат сделатьдалее XChangeKeyboardMapping.

Я могу исправить 99,9% ошибок, используя задержку до XChangeKeyboardMapping, и эта задержка рассчитывается неким уродливым колдовством (количество нажатий клавиш и т. д.) и становится слишком высокой, если 100% точности должна быть достигнута.

Поэтому мой вопрос заключается в том, есть ли какой-либо способ программно получить уведомление или проверить, завершил ли клиент X11 XRefreshKeyboardMapping илиs карта синхронизирована с картой сервера?

Если нет, есть ли способ получить текущее отображение другого клиента X11 через xlib (чтобы проверить, является ли карта текущей)?

Спасибо залюбые намеки!

1 Ответ

1 голос
/ 19 марта 2019

В прошлом я делал нечто похожее на Windows. Я мог позволить себе роскошь использовать функцию SendInput, которая принимает структуру KEYBDINPUT с флагом KEYEVENTF_UNICODE. К сожалению, X11 не поддерживает прямое синтезирование клавиш Unicode.

Поскольку я пока не могу комментировать, я вынужден дать предложение в качестве ответа:

Рассматривали ли вы вместо этого использование буфера обмена для передачи вашего " ввода Unicode " в поле ввода этого приложения X11?

Вы также можете рассмотреть возможность использования прямого ввода Unicode, если это приложение использует инструментарий, который поддерживает это:

например. программы на базе GTK + (включая все приложения GNOME) поддерживают ввод Unicode.
Удерживайте Ctrl + Shift, введите u, затем шестнадцатеричные цифры Unicode и снова отпустите Ctrl и Shift.

Полагаю, эти последовательности легко синтезировать с использованием расширения Xtest.

...