Issue
Hello i am using jnativehook library with javafx running with mvn javafx:run
works fine but with mvn javafx:jlink
fails to start with a launcher, here is javafx plugin xml,
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.6</version>
<executions>
<execution>
<id>default-cli</id>
<configuration>
<launcher>launcher</launcher>
<mainClass>facsimile/com.github.srilakshmikanthanp.facsimile.Launcher</mainClass>
</configuration>
</execution>
</executions>
</plugin>
Here is the stack trace,
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1071)
Caused by: java.lang.RuntimeException: Exception in Application start method
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.UnsatisfiedLinkError: URI scheme is not "file"
at [email protected]/com.github.kwhat.jnativehook.GlobalScreen.<clinit>(GlobalScreen.java:91)
at [email protected]/com.github.srilakshmikanthanp.facsimile.Launcher.start(Launcher.java:34)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
... 1 more
Exception running application com.github.srilakshmikanthanp.facsimile.Launcher
The github respository is here at line, How resolve this error ?
Solution
Caution
JavaFX has keyboard handling in-built.
Absolutely do not do this unless you need some capability not built into JavaFX.
That said . . . if you really need to do this . . .
I got this to work via the following steps:
Created a new JavaFX project via the Idea New JavaFX project wizard.
Added a dependency to JNativeHook 2.2-SNAPSHOT.
Snapshot was required because 2.2.1 release module-info would not work for me.
<dependency> <groupId>com.github.kwhat</groupId> <artifactId>jnativehook</artifactId> <version>2.2-SNAPSHOT</version> </dependency>
Needed to enable the sonatype snapshot repository to access it.
<repositories> <repository> <id>oss.sonatype.org-snapshot</id> <url>https://oss.sonatype.org/content/repositories/snapshots</url> <releases> <enabled>false</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories>
Added an import to the app:
import com.github.kwhat.jnativehook.GlobalScreen;
Added the following line to the start method of the app:
GlobalScreen.registerNativeHook();
Added the following line to the stop method of the app:
GlobalScreen.unregisterNativeHook();
Added the following line to module-info.java
requires com.github.kwhat.jnativehook;
Linked the app:
- In the maven window right click on Plugins | javafx | javafx:jlink and choose "Run Maven Build".
Extracted the native lib from the jar.
Right click on
jnativehook-<longversioninfo>.jar
.Choose Copy Path/Reference... | Absolute path
In a command line window
jar xvf <copied path>
Find the appropriate native lib for the platform.
find . | grep dylib
For me it is an intel mac, so the file was:
./com/github/kwhat/jnativehook/lib/darwin/x86_64/libJNativeHook.dylib
The name was confirmed by the output of this line added to the start method:
System.out.println("libname: " + System.mapLibraryName("JNativeHook"));
Copy the native lib
libJNativeHook.dylib
to the lib directory created for the app created by jlink, this was:<projectname>/target/app/lib
Attempt to run the app:
cd <projectname>/target/app/bin ./app
App run will fail with the following error (means that the native lib has loaded and there is another error):
Caused by: com.github.kwhat.jnativehook.NativeHookException: Failed to enable access for assistive devices.
Follow the instructions here to enable assistive devices for the Terminal app:
Run the app again:
./app
Now the app runs fine . . .
Perhaps there is an easier way to do this . . . I don't know.
If you want, you can create an issue asking the jnativehook developers to make this simpler. If you do that, definitely link back to this question for context.
Somehow (I don't know how) the JavaFX libraries are able to be picked up when a jlink is done without having to copy the native libraries to the jlink output lib directory manually. Perhaps whatever is done for JavaFX could be done for jnativehook to make it easier to use with jlink/jpackage.
Answered By - jewelsea
Answer Checked By - Candace Johnson (JavaFixing Volunteer)