Yesterday I discovered a situation wherein a keyboard ShortCut did not fire when I was expecting it to.
The specific situation was: I pressed the ShortCut key combination for an Action of an ActionList on an MDI child, while a side bar on the MDI form was focussed.
I always was under the impression that ShortCuts would work globally. In exactly which circumstances do or do they not fire?
That's a deceptively simple question with a surprisingly long answer. First I will deal with some basics and then follow the ShortCut through the VCL code to finally arrive at - I hope - a satisfying conclusion.
A ShortCut represents a special keyboard combination of one or more keys that cause an operation. Special means special to the programmer who gives meaning to the specific key combination.
In Delphi a ShortCut is of type TShortCut
which is declared as a whole number within the Word
range (0..65535). A ShortCut is often constructed out of several keys, e.g.:
CTRL+K = scCtrl
+ Ord('K')
= 16384
+ 75
= 16459
.
ShortCuts can be assigned to the ShortCut
or SecondaryShortCuts
property of an Action or to the ShortCut
property of a MenuItem, thus invoking that Action's OnExecute
event or MenuItem's OnClick
event when the ShortCut's keyboard combination is pressed.
For an Action's ShortCut to be processed, it is required that the Action is enabled, and added to a not suspended ActionList or attached to an enabled MenuItem. Likewise, for a MenuItem's ShortCut to be processed, it is required that the MenuItem is added to a Menu.
ShortCuts can also be interpreted from the Application's, a Form's or from an ApplicationEvents' OnShortCut
event. Within those events, the Msg
parameter holds the keycode in its CharCode
member, and possibly special keys like Shift, Ctrl or Alt can be extracted using GetKeyState
:
procedure TForm1.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
begin
if (Msg.CharCode = Ord('K')) and (GetKeyState(VK_CONTROL) < 0) then
begin
Caption := 'CTRL+K pressed';
Handled := True;
end;
end;
If the Handled
parameter is set to True
, any subsequent processing for the key will be skipped.
The VCL does not keep a list of all specified ShortCuts. (How could it?). Thus all keystrokes could potentially be a ShortCut. And that is exactly how the VCL interprets ShortCuts: by evaluating every key that is pressed.
Peter Below wrote an excellent and comprehensive article dealing with A Key's Odyssey through the VCL. In short, a ShortCut is catched as follows:
TApplication.Run
picks up every Windows message send to the application,TApplication.ProcessMessage
calls IsKeyMsg
which passes the message - if a WM_KEYDOWN
message - on to the CN_KEYDOWN
message handler of the focussed Control.TWinControl.CNKeyDown
examines whether the key is a menu key (we'll see the definition of this menu is beyond a physical Menu):
TWinControl.IsMenuKey
first examines whether the key is a ShortCut within the Control's or one of its parent's PopupMenu,
TMenu.IsShortCut
1) traverses all its (sub)menu items and calls the OnClick
event handler of the enabled MenuItem with the ShortCut, if any,TCustomForm.IsShortCut
2),
OnShortCut
event of the Form is called, if assigned,FActionLists
. That was considered a bug and as from BDS2006, the field was eliminated and the ActionLists could be indirectly owned by the Form too.
TCustomActionList.IsShortCut
traverses all its Actions and calls HandleShortCut
of the enabled Action with the ShortCut set in its ShortCut
or SecondaryShortCuts
property, if any,Application.IsShortCut
is called (via CM_APPKEYDOWN
),
OnShortCut
event of the Application is fired, this includes OnShortCut
events of all ApplicationEvents components within the project, if any assigned,IsShortCut
routine of the MainForm (see 2)), but only when the MainForm is enabled. E.g. when the active Form is a modal Form, then the MainForm will be disabled. This will fire the OnShortCut
event of the MainForm or will traverse all directly or indirectly owned ActionLists of the MainForm (depending on Delphi version as mentioned above).When it is:
OnShortCut
event of the currently active Form or of the MainForm, but only when the MainForm is enabled,OnShortCut
event of the Applicaton or any ApplicationEvents components.When it is set for:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With