Search code examples
firemonkey

FMX: How to create a menu item shortcut for a single key?


I need this to create a shortcut for a single key in a TMainMenu and TMenuBar, like 'I' for example. Options for single keys are not selectable in the property editor for the shortcut property of a TMenuItem. I have also tried setting the shortcut for the menu item at run time using either of the methods below.

MenuItem.ShortCut := vkI;
MenuItem.ShortCut := TextToShortcut('I');

The shortcut character 'I' does show up in the menu, however, it doesn't work. I press the 'I' key and nothing happens. However, if I set the shortcut using the following then it does work correctly, so I assume the issue is just that it doesn't allow single key shortcuts.

MenuItem.ShortCut := TextToShortcut('Ctrl+I');

I have also tried linking the menu item to an action in a TActionList and setting the shortcut of the action in the same way, but the result is the same.

The solution I've found is to handle the key press in the FormKeyDown event to trigger the action, but this seems unnecessary. Why doesn't it work as expected?

I'm using Delphi 10.4 and building for Windows 32-bit.


Solution

  • Because your shortcut didn't contain a dialog key.

    procedure TCommonCustomForm.IsDialogKey(const Key: Word; const KeyChar: WideChar; const Shift: TShiftState;
      var IsDialog: boolean);
    begin
      IsDialog := (KeyChar < ' ') or ((Shift * [ssAlt, ssCtrl, ssCommand]) <> []);
    end;
    

    In TCommonCustomForm.KeyDown, the code start to check if your shortcut contain a dialog key, if yes it will check your menu and execute the action :

      // 3. perform key in other Menus
      for I := ChildrenCount - 1 downto 0 do
        if Children[i] <> FocusPopup then
        begin
          if Children[I] is TMainMenu then
            TMainMenu(Children[I]).DialogKey(Key, Shift)
          else if Children[I] is TPopupMenu then
            TPopupMenu(Children[I]).DialogKey(Key, Shift);
          if Key = 0 then
            Exit;
        end;
    

    You can override this method and return true for each key you press