Ключевые события: 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.

Другие вопросы по тегам