Ответ 1
Это обманчиво простой вопрос с удивительно длинным ответом. Сначала я рассмотрю некоторые основы, а затем последую за ShortCut через код VCL, чтобы наконец прийти - надеюсь, - удовлетворительный вывод.
Что такое ShortCut?
ShortCut представляет собой специальную комбинацию клавиш из одной или нескольких клавиш, которые вызывают операцию. Специальные средства, специально предназначенные для программистов, которые придают смысл конкретной комбинации клавиш.
В Delphi ShortCut имеет тип TShortCut
, который объявляется как целое число в диапазоне Word
(0..65535). ShortCut часто строится из нескольких клавиш, например:
CTRL + K= scCtrl
+ Ord('K')
= 16384
+ 75
= 16459
.
Как указать ShortCut?
ShortCuts можно присвоить свойству ShortCut
или SecondaryShortCuts
свойства Action или для свойства ShortCut
для MenuItem, тем самым вызывая событие Action OnExecute
event или MenuItem OnClick
, когда комбинация клавиш ShortCut.
Чтобы обработать Action ShortCut, требуется, чтобы действие было активировано и добавлено к не приостановленному списку действий или подключен к включенному элементу MenuItem. Аналогично, для обработки MenuItem ShortCut требуется, чтобы MenuItem был добавлен в Меню.
ShortCuts также можно интерпретировать из Application, Form или из событие ApplicationEvents 'OnShortCut
. Внутри этих событий параметр Msg
содержит код ключа в своем элементе CharCode
, и, возможно, специальные клавиши, такие как Shift, CTRL или Alt, могут быть извлечены с помощью 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;
Если для параметра Handled
установлено значение True
, любая последующая обработка ключа будет пропущена.
Как выхватили ShortCut?
VCL не сохраняет список всех указанных ShortCuts. (Как это могло быть?). Таким образом, все нажатия клавиш могут быть ShortCut. И именно так VCL интерпретирует ShortCuts: оценивая каждый нажатый ключ.
Питер Ниже написал превосходную и всеобъемлющую статью, посвященную ключевой одиссее через VCL. Короче говоря, ShortCut отображается следующим образом:
-
TApplication.Run
выбирает каждое сообщение Windows, отправляемое в приложение, -
TApplication.ProcessMessage
вызываетIsKeyMsg
, который передает сообщение - если сообщениеWM_KEYDOWN
- на обработчик сообщенияCN_KEYDOWN
элемента с фокусом.
Как обрабатывается ShortCut?
TWinControl.CNKeyDown
проверяет, является ли ключ клавишей меню (мы увидим, что определение этого меню выходит за пределы физического меню):
-
TWinControl.IsMenuKey
сначала проверяет, является ли ключ ShortCut в элементе управления или одним из его родительских PopupMenu-
TMenu.IsShortCut
1) перемещает все его пункты (под) и вызывает обработчик событияOnClick
включенного MenuItem с помощью ShortCut, если есть,
-
- Если он не обрабатывается, он проверяет, является ли ключ ShortCut формы, на которой находится элемент управления, вызывая
TCustomForm.IsShortCut
2),- Вызывается
OnShortCut
событие, если оно назначено, - Если он не обрабатывается, он проверяет, является ли ключ ShortCut в форме MainMenu (см. 1)), если таковой имеется,
- Если он не обрабатывается, он отправляет ключ всем спискам действий, принадлежащим Form (все еще говорит об активной форме). До Delphi версии 10 (BDS2006) эти списки действий должны быть непосредственно принадлежат Форме и хранились в защищенном (что сделало возможным вмешательство в случае необходимости) поле
FActionLists
. Это было признано ошибкой, и с BDS2006 поле было удалено, и ActionLists может быть косвенно принадлежит Форме.-
TCustomActionList.IsShortCut
обходит все свои действия и вызываетHandleShortCut
активированного действия с набором ShortCut в свойствеShortCut
илиSecondaryShortCuts
, если он
-
- Вызывается
- Если не обрабатывается,
Application.IsShortCut
вызывается (черезCM_APPKEYDOWN
),- Запускается
OnShortCut
событие, в том числеOnShortCut
событий всех компонентов ApplicationEvents в проекте, если они назначены, - Если он не обрабатывается, он вызывает процедуру
IsShortCut
MainForm (см. 2)), но только при включенном MainForm. Например. когда активная форма является модальной формой, тогда MainForm будет отключен. Это вызовет событиеOnShortCut
MainFormили будет проходить все прямые или косвенно принадлежащие ActionLists MainForm (в зависимости от версии Delphi, как указано выше).
- Запускается
Итак, когда обрабатывается ShortCut?
Если это:
- Установить для активированного MenuItem в PopupMenu, который прикреплен к текущему сосредоточенному элементу управления или любому из его родителей,
- Установить для включенного MenuItem в MainMenu, который отображается в активной активной форме или в MainForm, но только при включенном MainForm,
- Установить для активированного действия в не приостановленном ActionList, который принадлежит текущей активной форме или MainForm, но только при включенном MainForm,
- Подключено к событию
OnShortCut
активной активной формы или MainForm, но только при включенном MainForm, - Отслеживается в событии
OnShortCut
приложения или любых компонентов ApplicationEvents.
А когда ShortCut не обрабатывается?
Когда он установлен для:
- Отключено MenuItem,
- Меню Menu без меню,
- Элемент MenuItem в MainMenu, который не привязан к форме,
- Элемент MenuItem в PopupMenu, прикрепленный к родному брату,
- Отключенное действие,
- Действие без ActionList,
- Действие в списке действий, которое не принадлежит активной форме или MainForm. Например: другая форма, DataModule, приложение, модуль утилит и т.д.
- Действие в списке действий, которое непосредственно не принадлежит активной форме или MainForm в версиях Delphi ниже BDS2006.