我需要钩住键盘,并找到了要在Delphi Console项目中使用的以下代码(引用here)。发生第一次测试后,我注意到从未执行过LowLevelKeyboardProc()
函数(你好从不显示在控制台窗口中)。 SetWindowsHookEx()
已经可以正常工作,并且返回 <> 0。
那有人可以帮我解决这个问题吗?
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.
答案 0 :(得分:3)
您的代码没有给钩子触发机会。您的代码的实际执行始于分配一个钩子:
llKeyboardHook := SetWindowsHookEx(WH_KEYBOARD_LL, @LowLevelKeyboardProc, HInstance, 0);
然后将那个句柄写给用户:
Writeln(llKeyboardHook);
假设未引发任何异常,接下来的一件事就是等待用户输入:
Readln;
这时,假设用户按下键盘上的一个键并按Enter。这导致ReadLn
退出,从而退出代码并终止应用程序。因此,钩子永远没有机会真正触发。
创建钩子之后,您应该进行某种等待,例如处理Windows消息。