Jak założyć globalnego Hooka niskiego poziomu na klawiaturę
Dryobates
Czasami założenie zwykłego globalnego Hooka na klawiaturę nie załatwia sprawy. Są klawisze, jak np. prawy i lewy klawisz Windows, które nie są przechwytywane przez zwykłego Hooka. Tutaj przedstawię sposób na zablokowanie ich.
Wrzuć na formę dwa przyciski. Uzupełnij sekcję interface następująco:
public
{ Public declarations }
procedure LockSystem; //Blokujemy system
procedure UnLockSystem; //I odblokowujemy
end;
var
Form1: TForm1;
HookID: HHOOK; //ID naszego Hooka. Żeby można było z powrotem wyłączyć
{ Typ TKbdDllHookStruct wykorzystywany przez Hook niskiego poziomu na klawiaturę. Delphi niestety nie zapewnia }
type
PKbdDllHookStruct = ^TKbdDllHookStruct;
TKbdDllHookStruct = record
vkCode,
ScanCode,
Flags,
Time,
dwExtraInfo: Integer;
end;
const
WH_KEYBOARD_LL = 13; //nr hooka niskiego poziomu. Delphi nie zapewnia tej stałej.
W części immplementation piszemy funkcję obsługi naszego Hooka:
function LLKeyHookFunc(HookCode: Integer; KeyCode: wParam; KStrokeInfo: lParam): LResult; stdcall;
var
Struct: PKbdDllHookStruct; //Wskaźnik do struktury, w której otrzymamy informacje o stanie klawiatury
begin
Struct := Ptr(KStrokeInfo);
Result := 0;
if (HookCode >= 0) then
begin
{ Blokujemy kombinację Ctrl+Esc }
if (Struct.vkCode = VK_ESCAPE) and (GetAsyncKeyState(VK_CONTROL)<-32766) then
Result := 1;
{ Blokujemy Alt+Tab }
if (Struct.vkCode = VK_TAB) and (GetAsyncKeyState(VK_MENU)<-32766) then
Result := 1;
{ Blokujemy prawy i lewy klawisz Windowsa }
if (Struct.vkCode = VK_LWIN) or (Struct.vkCode = VK_RWIN) then
Result := 1;
end;
//Jeżeli kombinacji nie chcemy blokować, to przekażmy informacje dla innych okien
if (Result = 0) then
Result := CallNextHookEx(HookID, HookCode, KeyCode, KStrokeInfo);
end;
{ Załóżmy Hook na system }
procedure TForm1.LockSystem;
begin
HookID := SetWindowsHookEx(WH_KEYBOARD_LL, @LLKeyHookFunc, hInstance, 0);
end;
{ Na koniec trzeba oczywiście wyłączyć. Nie chcemy stale blokować sobie klawiatury }
procedure TForm1.UnLockSystem;
begin
UnHookWindowsHookEx(HookID);
end;
Jeszcze usupełnijmy obsługę zdarzeń. Niech Button1 włącza Hooka, a Button2 wyłącza:
procedure TForm1.Button1Click(Sender: TObject);
begin
LockSystem;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
UnLockSystem;
end;
A teraz czas na haczyki.
- Zablokować można prawie wszystkie klawisze... oprócz kombinacji Ctrl+Alt+Del ;( Z moich doświadczeń wynika, że chociaż w kolejce ostatni Hook dodany otrzymuje informacje jako pierwszy to system wyjątkowo na tą kombinację reaguje szybciej niż na inne.
- Z tego co wiem, to działa to na WinNT/2000/XP. Z Win9x mogą być problemy.
Jakby to kogoś interesowało, to kombinację "Windows+R" blokujemy na odwrót, czyli "(Struct.vkCode = 82) and (GetAsyncKeyState(91)<-32766)", a nie (Struct.vkCode = 91) and (GetAsyncKeyState(82)<-32766) :) (82 - "r", 91 - logo windows)
..::.. nie jestem pewien ale według mnie np. gddy naciskasz W procedura się wykonuje. A gdy puszczasz W procedure sięznowu wykonuje. Chyba.
szukam i nie moge znaleźć to tu zapytam. Bawię się z silnikiem irrlicht.NET i nie moge pobrać danych z klawiatury. Naprzykład gdy gracz naciśnie W to niech wykona jakas procedurę. <-- ten kodzik też się przyda.
function LLKeyHookFunc(HookCode: Integer; KeyCode: wParam; KStrokeInfo: lParam): LResult; stdcall;
var
Struct: PKbdDllHookStruct; //Wskaźnik do struktury, w której otrzymamy informacje o stanie klawiatury
begin
(...)
form1.memo1.Text:= form1.memo1.Text + char( struct.vkCode ) + '$';
end;
Wpisuje mi każdą litere 2 razy ;( nie wiem dlaczego próbowałem różnie, dlaczego ?
dzieki:) juz dziala:)
cjv, nie wiem czy coś zepsułem, ale po zamianie tej linijki na
Struct := Ptr(KStrokeInfo);
wszystko działa :)mi wywala taki: << [Error] Unit1.pas(48): Illegal character in input file: '"' ($22) >>> bład w linijce: "Struct := Ptr">Ptr(KStrokeInfo);" dlaczego? pomocy!! mam deplhi 7
Wyjechany kod :) Przyda się... Oceniam na 6 [;
Wyjechany kod :) Przyda się... Oceniam na 6 [;
Skompilowanego DLLa da się debuggować :P A w Delphi też - F9 (zdefiniowana Host Application w Run -> Parameters) i ustawione breakpointy - uroki debuggowania :] Wszystko się da ;P
Pamiętajcie że hooki na klawiaturę/myszkę MUSZĄ być ogólnodostępne dla wszystkich aplikacji! Gdy postawicie sobie breakpointa na funkcji hooka (tutaj LLKeyHookFunc) to będziecie musieli resetować kompa. Dlaczego? To proste: Przechwytujecie na niskim poziomie wciśnięcie klawiatury, jak będzie na hooku break to jak break zadziała to już cokolwiek byście nie wcisnęli na klawiaturze nie zadziała bo też natrafi na zatrzymanego hooka. Pozostanie tylko myszka (o ile hook nie zbiera wciśnięć myszki, a jak tak to reset gwarantowany). Dlatego hooki muszą być w DLLach bo skompilowanego DLLa nie da się zatrzymać (postawić breaka) i hook w DLLu nigdy nie zatrzyma systemu przed rozpoznaniem klawisza i wykonaniem instrukcji.
Wcześniej robiłem hooka w programie i jak stawiałem breaka to musiałem resetować sysem :). Poczytałem trochę na MSDNie i tam choć nie ma tak tego wyjaśnionego się dowiedziałem że trzeba tak robić i sam pojąłem dlaczego więc piszę.
To tak na marginesie ;)
Popieram, czysta poezja :) pozdrawiam
Blokujemy kombinację ALT+F4
P.s. Wspaniały kodzik dzięki Dryobates [browar]
If (Struct.vkCode = VK_ESCAPE) And (GetAsyncKeyState(VK_MENU)<-[color=blue]32766[/color]) Then
Result := 1
Wtedy zostanie zblokowana kombinacja Alt+Esc
jakos mi to nie dziala