2
votes

I want to capture and process mouse wheel events in any condition and at all times in my Android application, while it's running and visible.

I used the main Form's event like this:

procedure THeaderFooterwithNavigation.FormMouseWheel(Sender: TObject;
  Shift: TShiftState; WheelDelta: Integer; var Handled: Boolean);
begin
  label2.text := inttostr(wheeldelta);
end;

It works very well with the Windows version of the app (Delphi builds by default for both Android and Windows simultaneously), but in the Android version it seems to not do anything.

Then I added that procedure to every component that had the same mouse wheel event, with the exact same results.

The OTG mouse wheel works well with the android device, scrolling through text windows, etc., only my Delphi application doesn't seem to respond to the mouse wheel at all.

What do I need to capture mouse wheel events?

1
You might be able to do it by creating an instance of a GestureDetector (imported as JGestureDetector in Androidapi.JNI.GraphicsContentViewText.pas), however you will also need to construct a class that descends from TJavaLocal that implements JGestureDetector_OnGestureListener, and code the onScroll method of it. I don't have time right now to "fill in the blanks", however I might be able to help if you become stuckDave Nottage
Scratch the above comment - apparently this will work only if the events for the view are implemented, which seems self-defeatingDave Nottage
At the moment I'm looking into this solution: stackoverflow.com/questions/11024809/….ralevash

1 Answers

1
votes

Two parts to this solution:

Part #1 - It required creating a descendant of the Android View class that overrides onGenericMotionEvent, and passes the event to a "delegate". I've added this code to my Kastri library, however I'll repeat them here for completeness:

https://github.com/DelphiWorlds/Kastri/blob/master/Java/Base/GenericView/DWGenericView.java

package com.delphiworlds.kastri;

import android.content.Context;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.View;

public class DWGenericView extends View {

  private DWGenericViewDelegate mDelegate;

  public DWGenericView(Context context, DWGenericViewDelegate delegate) {
    super(context);
    mDelegate = delegate;
  }

  @Override
  public boolean onGenericMotionEvent(MotionEvent event) {
    if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
      switch (event.getAction()) {
        case MotionEvent.ACTION_SCROLL:
          mDelegate.onMouseWheel(event);
          return true;
      }
    }
    return super.onGenericMotionEvent(event);
  }

}

https://github.com/DelphiWorlds/Kastri/blob/master/Java/Base/GenericView/DWGenericViewDelegate.java

package com.delphiworlds.kastri;

import android.view.MotionEvent;

public interface DWGenericViewDelegate {

  public void onMouseWheel(MotionEvent event);

}

You'll need to compile this Java code into a jar file (e.g. using Android Studio) that you add to the Libraries node under the Android platform in Project Manager in Delphi.

EDIT: In case you have trouble compiling the jar, I've also built one which contains only the code above:

https://github.com/DelphiWorlds/Kastri/blob/master/Lib/dw-genericview.jar

Part #2 - Import for the Java code:

https://github.com/DelphiWorlds/Kastri/blob/master/API/DW.Androidapi.JNI.DWGenericView.pas

unit DW.Androidapi.JNI.DWGenericView;

interface

uses
  // Android
  Androidapi.JNIBridge, Androidapi.JNI.JavaTypes, Androidapi.JNI.GraphicsContentViewText;

type
  JGenericView = interface;
  JGenericViewDelegate = interface;

  JGenericViewDelegateClass = interface(IJavaClass)
    ['{AF4620B1-9D15-4B8D-82F1-A8A2C1F411DB}']
  end;

  [JavaSignature('com/delphiworlds/kastri/DWGenericViewDelegate')]
  JGenericViewDelegate = interface(IJavaInstance)
    ['{43A4AF5E-4BDB-48E9-9E1F-1F939E4384E4}']
    procedure onMouseWheel(event: JMotionEvent); cdecl;
  end;

  JGenericViewClass = interface(JViewClass)
    ['{9002B46F-C616-4428-8FCA-F86ED28BD55B}']
    {class} function init(context: JContext; delegate: JGenericViewDelegate): JGenericView; cdecl;
  end;

  [JavaSignature('com/delphiworlds/kastri/DWGenericView')]
  JGenericView = interface(JView)
    ['{77A9B1B8-9412-4074-9BBF-FF81F6364174}']
  end;
  TJGenericView = class(TJavaGenericImport<JGenericViewClass, JGenericView>) end;

implementation

end.

Test project code:

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Memo.Types, FMX.Controls.Presentation, FMX.ScrollBox, FMX.Memo,
  Androidapi.JNI.GraphicsContentViewText,
  DW.Androidapi.JNI.DWGenericView;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
  private
    FGenericView: JGenericView;
    FGenericViewDelegate: JGenericViewDelegate;
  protected
    procedure DelegateMouseWheel(event: JMotionEvent);
  public
    constructor Create(AOwner: TComponent); override;
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

uses
  Androidapi.JNIBridge, Androidapi.Helpers,
  FMX.Platform.Android;

type
  TGenericViewDelegate = class(TJavaLocal, JGenericViewDelegate)
  private
    FForm: TForm1;
  public
    { JGenericViewDelegate }
    procedure onMouseWheel(event: JMotionEvent); cdecl;
  public
    constructor Create(AForm: TForm1);
  end;

{ TGenericViewDelegate }

constructor TGenericViewDelegate.Create(AForm: TForm1);
begin
  inherited Create;
  FForm := AForm;
end;

procedure TGenericViewDelegate.onMouseWheel(event: JMotionEvent);
begin
  FForm.DelegateMouseWheel(event);
end;

{ TForm1 }

constructor TForm1.Create(AOwner: TComponent);
begin
  inherited;
  FGenericViewDelegate := TGenericViewDelegate.Create(Self);
  FGenericView := TJGenericView.JavaClass.init(TAndroidHelper.Context, FGenericViewDelegate);
  WindowHandleToPlatform(Handle).FormLayout.addView(FGenericView);
end;

procedure TForm1.DelegateMouseWheel(event: JMotionEvent);
begin
  Memo1.Lines.Add('onMouseWheel: ' + JStringToString(event.toString));
end;

end.

The code creates an instance of the View descendant, passing the "delegate" reference (that passes the event on to the form code), and adds it to the native layout for the form.

That will get you as far as having an event instance available. Use the relevant methods of that to work out the delta etc.