“Hooking” KeyDown in a Firemonkey form

As said in my last post: " The hard part is hooking the form in a way so all I need to do is call TForm_ActivatePositioning as in the VCL."

As it turns out, that’s even easier to do than in the VCL. No subclassing of the window, just adding a new control is sufficient. As this StackOverflow answer points out, a Firemonkey form calls the DialogKey method of all its child controls when a key is pressed, starting with the one that has got the focus. So, all we’ve got to do is creating a control that handles the keys we want to intercept and add it to the form.

Here is the code:

type
  TFormPositioningActivator = class(TControl)
  private
    FModifier: TShiftState;
  protected
    procedure DialogKey(var Key: Word; Shift: TShiftState); override;
  public
    constructor Create(_Form: TCustomForm; _Modifier: TShiftState); reintroduce;
  end;

{ TFormHookChild }

constructor TFormPositioningActivator.Create(_Form: TCustomForm; _Modifier: TShiftState);
begin
  inherited Create(_Form);
  FModifier := _Modifier;
  Parent := _Form;
end;

procedure TFormPositioningActivator.DialogKey(var Key: Word; Shift: TShiftState);
begin
  inherited;
  if Shift = FModifier then begin
    case Key of
      vkLeft: TForm_MoveTo(self.Parent as TForm, dwpLeft);
      vkRight: TForm_MoveTo(self.Parent as TForm, dwpRight);
      vkUp: TForm_MoveTo(self.Parent as TForm, dwpTop);
      vkDown: TForm_MoveTo(self.Parent as TForm, dwpBottom);
      vkHome: TForm_MoveTo(self.Parent as TForm, dwpTopLeft);
      vkEnd: TForm_MoveTo(self.Parent as TForm, dwpBottomLeft);
      vkPrior: TForm_MoveTo(self.Parent as TForm, dwpTopRight);
      vkNext: TForm_MoveTo(self.Parent as TForm, dwpBottomRight);
    else
      Exit; // so Key doesn't get set to 0
    end;
    Key := 0;
  end;

end;

function TForm_ActivatePositioning(_Form: TForm; _Modifier: TShiftState = [ssCtrl, ssAlt]): TObject;
begin
  Result := TFormPositioningActivator.Create(_Form, _Modifier);
end;

All you have to do is call TForm_ActivatePositioning(Self) in the form’s constructor and be done.