* * *

Author Topic: catch key press messages  (Read 2022 times)

laggyluk

  • Jr. Member
  • **
  • Posts: 69
catch key press messages
« on: November 10, 2017, 10:11:03 am »
Hi
What I'm trying to do is capture all key presses on form and send them to chromium osr component for processing.

tried
Code: Pascal  [Select]
  1. procedure WndProc(var Message: TLMessage); override;
but no luck, then I've tried
Code: Pascal  [Select]
  1. function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam):LRESULT; stdcall;

They both captured windows messages, mouse clicks etc but neither was receiving any of key press messages I'm interested in:
Code: Pascal  [Select]
  1. WM_CHAR, WM_SYSCHAR,WM_SYSKEYDOWN,WM_SYSKEYUP,WM_KEYDOWN,WM_KEYUP
Why is that?

laggyluk

  • Jr. Member
  • **
  • Posts: 69
Re: catch key press messages
« Reply #1 on: November 10, 2017, 10:21:38 am »
I think I know why but still don't know the solution

https://stackoverflow.com/questions/20408071/form-wm-keydown-and-wm-keyup-messages-arent-captured-in-wndproc

there is no ProcessCmdKey method to override

GetMem

  • Hero Member
  • *****
  • Posts: 3083
Re: catch key press messages
« Reply #2 on: November 10, 2017, 11:44:38 am »
Works fine here. Just press different keys or key combinations like Alt + F, etc...
Code: Pascal  [Select]
  1. uses Windows;
  2.  
  3. var
  4.   FPrevWndProc: WNDPROC;
  5.  
  6. function WndCallback(AHWND: HWND; uMsg: UINT; wParam: WParam; lParam: LParam): LRESULT; stdcall;
  7. begin
  8.   case uMsg of
  9.     WM_CHAR: Form1.Caption := 'WM_CHAR';
  10.     WM_SYSCHAR: Form1.Caption := 'WM_SYSCHAR';
  11.     WM_SYSKEYDOWN: Form1.Caption := 'WM_SYSKEYDOWN';
  12.     WM_SYSKEYUP: Form1.Caption := 'WM_SYSKEYUP';
  13.     WM_KEYDOWN: Form1.Caption := 'WM_KEYDOWN';
  14.     WM_KEYUP: Form1.Caption := 'WM_KEYUP';
  15.   end;
  16.   Result := CallWindowProc(FPrevWndProc, Ahwnd, uMsg, WParam, LParam);
  17. end;
  18.  
  19. procedure TForm1.FormCreate(Sender: TObject);
  20. begin
  21.   FPrevWndProc := Windows.WNDPROC(SetWindowLongPtr(Self.Handle, GWL_WNDPROC, PtrUInt(@WndCallback)));
  22. end;

laggyluk

  • Jr. Member
  • **
  • Posts: 69
Re: catch key press messages
« Reply #3 on: November 10, 2017, 12:08:37 pm »
does work in blank project, dropping tmemo on form breaks it %)

I'm using memo for logging only, can it be prevented from stealing messages?

GetMem

  • Hero Member
  • *****
  • Posts: 3083
Re: catch key press messages
« Reply #4 on: November 10, 2017, 12:11:01 pm »
You have a window handle, change it when the focus shifts from one control to another.

FPrevWndProc := Windows.WNDPROC(SetWindowLongPtr(Self.Handle, GWL_WNDPROC, PtrUInt(@WndCallback)));

laggyluk

  • Jr. Member
  • **
  • Posts: 69
Re: catch key press messages
« Reply #5 on: November 10, 2017, 12:22:36 pm »
solved, thanks!

Code: Pascal  [Select]
  1. procedure TForm1.OnFocusChange(sender: tobject);
  2. begin
  3.   if screen.ActiveControl <>nil then
  4.    FPrevWndProc := Windows.WNDPROC(SetWindowLongPtr(screen.ActiveControl.Handle, GWL_WNDPROC, PtrUInt(@WndCallback)));
  5. end;
  6.  

ASerge

  • Hero Member
  • *****
  • Posts: 829
Re: catch key press messages
« Reply #6 on: November 11, 2017, 03:39:07 am »
Code: Pascal  [Select]
  1. procedure TForm1.OnFocusChange(sender: tobject);
  2. begin
  3.   if screen.ActiveControl <>nil then
  4.    FPrevWndProc := Windows.WNDPROC(SetWindowLongPtr(screen.ActiveControl.Handle, GWL_WNDPROC, PtrUInt(@WndCallback)));
  5. end;
  6.  
Very bad decision. You overwrite the variable FPrevWndProc, and the WndCallback procedure calls the code not for its own window class.
Use message hooks:
Code: Pascal  [Select]
  1.   private
  2.     procedure KeyMessage(const Msg: TMsg);
  3.   end;
  4.  
  5. var
  6.   Form1: TForm1;
  7.  
  8. implementation
  9.  
  10. uses Windows;
  11.  
  12. {$R *.lfm}
  13.  
  14. var
  15.   GHook: HHOOK;
  16.  
  17. function MessageHookProc(nCode: Integer; wParam: WPARAM;
  18.   lParam: LPARAM): LRESULT; stdcall;
  19. var
  20.   Msg: LCLType.PMsg absolute lParam;
  21. begin
  22.   if nCode >= 0 then
  23.     case Msg^.message of
  24.       WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_CHAR, WM_SYSCHAR:
  25.         Form1.KeyMessage(Msg^);
  26.     end;
  27.   Result := CallNextHookEx(GHook, nCode, wParam, lParam);
  28. end;
  29.  
  30. procedure TForm1.FormCreate(Sender: TObject);
  31. begin
  32.   GHook := SetWindowsHookEx(WH_GETMESSAGE, @MessageHookProc, 0, MainThreadID);
  33.   if GHook = 0 then
  34.     RaiseLastOSError;
  35. end;
  36.  
  37. procedure TForm1.FormDestroy(Sender: TObject);
  38. begin
  39.   if GHook <> 0 then
  40.   begin
  41.     UnhookWindowsHookEx(GHook);
  42.     GHook := 0;
  43.   end;
  44. end;
  45.  
  46. procedure TForm1.KeyMessage(const Msg: LCLType.TMsg);
  47. begin
  48.   case Msg.message of
  49.     WM_KEYDOWN:
  50.       Memo1.Append('WM_KEYDOWN: ' + IntToStr(Msg.wParam));
  51.     WM_KEYUP:
  52.       Memo1.Append('WM_KEYUP: ' + IntToStr(Msg.wParam));
  53.     WM_SYSKEYDOWN:
  54.       Memo1.Append('WM_SYSKEYDOWN: ' + IntToStr(Msg.wParam));
  55.     WM_SYSKEYUP:
  56.       Memo1.Append('WM_SYSKEYUP: ' + IntToStr(Msg.wParam));
  57.     WM_CHAR:
  58.       Memo1.Append('WM_CHAR: ' + IntToStr(Msg.wParam) + ' "' + Chr(Msg.wParam) + '"');
  59.     WM_SYSCHAR:
  60.       Memo1.Append('WM_SYSCHAR: ' + IntToStr(Msg.wParam) + ' "' + Chr(Msg.wParam) + '"');
  61.   end;
  62. end;

laggyluk

  • Jr. Member
  • **
  • Posts: 69
Re: catch key press messages
« Reply #7 on: November 15, 2017, 01:52:38 pm »
True and it resulted in occasional crashes. Your solution works better.

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus