4

I'm developing a Delphi XE7 multi-platform application and want to use some hotkeys / shortcuts.

TActionList, TMainMenu and TMenuBar all have properties to assign ShortCuts.

I am using an shortcut to add a new TTabItem on a TTabControl. That ShortCut is Ctrl + T.

So if the user presses Ctrl + T a new tab is added on said TTabControl - working correctly.

However if the user keeps holding down those 2 keys multiple tabs are created as well.

The shortcut event is triggered as long as the user keeps holding down those keys.

Adding a new tab is only an example. I am using multiple shortcuts that I only want to trigger once.

Is there any way to only trigger a shortcut event once?

I tried timers / waiting a specific amount of time. But that causes problems if the user wants to quickly perform 2 hotkeys.

Thanks for reading and I appreciate all help.

vasili111
  • 6,032
  • 10
  • 50
  • 80
ChrisB
  • 2,497
  • 2
  • 24
  • 43
  • It is not related just to Firemonkey. That is a default behavior in VCL apps. too. It's been [`asked here`](http://stackoverflow.com/q/503538/960757), but you won't be able to use the accepted solution for FMX. – TLama Nov 12 '14 at 16:06
  • I don't think there is another solution than using timer becouse hotkey does not detect when key is pressed down but periodically checks to see if certain combination of keys is pressed down at that specific time. If it is event is fired. – SilverWarior Nov 12 '14 at 16:51
  • 2
    This doesn't seem like a problem worth spending the time to solve. Don't your customers quickly figure this out and stop holding keys down so long? Is this a problem any *other* software vendor has fixed? If not, then why should you? – Rob Kennedy Nov 12 '14 at 17:00
  • @RobKennedy I don't have any customers as this is a personal project i am working on (I'm a student). I asked this question out of curiosity. But i guess you are right. If it ain't broke don't fix it. – ChrisB Nov 13 '14 at 13:22
  • You can use a flag, to disable multi firing. Do the work just if it is enabled. Set this disabler flag after processing the action and clear on the right key up event. – User007 Sep 17 '18 at 16:27

1 Answers1

0

Here is an example of how to solve this using Timer so that it doesent block users from using multiple different actions in a row. The speed for using of the same action depends on your configuration but is limited by system Key Autorepeat delay interval. See in code comments.

const
  //Interval after which the action can be fired again
  //This needs to be greater than system key autorepeat delay interval othervise
  //action event will get fired twice
  ActionCooldownValue = 100;

implementation

...

procedure TForm2.MyActionExecute(Sender: TObject);
begin
  //Your action code goes here
  I := I+1;
  Form2.Caption := IntToStr(I);
  //Set action tag to desired cooldown interval (ms before action can be used again )
  TAction(Sender).Tag := ActionCooldownValue;
end;

procedure TForm2.ActionList1Execute(Action: TBasicAction; var Handled: Boolean);
begin
  //Check to see if ActionTag is 0 which means that action can be executed
  //Action tag serves for storing the cooldown value
  if Action.Tag = 0 then
  begin
    //Set handled to False so that OnExecute event for specific action will fire
    Handled := False;
  end
  else
  begin
    //Reset coldown value. This means that user must wait athleast so many
    //milliseconds after releasing the action key combination
    Action.Tag := ActionCooldownValue;
    //Set handled to True to prevent OnExecute event for specific action to fire
    Handled := True;
  end;
end;

procedure TForm2.Timer1Timer(Sender: TObject);
var Action: TContainedAction;
begin
  //Itearate through all actions in the action list
  for Action in ActionList1 do
  begin
    //Check to see if our cooldown value is larger than zero
    if Action.Tag > 0 then
      //If it is reduce it by one
      Action.Tag := Action.Tag-1;
  end;
end;

NOTE: Set timer interval to 1 ms. And don't forget to set ActionCooldownValue to be greater than system key autorepeat delay interval

SilverWarior
  • 7,372
  • 2
  • 16
  • 22
  • Thanks for your effort. I wasn't looking for a timer solution but yours is working fine. – ChrisB Nov 13 '14 at 13:26
  • I know you wasn't looking for this kind of a solution but since I already had something similar working in one of my projects I thought I might share it. Anywhay another possible approach would be to compleetly omit the built-in HotKey functionality and reimplement similar functionality using Forms OnKeyDown and OnKeyUp events while having KeyPreviewEnabled. In this case you would be implmenting shortcut functionality as it was commonly used in previeous version of Delphi which didn't have this feature already built in. Implementing this would require quite some code and not be so easy to use. – SilverWarior Nov 13 '14 at 13:51