I'm need hook my keyboard and found the following code (reference here) that i want use in a Delphi Console project. Happens that after the first test i noted that LowLevelKeyboardProc() function never is executed (hello never is displayed on console window). Already SetWindowsHookEx() is working fine and returning <> 0.
Then someone can help me to solve this problem please?
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows,
Messages,
SysUtils;
function ToUnicodeEx(wVirtKey, wScanCode: UINT; lpKeyState: PByte; pwszBuff: PWideChar; cchBuff: Integer; wFlags: UINT; dwhkl: HKL): Integer; stdcall; external 'user32.dll';
const
LLKHF_ALTDOWN = KF_ALTDOWN shr 8;
WH_KEYBOARD_LL = 13;
type
PKBDLLHOOKSTRUCT = ^TKBDLLHOOKSTRUCT;
TKBDLLHOOKSTRUCT = packed record
vkCode: DWORD;
scanCode: DWORD;
flags: DWORD;
time: DWORD;
dwExtraInfo: DWORD;
end;
var
llKeyboardHook: HHOOK = 0;
AltDown, ShiftDown, CtrlDown: Boolean;
KeyBoardState: TKeyboardState;
KeyBoardLayOut: HKL;
function TranslateVirtualKey(VirtualKey: integer): WideString;
begin
Result := '';
{$Region 'Translate VirtualKey'}
case VirtualKey of
VK_RETURN: Result := sLineBreak;
VK_TAB: Result := ' ';
VK_BACK: Result := '[BackSpace]';
VK_SHIFT: Result := '[Shift]';
VK_CONTROL: Result := '[Ctrl]';
VK_MENU: Result := '[Alt]';
VK_ESCAPE: Result := '[Esc]';
VK_PAUSE: Result := '[Pause]';
VK_CAPITAL: Result := '[Caps Lock]';
VK_PRIOR: Result := '[Page Up]';
VK_NEXT: Result := '[Page Down]';
VK_END: Result := '[End]';
VK_HOME: Result := '[Home]';
VK_LEFT: Result := '[Left Arrow]';
VK_UP: Result := '[Up Arrow]';
VK_RIGHT: Result := '[Right Arrow]';
VK_DOWN: Result := '[Down Arrow]';
VK_SELECT: Result := '[Select]';
VK_PRINT: Result := '[Print Screen]';
VK_EXECUTE: Result := '[Execute]';
VK_SNAPSHOT: Result := '[Print]';
VK_INSERT: Result := '[Ins]';
VK_DELETE: Result := '[Del]';
VK_HELP: Result := '[Help]';
VK_F1: Result := '[F1]';
VK_F2: Result := '[F2]';
VK_F3: Result := '[F3]';
VK_F4: Result := '[F4]';
VK_F5: Result := '[F5]';
VK_F6: Result := '[F6]';
VK_F7: Result := '[F7]';
VK_F8: Result := '[F8]';
VK_F9: Result := '[F9]';
VK_F10: Result := '[F10]';
VK_F11: Result := '[F11]';
VK_F12: Result := '[F12]';
VK_NUMPAD0: Result := '0';
VK_NUMPAD1: Result := '1';
VK_NUMPAD2: Result := '2';
VK_NUMPAD3: Result := '3';
VK_NUMPAD4: Result := '4';
VK_NUMPAD5: Result := '5';
VK_NUMPAD6: Result := '6';
VK_NUMPAD7: Result := '7';
VK_NUMPAD8: Result := '8';
VK_NUMPAD9: Result := '9';
VK_SEPARATOR:Result := '+';
VK_SUBTRACT: Result := '-';
VK_DECIMAL: Result := '.';
VK_DIVIDE: Result := '/';
VK_NUMLOCK: Result := '[Num Lock]';
VK_SCROLL: Result := '[Scroll Lock]';
VK_PLAY: Result := '[Play]';
VK_ZOOM: Result := '[Zoom]';
VK_LWIN,
VK_RWIN: Result := '[Win Key]';
VK_APPS: Result := '[Menu]';
end;
{$EndRegion}
end;
function LowLevelKeyboardProc(nCode: Integer; wParam: wParam; lParam: lParam): HRESULT; stdcall;
var
pkbhs: PKBDLLHOOKSTRUCT;
AChr: array[0..1] of WideChar;
VirtualKey: integer;
ScanCode: integer;
ConvRes: integer;
ActiveWindow: HWND;
ActiveThreadID: DWord;
Str: widestring;
begin
pkbhs := PKBDLLHOOKSTRUCT(Pointer(lParam));
if nCode = HC_ACTION then
begin
VirtualKey := pkbhs^.vkCode;
Str := '';
if LongBool(pkbhs^.flags and LLKHF_ALTDOWN) and (not AltDown) then
begin
Str := '[Alt]';
AltDown := True;
end;
if (not LongBool(pkbhs^.flags and LLKHF_ALTDOWN)) and (AltDown) then
AltDown := False;
if (WordBool(GetAsyncKeyState(VK_CONTROL) and $8000)) and (not CtrlDown) then
begin
Str := '[Ctrl]';
CtrlDown := True;
end;
if (not WordBool(GetAsyncKeyState(VK_CONTROL) and $8000)) and (CtrlDown) then
CtrlDown := False;
if ((VirtualKey = VK_LSHIFT) or (VirtualKey = VK_RSHIFT)) and (not ShiftDown) then
begin
Str := '[Shift]';
ShiftDown := True;
end;
if (wParam = WM_KEYUP) and ((VirtualKey = VK_LSHIFT) or (VirtualKey = VK_RSHIFT)) then
ShiftDown := False;
if (wParam = WM_KEYDOWN) and ((VirtualKey <> VK_LMENU) and (VirtualKey <> VK_RMENU)) and (VirtualKey <> VK_LSHIFT) and (VirtualKey <> VK_RSHIFT) and (VirtualKey <> VK_LCONTROL) and (VirtualKey <> VK_RCONTROL) then
begin
Str := TranslateVirtualKey(VirtualKey);
if Str = '' then
begin
ActiveWindow := GetForegroundWindow;
ActiveThreadID := GetWindowThreadProcessId(ActiveWindow, nil);
GetKeyboardState(KeyBoardState);
KeyBoardLayOut := GetKeyboardLayout(ActiveThreadID);
ScanCode := MapVirtualKeyEx(VirtualKey, 0, KeyBoardLayOut);
if ScanCode <> 0 then
begin
ConvRes := ToUnicodeEx(VirtualKey, ScanCode, @KeyBoardState, @AChr, SizeOf(AChr), 0, KeyBoardLayOut);
if ConvRes > 0 then
Str := AChr;
end;
end;
end;
if Str <> '' then
writeln('hello!');
end;
Result := CallNextHookEx(llKeyboardHook, nCode, wParam, lParam);
end;
begin
try
llKeyboardHook := SetWindowsHookEx(WH_KEYBOARD_LL, @LowLevelKeyboardProc, HInstance, 0);
Writeln(llKeyboardHook);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
ReadLnwhere it waits for the user to input anything. Once the user types something, the code exits and terminates. So yeah, this hook is never called, or by the time it gets called, it's too late and the app is already terminated. I presume you should be doing some sort of waiting to actually give it a chance to trigger. For example, a message loop. - Jerry Dodge