Для автоматизированного тестового приложения мне нужно смоделировать большое количество ввода с клавиатуры в юникоде в старое приложение X11 (из которого у меня нет доступа к источнику).Моя программа берет ввод из кодированного входного потока UCS-2 LE через stdin, и основные операции выполняются следующим образом:
- Сохранение текущей раскладки клавиатуры и модификаторов блокировки (
XDisplayKeycodes
, XGetKeyboardMapping
, XkbGetState
) - Разблокировать активные модификаторы (
XkbLockModifiers
) - Отключить все подчиненные устройства клавиатуры X11 через расширение Xinput2
- Считывать ввод в очередь нажатия клавиш до тех пор, пока
n
не станет уникальнымвстречаются символы, где n
- количество возможных кодов клавиш, возвращаемых XDisplayKeycodes
. - Сопоставьте эти
n
уникальные X11 KeySyms с помощью XChangeKeyboardMapping
на n
доступных KeyCodes - Введите правильные коды клавиш для всех перечисленных ключей KeySyms через
XTestFakeKeyEvent
- Очистите очередь и продолжайте в 4.), пока не будет доступен ввод
- Повторно активируйте клавиатуры и восстановите начальные модификаторы и сопоставления
По сути, эта система работает лучше и намного более производительно, чем любой инструмент ввода виртуальных клавиш 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 (чтобы проверить, является ли карта текущей)?
Спасибо залюбые намеки!