События клавиатуры

В оконных компонентах Delphi определены три события, связанные с клавиатурой.

OnKeyDown - наступает при нажатии пользователем любой клавиши.

Можно распознать нажатые клавиши, включая функциональные, и кнопки мыши, но нельзя распознать символ нажатой клавиши

OnKeyPress - наступает при нажатии пользователем клавиши символа.
!

Можно распознать нажатую клавишу символа, различить символ в верхнем и нижнем регистре, различить символы кириллицы и латинские, но нельзя распознать функциональные клавиши и кнопки

OnKeyUp - наступает при отпускании пользователем любой клавиши.
!

  Можно распознать нажатые клавиши, включая функциональные, и кнопки мыши, но нельзя распознать символ отпускаемой клавиши

Кроме того, при нажатии пользователем клавиши табуляции фокус может переключаться с элемента на элемент, что вызывает события OnEnter и OnExit.

Важно четко представлять последовательность событий, происходящих при нажатии пользователем клавиши или комбинации клавиш.

Пусть, например, пользователь нажал клавишу Shift (перевел ввод в верхний регистр), а затем нажал клавишу символа “н”. Последовательность событий для этого случая приведена в таблице.
Нажатие клавиши Shift

OnKeyDown. Возможно распознавание нажатой клавиши Shift

Нажатие клавиши “н”

OnKeyDown. Возможно распознавание нажатой клавиши Shift, нажатой клавиши “н”, но отличить верхний регистр от нижнего и латинский символ от русского невозможно

ОпКеу Press. Возможно распознавание символа с учетом регистра и языка, но невозможно распознавание нажатой кла­виши Shift

Отпускание клавиши “н”

OnKeyUp. Возможно распознавание нажатой клавиши Shift, отпущенной клавиши “н”, но отличить верхний регистр от нижнего и латинский символ от русского невозможно

Отпускание клавиши Shift

OnKeyUp. Возможно распознавание отпущенной клавиши Shift




Замечание. Событие OnKeyPress заведомо наступает, если нажимается только клавиша символа или клавиша символа при нажатой клавише Shift. Если же клавиша символа нажимается одновременно с какой-то из вспомогательных клавиш, то событие OnKeyPress может не наступить (произойдут только события OnKeyDown при нажатии и OnKeyUp при отпускании) или, если и наступит, то укажет на неверный символ. Например, при нажатой клавише Alt событие OnKeyPress при нажатии символьной клавиши не наступает. А при нажатой клавише Ctrl событие OnKeyPress при нажатии символьной клавиши наступает, но символ не распознается.

Куда поступают события клавиатуры?

У формы имеется свойство KeyPreview. Оно влияет на обработку событий, поступающих от клавиатуры (в число этих событий не входит нажатие клавиш со стрелками, клавиш табуляции и т.п.). По умолчанию свойство KeyPreview = false и события клавиатуры поступают на обработчики, предусмотренные в активном в данный момент компоненте. Но если задать значение KeyPreview = true, то сначала эти события будут поступать на обработчики формы, если таковые предусмотрены, и только потом поступят на обработчики активного компонента.

Распознавание нажатых клавиш

Заголовок обработчика события OnKeyDown может иметь, например, следующий вид:

procedure TForm1.Edit1KeyDown (Sender: TObject; var Key: Word; Shift: TShiftState);

Параметр Sender указывает на источник события

Параметр Shift, представляет множество элементов, отражающих нажатые в это время функциональные клавиши.
!

Здесь множество возможных элементов параметра Shift сокращено до ssShift (нажата клавиша Shift), ssAlt (нажата клавиша Alt) и ssCtrl (нажата клавиша Ctrl). Информация о нажатых кнопках мыши отсутствует.   

Основной параметр - параметр Key.
!

Обратите внимание, что он определен как var, т.е. может изменяться в обработчике события. Обратите внимание, что это целое число, а не символ.             

         

Параметр Key определяет нажатую в момент события клавишу клавиатуры.

Полную таблицу этих кодов можно посмотреть во встроенной справке Delphi. Ниже приведены для дальнейшего обсуждения только несколько строк из нее, соответствующих наиболее распространенным клавишам.                                         

Параметр Key является целым числом, определяющим кдавишу, а не символ. Например, один и тот же код соответствует прописному и строчному символам “Y” и “у”. Если, как это, обычно бывает, в русской клавиатуре этой клавише соответствуют символы кириллицы “Н” и “н”, то их код будет тем же самым. Различить прописные и строчные символы или символы латинские и кириллицы невозможно.

Проверять нажатую клавишу можно:

• сравнивая Key с целым десятичным кодом клавиши

Например,       if (Key = 13) then ... ;

