Обробка подій від клавіатури I.Емуляція натиснення клавіші. Всередині програми це виконується досить просто за допомогою виклику функції Windows API SendMessage () (можна скористатися і методом Perform того об'єкта (або форми), кому надсилається повідомлення про самій клавіші). Код Memo1.Perform (WM_CHAR, Ord ('A'), 0); або SendMessage (Memo1.Handle, WM_CHAR, Ord ('A'), 0); призведе до друку символу "A" в об'єкті Memo 1. II.Перехоплення натисків клавіші всередині програми. Завдання вирішується дуже просто. Можна у форми встановити властивість KeyPreview в True і обробляти подія OnKeyPress. Другий спосіб - перехоплювати подія OnMessage для об'єкта Application. III.Перехоплення натиснутийия клавіші в Windows. Існують програми, яким необхідно перехоплювати всі натиснення клавіш в Windows, навіть якщо в даний момент активно інший додаток. Це може бути, наприклад, програма, що перемикає розкладку клавіатури, резидентний словник або програма, виконує інші дії після натискання "гарячої" комбінації клавіш. Перехоплення всіх подій в Windows (у тому числі і подій від клавіатури) виконується за допомогою виклику функції SetWindowsHook (). Ця функція реєструє в системі Windows пастку (hook) для певного типу подій / повідомлень. Пастка - це призначена для користувача процедура, яка буде обробляти вказану подію. Основне тут те, що ця процедура повинна завжди бути присутнім в пам'яті Windows. Тому пастку поміщають в DLL і завантажують цю DLL з програми. Поки хоч одна програма використовує DLL, та не може бути вивантажено з пам'яті. Наведемо приклад такої DLL і програми, її використовує. У прикладі пастка перехоплює натиснення клавіш на клавіатурі, перевіряє їх і, якщо це клавіші "+" або "-", посилає відповідне повідомлення в конкретний додаток (вікно). Вікно шукається по імені його класу ("TForm 1") і заголовку (caption, "XXX"). {Текст бібліотеки} library SendKey; uses WinTypes, WinProcs, Messages; const {Користувальницькі повідомлення} wm_NextShow_Event = wm_User + 133; wm_PrevShow_Event = wm_User + 134; {Handle для пастки} HookHandle: hHook = 0; var SaveExitProc: Pointer; {Власне пастка} function Key_Hook (Code: integer; wParam: word; lParam: Longint): Longint; export; var H: HWND; begin {Якщо Code> = 0, то пастка може обробити подію} if Code> = 0 then begin {Це ті клавіші?} if ((wParam = VK_ADD) or (wParam = VK_SUBTRACT)) and (LParam and $ 40000000 = 0) then begin {Шукаємо вікно по імені класу і по заголовку} H: = FindWindow ('TForm 1', 'XXX'); {Посилаємо повідомлення} if wParam = VK_ADD then SendMessage (H, wm_NextShow_Event, 0, 0) else SendMessage (H, wm_PrevShow_Event, 0, 0); end; {Якщо 0, то система повинна далі обробити цю подію} {Якщо 1 - немає} Result: = 0; end else {Якщо Code <0, то потрібно викликати наступну пастку} Result: = CallNextHookEx (HookHandle, Code, wParam, lParam); end; {При розвантаженні DLL треба зняти пастку} procedure LocalExitProc; far; begin if HookHandle <> 0 then begin UnhookWindowsHookEx (HookHandle); ExitProc: = SaveExitProc; end; end; {Ініціалізація DLL при завантаженні її в пам'ять} begin {Встановлюємо пастку} HookHandle: = SetWindowsHookEx (wh _ Keyboard, Key _ Hook, hInstance, 0); if HookHandle = 0 then MessageBox (0, 'Unable to set hook!', 'Error', mb_Ok) else begin SaveExitProc: = ExitProc; ExitProc: = @ LocalExitProc; end; end. Розмір такої DLL в скомпільованому вигляді буде близько 3Кб, оскільки в ній не використовуються об'єкти з VCL. Далі приведений код модуля в Delphi, який завантажує DLL і обробляє повідомлення від пастки, просто відображаючи їх в Label1. unit Unit1; interface uses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; {Повідомлення користувача} const wm_NextShow_Event = wm_User + 133; wm_PrevShow_Event = wm_User + 134; type TForm1 = class (TForm) Label1: TLabel; procedure FormCreate (Sender: TObject); private {Обробники повідомлень} procedure WM_NextMSG (Var M: TMessage); message wm_NextShow_Event; procedure WM_PrevMSG (Var M: TMessage); message wm_PrevShow_Event; end; var Form1: TForm1; P: Pointer; implementation {$ R *. DFM} {Завантаження DLL} function Key_Hook: Longint; far; external 'SendKey'; procedure TForm1.WM_NextMSG (Var M: TMessage); begin Label1.Caption: = 'Next message'; end; procedure TForm1.WM_PrevMSG (Var M: TMessage); begin Label1.Caption: = 'Previous message'; end; procedure TForm1.FormCreate (Sender: TObject); begin {Якщо не використовувати виклик процедури з DLL в програмі, то компілятор видалить завантаження DLL з програми} P: = @ K e y_Hook; end; end. Звичайно, властивість Caption у цій формі має бути встановлено в "XXX". Зміна виду вікна програми В розділ private напишіть наступне: private {Private declarations} FormRgn, EllipseRgn: HRGN; Тепер для головної форми створи подія "OnCreate". Для цього досить двічі клацнути по головній формі і Delphi створить процедуру FormCreate. У ній напишіть наступне: procedure TForm1.FormCreate (Sender: TObject); begin FormRgn: = CreateEllipticRgn (0,0, Width, Height); SetWindowRgn (Handle, FormRgn, True); end; У Вас повинен вийти ось такий текст: unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class (TForm) Button1: TButton; procedure FormCreate (Sender: TObject); procedure Button1Click (Sender: TObject); private {Private declarations} FormRgn, EllipseRgn: HRGN; public {Public declarations} end; var Form1: TForm1; implementation {$ R *. DFM} procedure TForm1.FormCreate (Sender: TObject); begin FormRgn: = CreateEllipticRgn (0,0, Width, Height); SetWindowRgn (Handle, FormRgn, True); end; procedure TForm1.Button1Click (Sender: TObject); begin Close; end; end.  Тепер розглянемо детальніше: CreateEllipticRgn ( NLeftRect: Integer, / / Ліва позиція nTopRect: Integer, / / Верхня nRightRect: Integer, / / Права nBottomRect: Integer / / Нижня ): HRGN; Ця процедура створює регіон у вигляді еліпса. SetWindowRgn ( HWnd: HWND, / / Покажчик на нашу форму HRgn: HRGN, / / Попередньо створений регіон BRedraw: Boolean / / Прапор перемальовування вікна ): Integer; Ця процедура прив'язує створений нами регіон з нашою формою. Прапор bRedraw повинен бути true, інакше регіон ну буде промальований. Розглянемо ще дві функції. CreateRectRgn ( nLeftRect: Integer, / / Ліва позиція nTopRect: Integer, / / Верхня nRightRect: Integer, / / Права nBottomRect: Integer / / Нижня ): HRGN; Ця функція схожа на CreateEllipticRgn. Вона також створює регіон, але вже квадратний. CombineRgn ( HrgnDest: HRGN, / / Покажчик на результуючий регіон hrgnSrc1: HRGN, / / Покажчик на регіон 1 hrgnSrc2: HRGN, / / Покажчик на регіон 2 fnCombineMode: Integer / / Метод об'єднання ): Integer; Ця функція комбінує два регіони з hrgnSrc1 і hrgnSrc2 і поміщає результат в HrgnDest. FnCombineMode - метод комбінування, який може бути: RGN_AND, RGN_COPY, RGN_DIFF, RGN_OR або RGN_XOR. Тепер підправимо нашу програму з урахуванням нових функцій. Для цього, потрібно змінити процедуру FormCreate. procedure TForm1.FormCreate (Sender: TObject); begin FormRgn: = CreateEllipticRgn (0,0, Width, Height); EllipseRgn: = CreateRectRgn (round (Width / 4), round (Height / 4), round (3 * Width / 4), round (3 * Height / 4)); CombineRgn (FormRgn, FormRgn, EllipseRgn, RGN_DIFF); SetWindowRgn (Handle, FormRgn, True); end; 
|