Kristian Kraljić You may compare programming with poetry,
a harmonic script is a piece of creativity which will last forever.
- Kristian Kraljić

Java – Global (low level) Keyboard / Mouse Hook

by Kristian Kraljic, February 9, 2016

About five years ago I started this blog by picking up an idea of Johannes Schüth (Jotschi) about a global keyboard and mouse listener for Java. Today I am very happy to announce the next major version of the library now available on GitHub!

system-hook-logo

Keyboard and mouse events in Java only work, if the registered component is in focus. For example, in case a window looses its focus (e.g. when minimized), it stops receiving any more events. Through a low-level system-wide hook it’s possible to deliver those events regardless. You’ll find all sources of the latest release, as well as binary bundles / prepackaged Java archives (JAR) on the GitHub project page.

The old post describes all changes I did to the initial version by Johannes (Jotschi). For the new major release I again reworked nearly every part of the library, to make it more stable and versatile. Here is what I did:

  • Optimized the native library C code, fixed bugs and removed all parts requireing a C++ compiler in the first place.
  • Renamed the event classes and listener interfaces and prepended Global to avoid conflicts with existing (Swing) event listeners.
  • Added support for mouseWheel events to the GlobalMouseListener.
  • Again allowed negative "out of bounds" values for GlobalMouseEvents, to also track the mouse pointer off screen (e.g. on multi-monitor setups).
  • Improved the threading concept and implemented a native error handling. The GlobalKeyboardHook and GlobalMouseHook constructors will now throw a UnsatisfiedLinkError if the native libraries can not be loaded or a RuntimeException in case hooking fails.
  • All the code has been moved to GitHub and binaries are now beeing continuously built by AppVeyor. Feel free to contribute on GitHub!

(Again) Last but not least, please share your ideas and problems in the comments. I will try to enhance the Global Keyboard / Mouse Hook based on your feedback. For the next release let’s see if we can get Linux and / or Mac OSX support going.

202 Comments

  1. Kristian Kraljic says:

    Hey! Thanks a lot to Timo, Thomas, Byron, Lucas, Jason and Frank.

    You were absolutely right. I have compiled the library using a 64-bit JVM (Java 7.0) and tested it on Windows Vista & 7 (x64). Everything should work fine now.

    Please let me know if you encounter any further issues (especially with the dependencies Thomas mentioned).

  2. rachid says:

    I have this problem at compilation

    C:\MouseHook\src\MouseHook>javac c:\MouseHook\test\de\ksquared\test\system\mouse\MouseHookTest.java
    .\de\ksquared\system\mouse\GlobalMouseListener.java:35: cannot find symbol
    symbol : class PoolHook
    location: class de.ksquared.system.mouse.GlobalMouseListener
    protected PoolHook hook;
    ^
    .\de\ksquared\system\mouse\MouseAdapter.java:32: method does not override a method from its superclass
    @Override public void mouseMoved(MouseEvent event) {}
    ^
    .\de\ksquared\system\mouse\MouseAdapter.java:33: method does not override a method from its superclass
    @Override public void mousePressed(MouseEvent event) {}
    ^
    .\de\ksquared\system\mouse\MouseAdapter.java:34: method does not override a method from its superclass
    @Override public void mouseReleased(MouseEvent event) {}
    ^
    .\de\ksquared\system\mouse\GlobalMouseListener.java:36: cannot find symbol
    symbol : class PoolHook
    location: class de.ksquared.system.mouse.GlobalMouseListener
    public GlobalMouseListener() { (hook=new PoolHook(this)).start(); }
    ^
    5 errors

    thanks

  3. derstromi says:

    Alright heres how to solve the Unsatisfied Link thing:

    Download the libraries. Then load the *.dll (beware of 64bit and 32bit OS)

    f.e.:
    add line directly under your main method:
    System.load(“C:\\Downloads\\mousehook-win-amd64.dll”)

  4. wojtaw says:

    Hi, great piece of software! However, I would like to use keyboardhook on MAC OS X as well. Is it possible, can you compile libraries for other platforms? In your JAVA code, it seems to be prepared for other platforms.
    Thanks a lot for great work!
    V.

  5. Kristian Kraljic says:

    @rachid: The Java code is valid. There is no reason why there should be a compilation problem with it. Make sure you are using at least Java 6 and that the .jar file of the library is in your build path.

    @derstormi: With version 0.3 nobody should have the “Unsatisfied” link error anymore. The method you suggested is basically correct, but in version 0.3 this is done automatically and platform independent. Your suggestion would only work on your computer, because you used a relative path and only on Windows x64 installations, because you didn’t check the processor’s architecture. This is all done by the “Native”-class automatically and without including the library files manually.

    @wojtaw: Thanks! ;-) Anyways, generally as you said, the Java code is prepared to run on other platforms. Unfortunately compiling the C++ classes on Mac or Linux will not work. At the moment the library uses native Windows libraries to “hook” into the system. In Unix you will need to use a different method to read the mouse position and/or keyboard state. I plan to include all Unix based systems in future as well. Stay tuned for the new version.

    Regards, Kristian

  6. derstromi says:

    i have the unsatisfied link error with the code shown above like i see it now

  7. derstromi says:

    btw:

    i clicked “view raw code” and copied it into the files

  8. wojtaw says:

    Alright, I see. That would be great if working on other platforms. Keep me updated! Do you have any kind of donate button? I would like to send you some donation, if you would help me to run my app on Mac etc…

  9. Kristian Kraljic says:

    @derstormi: Please use the .jar file from the “Binary & example build” package, instead of just copying the source from the raw display. The Native-class loads the required libraries automatically if they are available. They are already included into the bundled jar files. Otherwise you would have to add the libraries manually to your project and adapt the Native-class to match the new relative path.
    Adding another System.load() command using an absolute path is quite a bad idea when thinking about distributing your application.

    @wojtaw: For sure, I will keep you updated. Please feel free to use the subscribe button below the comment area, so will be notified automatically. I would greatly appreciate a donation. Check out the about-page for details. Thank in advance for your support! :-)

  10. guest says:

    if i use the binary & example build, am i able to vary the content?

    want to make a mouse click counter with that, so i need the code, not the jar

  11. Kristian Kraljic says:

    @guest: Please check the Binary & example bundle. You do not need to modify any of the framework code to realize your task. The framework implements the so called “observer pattern”, so you are able to add a listener and “listen” to global mouse click events.

  12. rajan says:

    Hi…

    I’m trying to read a scanner input by using your code… it works perfectly fine but I coudn’t find the virtual key for enter as my scanner put an ENTER at the end of code

    What I’m want to do is :

    ((char) event.getVirtualKeyCode()==VK_ENTER)
    {
    add all the codes to gather in one string variable..
    }

    but am not able to find out the virtual key code for Enter key..

    any help would be greatly appreciated…