'How do I make Enter key behave as a tab in a Delphi FireMonkey Application?

Previously in Delphi VCL applications it was easy to "over ride" the key strokes on either the onkeyup or onkeydown events of components to make the Enter key behave as a TAB key. FireMonkey applications work differently from VCL, so how should one do this now?



Solution 1:[1]

I'm editing my answer to provide another solution thanks to the simple solution provided by @Uwe Raabe. I'm leaving everything here as this answer exposes some of the "magic" in Firemonkey which often isn't obvious.

I needed to create the "TAB" functionality dynamically on FormShow event of a Form to save myself time on implementation. I needed to make a class to handle the TNotifyEvent (OnClick). Here is my other solution which I have tested now with success. Please note the code below will attempt to remove "Default" button action on Enter so it works.

type  
  TClickObject = class(TObject)
  public
    Form: TForm;
    procedure MyTabOnClick(Sender: TObject);
  end;

{ ClickClass }

procedure TClickObject.MyTabOnClick(Sender: TObject);
var
  ch: Char;
  key: Word;
begin
  if Form = nil then Exit;
  key := vkTab;
  ch := #9;
  Form.KeyDown(key, ch, []);
end;

function CreateTabButton(Form: TForm): TButton;
var
  Count: Integer;
  ClickObject: TClickObject;

begin
  //Make the click object
  ClickObject := TClickObject.Create;
  ClickObject.Form := Form;

  //Make other buttons not default
  for Count := 0 to Form.ComponentCount-1 do
  begin
    if (Form.Components[Count] is TButton) then //Extend for other buttons ?
    begin
      (Form.Components[Count] as TButton).Default := False;
    end;
  end;

  //Make a button far off the screen
  Result := TButton.Create(Form);
  Result.Parent := Form;
  Result.Default := True;
  Result.OnClick := ClickObject.MyTabOnClick;
  Result.Text := 'TAB';
  Result.Position.X := -10000;
  Result.Position.Y := -10000;
end;

//Form OnShow Event, declare tabButton as TButton in your Form then you can use it on other components like combo boxes where you want to fire tab / enter event

tabButton :=  CreateTabButton(Self);

The TComboBox for example does does not place nice with the Button solution, here is an example of making it work

procedure TForm1.CommboBox1KeyUp(Sender: TObject; var Key: Word;
  var KeyChar: Char; Shift: TShiftState);
begin
  if (Key = 13) then
  begin
    tabButton.OnClick(self); //tabButton declared in the Form an initialized with CreateTabButton
  end;
end;

The following code is a procedure which can be used from a global library or TDataModule to provide you with the Enter to Tab functionality. I used the onkeyup events on inputs to test it.

procedure HandleEnterAsTab(Form: TForm; Sender: TObject; Key: Word);
var
  TabList: ITabList;
  CurrentControl, NextControl: IControl;
begin
  if (Key = vkReturn) then
  begin
    TabList := Form.GetTabList;
    CurrentControl := TControl(Sender);
    NextControl := TabList.FindNextTabStop(CurrentControl, True, False);
    if (NextControl = nil) then  //go to first item if reached end
    begin
      NextControl := TabList.GetItem(0);
    end;
    
    NextControl.SetFocus;
  end;
end;

The following is an example snippet of it's use

procedure TForm1.Edit2KeyUp(Sender: TObject; var Key: Word; var KeyChar: Char;
  Shift: TShiftState);
begin
  HandleEnterAsTab(Form1, Sender, Key);
end;

Obviously you could change the procedure to work differently according to your needs however I have tried to make it as generic as possible by using TComponent and TForm as the container for getting the TabList.

Solution 2:[2]

As I already mentioned in a comment, another way is to drop a TButton on the form, set TabStop = False and Default = True. The make it small and hide it under another control.

In the OnClick event of the button execute the following code:

var
  ch: Char;
  key: Word;
begin
  key := vkTab;
  ch := #9;
  KeyDown(key, ch, []);
end;

Note that any other button having focus takes precedence over this, so the expected behavior is preserved.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Uwe Raabe