1

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 com.github.kwhat.jnativehook@2.2-SNAPSHOT/com.github.kwhat.jnativehook.GlobalScreen.<clinit>(GlobalScreen.java:91)        
        at facsimile@1.0.0/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 ?

srilakshmikanthanp
  • 2,231
  • 1
  • 8
  • 25
  • “ i am using jnativehook library with javafx ” -> why? – jewelsea Jan 12 '22 at 07:18
  • To listen the Global keyboard and mouse event to show and hide a stage with a specified shortcut ;) – srilakshmikanthanp Jan 12 '22 at 07:19
  • You are going through a [fallback](https://github.com/kwhat/jnativehook/blob/2.2/src/main/java/com/github/kwhat/jnativehook/GlobalScreen.java#L68) for native library lookup. Set the path to the native library correctly in your startup script launcher, by ensuring the appropriate jbativehook native lib is in the path you define for the property System.getProperty("jnativehook.lib.name", "JNativeHook"). – jewelsea Jan 12 '22 at 07:35
  • I try to package the image with jpackage it is possible to bundle both together ? – srilakshmikanthanp Jan 12 '22 at 07:37
  • Try to make [loadLibrary](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/System.html#loadLibrary(java.lang.String)) work for name JNativeHook. Check where the system dependent mapping of that name [maps to on your system](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/System.html#mapLibraryName(java.lang.String)) and ensure the library is there. – jewelsea Jan 12 '22 at 07:39
  • JavaFX packages libs with modules and is deployable via jlink or jpackage, so, yes, it is possible, though I have never tried it and don’t know how to do it unless I did more work and research. – jewelsea Jan 12 '22 at 07:41
  • I still don't get what are you coming to say do i need to download the lib manually ? – srilakshmikanthanp Jan 12 '22 at 07:42
  • No, the lib isn’t where it is supposed to be because you haven’t put it there, so it can’t find it. Where it is supposed to be you can determine by checking the mapping for the lib name when executing your jlinked app (just output the string returned by the map api I linked earlier), then you know where the lib is supposed to be, then make sure the lib is in that location for your package install. I haven’t tried it, but that would appear to be a solution as far as I can tell. – jewelsea Jan 12 '22 at 07:47
  • You already have the lib on your machine somewhere or it would not have worked before you tried to jlink. – jewelsea Jan 12 '22 at 07:49
  • I checked in the libs are actually inside the jar file rather than external to it. Jar file is jnativehook-2.2.1.jar at [https://repo1.maven.org/maven2/com/github/kwhat/jnativehook/2.2.1/](https://repo1.maven.org/maven2/com/github/kwhat/jnativehook/2.2.1/). You could extract the native libs from there and place them on the system library path in your app installer (note I don't know why the jlinked app is unable to pick the native libraries up directly out of the jar as when you don't use jlink it seems as if it is able to). – jewelsea Jan 12 '22 at 08:10
  • Really thanks for effort – srilakshmikanthanp Jan 12 '22 at 09:36
  • Added an answer, I might cleanup the comments and add them to the answer, but maybe I'll just leave them there as is, I think they are still reasonably accurate and relevant, but they can't be edited and most accurate info is always in answers rather than comments usually. – jewelsea Jan 12 '22 at 09:44

1 Answers1

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:

  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.

jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • 1
    Does javafx has global Keyboard listener ? – srilakshmikanthanp Jan 12 '22 at 09:47
  • 1
    I followed your instruction by coping the dill file to image/bin now it's working. It temporarily Fixes my problem :) – srilakshmikanthanp Jan 12 '22 at 09:52
  • @srilakshmikanthanp I think not, I think the key listeners are all app-based, but I could be wrong and there could be something in its public API or private internal implementation which would allow you to do that. There is a related question which currently has no definitive answer, but points to some references (including jnativehook): [JavaFX global keyboard listener](https://stackoverflow.com/questions/19768614/javafx-global-keyboard-listener) – jewelsea Jan 12 '22 at 09:53
  • My instructions are for the image lib directory not bin directory, but perhaps it works for both or the target directory is different on your setup, either way, nice that it works :-) – jewelsea Jan 12 '22 at 09:55
  • First i tried put in lib it does't work next i put where all the dill files located :) – srilakshmikanthanp Jan 12 '22 at 09:58
  • 1
    But the problem i need to do it All the when ever i build i have raised issue on [jnativehook](https://github.com/kwhat/jnativehook/issues/394), I appreciate your efforts Thanks ;) – srilakshmikanthanp Jan 12 '22 at 09:59