如何从 WM_KeyUp 或任何地方提取正确大小写的 CharCode

How to extract correctly cased CharCode from WM_KeyUp or whereever

我正在尝试处理 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 的例子,但是 none 我可以找到交易 我本以为 "simple" 任务是渲染字母数字键 在正确的情况下。我的问题是,有人可以告诉我该怎么做吗?

请注意:我知道我可以通过处理 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             =  [=10=]80;
var
  act:   PKbdllHookStruct;
  CH : Char;
  S : String;
  KeyState : TKeyboardState;
  NewChar: array[0..1] of Char;
begin

  //  adapted from 
  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 
          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;