【发布时间】:2021-06-09 15:26:45
【问题描述】:
参考this question,更具体地说是this answer,似乎只有在MSB 操作之后,才会在键盘挂钩上捕获死键。答案的作者留下了固定的代码,但不知道Delphi等价物是什么。
我的实际代码:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows,
Messages,
SysUtils;
var
hhk: HHOOK;
Msg: TMsg;
{==================================================================================}
function ReverseBits(b: Byte): Byte;
var
i: Integer;
begin
Result := 0;
for i := 1 to 8 do
begin
Result := (Result shl 1) or (b and 1);
b := b shr 1;
end;
end;
function GetCharFromVirtualKey(Key: Word): string;
var
keyboardState: TKeyboardState;
keyboardLayout: HKL;
asciiResult: Integer;
begin
GetKeyboardState(keyboardState);
keyboardLayout := GetKeyboardLayout(0);
SetLength(Result, 2);
asciiResult := ToAsciiEx(Key, ReverseBits(MapVirtualKey(Key, MAPVK_VK_TO_CHAR)), keyboardState, @Result[1], 0, keyboardLayout);
case asciiResult of
0:
Result := '';
1:
SetLength(Result, 1);
2:
;
else
Result := '';
end;
end;
{==================================================================================}
function LowLevelKeyboardProc(nCode: Integer; wParam: wParam; lParam: lParam): LRESULT; stdcall;
type
PKBDLLHOOKSTRUCT = ^TKBDLLHOOKSTRUCT;
TKBDLLHOOKSTRUCT = record
vkCode: cardinal;
scanCode: cardinal;
flags: cardinal;
time: cardinal;
dwExtraInfo: Cardinal;
end;
PKeyboardLowLevelHookStruct = ^TKeyboardLowLevelHookStruct;
TKeyboardLowLevelHookStruct = TKBDLLHOOKSTRUCT;
var
LKBDLLHOOKSTRUCT: PKeyboardLowLevelHookStruct;
begin
case nCode of
HC_ACTION:
begin
if wParam = WM_KEYDOWN then
begin
LKBDLLHOOKSTRUCT := PKeyboardLowLevelHookStruct(lParam);
Writeln(GetCharFromVirtualKey(LKBDLLHOOKSTRUCT^.vkCode));
end;
end;
end;
Result := CallNextHookEx(hhk, nCode, wParam, lParam);
end;
procedure InitHook;
begin
hhk := SetWindowsHookEx(WH_KEYBOARD_LL, @LowLevelKeyboardProc, HInstance, 0);
if hhk = 0 then
RaiseLastOSError;
end;
procedure KillHook;
begin
if (hhk <> 0) then
UnhookWindowsHookEx(hhk);
end;
begin
try
InitHook;
while GetMessage(Msg, 0, 0, 0) do
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
【问题讨论】:
-
如果它是正确的,您希望程序的哪个输出?
-
@fpiette,例如:Shift + 2 = @, Shift + "a" = A, Caps = 所有 a..z 大写 ...
-
@Coringa 为什么要反转
MapVirtualKey()的返回值的位?当MapVirtualKey()返回UINT时,为什么作为Byte?您链接到的答案根本没有反转任何位。它只是将它们向下移动,因此它可以检查高位是否为 1。该答案的 Delphi 等效项将是if ((MapVirtualKey(Key, MAPVK_VK_TO_CHAR) shr 31) and 1) = 0 then ...或更简单的if (MapVirtualKey(Key, MAPVK_VK_TO_CHAR) and $80000000) = 0 then ...甚至Int32(MapVirtualKey(Key, MAPVK_VK_TO_CHAR)) >= 0 then ... -
@Coringa 我认为您误解了死键实际上是什么。死键是特殊键或键组合,它们不会立即处理,而是与下一个键输入事件相结合,前提是死键可以与下一个键组合。如果可以组合,则返回一个
combined character。如果不是两个单独的字符(一个代表死键,一个代表第二个输入),则一个接一个地返回。所以基本上你需要在两个连续的键盘钩子事件中处理死键。 -
@Coringa 但是根据您上面的评论,您似乎对处理 Shift State 更感兴趣,它可以告诉您是否按下了 Shift、Ctrl 或 Alt 等键或者
Caps Lock,Num Lock或Scroll Lock已启用或禁用。这些不被称为死键,而是修饰键。
标签: delphi keyboard hook delphi-10.3-rio