DataLife Engine > Windows > Перехват нажатия клавиши в Windows
Перехват нажатия клавиши в Windows6 марта 2008. Разместил: podpole |
Существуют приложения, которым необходимо перехватывать все нажатия клавиш в windows, даже если в данный момент активно другое приложение. Это может быть, например, программа, переключающая раскладку клавиатуры, резидентный словарь или программа, выполняющая иные действия по нажатию "горячей" комбинации клавиш. Перехват всех событий в windows (в том числе и событий от клавиатуры) выполняется с помощью вызова функции setwindowshook(). Данная функция регистрирует в системе windows ловушку (hook) для определенного типа событий/сообщений. Ловушка - это пользовательская процедура, которая будет обрабатывать указанное событие. Основное здесь то, что эта процедура должна всегда присутствовать в памяти windows. Поэтому ловушку помещают в dll и загружают эту dll из программы. Пока хоть одна программа использует dll, та не может быть выгружена из памяти. Приведем пример такой dll и программы, ее использующей. В примере ловушка перехватывает нажатие клавиш на клавиатуре, проверяет их и, если это клавиши "+" или "-", посылает соответствующее сообщение в конкретное приложение (окно). Окно ищется по имени его класса ("t form1") и заголовку (caption, "xxx"). {текст библиотеки} library s endkey; 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('t form1', 'xxx'); {посылаем сообщение} if wparam = vk_add then s endmessage(h, wm_nextshow_event, 0, 0) else s endmessage(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 t form1 = class(t form) label1: tlabel; procedure formcreate(s ender: 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: t form1; p : pointer; implementation {$r *.dfm} {загрузка dll} function key_hook : longint; far; external 's endkey'; procedure t form1.wm_nextmsg ( var m : tmessage); begin label1.caption:='next message'; end; procedure t form1.wm_prevmsg ( var m : tmessage); begin label1.caption:='previous message'; end; procedure t form1. formcreate(s ender: tobject); begin {если не использовать вызов процедуры из dll в программе, то компилятор удалит загрузку dll из программы} p:=@key_hook; end; end. Конечно, свойство caption в этой форме должно быть установлено в "xxx". |