События клавиатуры: гарантируется ли порядок?


Для нажатия одной клавиши существует несколько событий, которые могут быть обработаны.

Есть: KeyDown, KeyPressed, KeyUp.

Гарантируется ли, что приложение будет получать эти события в таком порядке?

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

Контекст:

После того, как у меня возникли некоторые проблемы с событиями нажатия клавиш в устаревшем приложении C++ Я изучал события с spy++. Там я и увидел это. порядок, похоже, иногда не быть правым и keypressed не уволить за каждый keydownили keyup.

Но я был уверен, что события должны происходить именно в таком порядке, но ... не смог ничего найти в интернете. Вот я и задал этот вопрос. Пожалуйста, обратите внимание, что это не проблема нескольких языков, но мне интересно, верно ли это для C++, Java и C#.
2 2

2 ответа:

Они должны происходить в таком порядке, когда они происходят, в большинстве приложений. Но ваше окно может не получать каждое событие для каждого введенного символа.

Например, в Windows, Если вы удерживаете клавишу, вы увидите KeyDown и/или KeyPressed несколько раз, когда ключ повторяется, и один KeyUp, когда ключ отпущен.

Правка:

Однако теперь, когда я об этом думаю...Windows начинает публиковать только сообщения WM_KEYDOWN и WM_KEYUP в вашем окне (и только если у вас есть фокус). WM_CHAR сообщения (аналог Win32 для KeyPressed) публикуются на основе тех, когда цикл сообщений вызывает TranslateMessage. Это означает две вещи:
  • Если у окна есть отставание сообщений, API может просто добавить сообщение в конец очереди (IDK); это имеет больше смысла для меня (очередь сообщений-это очередь , в конце концов, а не стек), но это означает, что если в очереди уже есть WM_KEYUP для этого ключа (например, если пользователь нажал и отпустил ключ, пока он находится в очереди), то обрабатывается другое сообщение), то после может появиться соответствующее WM_CHAR .
  • языки, такие как C и C++, обладают большей гибкостью (читай: меньше встроенной автоматизации) в том, как они обрабатывают сообщения; для того, чтобы они получили сообщения WM_CHAR, они должны либо вызвать TranslateMessage явно, либо сделать перевод самостоятельно (за исключением другого приложения, отправляющего такие сообщения). В последнем случае неизвестно, в каком порядке будут отправлены сообщения.

Также, как как уже упоминалось в комментариях, если фокус переключается при выключенной клавише, вы можете увидеть только KeyUp или KeyDown. (Состояние ключа было уже таким до переключения фокуса, и Windows, вероятно, не расскажет вам об этом.) И мертвые ключи (те, которые не генерируют символ сами по себе) вообще не вызовут KeyPressed (хотя обычно они запускают KeyUp и KeyDown). Обычно они просто ждут следующего реального персонажа и модифицируют его.

Краткая версия всего этого : вы можете положиться о порядке появления событий KeyDown относительно друг друга. То же самое с KeyPressed и даже KeyUp. Но, по крайней мере в Windows, эти три типа сообщений на самом деле не согласованы друг с другом. Поэтому не предполагайте, что каждый KeyUp будет соответствовать KeyDown (или наоборот), или что KeyPressed появляется перед KeyUp.

Вероятно, вам также следует решить, хотите ли вы обрабатывать символы или ключи. Это часть путаницы здесь, я думаю; эти два на самом деле разные понятия, и большую часть времени вы действительно заботитесь только об одном или другом. В то время как Win32 якобы сообщит вам код ключа, когда вы обрабатываете событие KeyPressed, реальная цель этого события-сообщить вам, какой символ был введен. (Есть причина, по которой он называется WM_CHAR, а не WM_KEYPRESS. :) И почему тип .net KeyPressEventArgs имеет только KeyChar, а не KeyCode.) Другие два рассматривают клавиатуру как в основном кучу кнопок.

Если вы являетесь пользователем Windows, эмпирическое правило здесь таково: проверьте порядок событий путем регистрации или в отладчике, а затем предположите, что это будет всегда так.

Это не идеально, но это работает в 95% случаев. Я много раз слышал истории о том, что команда Windows всегда отталкивает назад, чтобы что-то изменить, потому что на 100% уверена, что это что-то сломает.

Это прямой результат плохой документации эпохи Windows 2.0.