LowLevelKeyboardProc()永远不会执行

时间:2019-07-29 20:04:26

标签: delphi keyboard-hook delphi-10.3-rio

我需要钩住键盘,并找到了要在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.

1 个答案:

答案 0 :(得分:3)

您的代码没有给钩子触发机会。您的代码的实际执行始于分配一个钩子:

llKeyboardHook := SetWindowsHookEx(WH_KEYBOARD_LL, @LowLevelKeyboardProc, HInstance, 0);

然后将那个句柄写给用户:

Writeln(llKeyboardHook);

假设未引发任何异常,接下来的一件事就是等待用户输入:

Readln;

这时,假设用户按下键盘上的一个键并按Enter。这导致ReadLn退出,从而退出代码并终止应用程序。因此,钩子永远没有机会真正触发。

创建钩子之后,您应该进行某种等待,例如处理Windows消息。