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!
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 theGlobalMouseListener
. - 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
andGlobalMouseHook
constructors will now throw aUnsatisfiedLinkError
if the native libraries can not be loaded or aRuntimeException
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
« Older CommentsNewer Comments »
« Older CommentsNewer Comments »
Fantastic!!! Works soooooooo well!!!
I have one question though. When we are typing on Windows pop-up windows (username and Password Windows) it doesn’t capture any. Is it because of the security that they are using or do we need to tweak something on this?
Hello Pradeep,
> Is it because of the security that they are using…
Actually that’s the case, yes. And I don’t think you can do anything about it either, as the low-level hook uses the Windows API, so they have all the mechanisms in hand to prevent your program from capturing the log-in username & password.
Regards, Kristian
I am getting this issue can anyone help one the same ?
Exception in thread “Thread-0” java.lang.UnsatisfiedLinkError: KeyboardHook.de.ksquared.system.keyboard.KeyboardHook.registerHook(LKeyboardHook/de/ksquared/system/keyboard/GlobalKeyListener;)V
at KeyboardHook.de.ksquared.system.keyboard.KeyboardHook.registerHook(Native Method)
at KeyboardHook.de.ksquared.system.keyboard.PoolHook.run(KeyboardHook.java:46)
Hi Guys,
this is simply fantastic.. :)
but can you provide code for mouse wheel listener as well.. I want to get notified whenever mouse wheel is moved..
Thanks in advance.
Raj
Kris,
I should mention again, that’s really amazing work.
Really thanks.
But as posted earlier, I am in urgent need of Mouse Wheel Listener..
Please help me. (hereisrajiv@gmail.com)
Thanks,
Raja M
Hello Raja,
I am verry happy to announce that I just released version 2.0 of the library, featuring a mouseWheel event for the GlobalMouseListener. Please find the code on GitHub.
Hope this helps. Regards,
Kristian
my website is upcoming and I want to trace the ALT key pressed event using your api, please provide me a way.
Hello Mohammad,
Check the
GlobalKeyboardExample
class on GitHub. If the ALT key is pressed theGlobalKeyboardHook
provides you with aGlobalKeyEvent
which you can checkevent.isMenuPressed()
if the “alt” key has been pressed.Hope this helps. Regards,
Kristian
Thanks man, that’s works smoothly,
Surprised to get as earlier reply on any kind of blog, really thumbs up man…
Glad to hear that and happy to help. :-)
Exception in thread “main” java.lang.UnsatisfiedLinkError: lib: keyboardhook-windows-amd64.dll not found in lib directory
at lc.kra.system.LibraryLoader.loadLibrary(LibraryLoader.java:68)
at lc.kra.system.keyboard.GlobalKeyboardHook.(GlobalKeyboardHook.java:86)
at keyLogger.GlobalKeyboardExample.main(GlobalKeyboardExample.java:11)
Hello Mehmet, when does the exception occour? And how do you consume the library (Maven, downloaded the JAR from GitHub, as part of another JAR, etc.).
Hi Kristian, thanks for this project! Was wondering if you had a timeline for mac/unix support? Thanks
Hey Chuck, providing support for Mac / Unix requires a lot of effort. Unfortunately I don’t think I will be able to implement it in near future. I have plans to do so, but don’t expect it in the next couple of month.
Sorry & regards, Kristian
As soon as my java application starts, I received this exception, please help..why i am receiving this…
Exception in thread “Thread-7” java.lang.RuntimeException: Low-level keyboard hook failed (-2)
at lc.kra.system.keyboard.GlobalKeyboardHook$NativeKeyboardHook.(GlobalKeyboardHook.java:169)
at lc.kra.system.keyboard.GlobalKeyboardHook$2.(GlobalKeyboardHook.java:89)
at lc.kra.system.keyboard.GlobalKeyboardHook.(GlobalKeyboardHook.java:89)
at com.whodesire.kratis.Kratiso$9.run(Kratiso.java:808)
at java.lang.Thread.run(Thread.java:745)
Hello Mohammed, this error occours if the low-level hooking mechanism fails. For Windows it is
SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hInst, 0);
. This is most likely the case if your user does not have the authorizations to do so, if there are no more hook handles available, or if you are running on an Windows release pre 2000. Which JVM / operating system are you using?Windows 8.1 x64bit, JVM JDK 1.7
Hmm, so from a system spec. the system hook should be possible. Still could be an authorization error. Are you executing the JVM as an administrator? To figure out why the hook is failing do the following. Download the debug artifact JAR for your architecture from Appveyor. Use the JAR file to run your code. On standard out, you should see some new “NATIVE:” messages. If hooking fails, you should get a debug output why it fails. Please post your full console output here.
Hope this helps. Regards, Kristian
See, first 10-11 attempts are good in working of keyboard hooking certainly after it got failed & shows that the hook failed.
Hello Mohammad, as I said in my previous comment. To find out the root cause, you will have to use the debug JARs, which will provide an extended log output on standard out. Other than that, if hooking succeeds 10-11 times and fails afterwards, actually my first assumtion was right already that
. My guess is, you don’t shut down the hook properly by calling shutdownHook() of the hooking class. This happens, e.g. if you forcibly kill the JVM or simply never call shutdownHook(). In that case all hook handles are still occupied and the hooking fails on the 10th or 11th try.Hi,
This is the best work in this direction. Great, great, great!
I’ve a question: can I capture the selected text on a page, document in an external application?
Hello Francesco, glad you like it!
Well the purpose of this library is to provide a low-level keyboard and mouse hook. The system hook is able to capture keyboard and mouse inputs, so everything which you type on your keyboard and every mouse movement. Going for your text selection example, the mouse hook would be able to capture the mouse button press and drag for the text selection, but it won’t be able to recognize a “text selection”, because it’s just for the low-level input.
Hope this helps anyways. Regards, Kristian
Hey Man, Happy to listen those words, you are right, I am not calling the ShutdownHook thing and forcibly shutting my java application, and that the reason of getting crashed or not getting handler due to busy.
How do I get the examples to work? Where do the DLLs come from? This is confusing as shit you need to make a step by step guide.
Hello Jack, sorry for the confusion. Let me try to put it simple:
Hope this helps. Regards, Kristian
Hello Kristian,
Fantastic job. I tried using the code but unable to compile the code and produce .class files.
As in previous post I have placed the jar file CLASSPATH dir and complied it.
cmd>java GlobalKeyboardExample.java
KeyboardExample.java:24: error: cannot find symbol
import lc.kra.system.keyboard.GlobalKeyboardHook;
^
symbol: class GlobalKeyboardHook
location: package lc.kra.system.keyboard
C:\raju\hook\system-hook-2.0\src\main\java\lc\kra\system\keyboard\example\Global
KeyboardExample.java:25: error: package lc.kra.system.keyboard.event does not ex
ist
import lc.kra.system.keyboard.event.GlobalKeyAdapter;
^
C:\raju\hook\system-hook-2.0\src\main\java\lc\kra\system\keyboard\example\Global
KeyboardExample.java:26: error: package lc.kra.system.keyboard.event does not ex
ist
import lc.kra.system.keyboard.event.GlobalKeyEvent;
^
C:\raju\hook\system-hook-2.0\src\main\java\lc\kra\system\keyboard\example\Global
KeyboardExample.java:32: error: cannot find symbol
GlobalKeyboardHook keyboardHook = new GlobalKeyboardHook();
^
symbol: class GlobalKeyboardHook
location: class GlobalKeyboardExample
C:\raju\hook\system-hook-2.0\src\main\java\lc\kra\system\keyboard\example\Global
KeyboardExample.java:32: error: cannot find symbol
GlobalKeyboardHook keyboardHook = new GlobalKeyboardHook();
^
symbol: class GlobalKeyboardHook
location: class GlobalKeyboardExample
C:\raju\hook\system-hook-2.0\src\main\java\lc\kra\system\keyboard\example\Global
KeyboardExample.java:35: error: cannot find symbol
keyboardHook.addKeyListener(new GlobalKeyAdapter() {
^
symbol: class GlobalKeyAdapter
location: class GlobalKeyboardExample
6 errors
Can you provide in details how to use the proj.
Thanks.
Hello Albert, from your log output it seems, that the system hook JAR is actually not part of your CLASSPATH. Try the following. Place the system-hook-<version>.jar together with the example .java file into any same folder. To compile the (keyboard) example, navigate to the folder and execute:
javac -cp system-hook-<version>.jar GlobalKeyboardExample.java
Before compiling, I actually recommend you to remove the package declaration, from the start of the GlobalKeyboardExample file. After compiling you can then execute the example with:
java -cp ".;system-hook-<version>.jar" GlobalKeyboardExample
If everything succeeded you should see the following console output:
Global keyboard hook successfully started, press [escape] key to shutdown.
Hope this helps. Regards, Kristian
Hey Thanks. It worked after placing the jar file in the same directory.
I see that acsi numbers are printed on the command console. Is there a way they can be converted into alphabets symbols and redirect then to some test file logging.
Thanks.
Hello Albert, please have a look at the GlobalKeyEvent interface. But you have to be aware that you are using a low-level keyboard hook. Which means, the numbers you see on the console aren’t ACSII numbers, they are virtual key codes. Please find a list of virtual key codes in the GlobalKeyEvent interface. This means basically, that the physical keys on your keyboard is mapped. For so called “dead keys” you wont get the appropriate ACSII value, e.g. the “1” key is mapped to VK_1, but also if you press SHIFT+1, it’s mapped to VK_1. However the ASCII value for the key can be received from the GlobalKeyEvent by calling getKeyChar.
To pipe the response into a log file, you can for instance use a FileWriter. Hope this helps. Regards, Kristian