2.2 Распознавание нажатых клавиш
Заголовок обработчика события OnKeyDown может иметь, например, следующий вид:
procedure TForml.EditlMouseDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
Параметр Sender, указывающий на источник события, уже обсуждался выше при описании событий мыши (см. раздел 1.2). Там же рассматривался и параметр Shift, представляющий собой множество элементов, отражающих нажатые в это время функциональные клавиши. Только в обработчике события OnKeyDown множество возможных элементов параметра Shift сокращено до ssShift (нажата клавиша Shift), ssAlt (нажата клавиша Alt) и ssCtrl (нажата клавиша Ctrl). Информация о нажатых кнопках мыши отсутствует.
Основной параметр, которого не было раньше — это параметр Key. Обратите внимание, что он определен как var, т.е. может изменяться в обработчике события. Кроме того, обратите внимание, что это целое число, а не символ.
Параметр Key определяет нажатую в момент события клавишу клавиатуры. Для не алфавитно-цифровых клавиш используются виртуальные коды API Windows. Ниже в таблице 5.4 приведены для дальнейшего обсуждения только несколько строк из нее, соответствующих наиболее распространенным клавишам.
Таблица 5.4. Некоторые коды клавиш
Клавиша |
Десятичное число |
Шестнадцате-ричное число |
Символическое имя |
Сравнение по функции Ord |
F1 |
112 |
$70 |
VK_F1 |
|
Enter |
13 |
$OD |
VK_RETURN |
|
Shift |
16 |
$10 |
VK_SHIFT |
|
Ctrl |
17 |
$11 |
VK_CONTROL |
|
Alt |
18 |
$12 |
VK_MENU |
|
Esc |
27 |
$1В |
VK_ESCAPE |
|
0,) |
48 |
$30 |
|
ord('O') |
1 ! |
49 |
$31 |
|
ord('l') |
n,N,т,Т |
78 |
$4Е |
|
ord('N') |
y,Y,H,H |
89 |
$59 |
|
ord('Y') |
Параметр Key является целым числом, определяющим клавишу, а не символ. Например, один и тот же код соответствует прописному и строчному символам «Y» и «у». Если, как это обычно бывает, в русской клавиатуре этой клавише соответствуют символы кириллицы «Н» и «н», то их код будет тем же самым. Различить прописные и строчные символы или символы латинские и кириллицы невозможно.
Проверять нажатую клавишу можно, сравнивая Key с целым десятичным кодом клавиши, приведенном во втором столбце таблицы 5.4. Например, реакцию на нажатие пользователем клавиши Enter можно оформить оператором:
if (Key = 13) then ... ;
Можно сравнивать Key и с шестнадцатеричным эквивалентом кода, приведенным в третьем столбце таблицы 5.4. Например, приведенный выше оператор можно записать в виде:
if (Key = $OD) then ... ;
Для клавиш, которым не соответствуют символы, введены также именованные константы, которые облегчают написание программы, поскольку не требуют помнить численные коды клавиш. Например, приведенный выше оператор можно записать в виде:
if (Key = VK_RETURN) then ... ;
Для клавиш символов и цифр можно производить проверку сравнением с десятичным или шестнадцатеричным кодом, но это не очень удобно, так как труднс помнить коды различных символов. Другой путь — воспользоваться функцией ord, определяющей код символа. Коды латинских символов в верхнем регистре совпадают с виртуальными кодами, используемыми в параметре Key. Поэтому, на пример, если вы хотите распознать клавишу, соответствующую символу «Y», вы можете написать:
if (Key = ord('Y') then ... ;
В этом операторе можно использовать только латинские символы в верхнем регистре. Если вы напишете ord('y') или захотите написать русские символы, соответствующие этой клавише — ord('H') или огд('н'), то оператор на сработает.
Помните также, что оператор будет действовать на все символы, относящиеся к указанной клавише: «Y», «у», «Н» и «н». Иногда это хорошо, а иногда плохо. Например, если вы задали пользователю какой-то вопрос, на который он должен ответить Y (да) или N (нет), то подобный оператор избавляет пользователя от необходимости следить, в каком регистре он вводит символ и какой язык — английский или русский включен в данный момент. Ему достаточно просто нажать клавишу, на которой написано «Y». Однако, если пользователь более привык к символам кириллицы, то могут возникнуть неприятности, поскольку нажимая клавишу с латинской буквой «Y» и русской буквой «Н» он может думать, что отвечает не положительно (Yes — да), а отрицательно (Нет).
Приведем еще один пример — автоматическую передачу фокуса очередному оконному компоненту при нажатии пользователем клавиши Enter. Это можно сделать, включив в общий обработчик событий OnKeyDown всех оконных компонентов оператор:
if (Key = VK_RETURN) then
FindNextControl(Sender as TWinControl,true,true, false) .SetFocus;
Этот оператор с помощью метода FindNextControl ищет очередной компонент в последовательности табуляции и передает ему фокус. Подробнее этот пример и метод FindNextControl рассмотрен в разделе 5.1.8.
В заключение приведем пример распознавания комбинации клавиш. Пусть вы хотите, например, распознать комбинацию Alt-X. Для этого вы можете написать оператор:
if((Key = ord('X'))and (ssAlt in Shift)) then ... ;
Мы рассмотрели распознавание клавиш при событии OnKeyDown. Заголовок обработчика события OnKeyUp имеет такой же вид, так что все сказанное в равной степени относится и к событиям при отпускании клавиш.
Теперь перейдем к рассмотрению события OnKeyPress. Заголовок обработчика этого события имеет вид':
procedure (Sender: TObject; var Key: Char);
В этот обработчик, как и в описанные выше, передается параметр Key, определяющий нажатую клавишу символа. Но обратите внимание, что тип этого параметра не целое число, как в предыдущих случаях, a Char — символ. В данном случае в обработчик передается не виртуальный код клавиши, а символ, по которому можно определить, прописная это буква, или строчная, русская, или латинская. Поэтому описанных выше сложностей с распознаванием символов не возникает.
Пусть, например, вы задали пользователю вопрос, на который он должен ответить символами «Д» или «д» (да), или символами «Н» или «н» (нет). Тогда распознать положительный ответ в обработчике события OnKeyPress можно оператором:
if ((Key = 'Д') or (Key = 'д')) then ...
Этот оператор можно записать короче, воспользовавшись операцией 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 ['О'..'9', ' ', ',']) then
begin
Key := #0;
Beep;
end;