delphi自定义组件 - 捕获(ctrl或alt键)keydown和keyup keyevents

时间:2016-04-14 23:49:45

标签: delphi components key-events

我有一个自定义组件(来自tpanel的后代),我想做的是在ctrl或alt键向下和向上时捕获

任何想法怎么做?

1 个答案:

答案 0 :(得分:1)

在途中将覆盖 KeyDown() KeyUp()受保护的方法。这些方法的Key参数是Virtual Key code,对应于已经下降/上升的键。

对于 Ctrl 键,感兴趣的关键代码为 VK_CONTROL

对于 Alt 键,关键代码不太明显 VK_MENU

这些键码不区分键盘上的左/右键。如果这很重要,您可以使用 VK_LCONTROL VK_RCONTROL VK_LMENU VK_RMENU

因此,例如,如果您要在布尔成员变量中维护Ctrl键状态,那么当Ctrl键关闭时,可以将此设置为TRUE:

procedure TMyButton.KeyDown(var Key: Word; Shift: TShiftState);
begin
  inherited;
  fCtrlKeyDown := (Key = VK_CONTROL);
end;

但是,当您的控件具有输入焦点时,对于按下的键,这些事件将仅

因此,如果用户按下 Ctrl 键而某个其他控件具有焦点,则您的控件将无法识别它。如果您需要在任意时刻知道密钥的状态,请致电GetAsyncKeyState()

要在某些输入事件(即窗口消息,例如鼠标按钮单击)时获取键的状态,然后在响应该代码的代码中调用GetKeyState()事件

要理解两者之间的区别,请考虑您有一些响应鼠标单击的Click处理程序,这会触发一些可能消耗用户可能按下(或释放)的非常重要时间的处理)一个密钥,然后是一些依赖于关键状态的进一步处理:

procedure TMyButton.Click;
begin
  // .. some non-trivial processing - if the user presses or releases 
  //  the Ctrl key while this processing occurs, then this could affect
  //  how the following code behaves, depending on which 'KeyState'
  //  function is used to determine that key state ....

  // ...

  GetKeyState(VK_CONTROL);  // Will return the state of the Ctrl key at
                            //  the time of the mouse event that resulted 
                            //  in this Click code being executed, regardless
                            //  of the state of that key NOW.

  GetAsyncKeyState(VK_CONTROL);  // Will return the state of the Ctrl key NOW
                                 //  regardless of the state of the key at    
                                 //  the time of the 'Click' mouse event.
end;

请注意,GetAsyncKeyState()的返回值不是简单的布尔值。它包含有关自上次调用函数以来密钥是否被按下以及密钥的当前状态的信息。

类似地,GetKeyState()包含有关键的“切换”状态的信息,也不是简单的布尔值。

有关解释其返回值的详细信息,请参阅这些API的文档。

响应其他控制中的输入

如果您的控件需要能够立即响应键,而某些其他控件具有输入焦点,例如为键盘状态的用户提供一些视觉反馈,然后你需要实现一些额外的机制,通过它可以使控件知道这些事件。

一种方法是在表单上使用 KeyPreview ,并在控件上提供一个方法,只要表单收到一个键事件(每个键都会启用KeyPreview,就会调用该方法)事件,在实际输入控件接收到该事件之前。因此名称...事件允许表单“预览”“键”事件)。此方法可以使您的控件确定键盘状态并做出相应的响应和反应。

然而,这意味着您的控件依赖于外部代码(在窗体上)来运行,并且仍然只适用于在同一窗体上的某些控件具有输入焦点时发生的键盘事件。

要使控件完全自包含,可以安装keyboard hook来建立应用程序范围的“预览”机制。如果您在应用程序中有很多控件实例,您可能希望设计一种跟踪这些实例的机制,并且只使用一个钩子来更新它们,而不是每个控件都安装它自己的钩子。

我认为在这里详细讨论这种机制并不合适。如果您难以实现,那么这应该作为一个单独的问题解决(可能已经在StackOverflow的其他地方回答)。