4

On my (Windows) Surface Go 2 tablet I'm not able to retrieve any (multitouch) TouchEvents. I tried it with several Java/FX versions. Even with JavaFX 17 (and older versions) no TouchEvents events are generated only mouse events. Is there some sort of configuration parameter needed?

package fx;

import javafx.application.Application;
import javafx.collections.ListChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TouchEvent;
import javafx.scene.layout.Pane;
import javafx.stage.PopupWindow;
import javafx.stage.Stage;
import javafx.stage.Window;

public class test {

    public static void main(String[] args) {
        System.setProperty("com.sun.javafx.touch", "true");
        System.setProperty("com.sun.javafx.isEmbedded", "true");   
        Application.launch(JFXApp.class, args);
    }

    public static class JFXApp extends Application implements ListChangeListener<Window> {

        @Override
        public void start(Stage primaryStage) {
//            primaryStage.addEventFilter(TouchEvent.ANY, e -> System.out.println("touch event: " + e.getEventType()));
//            primaryStage.addEventFilter(MouseEvent.ANY, e -> System.out.println("mouse event: " + e.getEventType()));
            final ComboBox<String> comboBox = new ComboBox<>();
            comboBox.getItems().addAll("Test1", "Test2", "Test3");
            Scene scene = new Scene(new Pane(comboBox));
            scene.addEventFilter(TouchEvent.ANY, e -> System.out.println("scene touch event: " + e.getEventType()));
            scene.addEventFilter(MouseEvent.ANY, e -> System.out.println("scene mouse event: " + e.getEventType()));
            primaryStage.setScene(scene);
            primaryStage.setWidth(800);
            primaryStage.setHeight(800);
            primaryStage.show();
            Window.getWindows().addListener(this);
        }

