delphi - 如何从 WM_KeyUp 或任何地方提取正确大小写的 CharCode
问题描述
我正在尝试以区分大小写的方式处理 WM_KeyUp 消息以识别按下了哪个字母数字键(如果有)。在 TApplicationEvents 我们有 OnMessage 处理程序,在我的项目中分配给
procedure TForm1.DoOnAppMessage(var Msg: tagMSG; var Handled: Boolean);
var
CH : Char;
[...]
begin
Inc(MsgCount);
case Msg.Message of
WM_KeyUp : begin
CH := Chr(Msg.WParam);
// do something with CH
end;
end; { case ]
就目前而言,这很好,当然除了我总是得到这封信的大写版本。
所以我显然需要解码 Msg 的 LParam。谷歌搜索,我遇到了许多解码 LParam 的例子,但没有一个我能找到处理我认为在正确的情况下呈现字母数字键的“简单”任务。我的问题是,请有人告诉我如何做到这一点。
请注意:我知道我可以通过处理 WM_Char 消息获得正确大写的字母,但我无法在我试图处理的实际情况中使用它(实际上是在键盘钩子内)。
解决方案
我找到了一个基于早期 SO q&a的解决方案,其中涉及设置低级键盘挂钩。最初,当我尝试这个时,我得到了与我的 q 中发布的代码相同的结果,即所有返回的字符都是小写的。
有趣的是,没有大写和正确大写之间的区别 - 下面的代码所做的 - 是包含对 GetKeyState 的调用的 4 行之一,即KeyState[VK_SHIFT] := GetKeyState(VK_SHIFT)
. 没有它,返回的字符都是小写的(不像我的 q 中的代码,它们都是大写的);
type
TOutProc = procedure(AString : String) of object;
var
OutProc : TOutProc; // requires assignment to a suitable proc in the host application
type
PKbdLlHookStruct = ^TKbdLlHookStruct;
TKbdLlHookStruct = packed record
vkCode: DWORD;
scanCode: DWORD;
flags: DWORD;
time: DWORD;
dwExtraInfo: DWORD;
end;
const
WH_KEYBOARD_LL = 13;
var
FKeyboardLayoutHandle: HKL;
hhkLowLevelKybd: HHOOK;
function LowLevelKeyBoardProc(nCode: Integer; awParam: WPARAM;
alParam: LPARAM): LRESULT; stdcall;
const
LLKHF_UP = $0080;
var
act: PKbdllHookStruct;
CH : Char;
S : String;
KeyState : TKeyboardState;
NewChar: array[0..1] of Char;
begin
// adapted from https://stackoverflow.com/q/1590983
if (nCode = HC_ACTION) then begin
case awParam of
WM_SYSKEYDOWN,
WM_KEYUP,
WM_SYSKEYUP: begin
act := PKbdLlHookStruct(alParam);
if awParam=WM_KEYUP then begin
FillChar(NewChar,2,#0);
GetKeyboardState(KeyState);
// Next four lines from https://stackoverflow.com/a/10480563
KeyState[VK_CAPITAL] := GetKeyState(VK_CAPITAL);
KeyState[VK_SHIFT] := GetKeyState(VK_SHIFT);
KeyState[VK_CONTROL] := GetKeyState(VK_CONTROL);
KeyState[VK_MENU] := GetKeyState(VK_MENU);
if ToAsciiEx(act^.vkCode, act^.scanCode, KeyState, NewChar, 0, FKeyboardLayoutHandle) = 1 then
CH := NewChar[0];
if (CH in [#8, #10, #13]) Or (CH >= ' ') then begin
S := CH;
OutProc(S);
GetClassName(GetForegroundWindow, @ClassBuffer, 100);
end;
end;
end; { case }
end; { case }
end;
Result := CallNextHookEx(hhkLowLevelKybd, nCode, awParam, alParam);
end;
推荐阅读
- html - 防止“float:right” div 占据整个空间
- audio - Wavesurfer 在播放失败时获取错误详细信息
- c# - 如何在后台线程上将 UI 元素序列化为 JSON?
- android - 当我向下滑动或向上滑动时更改运动事件的视图高度
- pine-script - 如何实现更高分辨率的平滑?
- java - Spring Boot 内部基于参数转发请求
- php - 为什么 mysqli_stmt::get_result() 方法在作为函数参数传递时会出错?
- c++ - 如何检查字符串是否包含另一个字符串(但中间可能有其他字母)?
- python - 用 Pymc 拟合卡方分布
- nosql - Cosmos DB 查询以连接主文档上的子文档