0

在我的钩子 proc 中,我如何确定一个 used 是否按下 SHIFT(不释放它)然后是一个字符键(如 A)?

例如,如果我按 Shift+A,我想知道它是大写的 a,而不是像 Shift、a

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

安装的钩子是 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;
4

2 回答 2

3

这是我们在日常使用中用于检测 shift 键的代码。我从来没有在挂钩的上下文中使用过它,所以我不知道它是否会在那里工作,或者在那个上下文中是否有什么不同会阻止它。

function ShiftIsDown : Boolean;
var
  State: TKeyboardState;
begin
  WINDOWS.GetKeyboardState(State);
  Result := ((State[vk_Shift] and 128) <> 0);
end; 
于 2013-05-05T14:33:57.000 回答
0

SHIFT当您的 hook proc 被调用时,您检测到按键的按下wParamequal to VK_SHIFT

当你的钩子程序被调用对应于被按下的键时,无论A键是否按下,wParam和值都是相同的。由于您没有调用并且在正常的消息循环中会发生这种情况,因此您将不得不将原始的按键向下/向上事件转换为实际的按键。lParamSHIFTTranslateMessageDispatchMessage

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


其他一些评论:

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