Как правильно извлечь CharCode в регистре из WM_KeyUp или где угодно - PullRequest
0 голосов
/ 27 мая 2020

Я пытаюсь обработать сообщения WM_KeyUp, чтобы определить, какая буквенно-цифровая c клавиша (если есть) была нажата, с учетом регистра. В 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 ]

. Это нормально, пока, конечно, за исключением того, что я всегда получаю букву в верхнем регистре.

Так что мне, очевидно, нужно вместо этого декодировать LParam сообщения. Погуглил, я наткнулся на множество примеров декодирования LParam, но ни одного из них я не смог найти, касающийся того, что, как я думал, будет «простой» задачей получения буквенно-цифровых c ключей, отображаемых в правильном регистре. Мой вопрос: пожалуйста, не мог бы кто-нибудь показать мне, как это сделать.

Обратите внимание: я знаю, что могу получить правильные заглавные буквы, обработав сообщение WM_Char, но я не могу использовать это в реальной ситуации Я пытаюсь разобраться с (который на самом деле находится внутри крючка клавиатуры).

1 Ответ

1 голос
/ 01 июня 2020

Я нашел решение этой проблемы на основе более раннего SO q & a , который включает настройку низкоуровневого перехватчика клавиатуры. Первоначально, когда я попробовал это, я получил те же результаты, что и с кодом, опубликованным в моем q, а именно, что все возвращенные символы были в нижнем регистре.

Интересно, что разница между отсутствием заглавной буквы и правильной - что и делает код ниже - был одной из 4 строк, содержащих вызовы GetKeyState, а именно 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...