17.6.3. Клавиатура в MS-DOS и Windows

Следует заметить, что Windows значительно “строже” относится к использованию клавиатуры, чем MS-DOS. Это может вызывать проблемы при переносе игровых приложений, а также приложений, созданных с помощью FoxPro или Clipper, в среду Delphi.

Если вы захотите сохранить устоявшиеся приемы использования клавиатуры в новой разработке (а я настоятельно рекомендую сделать это), вам, возможно, придется перехватывать сообщения Windows, так как только таким способом программа сможет опознать факт нажатия на системные клавиши Alt, Tab, Shift и т. п. Нажатие на остальные клавиши можно анализировать с помощью перехвата сообщений от клавиатуры в обработчиках Опкеуххх формы при установленном значении True в ее свойство Keypreview. Например, пусть акселератор Alt+X используется в существующей программе для закрытия модального диалогового окна. Чтобы сконструированное вами окно закрывалось по этой команде, напишите для него такой Обработчик события OnKeyDown:

procedure TForm2.FormKeyDown(Sender: TObject;

var Key: Word; Shift: TShiftState) ;

begin

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

end;

Во многих случаях можно использовать собственные клавиши-акселераторы Windows. К сожалению, такими клавишами снабжаются лишь опции меню, но связанные с ними (опциями) обработчики OnClick выйолняются даже в том случае, когда опция меню не видна (ее свойство visible имеет значение False). Этим можно воспользоваться, чтобы вставить в главное меню окна фиктивные невидимые опции, связав их с нужными акселераторами. Пусть, например, клавиша Buttoni должна “нажиматься” при нажатии Ctrl+S. Поместите на форму главное меню (если его еще нет) и создайте в нем опцию-заголовок с произвольным именем, например, MyButton. В списке свойства Shortcut опции выберите Ctrl+S и установите False в ее свойство visible. Теперь можно связать ее обработчик события OnClick непосредственно с Button1Click или написать такой обработчик:

procedure TForm2.MyButtonClick(Sender: TObject);

begin

ButtonlClick(Self)

end;

И хотя опция MyButton главного меню не видна, нажатие связанных с ней клавиш Ctrl+S вызовет срабатывание нужного обработчика. В этом случае форма может не перехватывать клавиатурный ввод.

Как уже отмечалось, обработчики Опкеуххх не реагируют на нажатие системных клавиш Windows, в том числе - клавиш смещения курсора. Происходит это из-за того, что умалчиваемая оконная функция программы осуществляет стандартную обработку соответствующих сообщений Windows. Оконная функция связывается с каждым программным окном. Ее назначение - осуществлять связь программы с Windows. В оконную функцию главного окна программы Windows помещает сообщения о наступлении того или иного события, в том числе - о нажатии на клавишу. Оконная функция главного окна передает это сообщение оконной функции окна с фокусом ввода (см. ниже п. 17.6.4), а та, в свою очередь - функции сфокусированного оконного компонента. Чтобы получать все адресованные программе сообщения Windows, необходимо использовать метод HookMainwindow глобального объекта-программы Application или его обработчик события OnMessage. Единственным параметром обращения к методу Application. HookMainwindow является имя функции типа

TWindowHook = function(var Message: TMessage): Boolean of object;

которая будет получать сообщение Message. Возвращаемый ею результат и возможные изменения сообщения Message игнорируются. Фактически функция получает сообщение параллельно с иконной функцией и не может воздействовать на обработку сообщения. В отличие от этого обработчик Application. OnMessage

type

TMsg = packed record

hwnd: HWND; message: UINT; wParam: WPARAM; IParam: LPARAM;

time: DWORD; pt: TPoint;

end;

TMessageEvent = procedure (var Ms.g: TMsg;

var Handled: Boolean) of object-property OnMessage: TMessageEvent;

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

В переменных типа TMsg ядро Windows передает программе так называемые сообщения - небольшие пакеты данных, оповещающие программу о наступлении того или иного события, будь то нажатие на клавишу, перемещение мыши или наступление нужного момента времени. Три параметра этого пакета используются следующим образом: Message - код события, wParam и lParam - уточняющие параметры. Для сообщения о нажатии клавиши код Message определен константой wm_KeyDown (256) или (при отпускании клавиши) wm_KeyUp (257), параметр wParam содержит виртуальный код нажатой клавиши, а IParam - дополнительные параметры, такие как количество нажатий клавиши с момента последнего обращения к функции перехвата, признак нажатой и удерживаемой Shift-клавиши и т. п.

