java.lang.UnsatisfiedLinkError: URI scheme is not "file" with javafx:jlink

Solution 1:

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:

  1. Created a new JavaFX project via the Idea New JavaFX project wizard.

  2. 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>
      
  3. Added an import to the app:

    import com.github.kwhat.jnativehook.GlobalScreen;
    
  4. Added the following line to the start method of the app:

    GlobalScreen.registerNativeHook();
    
  5. Added the following line to the stop method of the app:

    GlobalScreen.unregisterNativeHook();
    
  6. Added the following line to module-info.java

    requires com.github.kwhat.jnativehook;
    
  7. Linked the app:

    • In the maven window right click on Plugins | javafx | javafx:jlink and choose "Run Maven Build".
  8. 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"));           
      
  9. Copy the native lib libJNativeHook.dylib to the lib directory created for the app created by jlink, this was:

    <projectname>/target/app/lib
    
  10. Attempt to run the app:

    cd <projectname>/target/app/bin
    ./app
    
  11. 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.
    
  12. Follow the instructions here to enable assistive devices for the Terminal app:

    • https://mizage.com/help/accessibility.html#10.14
  13. 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.