i have a custom component (descendant from tpanel) and what i wanna do is to catch when the ctrl or alt key is down and up
any idea how can it be done?
i have a custom component (descendant from tpanel) and what i wanna do is to catch when the ctrl or alt key is down and up
any idea how can it be done?
On way would be to override the KeyDown() and KeyUp() protected methods. The Key
parameter to these methods is the Virtual Key code that corresponds to the key that has gone down/up.
For the Ctrl key the key code of interest is VK_CONTROL.
For the Alt key the key code is the slightly less obvious VK_MENU.
These key codes do not distinguish between left/right keys on a keyboard. If this is important you can use VK_LCONTROL, VK_RCONTROL, VK_LMENU and VK_RMENU.
So, for example, if you were to maintain the Ctrl
key state in a boolean member variable you could set this TRUE when either Ctrl
key does down with something similar to this:
procedure TMyButton.KeyDown(var Key: Word; Shift: TShiftState);
begin
inherited;
fCtrlKeyDown := (Key = VK_CONTROL);
end;
However, these events will only occur for keys pressed while your control has the input focus.
So, if a user presses the Ctrl key while some other control has the focus, your control will not be aware of it. If you need to know the state of the keys at some arbitrary moment in time you call GetAsyncKeyState()
.
To obtain the state of a key at the time of some input event (i.e. window message, such as a mouse button click) then call GetKeyState()
in the code that responds to that event.
To understand the difference between the two consider that you had some Click
handler that responded to a mouse click which triggered some processing that potentially consumed a non-trivial amount of time in which the user might press (or release) a key, followed by some further processing that depended on the key state:
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;
Note that the return value of GetAsyncKeyState() is not a simple boolean. It contains information about whether the key was pressed since the last call to the function as well as the current state of the key.
Similarly GetKeyState() includes information about the "toggled" state of a key, and is also not a simple boolean.
Refer to the documentation for these API's for details on interpreting their return values.
If your control needs to be able to respond immediately to a key going down while some other control has the input focus, e.g. to provide some visual feedback to the user of the keyboard state, then you will need to implement some additional mechanism by which the control can be made aware of these events.
One way would be to use KeyPreview on the form and provide a method on the control which is required to be called whenever the form receives a key event (which with KeyPreview enabled will occur for every key event, before the actual input control receives that event. Hence the name... the event allows the form to "Preview" the "Key" events). This method could enable your control to determine the keyboard state and respond and react appropriately.
This however means that your control is reliant on external code (on the form) to function and still only works for keyboard events that occur while some control on the same form has the input focus.
To make your control entirely self contained, it could install a keyboard hook to establish an application wide "preview" mechanism. If you have potentially lots of instances of your control in an application, you may wish to devise a mechanism which tracks those instances and uses only a single hook to update them all, rather than each control installing it's own individual hook.
I don't think it would be appropriate to go into the details of such a mechanism here. If you have difficult implementing that then this should be addressed as a separate question (which may already be answered elsewhere on StackOverflow).