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

    Hi Kristian,
    I want to capture the ctrl+c event, but with your library capture only a single key press . If i am not correct, please tell me a way to capture the copy(ctrl+c) event globally.
    Thanks

    • Hello Puspender, please have a look at the GlobalKeyEvent class. Not only you do get the key currently pressed, but you can also call isControlPressed to check for the CTRL key. Hope this helps, regards Kristian

  2. hsqr says:

    Is it possible to listen to certain key events and prevent them form being processesd by other processes? I’d like to code a tool similiar to AutoHotKey and that’s a feature needed..

    • Hello hsqr, for listening to key events just use the GlobalKeyboardHook class, as explained on GitHub. Regarding your second question, blocking keys is not really possible (at least for Windows). To explain it in detail, it’s important to understand how low-level hooks work in Windows, please see this comment on GitHub. So the order of hooks determines “who” will get the information. If you are luckly, you’ll be the first one in the chain, so by not calling CallNextHookEx you’ll “block” the key for other programs. But because the behaviour of not calling CallNextHookEx is undefined, the Java library doesn’t implement it. You could go ahead and recompile the C-Library, as outlined on GitHub, removing the call to CallNextHookEx. So whenever a keyboard hook is active, the key input won’t be forwarded. Hope this helps. Regards, Kristian

  3. Gonzalo says:

    When i start the example i got this error:

    Global keyboard hook successfully started, press [escape] key to shutdown.
    Exception in thread “Global Keyboard Hook Thread” java.lang.UnsatisfiedLinkError: lc.kra.system.keyboard.GlobalKeyboardHook$NativeKeyboardHook.registerHook()I
    at lc.kra.system.keyboard.GlobalKeyboardHook$NativeKeyboardHook.registerHook(Native Method)
    at lc.kra.system.keyboard.GlobalKeyboardHook$NativeKeyboardHook.run(GlobalKeyboardHook.java:174)

    do u know what is the problem?.. i copy keyboardhook-win-x86.dll and .lib and keyboardhook-win-amd64.dll and .lib on the java path.

    • Hello Gonzalo, please do try to use a packaged JAR release downloaded from the GitHub releases section, instead of adding the code / lib files manually. Alternatively you can try to set the mousehook.lib.path property, when running your application and point to the directory of your DDL files. Hope this helps. Regards, Kristian

  4. Hello Kristian, how are you?

    I would like you help me with some problem. I need capture a combination of keys between 2 seconds. For example:

    (CTRL)+5 and still pressing the (CTRL) I press the 5 again. So the combination would be CTRL +5+5. Could you tell me what should I did?

    For example:
    I pressed CTRL+5..and I press key 5 again until 1.9 seconds after first key 5 I would like capture this and log in the console. Can you explain how I could do this?

    Thank you

  5. Ben Durkin says:

    Hello,
    I have been using your library with great success so far.
    However I need to detect when someone enters a key with ‘alt’ pressed.
    I figured I could use a boolean that updates with key presses when ‘alt’ is pressed
    acting as a custom isAltPressed thing,
    but I wondered if there was a way to do it through your library that I have missed?
    Thanks a lot,
    Ben

  6. Matheus says:

    Hello friend
    First of all, thank you for the effort you’ve put into this.
    Secondly, I was hoping you could help me with this problem I am facing.
    I am developing an application that listens for the caps lock key. Your .jar comes in handy because I want to listen globally and not only when the program is focused(and it does this well). So, whenever my program detects that the Capital key is toggled, is makes a .beep() sound. I used the function Toolkit.getDefaultToolkit().getLockingState(GetKeyEvent.VK_CAPITAL) to identify wheter the Capital key was toggled or not. It works flawlessly if I set my Frame to visible. If I decide to hide the Frame it doesn’t produce the. beep()sounds. To be more clear, it captures the key strokes either way, but only produces the .beep() sound when my Frame is set to visible. And this only happens with this function. Other functions work and produce the sound, but only this one can detect if Capital is toggled.

    Can you help me?

  7. Krispy Creme says:

    Sup dude,

    Thanks for your effort. I’m wondering how to do capitalization. There’s an event.isShiftPressed(), but not for Caps Lock. I was going to do a boolean to keep track of Caps Lock presses, but sometimes Caps Lock can be on BEFORE my Java program is launched. How can I tell if Caps Lock is currently active?

  8. lo says:

    Hi,

    Thank you for sharing the jar.
    I am trying to listen the keybord even when Task manager is focus.
    Is it possible with your jar?

    Ths

  9. Jose C. says:

    Hi Kristian, I see that the native code is implemented to set a SetWindowsHookEx in Windows. Are there any plans to also implement a global hook for MacOS and Linux systems?

    • Hey Jose, support for MacOS and Linux is still planned, but currently I find no time implementing it. I am very sorry. If anyone would volunteer, I would love to accept any pull request on GitHub. Unfortunately I just don’t find time to build it from scratch. Hope this explains. Regards, Kristian

  10. mDaniels says:

    Hi, we have a Java application that uses Sys-Hook to listen for “alt-shift-home” which resets the focus to our app. It works great but seems to interfere with Windows’ alternate keyboard languages. If the keyboard language is set to Spanish for example, the key sequences for special characters do not work while our application is running with Sys-Hook and resume working when the application terminates or the application is run without Sys-Hook. It seems the keyboard’s listener is not getting a chance to run possibly – is there any way to get around this?
    Thanks

  11. Vandhuy Martins says:

    Hey Kristian, I would like to thank you immensely for this library! It saved my life!

  12. Andres Garcia says:

    Hello Kristian, how can I run the library from a Windos host inside a virtual machine, while I move the mouse in the virtual machine stops capturing, even if you press a key from the host machine with Windows to the virtual machine this is not captured.

    • Hello Andres, sorry for my late reply. Most virtual machines will actually catch the inputs on a very low-level, some even to the level of the input driver, to forward the input one-to-one to the virtual machine. There are even cases w/o any software involved (e.g. VMware can tunnel USB directly through to the VM, so essentially this is the same as you would directly plug-in your keyboard to the VM). In those cases a library like JSysHook will never be able to capture the inputs. JSysHook supports two modes: The normal mode will capture the events from a high-level Windows OS and then there is “raw” mode (you can enable it by passing “true”, to the constructor). The “raw” mode is slightly more low-level, so you may try to still capture it.

      Hope this helps. Regards, Kristian