• сравнивая Key  с шестнадцатеричным эквивалентом

Например,       if (Key = $OD) then ... ;

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

      Например,       if (Key = VK_RETURN) then ... ;

• Другой путь — воспользоваться функцией ord, определяющей код символа. Коды латинских символов в верхнем регистре совпадают с виртуальными кодами, используемыми в параметре Key.

Например, чтобы распознать клавишу, соответствующую символу “Y”, можно

                              if (Key = ord('Y') then ... ;

Замечание ! В этом операторе можно использовать только латинские символы в верхнем регистре. Если ord('y') или русские символы, соответствующие этой клавише — ord('H') или ord('н'), то оператор на сработает.

!

Оператор будет действовать на все символы, относящиеся к указанной клавише: “Y”, “у”, “Н” и “н”.

Распознавание комбинаций клавиш

Например, для распознавания  комбинации Alt-X следует воспользоваться оператором           

if  (Key = ord('X')) and (ssAlt in Shift)) then .. . ;   

Автоматическая передача фокуса очередному компоненту при нажатии пользователем клавиши Enter.

Это можно сделать, обрабатывая событие нажатия клавиши OnKeyDown, двумя способами.

1.   Ввести во все окна операторы передающие фокус, обеспечивая требуемую последовательность действий

Например, после ввода данных в окно Edit1 необходимо переключиться в окно Edit2

procedure  TForm1.Edit1KeyDown (Sender: TObject; var Key: Word; Shift: TShiftState);

begin

   if (Key = VK_RETURN) then  Edit2.SetFocus;

end;

2.   Использовать единый обработчик событий OnKeyDown для различных окон (для различных кнопок - обработчик события OnClick).

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

Метод определен следующим образом:

FindNextControl (CurControl: TWinControl; GoForward, CheckTabStop,

                              CheckParent : boolean) :   TWinControl;

Возвращает следующий за указанным в параметре CurControl дочерний оконный компонент в соответствии  с последовательностью табуляции.

Здесь GoForward определяет направление поиска (True - вперед).

Параметры CheckTabStop, CheckParent определяют условия поиска:

если CheckTabStop=true, то просматриваются компоненты, у которых  TabStop=True,

если CheckTabStop=false, то значение  TabStop не принимается во внимание

если CheckParent =true, то просматриваются только прямые потомки

если CheckParent =false, то просматриваются все (и косвенные)потомки данного элемента

Итак, чтобы автоматически передавать фокус при нажатии клавиши Enter следует написать единый обработчик событий OnKeyDown для всех оконных компонентов, содержащий оператор

     if (Key = VK_RETURN)

          then  FindNextControl (Sender as TWinControl, true, true, false).SetFocus;

Этот оператор обеспечивает передачу фокуса очередному компоненту.

Для кнопок в  обработчик события OnClick следует вставить оператор

          FindNextControl (Sender as TWinControl, true, true, false).SetFocus;

Заголовок обработчика события OnKeyUp имеет такой же вид как и OnKeyDown, так что все сказанное в равной степени относится и к событиям при отпускании клавиш.                           

Рассмотрим событие OnKeyPress. Заголовок обработчика этого события имеет вид:               

procedure (Sender: TObject; var Key: Char);

В этот обработчик также передается пapаметр Key, определяющий нажатую клавишу символа.

! Но тип этого параметра не целое число, a Char.

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

Пусть, например, вы задали пользователю вопрос, на который он должен ответить символами “Д” или “д” (да), или символами “Н” или <н” (нет). Тогда распознать положительный ответ в обработчике события OnKeyPress можно оператором:            1

if ((Key = 'Д') or (Key = 'д')) then ...             

Или короче, воспользовавшись oперацией in:     if (Key in ['Д', 'д']) then ...;                       

Приведенные операторы реагируют только на положительный ответ пользователя, не реагируя на отрицательный или ошибочный ответ.

Реакцию на все возможные ответы обеспечивает структура case:

case Key  of

  ‘Д','д':      ...;

   ‘Н',’н':      ...;

else Beep;

end;

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

Параметр Key передается как var. Это позволяет в обработчике изменять этот параметр, изменяя соответственно его стандартную обработку в компоненте, поскольку ваш обработчик события срабатывает раньше стандартного обработчика компонента.

Пусть, например, вы хотите иметь на форме окно редактирования Edit1, в котором пользователь должен вводить только целые числа без знака, разделенные запятыми или пробелами. Вы можете обеспечить безошибочный ввод, подменяя все недопустимые символы нулевым с помощью, например, такого оператора:

if not (Key in ['0'..'9', '  ' , ', ']) then Key := #0;

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

if not (Key in ['0'..'9', ' ', ',']) then

begin

Key := #0;

   Beep;

end;