方法是覆盖 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 处理程序响应鼠标单击,该处理程序触发了一些可能消耗用户可能按下(或释放)a键,然后是一些取决于键状态的进一步处理:
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 的其他地方得到了回答)。