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 в дополнительной.