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. Narender says:

    Hi,

    First of thanks for this tutorial. I want a java keyloger which can install in windows silently and start when windows start. Can you tell me how your code works.

    • Kristian Kraljic says:

      No…, no I’m sorry. ;-) Regards, Kristian

    • Tareq says:

      Dear Sir,
      Is it work in MAC and Linux OS?

      Thanks
      Sajedur Rahman Tareq

    • Kristian Kraljic says:

      Dear Tareq. No unfortunately not at the moment. I plan to do that.

      Regards,
      Kristian

  2. Zept says:

    Very nicely done, helps alot.

    Found one bug however:
    I’m using two monitors right now, with the main monitor to the right.
    When I move the mose to the left monitor the x value will be 0 over the entire monitor, while it’s expected to show negative values, like java.awt.MouseInfo.

  3. alex says:

    hi Kristian,
    thank you so much for you code, that is brilliant. I am using it in my project.
    Could you help me add WM_MOUSEWHEEL message in your code? It was a long time since I coded C++.
    really appreciate

  4. jimbo says:

    Thanks you for your work, this is awesome.

    btw it seems not working on some maximized application (games etc). Is it possible? Please tell me how.

  5. maiko says:

    is there a way that i can use the mouse and keylisner at the same time?

  6. Laurent Muller says:

    Very nice code. I have updated your GlobalKeyListener class with the singleton pattern. So only one hook is needed.

    /*
    * the singleton instance
    */
    private static volatile GlobalKeyListener instance = null;

    /**
    * Returns the singleton instance.
    *
    * @return the singleton instance.
    */
    public synchronized static GlobalKeyListener getInstance() {
    // double check locking
    if (instance == null) {
    synchronized (GlobalKeyListener.class) {
    if (instance == null) {
    instance = new GlobalKeyListener();
    }
    }
    }
    return instance;
    }

  7. Chiang says:

    Hi Kristian,
    I am trying to compile your KeyboardHook at the moment with a new getTime method to get a high-resolution time from the system as well as when a key was pressed. However when I am trying to build the lib on a 64bit system I always get an UnsatisfiedLinkError just as you did (no valid Win32 application). I also set the flags as you described (however O0, g3, fmessage-length=0 and mno-cygwin are ignored). I am using MS Visual Studio to compile. It seems to be a compiler problem since most of the flags are ignored. Can you give me and advice?
    All the best and thanks,
    Chiang

    • Chiang says:

      Trying to compile it now with mingw64 with all flags set except -mno-cygwin and I still have the same issue when loading the lib in Java: UnsatisfiedLinkError no valid Win32 application.
      compiling like the following: g++ -Wall -c -D_JNI_IMPLEMENTATION_ -Wl,-kill-at -O0 -g3 -fmessage-length=0 -static-libgcc -I”%JAVA_HOME%\include” -m64 -I”%JAVA_HOME%\include\win32″ -shared -o keylib.lib KeyboardHook.cpp

  8. Rahul says:

    Hi Kristian,

    Great library/package. It looks really easy to use.

    In addition to Keyboard and Mouse events, I need to when window is locked/unlocked or screen saver comes on. I think they all belong together. Is that something you could add to this library?

    Thanks again.
    Rahul

    • Kristian Kraljic says:

      Hey Rahul,

      the library is just to track keyboard and mouse events, not to track any other system events, such as window locks etc. To track this, you would need to access other low-level API’s of windows.

      Regards,
      Kristian

  9. komal says:

    How we can capture keypress time by this hook

    • Kristian Kraljic says:

      Hello Kornal,

      the simplest solution I can think about right now is to register for both the keyPressed and keyReleased event. Call System.currentTimeMillis() in both and subtract the time from keyPressed from the time taken in keyReleased. This should do the trick.

      Regards,
      Kristian

  10. Kristian Kraljic says:

    Not yet… Sorry for that one.

  11. Jack says:

    Hello there!! I have a problem. When I close my application and start again mouse hook doesn’t start. How should I do?

  12. hassan says:

    hi , thank you for this a good exercice ;

    when i tried to compile this project i have this

    Exception in thread “Thread-0” java.lang.UnsatisfiedLinkError: de.ksquared.system.keyboard.KeyboardHook.registerHook(Lde/ksquared/system/keyboard/GlobalKeyListener;)V
    at de.ksquared.system.keyboard.KeyboardHook.registerHook(Native Method)
    at de.ksquared.system.keyboard.PoolHook.run(KeyboardHook.java:52)

    please you can telle me what’s a wrong!

    thanks , best regards