确定键盘Hook Proc中是否按下了SHIFT

时间:2013-05-05 14:22:40

标签: delphi hook

在我的钩子proc中,如何判断一个是否按下了SHIFT(不释放它)然后是一个char键(如A)?

例如,如果我按Shift + A,我想知道它将是一个大写的,而不是像Shift一样,

所以它将是A,如果用户按下并释放Shift,它将仅捕获Shift。

instaleld钩子是WH_KEYBOARD(全局)

function KeyHookProc(Code: Integer; wVirtKey: WPARAM; lKeyStroke: LPARAM)
  : LRESULT; stdcall;
type
  TTransitionState = (tsPressed, tsReleased);

  PKeystrokeData = ^TKeystrokeData;

  TKeystrokeData = record
    VirtualKey: WPARAM;
    KeyStroke: LPARAM;
    KeyState: TKeyboardState;
  end;
var
  Transition: TTransitionState;
  KeystrokeDataPtr: PKeystrokeData;
begin
  Result := CallNextHookEx(hKeyHook, Code, wVirtKey, lKeyStroke);

  Transition := TTransitionState((lKeyStroke shr 31) and 1);

  if (Code = HC_ACTION) and (Transition = tsPressed) then
  begin
    New(KeystrokeDataPtr);
    try
      KeystrokeDataPtr^.VirtualKey := wVirtKey;
      KeystrokeDataPtr^.KeyStroke := lKeyStroke;
      GetKeyboardState(KeystrokeDataPtr^.KeyState);
      SendMessage(hConsole, WM_NULL, 0, LPARAM(KeystrokeDataPtr));
    finally
      Dispose(KeystrokeDataPtr);
    end;
  end;
end;

2 个答案:

答案 0 :(得分:3)

以下是我们在正常日常使用中检测换档键的代码。我从来没有在钩子上下文中使用它,所以我不知道它是否会在那里工作,或者在那种情况下会有什么不同会阻止它。

function ShiftIsDown : Boolean;
var
  State: TKeyboardState;
begin
  WINDOWS.GetKeyboardState(State);
  Result := ((State[vk_Shift] and 128) <> 0);
end; 

答案 1 :(得分:0)

当您使用wParam等于VK_SHIFT调用钩子proc时,您会检测到按下 SHIFT 键。

当按下 A 键对应的钩子proc时,无论 SHIFT wParam和lParam值都是相同的>关键是关闭。由于您没有像在正常的消息循环中那样调用TranslateMessageDispatchMessage,因此您必须将原始键向下/向上事件转换为实际的按键操作。

使用GetKeyState(VK_SHIFT)<0来检测 SHIFT 键是否关闭可能最容易。这取决于你想要做什么。它看起来有点像你正在制作一个功能齐全的键盘记录器。在这种情况下,对GetKeyState(VK_SHIFT)<0的临时呼叫可能无法满足您的需求,并且正确处理单个按键向下/向上消息会更好。


其他一些评论:

  1. 你为什么要分配你的TKeystrokeData记录?你可以很好地使用堆栈分配记录。
  2. 我希望hConsole是一个与你的钩子在同一个过程中的窗口。如果不是,它将不会收到任何有用的信息,因为您发送它的指针仅在定义它的过程中有意义。如果您想发送信息,那么他们就是WM_COPYDATA