        @Override
        public void onChanged(Change<? extends Window> c) {
            if (!c.next()) return;
            for (Window w : c.getAddedSubList()) {
                if (w instanceof PopupWindow) {
                    w.addEventFilter(TouchEvent.ANY,
                            e -> System.out.println("touch event (PopupWindow): " + e.getEventType()));
                    w.addEventFilter(MouseEvent.ANY,
                            e -> System.out.println("mouse event (PopupWindow): " + e.getEventType()));
                    Window.getWindows().removeListener(this);
                }
            }
        }
    }
}
Waverick
  • 1,984
  • 1
  • 11
  • 16
  • I haven’t got a PC to try this at the moment, but I would have thought the touch events would get dispatched to nodes and perhaps the scene but not the Window. All the [onTouch properties](https://openjfx.io/javadoc/16/javafx.graphics/javafx/scene/input/class-use/TouchEvent.html) are only on scenes and nodes. – jewelsea Sep 16 '21 at 07:31
  • I change the listener to the scene, still no touch events – Waverick Sep 16 '21 at 08:56
  • Have you tried adding `System.setProperty("com.sun.javafx.touch", "true");` right before `Application.launch`? You might also need `"com.sun.javafx.isEmbedded"`. – José Pereda Sep 19 '21 at 10:14
  • I add those two lines. But the still now touch events. – Waverick Sep 19 '21 at 11:03
  • Yes, I tried also the https://docs.oracle.com/javafx/2/events/TouchEventsExample.zip example. That also didn't work. I waited for JavaFX 17, but that didn't help also. – Waverick Sep 19 '21 at 12:56
  • 2
    When you say "Also with JavaFX 17 no TouchEvents events are generated ", does it mean that with 16 you get them? With older JavaFX versions you get Touch events, but not multitouch? There is also a `com.sun.javafx.multiTouch` property. – José Pereda Sep 19 '21 at 12:58
  • @Waverick if their basic example doesn't work on a supported platform, I would suggest filing a bug report. What os are you using? – matt Sep 19 '21 at 13:24
  • Right after the release of JavaFX 16, this issue [JDK-8249737](https://bugs.openjdk.java.net/browse/JDK-8249737) was fixed. It changed the way touch events were treated on Windows: not all events are direct events. Before this fix, touch events reported to scene, but now indirect events bail out: [link](https://github.com/openjdk/jfx/blob/master/modules/javafx.graphics/src/main/java/javafx/scene/Scene.java#L2799), and treated as mouse events. Can you use a pen with your tablet? – José Pereda Sep 19 '21 at 13:59
  • @matt Is use Windows 10 on a Surface Go 2 tablet. I will fill a bug report, if my example should work. After all I'm not using an exotic OS. – Waverick Sep 19 '21 at 18:25
  • @JoséPereda I even tried it with JavaFX 8, I almost cannot believe that multitouch doesn't work on Windows for so long. – Waverick Sep 19 '21 at 18:27
  • @JoséPereda I don't use a pen, I see that MouseEvent have the isSynthesized() == true set. the setOnTouch(..) on a scene also doesn't work. – Waverick Sep 19 '21 at 18:28
  • Can you test Gestures like rotate swipe or zoom? I have a touch enabled monitor and I can see Rotate gesture works fine, but touch events are not processed (direct is false). – José Pereda Sep 19 '21 at 18:31
  • This one is working https://docs.oracle.com/javafx/2/events/gestures.htm I did also a test on a small touchscreen Windows PC, also no touch events on that machine. I'm getting the feeling that touch events are broken on Windows. I have also a iMac, the trackpad also don't generate touch events but I think these are always mapped to mouseevents. – Waverick Sep 19 '21 at 20:57
  • If gestures work, it is only because touch work: `GestureRecognizers` works from touch begin/next/end [notifications](https://github.com/openjdk/jfx/blob/master/modules/javafx.graphics/src/main/java/com/sun/javafx/tk/quantum/GestureRecognizers.java#L31), so that's good news. As I mentioned before, the problem is touch events are indirect and you only get mouse events. However, I still wonder why your Surface doesn't show touch events with JavaFX 16 or lower, as touch events were direct. – José Pereda Sep 19 '21 at 23:52
  • The gesture calls setOnRotation... and setOnZoom... etc are working. But not the setOnTouch... methods. I couldn't find any JavaFX version which worked on my two Windows systems (PC with touch screen & Surface Go 2), so I wonder if it works at all (for Windows). Also for MacOS it would be nice that the Trackpad event also generate touch events. – Waverick Sep 20 '21 at 06:56
  • Can confirm TouchEvents are not fired while using OpenJDK/JFX 18 on Win10 with a Dell touch screen monitor, while prepackaged Gestures still fire. Same code works perfect with OpenJDK/JFX 18/16. – Birdasaur May 02 '22 at 16:26
  • I proposed an extension of the Scene API. It allows to disable the newly introduced event filtering based on direct/indirect. As it turns out, the feature only works on a subset of touch devices. And if multiple screens are used it can even depend on the screen that is used to generate the touch event. It can be found on GitHub: https://github.com/miho/jfx/issues/1. I created a working preview release build with my API proposal: https://github.com/miho/jfx/releases/tag/v20-SNAPSHOT%2Bbuild.1 We might end up using this as long as the issue is not officially resolved. – miho Oct 24 '22 at 08:32

1 Answers1

2

I get TouchEvents on Java/JavaFX 16 using a Microsoft SurfaceBook 2 laptop running Windows.

Sample source

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.TouchEvent;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class TouchTest extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        System.out.println("java.version: " + System.getProperty("java.version"));
        System.out.println("javafx.runtime.version: " + System.getProperties().get("javafx.runtime.version"));

        Scene scene = new Scene(new Pane(), 800, 800);
        scene.addEventFilter(TouchEvent.ANY, System.out::println);

        stage.setScene(scene);
        stage.show();
    }
}

Execution instructions

Using Java 16 and JavaFX 16, run the sample program and touch the empty pane displayed (by touching with your finger to the the touchscreen, not using the trackpad and pressing it).

Program output

C:\Users\send2\.jdks\temurin-16.0.2\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.3.2\lib\idea_rt.jar=56576:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.3.2\bin" -Dfile.encoding=UTF-8 -classpath C:\Users\send2\.m2\repository\org\openjfx\javafx-controls\16\javafx-controls-16.jar;C:\Users\send2\.m2\repository\org\openjfx\javafx-graphics\16\javafx-graphics-16.jar;C:\Users\send2\.m2\repository\org\openjfx\javafx-base\16\javafx-base-16.jar;C:\Users\send2\.m2\repository\org\openjfx\javafx-fxml\16\javafx-fxml-16.jar -p C:\Users\send2\.m2\repository\org\openjfx\javafx-base\16\javafx-base-16-win.jar;C:\Users\send2\.m2\repository\org\openjfx\javafx-graphics\16\javafx-graphics-16-win.jar;C:\dev\fxdemo\target\classes;C:\Users\send2\.m2\repository\org\openjfx\javafx-controls\16\javafx-controls-16-win.jar;C:\Users\send2\.m2\repository\org\openjfx\javafx-fxml\16\javafx-fxml-16-win.jar -m org.jewelsea.fxdemo/org.jewelsea.fxdemo.TouchTest
java.version: 16.0.2
javafx.runtime.version: 16+8
TouchEvent [source = javafx.scene.Scene@3968dc9e, target = Pane@295c8184[styleClass=root], eventType = TOUCH_PRESSED, consumed = false, touchCount = 1, eventSetId = 1, touchPoint = TouchPoint [state = PRESSED, id = 1, target = Pane@295c8184[styleClass=root], x = 394.5, y = 330.5, z = 0.0, pickResult = PickResult [node = Pane@295c8184[styleClass=root], point = Point3D [x = 394.5, y = 330.5, z = 0.0], distance = 1492.820323027551]]
TouchEvent [source = javafx.scene.Scene@3968dc9e, target = Pane@295c8184[styleClass=root], eventType = TOUCH_MOVED, consumed = false, touchCount = 1, eventSetId = 2, touchPoint = TouchPoint [state = MOVED, id = 1, target = Pane@295c8184[styleClass=root], x = 394.0, y = 331.0, z = 0.0, pickResult = PickResult [node = Pane@295c8184[styleClass=root], point = Point3D [x = 394.0, y = 331.0, z = 0.0], distance = 1492.820323027551]]
TouchEvent [source = javafx.scene.Scene@3968dc9e, target = Pane@295c8184[styleClass=root], eventType = TOUCH_STATIONARY, consumed = false, touchCount = 1, eventSetId = 3, touchPoint = TouchPoint [state = STATIONARY, id = 1, target = Pane@295c8184[styleClass=root], x = 394.0, y = 331.0, z = 0.0, pickResult = PickResult [node = Pane@295c8184[styleClass=root], point = Point3D [x = 394.0, y = 331.0, z = 0.0], distance = 1492.820323027551]]
TouchEvent [source = javafx.scene.Scene@3968dc9e, target = Pane@295c8184[styleClass=root], eventType = TOUCH_STATIONARY, consumed = false, touchCount = 1, eventSetId = 4, touchPoint = TouchPoint [state = STATIONARY, id = 1, target = Pane@295c8184[styleClass=root], x = 394.0, y = 331.0, z = 0.0, pickResult = PickResult [node = Pane@295c8184[styleClass=root], point = Point3D [x = 394.0, y = 331.0, z = 0.0], distance = 1492.820323027551]]
TouchEvent [source = javafx.scene.Scene@3968dc9e, target = Pane@295c8184[styleClass=root], eventType = TOUCH_RELEASED, consumed = false, touchCount = 1, eventSetId = 5, touchPoint = TouchPoint [state = RELEASED, id = 1, target = Pane@295c8184[styleClass=root], x = 394.0, y = 331.0, z = 0.0, pickResult = PickResult [node = Pane@295c8184[styleClass=root], point = Point3D [x = 394.0, y = 331.0, z = 0.0], distance = 1492.820323027551]]

The execution line is just provided for informational purposes, it was auto-generated by my IDE (Intellij Idea) when I used its internal run function to start the app. I am sure it would work fine outside of the IDE with a different execution command, but using the same JRE/JavaFX version.

Example worked on JavaFX 16, not 17.0.0.1

If you use the current version of JavaFX 17, the above example will not receive touch events (they are mapped to mouse events), on my setup of a Surface Book 2 running Windows. This is explained in Jose's comment on the question:

Right after the release of JavaFX 16, this issue JDK-8249737 was fixed. It changed the way touch events were treated on Windows: not all events are direct events. Before this fix, touch events reported to scene, but now indirect events bail out: link, and treated as mouse events.

This also goes (mostly) for the old Oracle TouchEvent tutorial sample code found here:

The multi-touch folder dragging portion of that code works on my setup for Java 16.

The dragging a ball to a box portion of that code did not work on Java 16 for me. It seemed to register the initial touch but I could not work out a touch or a touch and drag sequence which got the ball to another box, so it appeared broken.

For Java 17 nothing in the touch event sample responded to touch events (or mouse events).

FAQ

for MacOS it would be nice that the Trackpad event also generate touch events.

Using a Mac trackpad does not generate touch events (tested on JavaFX 17). Unlike the windows touch handling, I don't think this Mac code was updated for JavaFX 17, so it may have always been that way. I don't have a touch screen to try it out.

For the iOS implementation it appears from examining the code that it would generate touch events when you touch the iOS device's screen (but I haven't got a setup to run JavaFX iOS to test it).

It seems that there are multiple issues.

Yes, I agree.

I also think that some of the issues are platform and device-specific, and could end up being a bit nuanced and not entirely straightforward.

The info I provided is pretty much the limit of my knowledge on this subject, so I can't offer much more help, unfortunately.

When I test it with bell-sw or Azul Full-JDK 16, it doesn't work

It is kind of strange that it works with the gluon JavaFX 16 distribution, but not azul or bell-sw bundled distributions, as one would think they would have the same functionality, but that is about as much as could say about that.

I guess the makers of those bundled JDK/JavaFX distributions could be contacted or an issue report filed against them for this. But then, as the functionality changed for Java 17, I am not sure it makes a lot of difference going forward, at least currently.

When I use Oracle Java 17 and use the JavaFX 16 download from gluonhq.com/products/javafx it does work! But JavaFX 17 doesn't work in any case.

Yep, that is the same result as I got using the modular JavaFX versions sourced from Maven central.

or must the touchevents be retrieved in a different way?

I don't think there is another way to retrieve them short of hacking the JavaFX core. The implementation is in the JavaFX library code and not configurable via public API.

For some platforms (e.g. iOS) it looks like the TouchEvents are generated and routed through the standard event filters.

But for other platforms, there is specific code in there to ignore the TouchEvents under certain scenarios. For the 17.0.0.1 build, at least, TouchEvents are being deliberately ignored when detected in the JavaFX framework. They are not routed to the user JavaFX application code when a touch screen on a Windows OS device is touched with your finger. Note, under such scenarios, the touches are treated instead as MouseEvents and actioned accordingly (AFAICT).

So, you would need to customize and change the core JavaFX code to get the touch events on your Windows OS platform, either by hacking the JavaFX library code yourself or having a change integrated into the library for a future JavaFX version.

Thoughts on the JavaFX TouchEvent implementation (and changing it)

Perhaps the issue has already been thoroughly considered and the platform code in JavaFX 17.0.0.1 is working as designed. Perhaps the thought is that the current behavior, while not ideal is a reasonable compromise. Perhaps the outcome could be a documentation update to better describe the TouchEvent behaviour rather than a functional update to change it.

But IMO, from current behavior, there appear to be problems with the design and implementation of the TouchEvent processing feature in JavaFX when it is running on certain platforms (such as Windows OS). I do not know exactly how to categorize or address those problems.

If you wish to work with the JavaFX developers on this, I advise that you join the openjfx-dev mailing list and describe the issue there (linking back to this question) and start a discussion on what could be done about it.

jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • Thank you for your answer. Alas your example doesn't work on my systems. Java 16 or 17 the same results. What Java distribution did you use? I used the Java + FX integration from https://bell-sw.com/ and https://azul.com/ – Waverick Sep 23 '21 at 06:46
  • It is in the execution line: [`temurin-16.0.2`](https://adoptium.net/releases?variant=openjdk16&jvmVariant=hotspot). – jewelsea Sep 23 '21 at 07:41
  • Temurin is the JDK it is not packaged withJavaFX. The JavaFX version was sourced from [Maven Central](https://search.maven.org/search?q=g:org.openjfx) via a `pom.xml` dependency on version 16 of the appropriate JavaFX modules. `javafx.runtime.version: 16+8`. – jewelsea Sep 23 '21 at 08:10
  • It seems that there are multiple issues. When I test it with bell-sw or Azul Full-JDK 16, it doesn't work, when I use Oracle Java 17 and use the JavaFX 16 download from https://gluonhq.com/products/javafx/ it does work! But JavaFX 17 doesn't work in any case, or must the touchevents retrieved in a different way? – Waverick Sep 23 '21 at 10:16
  • @Waverick I updated the answer to include an FAQ section to address some of your questions. – jewelsea Sep 23 '21 at 21:45
  • Can confirm that TouchEvents still do not work (ie... are not fired) using OpenJDK 18 + OpenJFX on Win10 with a Touch screen monitor. :-( – Birdasaur May 02 '22 at 15:38