Search code examples
windowsdelphimouseeventfiremonkey

How detect the mouse back and forward buttons in a Delphi FMX Windows form?


Has anyone found a way to detect the mouse back and forward buttons in a Delphi FMX form in Windows (and only Windows)?

I understand this works fine in a VCL application, using

procedure WMAppCommand(var Msg: Winapi.Messages.TMessage); message WM_APPCOMMAND;

but this has no effect in an FMX application.

If anyone already has worked out a solution to this, would very much appreciate a hint (or the code they used, of course).


Solution

  • FMX heavily filters window messages, only dispatching the few messages it actually uses for itself. WM_APPCOMMAND is not one of them, which is why a simple message handler does not work in FMX, like it does in VCL.

    So, you are going to have to manually subclass the TForm's Win32 HWND directly, via SetWindowLongPtr(GWLP_WNDPROC) or SetWindowSubclass(), in order to intercept window messages before FMX sees them. See Subclassing controls.

    An ideal place to do that subclassing is to override the TForm.CreateHandle() method. You can use FMX's FormToHWND() function to get the TForm's HWND after it has been created.

    protected
      procedure CreateHandle; override;
    
    ...
    
    uses
      FMX.Platform.Win, Winapi.Windows, Winapi.CommCtrl;
    
    function MySubclassProc(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM;
      uIdSubclass: UINT_PTR; dwRefData: DWORD_PTR): LRESULT; stdcall;
    begin
      case uMsg of
        WM_APPCOMMAND: begin
         // use TMyForm(dwRefData) as needed...
        end;
        WM_NCDESTROY:
          RemoveWindowSubclass(hWnd, @MySubclassProc, uIdSubclass);
      end;
      Result := DefSubclassProc(hWnd, uMsg, wParam, lParam);
    end;
    
    procedure TMyForm.CreateHandle;
    begin
      inherited;
      SetWindowSubclass(FormToHWND(Self), @MySubclassProc, 1, DWORD_PTR(Self));
    end;
    
    procedure InitStandardClasses;
    var 
      ICC: TInitCommonControlsEx;
    begin
      ICC.dwSize := SizeOf(TInitCommonControlsEx);
      ICC.dwICC := ICC_STANDARD_CLASSES;
      InitCommonControlsEx(ICC);
    end;
    
    initialization
      InitStandardClasses;