在 Delphi 10.1.2 中,TActionList
我TAction
用这些属性创建了一个并为其分配了一个快捷方式Ctrl+F12
:
在运行时,当我按住快捷键时Ctrl+F12
,会重复执行该操作(速度取决于系统键盘的重复速度)。
那么如何让动作只执行一次(直到这些键被抬起),即使用户按住键或者用户的系统有一个高键盘重复速度设置?
在 Delphi 10.1.2 中,TActionList
我TAction
用这些属性创建了一个并为其分配了一个快捷方式Ctrl+F12
:
在运行时,当我按住快捷键时Ctrl+F12
,会重复执行该操作(速度取决于系统键盘的重复速度)。
那么如何让动作只执行一次(直到这些键被抬起),即使用户按住键或者用户的系统有一个高键盘重复速度设置?
您可以使用 检索系统键盘设置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
所述,重复计数不是累积的。这实际上意味着操作系统不提供此信息。但是提供了先前的关键状态信息。那将是回调的“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;
最后,不要忽视如果用户的系统设置了快速键盘重复的可能性,这是用户的选择,而不是不是。