Search code examples
formsdelphikeyboard

How to properly handle single-key shortcuts on a form with multiple input controls?


I have a form in Delphi with some panels. The panels do contain controls which can receive text input (like tEdit and tMemo), and also other controls which do not normally receive text input (like tButton). The main form also has a shortcut defined when the "A" character key is pressed, using the tActionList component.

When the "A" key is pressed, it will always trigger the shortcut. I can override the IsShortCut method in my form, and manually check whether the current focus is on one of the input controls. But this has the backside that I need to go through each of them explicitly (there are a lot of them), and as some of the components can have inner controls (like the finder in a grid) it is difficult to cover them all.

Is there some generic way to check whether the control that has focus on a form is some text input control?


Solution

  • Typically, if your form has controls that accept character input, you don't use plain characters as action shortcuts.

    Instead, you use modifiers, like Ctrl+S, or function keys, like F7.

    It might also be worth recalling that all buttons (except default OK and cancel Cancel buttons) should have access keys, like &Save. If a button's caption is &Save, the S will be underlined and pressing S when the form is focused will "click" the &Save button, even if it isn't focused itself -- as long as the currently focused control doesn't accept character input (like a TEdit), of course.

    Having said this, I'm not sure if you are aware of the possibility to test the class of the focused control?

    function TForm1.FocusedControlAcceptsChars: Boolean;
    begin
      var LCtl := ActiveControl;
      Result := (LCtl is TCustomEdit) {or (LCtl is TCustomRichEdit) or (LCtl is TCustomListView) or ...};
    end;
    

    This way, you don't need to test against 132 child controls, say, but against 3 or 4 control classes.

    If this is still not good enough, you may want to ask the focused control itself if it does accept character input:

    function TForm1.FocusedControlAcceptsChars2: Boolean;
    begin
      var LCtl := ActiveControl;
      if LCtl = nil then
        Exit(False);
      Result := LCtl.Perform(WM_GETDLGCODE, 0, 0) and DLGC_WANTCHARS <> 0;
    end;
    

    Obviously, these two approaches can be combined.