如何避免重复执行TAction.Shortcut?

时间:2017-03-24 18:02:49

标签: delphi keyboard-shortcuts delphi-10.1-berlin taction

在Delphi 10.1.2中,在ActiveSupport::Inflector.inflections(:en) do |inflect| inflect.irregular 'slave', 'slaves' end 内,我创建了一个包含这些属性的TActionList,并为其分配了一个快捷方式TAction

enter image description here

在运行时,当我按下快捷键Ctrl+F12时,操作会重复执行(速度取决于系统键盘的重复速度)。

那么,即使用户按下按键或者用户系统的键盘重复速度设置较高,如何才能使动作仅执行ONCE(直到这些按键被抬起)?

1 个答案:

答案 0 :(得分:1)

您可以使用SystemParametersInfo检索系统键盘设置。 SPI_GETKEYBOARDDELAY给出重复延迟;第一个和第二个生成事件之间的时间。 SPI_GETKEYBOARDSPEED给出键盘重复率;初始延迟后事件之间的持续时间。文档具有最慢和最快设置的近似值,可帮助您确定一个动作点。

假设您决定采取行动。由于快捷方式与生成它们的事件没有直接关系,因此它们没有任何属性或任何可以显示有关初始延迟的信息的内容重复执行。

然后,一个选项是一旦输入就禁用快捷方式的执行,并在释放适当的密钥后重新启用。您必须将表单的KeyPreview设置为true才能实现此解决方案,因为表单上的任何控件可能是生成快捷方式时具有焦点的控件。

我会发现一个不那么麻烦的解决方案是当它不是由初始按键生成时,防止生成快捷方式。你这次必须注意关键事件。

一种可能的实现方式是安装本地键盘钩。

var
  KeybHook: HHOOK;

procedure TForm1.FormCreate(Sender: TObject);
begin
  KeybHook := SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, 0, GetCurrentThreadId);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  UnhookWindowsHookEx(KeybHook);
end;

可能很容易测试回调中感兴趣的键的重复计数,但是,如WM_KEYDOWN的文档中所述,重复计数不是累积的。实际意味着操作系统不提供此信息。但是提供了先前的关键状态information。这将是" lParam"的第30位。回调。您可以在快捷键关闭时阻止任何键盘消息,并且主要快捷方式先前已关闭,从而无法到达聚焦控件的窗口过程。

function KeyboardProc(code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT;
    stdcall;
begin
  if code > 0 then begin
    if (wParam = vk_f12) and (GetKeyState(VK_CONTROL) < 0) and
        ((lParam and $40000000) > 0) then begin
      Result := 1;
      Exit;
    end;
  end;
  Result := CallNextHookEx(KeybHook, code, wParam, lParam);
end;

最后,不要忽视如果用户系统设置了快速键盘重复的可能性,它是用户的选择而不是不