Recent

Author Topic: Programmatically trigger an event  (Read 973 times)

Tommi

  • Full Member
  • ***
  • Posts: 229
Programmatically trigger an event
« on: March 26, 2025, 09:44:43 pm »
I would like to simulate an event, for example trigger TMemo.onKeyDown.

I guess I should use sendMessage but I don't really know how.

Any idea?

Thank you

Khrys

  • Full Member
  • ***
  • Posts: 208
Re: Programmatically trigger an event
« Reply #1 on: March 27, 2025, 07:45:11 am »
I wouldn't recommend using  SendMessage  since then you'd have to deal with the nitty-gritty (platform-dependent) details of how messages are encoded.
The simplest way is to just call the event handler directly:

Code: Pascal  [Select][+][-]
  1. procedure SimulateKeyPress(Memo: TMemo);
  2. var
  3.   Key: Word = VK_W;
  4. begin
  5.   Memo.OnKey(Nil, Key, []); // Sends 'W' without any modifiers
  6. end;

There exist other possibilities too; some wait for the event to complete, others just place it into the message queue and return immediately:

UnitFoo.pas
Code: Pascal  [Select][+][-]
  1. unit UnitFoo;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, Forms, StdCtrls, LMessages;
  9.  
  10. type
  11.   TFormFoo = class(TForm)
  12.     MemoBar: TMemo;
  13.     procedure AsyncMemoKey(Data: PtrInt);
  14.     procedure MemoBarKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  15.   end;
  16.  
  17. var
  18.   FormFoo: TFooForm;
  19.  
  20. procedure SimulateMemoBarEvent();
  21.  
  22. implementation
  23.  
  24. procedure SimulateMemoBarEvent();
  25. var
  26.   Key: Word = VK_W;
  27. begin
  28.  
  29.   // Option 1: Direct call
  30.   FormFoo.MemoBarKeyDown(Nil, Key, []);
  31.  
  32.   // Option 2: Indirect call
  33.   FormFoo.MemoBar.OnKeyDown(Nil, Key, []);
  34.  
  35.   // Option 3: Synchronous message
  36.   SendMessage(FormFoo.MemoBar.Handle, LM_KEYDOWN, Key, $00000000);
  37.  
  38.   // Option 4: Asynchronous message
  39.   PostMessage(FormFoo.MemoBar.Handle, LM_KEYDOWN, Key, $00000000);
  40.  
  41.   // Option 5: Asynchronous event
  42.   Application.QueueAsyncCall(@FormFoo.AsyncMemoKey, Key);
  43. end;
  44.  
  45. procedure TFormFoo.AsyncMemoKey(Data: PtrInt);
  46. var
  47.   Key: Word;
  48. begin
  49.   Key := Data;
  50.  
  51.   // Any of options 1-4, e.g. option 1
  52.   MemoBar.OnKeyDown(Nil, Key, []);
  53. end;
  54.  
  55. procedure TFormFoo.MemoBarKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  56. begin
  57.   // ...
  58. end;
  59.  
  60. end.

UnitFoo.lfm:
Code: Pascal  [Select][+][-]
  1. object FormFoo: TFormFoo
  2.   object MemoBar: TMemo
  3.     OnKeyDown = MemoBarKeyDown
  4.   end
  5. end

Tommi

  • Full Member
  • ***
  • Posts: 229
Re: Programmatically trigger an event
« Reply #2 on: March 28, 2025, 11:24:30 am »
Hi, thank you, but options 3 and 4 doesn't work (at least on my ubuntu 24.04).
I attach an implementation example. If you press buttons 3 or 4 nothing happens.

cdbc

  • Hero Member
  • *****
  • Posts: 2086
    • http://www.cdbc.dk
Re: Programmatically trigger an event
« Reply #3 on: March 28, 2025, 12:14:27 pm »
Hi
Don't forget to "SendMessage(FormFoo.MemoBar.Handle, LM_KEYUP, Key, $00000000);"
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 3.6 up until Jan 2024 from then on it's both above &: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 4.99

wp

  • Hero Member
  • *****
  • Posts: 12757
Re: Programmatically trigger an event
« Reply #4 on: March 28, 2025, 12:49:53 pm »
Install the LazMouseAndKeyInput package, it allows you to create virtual key presses and mouse clicks in a cross-platform way: https://wiki.freepascal.org/MouseAndKeyInput. Find the package in folder components/mouseandkeyinput of your Lazarus installation.

Khrys

  • Full Member
  • ***
  • Posts: 208
Re: Programmatically trigger an event
« Reply #5 on: March 28, 2025, 10:47:21 pm »
Hi, thank you, but options 3 and 4 doesn't work (at least on my ubuntu 24.04).

That's because I tested it on a different platform (Windows) and those options are platform-dependent . Which is why I wouldn't encourage using them unless absolutely necessary and sticking to the easier & clearer platform-agnostic options #1 and #2.

Install the LazMouseAndKeyInput package, it allows you to create virtual key presses and mouse clicks in a cross-platform way: https://wiki.freepascal.org/MouseAndKeyInput. Find the package in folder components/mouseandkeyinput of your Lazarus installation.

Note that this is only required if you want to simulate key presses and mouse clicks system-wide (outside your own program).

Zoran

  • Hero Member
  • *****
  • Posts: 1924
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Programmatically trigger an event
« Reply #6 on: March 28, 2025, 11:12:22 pm »
Install the LazMouseAndKeyInput package, it allows you to create virtual key presses and mouse clicks in a cross-platform way: https://wiki.freepascal.org/MouseAndKeyInput. Find the package in folder components/mouseandkeyinput of your Lazarus installation.

This package is GPL licensed, which can be acceptable for quite a limited number of projects.
Swan, ZX Spectrum emulator https://github.com/zoran-vucenovic/swan

 

TinyPortal © 2005-2018