Ключевые события: ProcessCmdKey
Я пытаюсь получить ответ клавиатуры в небольшом тестовом приложении Windows Form, и у меня есть грубое решение, которое заключается в переопределении ProcessCmdKey. Однако есть несколько проблем, с которыми я сталкиваюсь, и несоответствия, которые я нахожу.
Разные события: есть ли способ сказать, в аргументах ref Message msg, Keys keyData
, является ли даже KeyDown, KeyUp или KeyPress?
KeyPress: везде, где я смотрел, говорится, что KeyPress, то есть повторный ввод с клавиатуры, происходит только для символьных клавиш, а клавиши со стрелками - нет. Однако обработчик событий вызывается так же часто и в том же манере / с тем же поведением для клавиш со стрелками, как и символьные клавиши. Является ли это событием KeyPress, или это что-то еще?
В идеале мне бы хотелось, чтобы на уровне формы обрабатывались все события клавиатуры, чтобы они не передавались элементам управления в форме. Однако вся документация меня достаточно смутила и упустила ключевые моменты, так что я не смог это завершить.
Помощь по любой из этих тем приветствуется. Спасибо!
2 ответа
Структура сообщения, передаваемая в ProcessCmdKey(), содержит номер сообщения WINAPI в свойстве Msg:
WM_KEYDOWN
является0x100
(256),WM_KEYUP
является0x101
(257),WM_CHAR
(примерно эквивалентноKeyPress
) является0x102
(258),WM_SYSKEYDOWN
является0x104
(260),WM_SYSKEYUP
является0x105
(261).
По поводу вашего вопроса о KeyPress
, это правда, что не символьные клавиши, такие как клавиши со стрелками, не генерируют WM_CHAR
сообщения внутри, но они генерируют WM_KEYDOWN
и это сообщение также отправляется несколько раз для повторного ввода.
Также обратите внимание, что я не уверен ProcessCmdKey()
это правильный способ достичь того, что вы хотите. Документация описывает это как только обработку main menu command keys and MDI accelerators
, который может быть только подмножеством ключей, которые вы хотите поймать. Вместо этого вы можете переопределить ProcessKeyPreview(), который обрабатывает все сообщения клавиатуры, полученные дочерними элементами управления.
Переопределение ProcessCmdKey в вашей форме явно предназначено для того, чтобы позволить вам реализовать настраиваемую обработку сочетаний клавиш помимо встроенной обработки мнемоник в кнопках и элементах меню.
Он вызывается только при событии нажатия клавиши до того, как элемент управления с фокусом получает событие KeyDown и независимо от того, какой элемент управления клиента имеет фокус. Так что не связано с KeyUp и не с KeyPress. Вы возвращаете true из переопределения, когда узнаете клавишу после выполнения функции ярлыка. Это предотвращает дальнейшую обработку ключа и не генерирует никаких событий KeyDown/Press/Up.
Использовать аргумент msg метода очень редко, значение msg.Msg всегда будет иметь значение WM_KEYDOWN или WM_SYSKEYDOWN, причем последнее сообщение выдается, когда пользователь удерживает нажатой клавишу Alt. Что вас не волнует, так как вы всегда можете получить if из аргумента keyData. Как это:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
if (keyData == (Keys.Alt | Keys.F)) {
// Alt+F pressed
doSomething();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
Другие модификаторы, которые вы можете проверить с помощью | Оператор, используемый здесь, это Keys.Shift и Keys.Control. Поэтому (Keys.Shift | Keys.Control | Keys.F1) проверяет наличие Ctrl+Shift+F1. Вы можете интерпретировать данные сообщения, когда хотите сделать что-то необычное, например, проверку повторяющихся клавиш. Проверьте документы MSDN для уведомления WM_KEYDOWN. Значение msg.LParam содержит набор информации о нажатии клавиши.
Обратите внимание, что вы получаете только виртуальные ключи в этом методе. Keys.F - это клавиша F на английской раскладке клавиатуры, но не обязательно та же буква для клавиши в том же месте на раскладке пользователя. Пользуйтесь функциональными клавишами, чтобы избежать головной боли от документации.
Повторение клавиш является функцией контроллера клавиатуры и не ограничивается набором клавиш. Стрелка и функциональные клавиши будут обязательно повторяться при удерживании. Вы хотите игнорировать KeyPress в этом сценарии. Но если вы назначите комбинацию клавиш для клавиши, которая также является клавишей ввода (например, Keys.F), то вы также всегда должны проверять клавишу-модификатор, чтобы не нарушать элементы управления, такие как TextBox.
И последнее, но не менее важное: не забывайте о встроенной поддержке мнемоники в кнопках и элементах управления меню. Написание их свойства Text, как &OK
создает самодокументируемый ярлык без кода. Управляемый пользователем, в этом примере, набрав Alt+O.