Запускать горячую клавишу / ярлык только один раз

Я разрабатываю многоплатформенное приложение Delphi XE7 и хочу использовать несколько горячих клавиш / ярлыков.

TActionList, TMainMenu и TMenuBar имеют свойства для присвоения ShortCuts.

Я использую ярлык для добавления нового TTabItem на TTabControl. Этот ShortCut - это Ctrl + T.

Итак, если пользователь нажимает Ctrl + T, новая вкладка добавляется на указанном TTabControl - и работает правильно.

Однако, если пользователь продолжает удерживать эти 2 клавиши, также создается несколько вкладок.

Событие ярлыка запускается, пока пользователь удерживает эти клавиши.

Добавление новой вкладки - это только пример. Я использую несколько ярлыков, которые хочу активировать только один раз.

Есть ли способ вызвать событие ярлыка только один раз?

Я пробовал таймеры / ожидал определенное время. Но это вызывает проблемы, если пользователь хочет быстро выполнить 2 горячие клавиши.

Спасибо за чтение, и я ценю любую помощь.


person ChrisB    schedule 12.11.2014    source источник
comment
Это не связано только с Firemonkey. Это поведение по умолчанию в приложениях VCL. слишком. Это было asked here, но вы не сможете использовать принятое решение для FMX.   -  person TLama    schedule 12.11.2014
comment
Я не думаю, что есть другое решение, чем использование таймера, потому что горячая клавиша не определяет, когда клавиша нажата, но периодически проверяет, нажата ли определенная комбинация клавиш в это конкретное время. Если это событие запускается.   -  person SilverWarior    schedule 12.11.2014
comment
Это не похоже на проблему, на решение которой стоит тратить время. Разве ваши клиенты не понимают это быстро и не перестают так долго удерживать ключи? Исправил ли эту проблему какой-либо другой поставщик программного обеспечения? Если нет, то зачем?   -  person Rob Kennedy    schedule 12.11.2014
comment
@RobKennedy У меня нет клиентов, так как это личный проект, над которым я работаю (я студент). Я задал этот вопрос из любопытства. Но я думаю, ты прав. Если он не сломан, не чините его.   -  person ChrisB    schedule 13.11.2014
comment
Вы можете использовать флаг, чтобы отключить многократную стрельбу. Работайте, только если он включен. Установите этот флаг отключения после обработки действия и снимите флажок при нажатии правой клавиши.   -  person User007    schedule 17.09.2018


Ответы (1)


Вот пример того, как решить эту проблему с помощью таймера, чтобы он не блокировал пользователей от использования нескольких различных действий подряд. Скорость использования одного и того же действия зависит от вашей конфигурации, но ограничена системным интервалом задержки автоповтора клавиш. См. Комментарии к коду.

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;

ПРИМЕЧАНИЕ. Установите интервал таймера на 1 мс. И не забудьте установить ActionCooldownValue больше, чем интервал задержки автоповтора системного ключа.

person SilverWarior    schedule 12.11.2014
comment
Спасибо за ваши усилия. Я не искал решение для таймера, но у вас все работает нормально. - person ChrisB; 13.11.2014
comment
Я знаю, что вы не искали такого решения, но, поскольку у меня уже было что-то подобное, работающее в одном из моих проектов, я подумал, что могу поделиться им. Как бы то ни было, другой возможный подход заключался бы в полном отказе от встроенной функциональности HotKey и повторной реализации аналогичной функциональности с использованием событий Forms OnKeyDown и OnKeyUp при наличии KeyPreviewEnabled. В этом случае вы будете внедрять функциональность ярлыка, поскольку она обычно использовалась в предыдущей версии Delphi, в которой эта функция еще не была встроена. Реализация этого потребовала бы довольно некоторого кода и не была бы такой простой в использовании. - person SilverWarior; 13.11.2014