Вот как, например, можно использовать клавиши курсора для смещения изображения (квадрата) в компоненте PaintBox:

type

TFormI = class (TForm)

PaintBoxl: TPaintBox;

procedure FormCreate(Sender: TObject);

procedure FormDestroy(Sender: TObject);

procedure PaintBoxIPaint(Sender: TObject);

private

{ Private declarations }

public .

{ Public declarations }

X, Y: Integer- procedure Hook(var Msg: TMsg; var Handled: Boolean);

end;

procedure TFormI.FormCreate(Sender: TObject);

{Регистрируем обработчик OnMessage в момент создания главного окна программы и устанавливаем начальное положение квадрата} begin

Application.OnMessage := Hook;

X := 100;

Y := 100;

end;

procedure TFormI.Hook(var Msg: TMsg; var Handled: Boolean);

begin

if Msg.Message<>wm_keyDown then //Сообщение от клавиатуры?

Exit; //Нет case Msg.wParam of

vk_Left: dec(X,10); //Смещение влево

vk_Right: inc(X,10); //Смещение вправо

vk Up: dec(Y,10); //Смещение вверх

vk_Down: inc(Y,10); //Смещение вниз end;

Paintboxl.Repaint;

Handled := True; //Блокируем дальнейшую обработку end;

procedure TFormI.PaintBoxIPaint(Sender: TObject);

(Вычерчиваем квадрат со стороной 20 пикселей и центром в точке X, Y} begin

with PaintBoxl.Canvas do

Rectangle(X-10,Y-10,X+10,Y+10)

end;

Примечание

В Delphi 5 и 6 специальный компонент TApplicationEvents, который существенно упрощает обработку любых сообщений Windows до торр, как они поступят в оконную функцию активной

Для клавиш определены следующие виртуальные коды:

Код

Значение

Клавиша

Код

Значение

Клавиша

vk Back

8

Backspace

vk A..vk Z

65..90

A. .Z

vk Tab

9

Tab

vk LWin

91

Левая Windows

vk Clear

12

[5]

vk RWin

92

Правая Windows

vk Return

13

Enter

vk NumpadO.. vk Numpad9

96..105

[О]..[9]

vk Shift

16

Shift

vk Multiply

106

[*]

vk Control

17

Ctti

vk Add

107

[+]

vk Menu

18

Alt

vk Subtract

109

[-]

vk Pause

19

Pause

vk Decimal

110

[Del]

vk Capital

20

Caps Lock

vk Divide

111

[/]

vk Escape

27

esc

vkFl..vkF12

112..123

Fl..F12

vk Space

32

Пробел

vk Numlock

144

Num Lock

vk Prior

33

Page Up

vk Scroll

145

Scroll Lock

vk Next

34

Page Down

 

186

 

vk End

35

End

 

187

+

vk Home

36

Home

 

188

<

vk Left

37

Курсор влево

 

189

-

vk Up

38

Курсор вверх

 

190

>

vk Right

39

Курсор вправо

 

191

•?

vk Down

40

Курсор вниз

 

192

~

vk Insert

45

Insert

 

219

[

vk Delete

46

Delete

 

220

\

vk 0..vk 9

48..57

0..9

 

221

]

Примечание

В квадратных скобках указаны клавиши из зоны дополнительных цифровых клавиш.

Учтите, что константы vk_A.. .vk_z и vk_0.. .vk_9 не определены в файле source | rtl | win | windows . pas и следовательно в модуле System, поэтому для них компилятор выдаст сообщение о неизвестном идентификаторе - в этом случае используйте собственные определения констант или их числовые эквиваленты. Замечу также, что с помощью анализа параметра мзд. lParam в обработчике OnMes-заде можно отличить нажатие левых клавиш Alt, Ctrl, Shift от нажатия одноименных правых и нажатие Enter в основной клавиатуре от нажатия Enter в дополнительной.