|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
||||
|
||||
Подавление нажатия Alt для TMenu
Здравствуйте, форумчане!
В своей программе я реализовал механизм пользовательских горячих клавиш на разные типовые действия. В настройках для каждого такого действия задаётся сама клавиша, плюс, возможно, модификаторы (Alt, Ctrl, Shift). С двумя последними проблем нет, а вот нажатие Alt тут же перехватывается главным меню формы, и в результате: - если клавиатурная комбинация соответствует вызову какого-либо пункта меню, одновременно вываливается это меню, и срабатывает код горячей клавиши. - в противном случае просто срабатывает горячая клавиша, но с системным "бипом" - мол, ошибка тут у вас. Обе эти ситуации меня не радуют, хотелось бы исправить этот момент. Но никак не получается перехватить и подавить нажатие Alt - такое ощущение, что меню перехватывает коды клавиш до того, как их перехватывает форма, компонент ApplicationEvents и метод OnHook. Отследить факт нажатия Alt я могу (в частности, это делают мои обработчики OnKeyDown с целю отследить появление горячих комбинаций), но вот подавить его - никак. Либо давится всё и нет вообще реакции на клавиатуру, либо Alt обязательно добирается до главного меню, вызывая нежелательные действия. Может кто-нибудь сталкивался и знает, как побороть всемогущий Alt? Проблема точно решаемая, во многих приложениях это делается, но моей квалификации никак не хватает, чтобы найти ответ самостоятельно. Сколько ни гуглил - всё вокруг да около, реально действующего кода так и не увидел... Последний раз редактировалось Guaho, 04.04.2020 в 21:38. |
#2
|
|||
|
|||
Попробуй перехватить само сообщение нажатия кнопок. и если это альт, то обработать самому, а если нет, то пустиьт дальше. Перехват - что-то типа:
Код:
TForm1 = class(TForm) ... procedure WMKEYDOWN(var Msg : TMessage); message WN_KEYDOWN; ... |
#3
|
||||
|
||||
Да что я уже только не пробовал... Во все дыры засовывал свои перехватчики. Проблема в том, что определить факт нажатия Alt я могу, но подавить именно Alt - не могу, он же вроде как флаг идёт. Получается, или давится вообще всё тотально, или Alt не давится.
Для обнаружения нажатия Alt использую такую функцию: Код:
function Tdm.AltDown : Boolean; var State : TKeyboardState; begin GetKeyboardState(State); Result := ((State[vk_Menu] and 128) <> 0); end; |
#4
|
||||
|
||||
Попробовал такой подход: в обработчик OnKeyDown формы поставил такой код:
Код:
function Tdm.AltDown : Boolean; var State : TKeyboardState; begin GetKeyboardState(State); Result := ((State[vk_Menu] and 128) <> 0); if Result then begin beep; State[vk_Menu] := 0; // (State[vk_Menu] and not 128); SetKeyboardState(State); end; end; Последний раз редактировалось Guaho, 04.04.2020 в 22:54. |
#5
|
|||
|
|||
Тебе же надо в Memo?
Попробуй так. Сабклассим TMemo. У нашего класса отлавливаем сообщение нажатия и отпускания клавиш. Проверяем KeyboardState. Если Alt зажат, то сразу ставим, что сообщение мы обработали (что бы оно не шло дальше) и уже думаем - нужна нам нажатая комбинация или нет. Т.е. сообщение нажатия клавиш (не событие, которое от VCL, а именно сообщение Windows) ловим прямо в компоненте, который его получает. Там идеология такая, что сначала компонент (окно) получает сообщение и смотрит, нужно ли ему на него реагировать, если не нужно то он дальше отдает ему окну приложения, а уж оно начинает разбираться по всему стеку оконных компонентов. Т.е. наша задача что бы если Alt зажат, то это все остановилось на копоненте, который получил нажатие. Тогда, если нажали в Memo, то обработаем только мы, если в другом месте формы, то уже пойдет стандартная обработка сообщения. Как засаблассить компонент - в юните, где у тебя Memo делаем примерно так: Код:
type TMemo=class(StdCtrls.TMemo) protected procedure WmKeyDown(var Message : TMessage); message WM_KEYDOWN; ... end; TForm1 = class(TForm) Memo1 : TMemo; ... ЗЫ. Может не прокатить, т.к. этот компонент есть просто обертка над стандартным виндовым. Но, по идее, должно. |
Этот пользователь сказал Спасибо lmikle за это полезное сообщение: | ||
Guaho (06.04.2020)
|
#6
|
||||
|
||||
Спасибо за подробное разъяснение! Это новый подход, я такого ещё не встречал нигде.
Но у меня более общий случай. Сори, сразу не написал об этом. У меня большая база данных. Обработчики горячих клавиш вставлены как на уровне форм (для действий общего характера), так и на уровне компонентов на этой форме (преимущественно гридов, но не только, там и DBMemo, и DBEditы могут быть, и что угодно). Форм у меня почти 30 в проекте, поэтому очень желательно не дробиться на мелочи, а по возможности решить этот вопрос глобально. Попробую ещё в Application.OnHook воткнуть тот код, который вчера пробовал... Последний раз редактировалось Guaho, 05.04.2020 в 10:30. |
#7
|
|||
|
|||
Ну, если честно, я бы тогда пошел другим путем.
Просто налепил бы нужных TAction и уже в их обработчиках смотрел для какого компонента они вызваны. Это проще, чем бороть систему. |
Этот пользователь сказал Спасибо lmikle за это полезное сообщение: | ||
Guaho (06.04.2020)
|
#8
|
||||
|
||||
Уффф... Кажись что-то наконец нарисовалось! Спасибо за помощь!
Метод такой: всю обработку клавиатуры надо перенести в OnShortCut формы. И далее примерно так: Код:
procedure Tfm_komp.FormShortCut(var Msg: TWMKey; var Handled: Boolean); begin GlobalKeyBoardKey := dm.GetExtKey(Msg.CharCode); // Получение "расширенного" кода (свой формат) для последующего сравнения с кодами заданных в настройках горячих клавиш. GAlt := dm.AltDown; // определение факта нажатия Alt, код я приводил ранее. if GlobalKeyBoardKey = ukShowOperPanel then // пример обработчика (показ/скрытие панели) begin sbShowOperPanel.Down := not sbShowOperPanel.Down; sbShowOperPanelClick(Self); Handled := true; exit; end; ........ // (действия с другими клавишами) if GAlt then Handled := true; // если вдруг обнаружилась нажатая "неподавленная" Alt, "давим" её. end; Последний раз редактировалось Guaho, 06.04.2020 в 09:55. |