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 »
Are there any examples of how to use the keyboard hook? I downloaded the “Binary and example” bundle, but I don’t see any examples in the zip file.
i trust that your code works therefore i trust that i’m doing something wrong. the keyboardHookTest is giving me the following error:
***********************************
Exception in thread “Thread-2” java.lang.UnsatisfiedLinkError: KeyboardHook.registerHook(LGlobalKeyListener;)V
at KeyboardHook.registerHook(Native Method)
at PoolHook.run(KeyboardHook.java:46)
*************************************
is it familiar?what should i do to manage the error?
(NOTE i didn’t use the “KeyboardHook.dll”)
thank you..
thanks for sharing the code.
I has a question:
ascii : A->65 , a->97
when the capslock is off, press a , your code return virtualKeyCode=65
how to detect whether it’s upper or lower? thanks
if(event.getVirtualKeyCode()==KeyEvent.VK_A && event.isShiftPressed())
@Fanadin, I am working on a Win7 64bit machine and both, the keyboard and mousehook are working fine. Could you please describe in detail what you tried and which JVM parameters you used? Thanks.
@dazz007, you do not need to compile it by yourself. Simly use the .dll’s provided in the bundle and everything should work nicely.
@choi, you are welcome! ;-)
@wtblife, hey, thanks for noticing. It should have meant “Binary & library bundle” not “Binary & example bundle”, examples are available in the source bundle in the “test” folder, or just look at the bottom of my blog entry, there you will find some examples.
@abbas, what are you using instead? If you are linking the binaries by yourself, you will have to use the .dll files and they need to be in the right path so your JVM will find them, otherwise you will get this error message. Please describe what you are trying to do more in detail. Are you using the .jar bundle, which operating system are you using, etc. Thanks.
@TZ, Escalus has answered your question already. Thanks Escalus! Take a cookie, you deserved it ;-)
Dear Kristian,
I tried the code and it works perfectly, great work.
In this moments is possible to intercept the code when a key is pressed or released, but is possible to change or add a new code, for example when you press F12 add or swap the code correspond to “CTRL+C”.
My objective is copy to clipboard any text selected since any application.
Any idea?
Thanks you.
@y2001es Sounds good. Generally you should be able to track any kind of keyboard input, not only key up and down. If you want to listen to CTRL+C for example, please use the following code:
if(event.getVirtualKeyCode()==KeyEvent.VK_C && event.isCtrlPressed()) ...
Dear Kristian,
I re-read the post, is possible that I’m not explained correctly the first time.
With your code is possible to track any kind of keyboard input, but is possible to modify the scan/vkey codes prior to the values being presented to the process event loop?
Thank you.
@y2001es Oh, alright. Unfortunately not. Not in Java. The JNI interface is to slow to handle each key input natively, therefore I had to use an (asynchronous) observer pattern to handle the key inputs. Which means you can’t interfere into the event loop.
If you know how to modify the key map using C, you can easily enhance the JNI interface of the key hook component, by adding a method to he .cpp files of it.
Dear Kristian,
OK.
What tool you use to compile .cpp?
Do they come the libraries jni.h and windows.h included?
Thank you very much for all the help provided.
@y2001es, you could use Visual Studio or simply choose Eclipse CDT. You will have to compile it on a Windows computer. jni.h comes with every JDK installation, windows.h is a standard header file for accessing the windows API and is available on every Windows installation.
See http://java.sun.com/docs/books/jni/
Dear Kristian,
Thank you for sharing! I have a couple of problems with making it work, though; I’d appreciate if you helped me\told me what site\documentation to look into.
Using the .jar file you provided seems to work, but I want to understand how it works (the only languages I know are Java and Haskell, hence I know nothing about C\C++ and learnt about jni from the link you provided in your last post). Through hours of googling, I finally figured out how to compile a .dll. It didn’t work, though, and several google- hours later I added -m64 to the gcc parameters. That’s how I got rid of the UnsatisfiedLinkError. Instead Java ‘stops working’ as soon as I press a key (after launching the KeyboardHookTest).
So, I would be grateful if you provide me with some answers\clues on where to look for those answers.
1. your keyboardhook-win-amd64.dll is ~900kb, when mine is ~75kb. Did I do something wrong?
That’s what I did: took your KeyboardHokk.cpp, then compiled it as in the example: http://www.mingw.org/wiki/sampleDLL, i.e.
g++ -c -I”D:\Program Files\Java\jdk1.7.0_04\include” -DBUILDING_KEYBOARDHOOK -m64 KeyboardHook.cpp
g++ -shared -m64 -I”D:\Program Files\Java\jdk1.7.0_04\include” -o keyboardhook.dll KeyboardHook.o -Wl,–out-implib,libkeyboardhook.a
(Same as in example, I only added -m64 and included jdk-include)
Should I have compiled it in some other way? (When I used dev-c++ and created a dll-project, the compiled .dll was only about 12kb)
2. Your .jar file contains keyboardhook-win-amd64.lib, and not .dll. Should I do something after compiling .dll?
3. Should I (if I get it working) also pack the .dll into a jar library, or it was done purely because of convenience\aesthetical reasons?
Thanks in advance.
Hello genericname,
Thanks for commenting. Wow, this looks really like a hard time you had there. Generally I think you could have had it a little easier. To you link, mingw (especially the mingw compiler) is a minimalistic GNU for Windows. What I have provided is a Windows-only binary. Which means compiling it with g++ is kind of complex, because you will have to include all windows libraries into it (because you did not do this, your dll is smaller and you are getting an unsatisfied link error).
I would recommend using any version of Microsoft Visual Studio (e.g. Microsoft Visual Studio Express, it is a free to download version). Compiling it with Visual Studio is a lot easier. Simply include the files and the binaries will be included automatically.
I for my part used Eclipse CDT to compile the binaries. Please see the post, to see which linker-flags I have used.
To your third question. Well I have packaged the dll file into a .jar file, because without the .dll file your program would not be able to run. The signed package conains the dll file, and dynamically loads the dll, when the program is executed.
I hope this helps. If you have any further questions please feel free to conact me.
Regards,
Kristian