{"id":555,"date":"2011-07-06T15:51:14","date_gmt":"2011-07-06T13:51:14","guid":{"rendered":"http:\/\/kra.lc\/blog\/?p=555"},"modified":"2016-02-09T16:35:52","modified_gmt":"2016-02-09T14:35:52","slug":"java-global-system-hook-old","status":"publish","type":"post","link":"https:\/\/kra.lc\/blog\/2011\/07\/java-global-system-hook-old\/","title":{"rendered":"Java &#8211; Global (low level) Keyboard \/ Mouse Hook (Old)"},"content":{"rendered":"<p><strong>Note:<\/strong> This is the copy of an older post for reference. Please find the latest library version and description in this <a href=\"https:\/\/kra.lc\/blog\/2016\/02\/java-global-system-hook\/\"><strong>new blog post<\/strong><\/a>.<\/p>\n<p>I&#8217;d like to start my small blog with a neat little Java snippet. As I wanted to have a global key\/mouse hook for my Java programs, I found a great little script using the JNI at <a href=\"http:\/\/www.jotschi.de\/\">Jotschi\u2019s Blog<\/a>. Unfortuately Jotschi doesn&#8217;t develop on any windows binaries anymore, so he can not provide enhancements. Therefore I took Jotschi&#8217;s code, fixed some bugs and enhanced especially the Java part.<\/p>\n<p><!--more--><\/p>\n<p>Here is what I did:<\/p>\n<ul>\n<li>Compiled and testet the native libaries on Windows Vista &amp; 7 (x86 and x64, 32 &amp; 64 bit JVM)<\/li>\n<li>Split the keyboard \/ mouse hook into two different classes and native libraries, so they can be used separately<\/li>\n<li>Refactored the code in general<\/li>\n<ul>\n<li>Added KeyEvent &amp; KeyListener, MouseEvent &amp; MouseListener classes. So the overall concept is now more likely to the standard Java AWT keyboard &amp; mouse events<\/li>\n<li>Fixed some bugs, especially time consuming processes in the event handlers kept crashing the JNI (added a buffer mechansim)<\/li>\n<li>Added support for all keyboard events (such as key-up and also the control keys [ALT, CTRL and SHIFT] are now easier to access)<\/li>\n<li>Added support for all low level mouse events (such as mouse buttons)<\/li>\n<li>It is now guranteed that the mouse coordinate is inside the screen bounds (before -1 or 1026 have been valid values at a 1024&#215;800 pixel resolution)<\/li>\n<\/ul>\n<li>The hook&#8217;s are now non-blocking, which means, as the last (non-deamon) thread ends, also the hook-threads end<\/li>\n<li>The native libraries are now bundled into the jar files. So it is possible, but not required to specify them as a virtual machine parameter<\/li>\n<li>Last but not least, I will try to enhance the Global Keyboard \/ Mouse Hook, if you have any ideas \/ problems with it. Feel free to write it into the comments below!<\/li>\n<\/ul>\n<p>The general description: Global Keyboard \/ Mouse Hook for Java applications. Normally keyboard and mouse listeners in Java only work, if the registered component has the focus. If, for example, any window looses it&#8217;s focus (minimized) it isn&#8217;t possible to track any keyboard \/ mouse events anymore. Therefore we will have to use the JNI (Java Nativ Interface), to register a low level keyboard \/ mouse hook to the system. This is done using a native library (compiled on Windows 7 x64 using 32 &amp; 64 bit JVM).<\/p>\n<p><strong>Download Source \/ Binaries:<\/strong> (Distributed under the Simplified BSD License)<br \/>\nKeyboardHook (Version 0.3)<\/p>\n<ul>\n<li>Source &#038; binary bundle: <a href=\"http:\/\/ksquared.de\/blog\/releases\/stable\/keyboard_hook-0.3.zip\">Download<\/a><\/li>\n<li>Binary &#038; library bundle: <a href=\"http:\/\/ksquared.de\/blog\/releases\/stable\/keyboard_hook-bin-0.3.zip\">Download<\/a><\/li>\n<li>Library only: <a href=\"http:\/\/ksquared.de\/blog\/releases\/stable\/keyboard_hook-lib-0.3.zip\">Download<\/a><\/li>\n<\/ul>\n<p>MouseHook (Version 0.3)<\/p>\n<ul>\n<li>Source &#038; binary bundle: <a href=\"http:\/\/ksquared.de\/blog\/releases\/stable\/mouse_hook-0.3.zip\">Download<\/a><\/li>\n<li>Binary &#038; library bundle: <a href=\"http:\/\/ksquared.de\/blog\/releases\/stable\/mouse_hook-bin-0.3.zip\">Download<\/a><\/li>\n<li>Library only: <a href=\"http:\/\/ksquared.de\/blog\/releases\/stable\/mouse_hook-lib-0.3.zip\">Download<\/a><\/li>\n<\/ul>\n<p>Here is the code for the keyboard part:<\/p>\n<pre class=\"syntax c\" style=\"max-height:200px\" title=\"KeyboardHook.h\">\r\n#include &lt;jni.h&gt;\r\n\r\n\/* Header for class KeyboardHook *\/\r\n#ifndef _Included_KeyboardHook\r\n#define _Included_KeyboardHook\r\n#ifdef __cplusplus\r\nextern &quot;C&quot; {\r\n#endif\r\n\r\n\/*\r\n * Class:     KeyboardHook\r\n * Method:    registerHook\r\n * Signature: (LGlobalEventListener;)V\r\n *\/\r\nJNIEXPORT void JNICALL Java_de_ksquared_system_keyboard_KeyboardHook_registerHook(JNIEnv *,jobject thisObj,jobject listenerObj);\r\n\/*\r\n * Class:     KeyboardHook\r\n * Method:    unregisterHook\r\n * Signature: ()V\r\n *\/\r\nJNIEXPORT void JNICALL Java_de_ksquared_system_keyboard_KeyboardHook_unregisterHook(JNIEnv *env,jobject thisObj);\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n#endif\r\n<\/pre>\n<pre class=\"syntax c\" style=\"max-height:200px\" title=\"KeyboardHook.cpp\">\r\n#include &lt;windows.h&gt;\r\n#include &lt;jni.h&gt;\r\n#include &quot;KeyboardHook.h&quot;\r\n\r\n#ifdef DEBUG\r\n#define DEBUG_PRINT(x) printf x\r\n#else\r\n#define DEBUG_PRINT(x) do {} while (0)\r\n#endif \r\n\r\nHINSTANCE hInst = NULL;\r\n\r\nJavaVM * jvm = NULL;\r\nDWORD hookThreadId = 0;\r\n\r\njobject keyboardHookObject = NULL;\r\njobject globalKeyListenerObject = NULL;\r\njmethodID processKeyMethod = NULL;\r\n\r\nextern &quot;C&quot;\r\nBOOL APIENTRY DllMain(HINSTANCE _hInst,DWORD reason,LPVOID reserved)  {\r\n\tswitch(reason) {\r\n\t\tcase DLL_PROCESS_ATTACH:\r\n\t\t\tDEBUG_PRINT((&quot;NATIVE: DllMain - DLL_PROCESS_ATTACH.n&quot;));\r\n\t\t\thInst = _hInst;\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\tbreak;\r\n\t}\r\n\treturn TRUE;\r\n}\r\n\r\nLRESULT CALLBACK LowLevelKeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)  {\r\n\tJNIEnv* env;\r\n\tKBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT *)lParam;\r\n\tif(jvm-&gt;AttachCurrentThread((void **)&amp;env, NULL)&gt;=0) {\r\n\t\tjboolean transitionState = (jboolean)FALSE;\r\n\t\tswitch(wParam)  {\r\n\t\t\tcase WM_KEYDOWN: case WM_SYSKEYDOWN:\r\n\t\t\t\ttransitionState = (jboolean)TRUE;\r\n\t\t\tcase WM_KEYUP: case WM_SYSKEYUP:\r\n\t\t\t\tenv-&gt;CallVoidMethod(keyboardHookObject,processKeyMethod,transitionState,p-&gt;vkCode,globalKeyListenerObject);\r\n\t\t\t\tbreak;\r\n\t\t\tdefault:\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\t}\telse DEBUG_PRINT((&quot;NATIVE: LowLevelKeyboardProc - Error on the attach current thread.n&quot;));\r\n\treturn CallNextHookEx(NULL,nCode,wParam,lParam);\r\n}\r\n\r\nJNIEXPORT void JNICALL Java_de_ksquared_system_keyboard_KeyboardHook_registerHook(JNIEnv * env,jobject obj,jobject _globalKeyListenerObject) {\r\n\tDEBUG_PRINT((&quot;NATIVE: Java_de_ksquared_system_keyboard_KeyboardHook_registerHook - Hooking started!n&quot;));\r\n\t\r\n\tHHOOK hookHandle = SetWindowsHookEx(WH_KEYBOARD_LL,LowLevelKeyboardProc,hInst,0);\r\n\tglobalKeyListenerObject = _globalKeyListenerObject;\r\n\t\r\n\tif(hookHandle==NULL) {\r\n\t\tDEBUG_PRINT((&quot;NATIVE: Java_de_ksquared_system_keyboard_KeyboardHook_registerHook - Hook failed!n&quot;));\r\n\t\treturn;\r\n\t} else DEBUG_PRINT((&quot;NATIVE: Java_de_ksquared_system_keyboard_KeyboardHook_registerHook - Hook successfuln&quot;));\r\n\t\r\n\tkeyboardHookObject = env-&gt;NewGlobalRef(obj);\r\n\tjclass cls = env-&gt;GetObjectClass(keyboardHookObject);\r\n\tprocessKeyMethod = env-&gt;GetMethodID(cls,&quot;processKey&quot;,&quot;(ZILde\/ksquared\/system\/keyboard\/GlobalKeyListener;)V&quot;);\r\n\t\r\n\tenv-&gt;GetJavaVM(&amp;jvm);\r\n\thookThreadId = GetCurrentThreadId();\r\n\t\r\n\tMSG message;\r\n\twhile(GetMessage(&amp;message,NULL,0,0)) {\r\n\t\tTranslateMessage(&amp;message);\r\n\t\tDispatchMessage(&amp;message);\r\n\t}\r\n\t\r\n\tDEBUG_PRINT(((!UnhookWindowsHookEx(hookHandle))?(&quot;NATIVE: Java_de_ksquared_system_keyboard_KeyboardHook_registerHook - Unhook failedn&quot;)\r\n\t                                                :&quot;NATIVE: Java_de_ksquared_system_keyboard_KeyboardHook_registerHook - Unhook successfuln&quot;));\r\n}\r\n\r\nJNIEXPORT void JNICALL Java_de_ksquared_system_keyboard_KeyboardHook_unregisterHook(JNIEnv *env,jobject object) {\r\n\tif(hookThreadId==0) return;\t\r\n\tDEBUG_PRINT((&quot;NATIVE: Java_de_ksquared_system_keyboard_KeyboardHook_unregisterHook - call PostThreadMessage.n&quot;));\r\n\tPostThreadMessage(hookThreadId,WM_QUIT,0,0L);\r\n}\r\n<\/pre>\n<pre class=\"syntax java\" style=\"max-height:200px\" title=\"GlobalKeyListener.java\">\r\npackage de.ksquared.system.keyboard;\r\n\r\nimport java.util.List;\r\nimport java.util.Vector;\r\n\r\npublic class GlobalKeyListener {\r\n\tprotected PoolHook hook;\r\n\tpublic GlobalKeyListener() { (hook=new PoolHook(this)).start();\t}\r\n\tprotected List&lt;KeyListener&gt; listeners = new Vector&lt;KeyListener&gt;();\r\n\r\n\tpublic void addKeyListener(KeyListener listener) { listeners.add(listener); }\r\n\tpublic void removeKeyListener(KeyListener listener) { listeners.remove(listener); }\r\n\r\n\tvoid keyPressed(KeyEvent event) {\r\n\t\ttry {\r\n\t\t\tfor(KeyListener listener:listeners)\r\n\t\t\t\tlistener.keyPressed(event);\r\n\t\t} catch(Exception e) { e.printStackTrace(); }\r\n\t}\r\n\tvoid keyReleased(KeyEvent event) {\r\n\t\ttry {\r\n\t\t\tfor(KeyListener listener:listeners)\r\n\t\t\t\tlistener.keyReleased(event);\r\n\t\t} catch(Exception e) { e.printStackTrace(); }\r\n\t}\r\n}\r\n<\/pre>\n<pre class=\"syntax java\" title=\"KeyAdapter.java\">\r\npackage de.ksquared.system.keyboard;\r\n\r\npublic class KeyAdapter implements KeyListener {\r\n\t@Override public void keyPressed(KeyEvent event) {}\r\n\t@Override public void keyReleased(KeyEvent event) {}\r\n}\r\n<\/pre>\n<pre class=\"syntax java\" style=\"max-height:200px\" title=\"KeyboardHook.java\">\r\npackage de.ksquared.system.keyboard;\r\n\r\nimport java.util.Collections;\r\nimport java.util.LinkedList;\r\nimport java.util.List;\r\n\r\nclass PoolHook extends Thread {\r\n\tprivate KeyboardHook hook;\r\n\tprivate GlobalKeyListener listener;\r\n\r\n\tPoolHook(GlobalKeyListener listener) {\r\n\t\tthis.setDaemon(true);\r\n\t\tthis.listener = listener;\r\n\t}\r\n\r\n\tpublic void run() {\r\n\t\thook = new KeyboardHook();\r\n\t\thook.registerHook(listener);\r\n\t}\r\n}\r\n\r\nclass EventProcedure extends Thread {\r\n\tprivate KeyboardHook hook;\r\n\t\r\n\tEventProcedure(KeyboardHook hook) {\r\n\t\tthis.setDaemon(true);\r\n\t\tthis.hook = hook;\r\n\t}\r\n\t\r\n\t@Override public void run() {\r\n\t\twhile(true) {\r\n\t\t\tif(!hook.buffer.isEmpty()) {\r\n\t\t\t\tKeyEvent event = hook.buffer.remove(0);\r\n\t\t\t\tGlobalKeyListener listener = event.listener;\r\n\t\t\t\tif(event.transitionState)\r\n\t\t\t\t\t   listener.keyPressed(event);\r\n\t\t\t\telse listener.keyReleased(event);\r\n\t\t\t} else try { Thread.sleep(10); }\tcatch(InterruptedException e) { e.printStackTrace(); }\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass KeyboardHook {\t\r\n\tprivate boolean altPressed,shiftPressed,ctrlPressed,extendedKey;\r\n\t\r\n\tList&lt;KeyEvent&gt; buffer = Collections.synchronizedList(new LinkedList&lt;KeyEvent&gt;());\r\n\tprivate EventProcedure procedure = new EventProcedure(this);\r\n\t\r\n\tpublic KeyboardHook() { if(Native.load()) procedure.start(); }\r\n\tvoid processKey(boolean transitionState,int virtualKeyCode,GlobalKeyListener listener) {\r\n\t\tprocessControlKeys(transitionState,virtualKeyCode);\r\n\t\tbuffer.add(new KeyEvent(this,listener,transitionState,virtualKeyCode,altPressed,shiftPressed,ctrlPressed,extendedKey));\r\n\t}\r\n\t\r\n\tnative void registerHook(GlobalKeyListener listener);\r\n\tnative void unregisterHook();\r\n\t\r\n\tvoid processControlKeys(boolean transitionState,int virtualKeyCode) {\r\n\t\tswitch(virtualKeyCode) {\r\n\t\tcase KeyEvent.VK_RWIN: extendedKey = transitionState; break;\r\n\t\tcase KeyEvent.VK_RMENU: extendedKey = transitionState;\r\n\t\tcase KeyEvent.VK_MENU: case KeyEvent.VK_LMENU:\r\n\t\t\taltPressed = transitionState;\r\n\t\t\tbreak;\t\t\t\r\n\t\tcase KeyEvent.VK_RSHIFT: extendedKey = transitionState;\r\n\t\tcase KeyEvent.VK_SHIFT: case KeyEvent.VK_LSHIFT:\r\n\t\t\tshiftPressed = transitionState;\r\n\t\t\tbreak;\r\n\t\tcase KeyEvent.VK_RCONTROL: extendedKey = transitionState;\r\n\t\tcase KeyEvent.VK_CONTROL: case KeyEvent.VK_LCONTROL:\r\n\t\t\tctrlPressed = transitionState;\r\n\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n<pre class=\"syntax java\" style=\"max-height:200px\" title=\"KeyEvent.java\">\r\npackage de.ksquared.system.keyboard;\r\n\r\nimport java.util.EventObject;\r\n\r\npublic class KeyEvent extends EventObject {\r\n\tprivate static final long serialVersionUID = -8194688548489965445L;\r\n\t\r\n\tpublic static final int VK_UNDEFINED = 0x0;\r\n\tpublic static final int VK_LBUTTON = 0x01,VK_RBUTTON = 0x02,VK_CANCEL = 0x03,VK_MBUTTON = 0x04,VK_XBUTTON1 = 0x05,VK_XBUTTON2 = 0x06,VK_BACK = 0x08,VK_TAB = 0x09,VK_CLEAR = 0x0C,VK_RETURN = 0x0D,VK_SHIFT = 0x10,VK_CONTROL = 0x11,VK_MENU = 0x12,VK_PAUSE = 0x13,VK_CAPITAL = 0x14,VK_KANA = 0x15,VK_HANGUEL = 0x15,VK_HANGUL = 0x15,VK_JUNJA = 0x17,VK_FINAL = 0x18,VK_HANJA = 0x19,VK_KANJI = 0x19,VK_ESCAPE = 0x1B,VK_CONVERT = 0x1C,VK_NONCONVERT = 0x1D,VK_ACCEPT = 0x1E,VK_MODECHANGE = 0x1F,VK_SPACE = 0x20,VK_PRIOR = 0x21,VK_NEXT = 0x22,VK_END = 0x23,VK_HOME = 0x24,VK_LEFT = 0x25,VK_UP = 0x26,VK_RIGHT = 0x27,VK_DOWN = 0x28,VK_SELECT = 0x29,VK_PRINT = 0x2A,VK_EXECUTE = 0x2B,VK_SNAPSHOT = 0x2C,VK_INSERT = 0x2D,VK_DELETE = 0x2E,VK_HELP = 0x2F,VK_0 = 0x30,VK_1 = 0x31,VK_2 = 0x32,VK_3 = 0x33,VK_4 = 0x34,VK_5 = 0x35,VK_6 = 0x36,VK_7 = 0x37,VK_8 = 0x38,VK_9 = 0x39,VK_A = 0x41,VK_B = 0x42,VK_C = 0x43,VK_D = 0x44,VK_E = 0x45,VK_F = 0x46,VK_G = 0x47,VK_H = 0x48,VK_I = 0x49,VK_J = 0x4A,VK_K = 0x4B,VK_L = 0x4C,VK_M = 0x4D,VK_N = 0x4E,VK_O = 0x4F,VK_P = 0x50,VK_Q = 0x51,VK_R = 0x52,VK_S = 0x53,VK_T = 0x54,VK_U = 0x55,VK_V = 0x56,VK_W = 0x57,VK_X = 0x58,VK_Y = 0x59,VK_Z = 0x5A,VK_LWIN = 0x5B,VK_RWIN = 0x5C,VK_APPS = 0x5D,VK_SLEEP = 0x5F,VK_NUMPAD0 = 0x60,VK_NUMPAD1 = 0x61,VK_NUMPAD2 = 0x62,VK_NUMPAD3 = 0x63,VK_NUMPAD4 = 0x64,VK_NUMPAD5 = 0x65,VK_NUMPAD6 = 0x66,VK_NUMPAD7 = 0x67,VK_NUMPAD8 = 0x68,VK_NUMPAD9 = 0x69,VK_MULTIPLY = 0x6A,VK_ADD = 0x6B,VK_SEPARATOR = 0x6C,VK_SUBTRACT = 0x6D,VK_DECIMAL = 0x6E,VK_DIVIDE = 0x6F,VK_F1 = 0x70,VK_F2 = 0x71,VK_F3 = 0x72,VK_F4 = 0x73,VK_F5 = 0x74,VK_F6 = 0x75,VK_F7 = 0x76,VK_F8 = 0x77,VK_F9 = 0x78,VK_F10 = 0x79,VK_F11 = 0x7A,VK_F12 = 0x7B,VK_F13 = 0x7C,VK_F14 = 0x7D,VK_F15 = 0x7E,VK_F16 = 0x7F,VK_F17 = 0x80,VK_F18 = 0x81,VK_F19 = 0x82,VK_F20 = 0x83,VK_F21 = 0x84,VK_F22 = 0x85,VK_F23 = 0x86,VK_F24 = 0x87,VK_NUMLOCK = 0x90,VK_SCROLL = 0x91,VK_LSHIFT = 0xA0,VK_RSHIFT = 0xA1,VK_LCONTROL = 0xA2,VK_RCONTROL = 0xA3,VK_LMENU = 0xA4,VK_RMENU = 0xA5,VK_BROWSER_BACK = 0xA6,VK_BROWSER_FORWARD = 0xA7,VK_BROWSER_REFRESH = 0xA8,VK_BROWSER_STOP = 0xA9,VK_BROWSER_SEARCH = 0xAA,VK_BROWSER_FAVORITES = 0xAB,VK_BROWSER_HOME = 0xAC,VK_VOLUME_MUTE = 0xAD,VK_VOLUME_DOWN = 0xAE,VK_VOLUME_UP = 0xAF,VK_MEDIA_NEXT_TRACK = 0xB0,VK_MEDIA_PREV_TRACK = 0xB1,VK_MEDIA_STOP = 0xB2,VK_MEDIA_PLAY_PAUSE = 0xB3,VK_LAUNCH_MAIL = 0xB4,VK_LAUNCH_MEDIA_SELECT = 0xB5,VK_LAUNCH_APP1 = 0xB6,VK_LAUNCH_APP2 = 0xB7,VK_OEM_1 = 0xBA,VK_OEM_PLUS = 0xBB,VK_OEM_COMMA = 0xBC,VK_OEM_MINUS = 0xBD,VK_OEM_PERIOD = 0xBE,VK_OEM_2 = 0xBF,VK_OEM_3 = 0xC0,VK_OEM_4 = 0xDB,VK_OEM_5 = 0xDC,VK_OEM_6 = 0xDD,VK_OEM_7 = 0xDE,VK_OEM_8 = 0xDF,VK_OEM_102 = 0xE2,VK_PROCESSKEY = 0xE5,VK_PACKET = 0xE7,VK_ATTN = 0xF6,VK_CRSEL = 0xF7,VK_EXSEL = 0xF8,VK_EREOF = 0xF9,VK_PLAY = 0xFA,VK_ZOOM = 0xFB,VK_NONAME = 0xFC,VK_PA1 = 0xFD,VK_OEM_CLEAR = 0xFE;\r\n\t\r\n\tprotected GlobalKeyListener listener;\r\n\tprotected boolean transitionState,altPressed,shiftPressed,ctrlPressed,extendedKey;\r\n\tprotected int virtualKeyCode;\r\n\r\n\tpublic KeyEvent(Object source,GlobalKeyListener listener,boolean transitionState,int virtualKeyCode,boolean altPressed,boolean shiftPressed,boolean ctrlPressed,boolean extendedKey) {\r\n\t\tsuper(source);\r\n\t\tthis.listener = listener;\r\n\t\tthis.transitionState = transitionState;\r\n\t\tthis.virtualKeyCode = virtualKeyCode;\r\n\t\tthis.altPressed = altPressed;\r\n\t\tthis.shiftPressed = shiftPressed;\r\n\t\tthis.ctrlPressed = ctrlPressed;\r\n\t\tthis.extendedKey = extendedKey;\r\n\t}\r\n\r\n\tpublic boolean getTransitionState() { return transitionState; }\r\n\tpublic int getVirtualKeyCode() { return virtualKeyCode; }\r\n\tpublic boolean isAltPressed() { return altPressed; }\r\n\tpublic boolean isShiftPressed() { return shiftPressed; }\r\n\tpublic boolean isCtrlPressed() { return ctrlPressed; }\r\n\tpublic boolean isExtendedKey() { return extendedKey; }\r\n\tpublic boolean equals(KeyEvent event) {\r\n\t\treturn event.getVirtualKeyCode()==virtualKeyCode\r\n\t\t     &amp;&amp;event.isExtendedKey()==extendedKey\r\n\t\t     &amp;&amp;event.isAltPressed()==altPressed;\r\n\t}\r\n\t\r\n\t@Override public String toString() {\r\n\t\tStringBuilder string = new StringBuilder().append(virtualKeyCode).append(&quot; [&quot;).append(transitionState?&quot;down&quot;:&quot;up&quot;);\r\n\t\tif(altPressed) string.append(&quot;,alt&quot;);\r\n\t\tif(shiftPressed) string.append(&quot;,shift&quot;);\r\n\t\tif(ctrlPressed) string.append(&quot;,ctrl&quot;);\r\n\t\tif(extendedKey) string.append(&quot;,extended&quot;);\r\n\t\treturn string.append(&#039;]&#039;).toString();\r\n\t}\r\n}\r\n<\/pre>\n<pre class=\"syntax java\" title=\"KeyListener.java\">\r\npackage de.ksquared.system.keyboard;\r\n\r\nimport java.util.EventListener;\r\n\r\npublic interface KeyListener extends EventListener {\r\n  public void keyPressed(KeyEvent event);\r\n  public void keyReleased(KeyEvent event);\r\n}\r\n<\/pre>\n<pre class=\"syntax java\" style=\"max-height:200px\" title=\"Native.java\">\r\npackage de.ksquared.system.keyboard;\r\n\r\nimport java.io.File;\r\nimport java.io.FileOutputStream;\r\nimport java.io.InputStream;\r\nimport java.io.OutputStream;\r\n\r\npublic class Native {\r\n\tprivate static Boolean loaded = null;\r\n\r\n\tstatic boolean load() {\r\n\t\tif(loaded!=null)\r\n\t\t\treturn loaded==Boolean.TRUE;\r\n\r\n\t\tString libpath = System.getProperty(&quot;de.ksquared.system.keyboard.lib.path&quot;),\r\n\t\t\t\t   libname = System.getProperty(&quot;de.ksquared.system.keyboard.lib.name&quot;);\r\n\t\tif(libname==null)\r\n\t\t\tlibname = System.mapLibraryName(&quot;keyboardhook&quot;);\r\n\t\ttry {\r\n\t\t\tif(libpath==null)\r\n\t\t\t\t   System.loadLibrary(&quot;keyboardhook&quot;);\r\n\t\t\telse System.load(new File(libpath,libname).getAbsolutePath());\r\n\t\t\treturn (loaded=Boolean.TRUE);\r\n\t\t}\tcatch(UnsatisfiedLinkError e) { \/* do nothing, try next *\/ }\r\n\r\n\t\tString osname = System.getProperty(&quot;os.name&quot;).toLowerCase(),\r\n\t\t\t\t   osarch = System.getProperty(&quot;os.arch&quot;);\r\n\t\t     if(osname.startsWith(&quot;mac os&quot;)) { osname = &quot;mac&quot;; osarch = &quot;universal&quot;; }\r\n\t\telse if(osname.startsWith(&quot;windows&quot;)) osname = &quot;win&quot;;\r\n\t\telse if(osname.startsWith(&quot;sunos&quot;)) osname = &quot;solaris&quot;;\r\n\t\tif(osarch.startsWith(&quot;i&quot;)&amp;&amp;osarch.endsWith(&quot;86&quot;))\r\n\t\t\tosarch = &quot;x86&quot;;\r\n\t\tlibname = &quot;keyboardhook-&quot;+osname+&#039;-&#039;+osarch+&quot;.lib&quot;;\r\n\t\ttry {\r\n\t\t\tInputStream input = Native.class.getClassLoader().getResourceAsStream(libname);\r\n\t\t\tif(input==null)\r\n\t\t\t\tthrow new Exception(&quot;libname: &quot;+libname+&quot; not found&quot;);\r\n\t\t\tFile temp = File.createTempFile(&quot;keyboardhook-&quot;,&quot;.lib&quot;);\r\n\t\t\ttemp.deleteOnExit();\r\n\t\t\tOutputStream out = new FileOutputStream(temp);\r\n\t\t\tbyte[] buffer = new byte[1024];\r\n\t\t\tint read;\r\n\t\t\twhile((read = input.read(buffer))!=-1)\r\n\t\t\t\tout.write(buffer,0,read);\r\n\t\t\tinput.close(); out.close();\r\n\t\t\tSystem.load(temp.getAbsolutePath());\r\n\t\t\treturn (loaded=Boolean.TRUE);\r\n\t\t} catch(Exception e) { \/* do nothing, go on *\/ }\r\n\t\treturn (loaded=Boolean.FALSE);\r\n\t}\r\n}\r\n<\/pre>\n<p>And here is the code for the mouse part:<\/p>\n<pre class=\"syntax c\" style=\"max-height:200px\" title=\"MouseHook.h\">\r\n#include &lt;jni.h&gt;\r\n\r\n\/* Header for class MouseHook *\/\r\n#ifndef _Included_MouseHook\r\n#define _Included_MouseHook\r\n#ifdef __cplusplus\r\nextern &quot;C&quot; {\r\n#endif\r\n\r\n\/*\r\n * Class:     MouseHook\r\n * Method:    registerHook\r\n * Signature: (LGlobalEventListener;)V\r\n *\/\r\nJNIEXPORT void JNICALL Java_de_ksquared_system_mouse_MouseHook_registerHook(JNIEnv *,jobject thisObj,jobject listenerObj);\r\n\/*\r\n * Class:     MouseHook\r\n * Method:    unregisterHook\r\n * Signature: ()V\r\n *\/\r\nJNIEXPORT void JNICALL Java_de_ksquared_system_mouse_MouseHook_unregisterHook(JNIEnv *env,jobject thisObj);\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n#endif\r\n<\/pre>\n<pre class=\"syntax c\" style=\"max-height:200px\" title=\"MouseHook.cpp\">\r\n#include &lt;windows.h&gt;\r\n#include &lt;jni.h&gt;\r\n#include &quot;MouseHook.h&quot;\r\n#define DEBUG 1\r\n#ifdef DEBUG\r\n#define DEBUG_PRINT(x) printf x\r\n#else\r\n#define DEBUG_PRINT(x) do {} while (0)\r\n#endif \r\n\r\nHINSTANCE hInst = NULL;\r\n\r\nJavaVM * jvm = NULL;\r\nDWORD hookThreadId = 0;\r\n\r\njobject mouseHookObject = NULL;\r\njobject globalMouseListenerObject = NULL;\r\njmethodID processMouseButtonMethod = NULL;\r\njmethodID processMouseMoveMethod = NULL;\r\n\r\nLONG mouseLocationX=-1,mouseLocationY=-1;\r\n\r\nextern &quot;C&quot;\r\nBOOL APIENTRY DllMain(HINSTANCE _hInst,DWORD reason,LPVOID reserved)  {\r\n\tswitch(reason) {\r\n\t\tcase DLL_PROCESS_ATTACH:\r\n\t\t\tDEBUG_PRINT((&quot;NATIVE: DllMain - DLL_PROCESS_ATTACH.n&quot;));\r\n\t\t\thInst = _hInst;\r\n\t\t\tbreak;\r\n\t\tdefault:\r\n\t\t\tbreak;\r\n\t}\r\n\treturn TRUE;\r\n}\r\n\r\nLRESULT CALLBACK LowLevelMouseProc(int nCode,WPARAM wParam,LPARAM lParam) {\r\n\tJNIEnv* env;\r\n\tif(jvm-&gt;AttachCurrentThread((void **)&amp;env, NULL)&gt;=0) {\r\n\t\tif(nCode==HC_ACTION) {\r\n\t\t\tMOUSEHOOKSTRUCT* pStruct = (MOUSEHOOKSTRUCT*)lParam;\r\n\t\t\tswitch(wParam) {\r\n\t\t\tcase WM_LBUTTONDOWN: case WM_LBUTTONUP:\r\n\t\t\tcase WM_RBUTTONDOWN: case WM_RBUTTONUP:\r\n\t\t\t\tenv-&gt;CallVoidMethod(mouseHookObject,processMouseButtonMethod,(jint)wParam,globalMouseListenerObject);\r\n\t\t\t\tbreak;\r\n\t\t\tcase WM_MOUSEMOVE:\r\n\t\t\t\tif(pStruct-&gt;pt.x!=mouseLocationX||pStruct-&gt;pt.y!=mouseLocationY) {\r\n\t\t\t\t\tenv-&gt;CallVoidMethod(mouseHookObject,processMouseMoveMethod,(jint)pStruct-&gt;pt.x,(jint)pStruct-&gt;pt.y,globalMouseListenerObject);\r\n\t\t\t\t\tmouseLocationX = pStruct-&gt;pt.x;\r\n\t\t\t\t\tmouseLocationX = pStruct-&gt;pt.y;\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\t\t\tdefault:\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\t} else DEBUG_PRINT((&quot;NATIVE: LowLevelMouseProc - Error on the attach current thread.n&quot;));\r\n\treturn CallNextHookEx(NULL,nCode,wParam,lParam);\r\n}\r\n\r\nJNIEXPORT void JNICALL Java_de_ksquared_system_mouse_MouseHook_registerHook(JNIEnv * env,jobject obj,jobject _globalMouseListenerObject) {\r\n\tDEBUG_PRINT((&quot;NATIVE: Java_de_ksquared_system_mouse_MouseHook_registerHook - Hooking started!n&quot;));\r\n\r\n\tHHOOK hookHandle = SetWindowsHookEx(WH_MOUSE_LL,LowLevelMouseProc,hInst,0);\r\n\tglobalMouseListenerObject = _globalMouseListenerObject;\r\n\t\r\n\tif(hookHandle==NULL) {\r\n\t\tDEBUG_PRINT((&quot;NATIVE: Java_de_ksquared_system_mouse_MouseHook_registerHook - Hook failed!n&quot;));\r\n\t\treturn;\r\n\t} else DEBUG_PRINT((&quot;NATIVE: Java_de_ksquared_system_mouse_MouseHook_registerHook - Hook successfuln&quot;));\r\n\t\r\n\tmouseHookObject = env-&gt;NewGlobalRef(obj);\r\n\tjclass cls = env-&gt;GetObjectClass(mouseHookObject);\r\n\tprocessMouseButtonMethod = env-&gt;GetMethodID(cls,&quot;processButton&quot;,&quot;(ILde\/ksquared\/system\/mouse\/GlobalMouseListener;)V&quot;);\r\n\tprocessMouseMoveMethod = env-&gt;GetMethodID(cls,&quot;processMove&quot;,&quot;(IILde\/ksquared\/system\/mouse\/GlobalMouseListener;)V&quot;);\r\n\t\r\n\tenv-&gt;GetJavaVM(&amp;jvm);\r\n\thookThreadId = GetCurrentThreadId();\r\n\r\n\tMSG message;\r\n\twhile(GetMessage(&amp;message,NULL,0,0)) {\r\n\t\tTranslateMessage(&amp;message);\r\n\t\tDispatchMessage(&amp;message);\r\n\t}\r\n\t\r\n\tDEBUG_PRINT(((!UnhookWindowsHookEx(hookHandle))?(&quot;NATIVE: Java_de_ksquared_system_mouse_MouseHook_registerHook - Unhook failedn&quot;)\r\n\t                                                :&quot;NATIVE: Java_de_ksquared_system_mouse_MouseHook_registerHook - Unhook successfuln&quot;));\r\n}\r\n\r\nJNIEXPORT void JNICALL Java_de_ksquared_system_mouse_MouseHook_unregisterHook(JNIEnv *env,jobject object) {\r\n\tif(hookThreadId==0) return;\t\r\n\tDEBUG_PRINT((&quot;NATIVE: Java_de_ksquared_system_mouse_MouseHook_unregisterHook - call PostThreadMessage.n&quot;));\r\n\tPostThreadMessage(hookThreadId,WM_QUIT,0,0L);\r\n}\r\n<\/pre>\n<pre class=\"syntax java\" style=\"max-height:200px\" title=\"GlobalMouseListener.java\">\r\npackage de.ksquared.system.mouse;\r\n\r\nimport java.util.List;\r\nimport java.util.Vector;\r\n\r\npublic class GlobalMouseListener {\r\n\tprotected PoolHook hook;\r\n\tpublic GlobalMouseListener() { (hook=new PoolHook(this)).start();\t}\r\n\tprotected List&lt;MouseListener&gt; listeners = new Vector&lt;MouseListener&gt;();\r\n\r\n\tpublic void addMouseListener(MouseListener listener) { listeners.add(listener); }\r\n\tpublic void removeMouseListener(MouseListener listener) { listeners.remove(listener); }\r\n\r\n\tvoid mouseMoved(MouseEvent event) {\r\n\t\ttry {\r\n\t\t\tfor(MouseListener listener:listeners)\r\n\t\t\t\tlistener.mouseMoved(event);\r\n\t\t} catch(Exception e) { e.printStackTrace(); }\r\n\t}\r\n\tvoid mousePressed(MouseEvent event) {\r\n\t\ttry {\r\n\t\t\tfor(MouseListener listener:listeners)\r\n\t\t\t\tlistener.mousePressed(event);\r\n\t\t} catch(Exception e) { e.printStackTrace(); }\r\n\t}\r\n\tvoid mouseReleased(MouseEvent event) {\r\n\t\ttry {\r\n\t\t\tfor(MouseListener listener:listeners)\r\n\t\t\t\tlistener.mouseReleased(event);\r\n\t\t} catch(Exception e) { e.printStackTrace(); }\r\n\t}\r\n}\r\n<\/pre>\n<pre class=\"syntax java\" title=\"MouseAdapter.java\">\r\npackage de.ksquared.system.mouse;\r\n\r\npublic class MouseAdapter implements MouseListener {\r\n\t@Override public void mouseMoved(MouseEvent event) {}\r\n\t@Override public void mousePressed(MouseEvent event) {}\r\n\t@Override public void mouseReleased(MouseEvent event) {}\r\n}\r\n<\/pre>\n<pre class=\"syntax java\" style=\"max-height:200px\" title=\"MouseEvent.java\">\r\npackage de.ksquared.system.mouse;\r\n\r\nimport java.util.EventObject;\r\n\r\npublic class MouseEvent extends EventObject {\r\n\tprivate static final long serialVersionUID = -8194688548489965445L;\r\n\t\r\n\tpublic static final int TRANSITION_STATE_MOVE = 1,TRANSITION_STATE_DOWN = 2,TRANSITION_STATE_UP = 3;\r\n\tpublic static final int BUTTON_NO = 0x0,BUTTON_LEFT = 1&lt;&lt;1,BUTTON_RIGHT = 1&lt;&lt;2;\r\n\t\r\n\tprotected GlobalMouseListener listener;\r\n\tprotected int transitionState,button,buttons;\r\n\tprotected int x,y;\r\n\r\n\tpublic MouseEvent(Object source,GlobalMouseListener listener,int transitionState,int button,int buttons,int x,int y) {\r\n\t\tsuper(source);\r\n\t\tthis.listener = listener;\r\n\t\tthis.transitionState = transitionState;\r\n\t\tthis.button = button;\r\n\t\tthis.buttons = buttons;\r\n\t\tthis.x = x;\r\n\t\tthis.y = y;\r\n\t}\r\n\t\r\n\tpublic int getTransitionState() { return transitionState; }\r\n\tpublic int getButton() { return button; }\r\n\tpublic int getButtons() { return buttons; }\r\n\tpublic int getX() { return x; }\r\n\tpublic int getY() { return y; }\r\n\t\r\n\tpublic boolean equals(MouseEvent event) {\r\n\t\treturn event.getButton()==button\r\n\t\t     &amp;&amp;event.getButtons()==buttons\r\n\t\t     &amp;&amp;event.getX()==x\r\n\t\t     &amp;&amp;event.getY()==y;\r\n\t}\r\n\t\r\n\t@Override public String toString() {\r\n\t\tStringBuilder string = new StringBuilder().append(x).append(&#039;,&#039;).append(y);\r\n\t\tif(buttons!=BUTTON_NO) {\r\n\t\t\tstring.append(&quot; [&quot;);\r\n\t\t\tif((buttons&amp;BUTTON_LEFT)!=BUTTON_NO)\r\n\t\t\t\tstring.append(&quot;left,&quot;);\r\n\t\t\tif((buttons&amp;BUTTON_RIGHT)!=BUTTON_NO)\r\n\t\t\t\tstring.append(&quot;right,&quot;);\r\n\t\t\treturn string.deleteCharAt(string.length()-1).append(&#039;]&#039;).toString();\r\n\t\t} else return string.toString();\r\n\t}\r\n}\r\n<\/pre>\n<pre class=\"syntax java\" style=\"max-height:200px\" title=\"MouseHook.java\">\r\npackage de.ksquared.system.mouse;\r\n\r\nimport java.awt.Dimension;\r\nimport java.awt.GraphicsDevice;\r\nimport java.awt.GraphicsEnvironment;\r\nimport java.awt.Rectangle;\r\nimport java.util.Collections;\r\nimport java.util.LinkedList;\r\nimport java.util.List;\r\n\r\nclass PoolHook extends Thread {\r\n\tprivate MouseHook hook;\r\n\tprivate GlobalMouseListener listener;\r\n\r\n\tPoolHook(GlobalMouseListener listener) {\r\n\t\tthis.setDaemon(true);\r\n\t\tthis.listener = listener;\r\n\t}\r\n\r\n\tpublic void run() {\r\n\t\thook = new MouseHook();\r\n\t\thook.registerHook(listener);\r\n\t}\r\n}\r\n\r\nclass EventProcedure extends Thread {\r\n\tprivate MouseHook hook;\r\n\t\r\n\tEventProcedure(MouseHook hook) {\r\n\t\tthis.setDaemon(true);\r\n\t\tthis.hook = hook;\r\n\t}\r\n\t\r\n\t@Override public void run() {\r\n\t\twhile(true) {\r\n\t\t\tif(!hook.buffer.isEmpty()) {\r\n\t\t\t\tMouseEvent event = hook.buffer.remove(0);\r\n\t\t\t\tGlobalMouseListener listener = event.listener;\r\n\t\t\t\tswitch(event.transitionState) {\r\n\t\t\t\tcase MouseEvent.TRANSITION_STATE_DOWN:\r\n\t\t\t\t\tlistener.mousePressed(event);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase MouseEvent.TRANSITION_STATE_UP:\r\n\t\t\t\t\tlistener.mouseReleased(event);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase MouseEvent.TRANSITION_STATE_MOVE:\r\n\t\t\t\t\tlistener.mouseMoved(event);\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t} else try { Thread.sleep(10); }\tcatch(InterruptedException e) { e.printStackTrace(); }\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass MouseHook {\t\r\n\tprivate static final int WM_LBUTTONDOWN = 513,WM_LBUTTONUP = 514,WM_RBUTTONDOWN = 516,WM_RBUTTONUP = 517;\r\n\t\r\n\tprivate int buttons,x,y;\r\n\tprivate static Dimension size;\r\n\tstatic {\r\n\t\tRectangle bounds = new Rectangle();\r\n\t\tfor(GraphicsDevice device:GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices())\r\n\t\t\tbounds.add(device.getDefaultConfiguration().getBounds());\r\n\t\tsize = new Dimension(bounds.width,bounds.height);\r\n\t}\r\n\t\r\n\tList&lt;MouseEvent&gt; buffer = Collections.synchronizedList(new LinkedList&lt;MouseEvent&gt;());\r\n\tprivate EventProcedure procedure = new EventProcedure(this);\r\n\t\r\n\tpublic MouseHook() { if(Native.load()) procedure.start(); }\r\n\tvoid processButton(int parameter,GlobalMouseListener listener) {\r\n\t\tswitch(parameter) {\r\n\t\tcase WM_LBUTTONDOWN:\r\n\t\t\tbuttons |= MouseEvent.BUTTON_LEFT;\r\n\t\t\tbuffer.add(new MouseEvent(this,listener,MouseEvent.TRANSITION_STATE_DOWN,MouseEvent.BUTTON_LEFT,buttons,x,y));\r\n\t\t\tbreak;\r\n\t\tcase WM_LBUTTONUP:\r\n\t\t\tbuttons &amp;= (~MouseEvent.BUTTON_LEFT);\r\n\t\t\tbuffer.add(new MouseEvent(this,listener,MouseEvent.TRANSITION_STATE_UP,MouseEvent.BUTTON_LEFT,buttons,x,y));\r\n\t\t\tbreak;\r\n\t\tcase WM_RBUTTONDOWN:\r\n\t\t\tbuttons |= MouseEvent.BUTTON_RIGHT;\r\n\t\t\tbuffer.add(new MouseEvent(this,listener,MouseEvent.TRANSITION_STATE_DOWN,MouseEvent.BUTTON_RIGHT,buttons,x,y));\r\n\t\t\tbreak;\r\n\t\tcase WM_RBUTTONUP:\r\n\t\t\tbuttons &amp;= (~MouseEvent.BUTTON_RIGHT);\r\n\t\t\tbuffer.add(new MouseEvent(this,listener,MouseEvent.TRANSITION_STATE_UP,MouseEvent.BUTTON_RIGHT,buttons,x,y));\r\n\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\tvoid processMove(int x,int y,GlobalMouseListener listener) {\r\n\t\tthis.x = Math.min(Math.max(0,x),size.width);\r\n\t\tthis.y = Math.min(Math.max(0,y),size.height);\r\n\t\tbuffer.add(new MouseEvent(this,listener,MouseEvent.TRANSITION_STATE_MOVE,MouseEvent.BUTTON_NO,buttons,this.x,this.y));\r\n\t}\r\n\t\r\n\tnative void registerHook(GlobalMouseListener listener);\r\n\tnative void unregisterHook();\r\n}\r\n<\/pre>\n<pre class=\"syntax java\" title=\"MouseListener.java\">\r\npackage de.ksquared.system.mouse;\r\n\r\nimport java.util.EventListener;\r\n\r\npublic interface MouseListener extends EventListener {\r\n\tpublic void mouseMoved(MouseEvent event);\r\n  public void mousePressed(MouseEvent event);\r\n  public void mouseReleased(MouseEvent event);\r\n}\r\n<\/pre>\n<pre class=\"syntax java\" style=\"max-height:200px\" title=\"Native.java\">\r\npackage de.ksquared.system.mouse;\r\n\r\nimport java.io.File;\r\nimport java.io.FileOutputStream;\r\nimport java.io.InputStream;\r\nimport java.io.OutputStream;\r\n\r\npublic class Native {\r\n\tprivate static Boolean loaded = null;\r\n\r\n\tstatic boolean load() {\r\n\t\tif(loaded!=null)\r\n\t\t\treturn loaded==Boolean.TRUE;\r\n\r\n\t\tString libpath = System.getProperty(&quot;de.ksquared.system.mouse.lib.path&quot;),\r\n\t\t\t\t   libname = System.getProperty(&quot;de.ksquared.system.mouse.lib.name&quot;);\r\n\t\tif(libname==null)\r\n\t\t\tlibname = System.mapLibraryName(&quot;mousehook&quot;);\r\n\t\ttry {\r\n\t\t\tif(libpath==null)\r\n\t\t\t\t   System.loadLibrary(&quot;mousehook&quot;);\r\n\t\t\telse System.load(new File(libpath,libname).getAbsolutePath());\r\n\t\t\treturn (loaded=Boolean.TRUE);\r\n\t\t}\tcatch(UnsatisfiedLinkError e) { \/* do nothing, try next *\/ }\r\n\r\n\t\tString osname = System.getProperty(&quot;os.name&quot;).toLowerCase(),\r\n\t\t\t\t   osarch = System.getProperty(&quot;os.arch&quot;);\r\n\t\t     if(osname.startsWith(&quot;mac os&quot;)) { osname = &quot;mac&quot;; osarch = &quot;universal&quot;; }\r\n\t\telse if(osname.startsWith(&quot;windows&quot;)) osname = &quot;win&quot;;\r\n\t\telse if(osname.startsWith(&quot;sunos&quot;)) osname = &quot;solaris&quot;;\r\n\t\tif(osarch.startsWith(&quot;i&quot;)&amp;&amp;osarch.endsWith(&quot;86&quot;))\r\n\t\t\tosarch = &quot;x86&quot;;\r\n\t\tlibname = &quot;mousehook-&quot;+osname+&#039;-&#039;+osarch+&quot;.lib&quot;;\r\n\t\ttry {\r\n\t\t\tInputStream input = Native.class.getClassLoader().getResourceAsStream(libname);\r\n\t\t\tif(input==null)\r\n\t\t\t\tthrow new Exception(&quot;libname: &quot;+libname+&quot; not found&quot;);\r\n\t\t\tFile temp = File.createTempFile(&quot;mousehook-&quot;,&quot;.lib&quot;);\r\n\t\t\ttemp.deleteOnExit();\r\n\t\t\tOutputStream out = new FileOutputStream(temp);\r\n\t\t\tbyte[] buffer = new byte[1024];\r\n\t\t\tint read;\r\n\t\t\twhile((read = input.read(buffer))!=-1)\r\n\t\t\t\tout.write(buffer,0,read);\r\n\t\t\tinput.close(); out.close();\r\n\t\t\tSystem.load(temp.getAbsolutePath());\r\n\t\t\treturn (loaded=Boolean.TRUE);\r\n\t\t} catch(Exception e) { \/* do nothing, go on *\/ }\r\n\t\treturn (loaded=Boolean.FALSE);\r\n\t}\r\n}\r\n<\/pre>\n<p>Two examples how to use the classes:<\/p>\n<pre class=\"syntax java\">\r\npackage de.ksquared.test.system.keyboard;\r\n\r\nimport de.ksquared.system.keyboard.GlobalKeyListener;\r\nimport de.ksquared.system.keyboard.KeyAdapter;\r\nimport de.ksquared.system.keyboard.KeyEvent;\r\n\r\npublic class KeyboardHookTest {\r\n\tpublic static void main(String[] args) {\r\n\t\tnew GlobalKeyListener().addKeyListener(new KeyAdapter() {\r\n\t\t\t@Override public void keyPressed(KeyEvent event) { System.out.println(event); }\r\n\t\t\t@Override public void keyReleased(KeyEvent event) {\r\n\t\t\t\tSystem.out.println(event);\r\n\t\t\t\tif(event.getVirtualKeyCode()==KeyEvent.VK_ADD\r\n\t\t\t\t&amp;&amp; event.isCtrlPressed())\r\n\t\t\t\t\tSystem.out.println(&quot;CTRL+ADD was just released (CTRL is still pressed)&quot;);\r\n\t\t\t}\r\n\t\t});\r\n\t\twhile(true)\r\n\t\t\ttry { Thread.sleep(100); }\r\n\t\t\tcatch(InterruptedException e) { e.printStackTrace(); }\r\n\t}\r\n}\r\n<\/pre>\n<pre class=\"syntax java\">\r\npackage de.ksquared.test.system.mouse;\r\n\r\nimport de.ksquared.system.mouse.GlobalMouseListener;\r\nimport de.ksquared.system.mouse.MouseAdapter;\r\nimport de.ksquared.system.mouse.MouseEvent;\r\n\r\npublic class MouseHookTest {\r\n\tpublic static void main(String[] args) {\r\n\t\tnew GlobalMouseListener().addMouseListener(new MouseAdapter() {\r\n\t\t\t@Override public void mousePressed(MouseEvent event)  { System.out.println(event); }\r\n\t\t\t@Override public void mouseReleased(MouseEvent event)  { System.out.println(event); }\r\n\t\t\t@Override public void mouseMoved(MouseEvent event) {\r\n\t\t\t\tSystem.out.println(event);\r\n\t\t\t\tif((event.getButtons()&amp;MouseEvent.BUTTON_LEFT)!=MouseEvent.BUTTON_NO\r\n\t\t\t\t&amp;&amp; (event.getButtons()&amp;MouseEvent.BUTTON_RIGHT)!=MouseEvent.BUTTON_NO)\r\n\t\t\t\t\tSystem.out.println(&quot;Both mouse buttons are currenlty pressed!&quot;);\r\n\t\t\t}\r\n\t\t});\r\n\t\twhile(true)\r\n\t\t\ttry { Thread.sleep(100); }\r\n\t\t\tcatch(InterruptedException e) { e.printStackTrace(); }\r\n\t}\r\n}\r\n<\/pre>\n<p>Have fun! <del>Don&#8217;t forget to<\/del> <em>Since version 0.2 it is possible, but no longer necessary<\/em> to download the &#8220;KeyboardHook.dll&#8221; and\/or &#8220;MouseHook.dll&#8221; libraries and specify the libary path when starting your JVM using:<\/p>\n<pre class=\"syntax bash\">\r\njava ... -Djava.library.path=&quot;C:\/absolute\/path\/to\/mousehook.dll, C:\/absolute\/path\/to\/keyboardhook.dll&quot;\r\n<\/pre>\n<p>(If you specify the virtual machine parameter instead of using the bundled libraries it might gets you a little performance enhance)<\/p>\n<p><strong>Update (7.16.11):<\/strong> A new version (0.2) is out now. At first I lowercased the library names, which should sove some issues loading the libraries. The major change regards the loading mechanism of the libraries. With the new <em>Native<\/em> classes, it is no longer necesarry to specify the virtual machine parameter, because the libraries are bundled into the KeyboardHook and MouseHook archives. I think this is a great advantage, especially if you plan to bundle your application. The MouseHook.h\/.cpp files are now present in the source bundle aswell. Thanks to Adam.<\/p>\n<p><strong>Update (7.21.11):<\/strong> I made a minor change in version (0.2.1). Due to a missing linker flag, the virtual machine was not able to load the native libraries on some systems. An <em>java.lang.UnsatisfiedLinkError<\/em> was thrown. This issue should be solved now.<\/p>\n<p style=\"text-align:left\">Used compiler flags: <code>-I\"%JAVA_HOME%\\include\" -I\"%JAVA_HOME%\\include\\win32\" -O0 -g3 -Wall -c -fmessage-length=0 -mno-cygwin -D_JNI_IMPLEMENTATION_<\/code><br \/>\nUsed linker flags: <code>-Wl,--kill-at -mno-cygwin -shared -static-libgcc -shared<\/code><\/p>\n<p>Thanks a lot to Alexander Loob and Timo.<\/p>\n<p><strong>Update (10.11.11):<\/strong> Version 0.3 released! Now compiled and tested on a 32 &amp; <strong>64 bit<\/strong> JVM. Libraries have been splitted into a 32 &amp; 64 bit DLL. Before an <em>java.lang.UnsatisfiedLinkError<\/em> was thrown on 64 bit JVM&#8217;s. This issue should be solved now. Also the library has been compiled using Java 7.0 native libs. Packaged bundles now also include the 64 bit DLL.<\/p>\n<p>Thanks to Timo, Thomas, Byron, Lucas, Jason and Frank.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Note: This is the copy of an older post for reference. Please find the latest library version and description in this new blog post. I&#8217;d like to start my small blog with a neat little Java snippet. As I wanted to have a global key\/mouse hook for my Java programs, I found a great little [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[11,5,6,16,8,13,233,232,9,14,7,12,10,234],"class_list":["post-555","post","type-post","status-publish","format-standard","hentry","category-release","tag-hook","tag-java","tag-jni","tag-jotschi","tag-keyboard","tag-keyhook","tag-level","tag-low","tag-mouse","tag-mousehook","tag-native","tag-syshook","tag-system","tag-window"],"_links":{"self":[{"href":"https:\/\/kra.lc\/blog\/wp-json\/wp\/v2\/posts\/555","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kra.lc\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kra.lc\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kra.lc\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kra.lc\/blog\/wp-json\/wp\/v2\/comments?post=555"}],"version-history":[{"count":5,"href":"https:\/\/kra.lc\/blog\/wp-json\/wp\/v2\/posts\/555\/revisions"}],"predecessor-version":[{"id":560,"href":"https:\/\/kra.lc\/blog\/wp-json\/wp\/v2\/posts\/555\/revisions\/560"}],"wp:attachment":[{"href":"https:\/\/kra.lc\/blog\/wp-json\/wp\/v2\/media?parent=555"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kra.lc\/blog\/wp-json\/wp\/v2\/categories?post=555"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kra.lc\/blog\/wp-json\/wp\/v2\/tags?post=555"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}