Состояние физического ключа

Две функции состояния ключа в API WIndows, GetKeyState() и GetAsyncKeyState(), определяют состояние ключа на основе сообщений о включении/отключении ключа, а не на физическом состоянии ключа.

Я работаю над программой, которая манипулирует вводом, используя SendInput(), чтобы отпустить клавиши-модификаторы (alt, ctrl и т. д.), отправить ввод, а затем повторно нажать клавиши-модификаторы.

Проблема в том, что я не знаю, нажаты ли клавиши-модификаторы после отправки ввода, потому что я отправил событие нажатия клавиши, и обе вышеупомянутые функции возвращают, что клавиша нажата независимо от состояния физического ключ. Поэтому, если я предполагаю, что они все еще не работают, пользователь остается с оборванным ctrl-down, вызывающим проблемы, пока пользователь снова не нажмет и не отпустит cntl (или любую клавишу-модификатор). В противном случае ключ может оставаться нажатым, даже если физический ключ все еще нажат.

Итак, есть ли способ (желательно без чего-либо слишком низкого уровня) определить состояние физического ключа. Методы только для Windows подходят. Мониторинг клавиш (прослушивание событий нажатия клавиш) на самом деле невозможен (или, по крайней мере, действительно не предпочтителен).


person Chad Schouggins    schedule 21.11.2011    source источник


Ответы (3)


Вы не даете оконному менеджеру достаточно времени для обработки ввода, который вы только что ввели. Пока не будет достигнута часть кода «обновить состояния ключей для GetAsyncKeyState», GetAsyncKeyState будет сообщать о старом значении. (В частности, он не достигнет этой точки, пока все низкоуровневые перехватчики клавиатуры не получат возможность проверить действие и, возможно, отклонить его.)

Другими словами, ваш код имеет состояние гонки, и это то, что вы наблюдаете.

person Raymond Chen    schedule 28.12.2011

Вы тут немного путаетесь. На самом деле GetAsyncKeyState() возвращает состояние ключа в момент вызова GetAsyncKeyState(). С другой стороны, GetKeyState() возвращает состояние ключа на основе истории сообщений в очереди.

person David Heffernan    schedule 21.11.2011
comment
MSDN утверждает то же самое, однако при тестировании это не так. После отправки события нажатия клавиши GetAsyncKeyState() фактически сообщает, что клавиша включена, независимо от состояния физического ключа. (64-разрядная версия Win7) - person Chad Schouggins; 22.11.2011
comment
Итак, вы думаете, что что-то настолько фундаментальное сломано в Windows, и никто не замечал этого в течение 25 лет? - person David Heffernan; 22.11.2011
comment
Я знаю, что он вернет неверный результат после отправки события нажатия клавиши. - person Chad Schouggins; 22.11.2011
comment
Похоже, вы нашли ошибку в этом случае. Пожалуйста, отправьте отчет об ошибке в MS. Не забудьте включить полный пример рабочего кода, демонстрирующий обнаруженную проблему. - person David Heffernan; 24.11.2011
comment
@ЧадШоггинс; при использовании GetAsyncKeyState обязательно проверяйте только старший бит SHORT, чтобы проверить состояние ключа. Очень распространенной ошибкой является проверка младшего бита или просто проверка того, что общее значение не равно нулю, что даст неверный результат. См. MSDN для получения полной информации. Это отличается от GetKeyState(), где вы обычно можете обойтись простым сравнением с нулем; нельзя просто заменить одно другим. - person BrendanMcK; 27.11.2011
comment
@BrendanMcK Спасибо, но я проверяю только старший бит. - person Chad Schouggins; 28.11.2011

После долгих испытаний я, кажется, понял это. MSDN сообщает о GetKeyState() :

Состояние ключа, возвращаемое этой функцией, изменяется по мере того, как поток считывает ключевые сообщения из своей очереди сообщений.

GetAsyncKeyState() по-прежнему работает с сообщениями о включении/выключении клавиш (не о состоянии физической клавиши), однако он просто не ждет, пока сообщение будет прочитано. Таким образом, если сообщение о ключевом событии отправлено через SendInput(), оно все равно вернет неверный результат — на самом деле, оно будет неверным до GetKeyState(), потому что оно будет неверным сразу после вызова.

Простой тест для демонстрации этой функциональности находится здесь (решение VS2010) или просто исходный код здесь.

person Chad Schouggins    schedule 26.11.2011
comment
GetAsyncKeyState() по-прежнему работает с сообщениями о нажатии/нажатии клавиши (а не о состоянии физической клавиши) просто противоречит документация MSDN - person David Heffernan; 27.11.2011
comment
Это не имеет значения. Вот как это работает. Как только ключевое событие публикуется, возвращаемое значение GetAsyncKeyState() изменяется. - person Chad Schouggins; 28.11.2011
comment
Клавиша падает, сообщение публикуется. Да, примерно так и бывает! - person David Heffernan; 28.11.2011
comment
Или если ключевое событие моделируется через SendInput() - весь смысл этого вопроса. - person Chad Schouggins; 28.11.2011
comment
Что бы ни. Все это описано в MSDN. Вы считаете, что MSDN ошибается. - person David Heffernan; 28.11.2011
comment
MSDN явно не описывает реализацию. Помимо SendInput(), он работает как состояния MSDN. Но вам явно все равно, и вы столкнулись с проблемой, если вам когда-нибудь понадобится имитировать пользовательский ввод и определять ключевые состояния, помните этот пост. - person Chad Schouggins; 28.11.2011