diff --git a/README.md b/README.md index 37449b5..ff86283 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ You can include `system-hook` from this GitHub repository by adding this depende lc.kra.system system-hook - 3.4 + 3.5 ``` diff --git a/appveyor.yml b/appveyor.yml index ab3f5c0..5ee176e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 3.4.{build} +version: 3.5.{build} branches: only: diff --git a/pom.xml b/pom.xml index 36bd125..39de76a 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 lc.kra.system system-hook - 3.4 + 3.5 Global Keyboard / Mouse Hook for Java applications. https://github.com/kristian/system-hook diff --git a/src/main/java/lc/kra/system/GlobalHookMode.java b/src/main/java/lc/kra/system/GlobalHookMode.java new file mode 100644 index 0000000..28e2f5e --- /dev/null +++ b/src/main/java/lc/kra/system/GlobalHookMode.java @@ -0,0 +1,16 @@ +package lc.kra.system; + +public enum GlobalHookMode { + /** + * capture events via the low-level system hook, after a event was captured any next hook registered will be called + */ + DEFAULT, + /** + * capture events via the low-level system hook, this mode will not invoke any further hooks + */ + FINAL, + /** + * capturing events in raw mode will provide you additional information of the device + */ + RAW +} diff --git a/src/main/java/lc/kra/system/keyboard/GlobalKeyboardHook.java b/src/main/java/lc/kra/system/keyboard/GlobalKeyboardHook.java index a988174..a398ea5 100644 --- a/src/main/java/lc/kra/system/keyboard/GlobalKeyboardHook.java +++ b/src/main/java/lc/kra/system/keyboard/GlobalKeyboardHook.java @@ -21,17 +21,19 @@ */ package lc.kra.system.keyboard; +import static lc.kra.system.GlobalHookMode.DEFAULT; +import static lc.kra.system.GlobalHookMode.RAW; import static lc.kra.system.keyboard.event.GlobalKeyEvent.TS_DOWN; import static lc.kra.system.keyboard.event.GlobalKeyEvent.VK_CONTROL; import static lc.kra.system.keyboard.event.GlobalKeyEvent.VK_LCONTROL; import static lc.kra.system.keyboard.event.GlobalKeyEvent.VK_LMENU; import static lc.kra.system.keyboard.event.GlobalKeyEvent.VK_LSHIFT; +import static lc.kra.system.keyboard.event.GlobalKeyEvent.VK_LWIN; import static lc.kra.system.keyboard.event.GlobalKeyEvent.VK_MENU; import static lc.kra.system.keyboard.event.GlobalKeyEvent.VK_RCONTROL; import static lc.kra.system.keyboard.event.GlobalKeyEvent.VK_RMENU; import static lc.kra.system.keyboard.event.GlobalKeyEvent.VK_RSHIFT; import static lc.kra.system.keyboard.event.GlobalKeyEvent.VK_RWIN; -import static lc.kra.system.keyboard.event.GlobalKeyEvent.VK_LWIN; import static lc.kra.system.keyboard.event.GlobalKeyEvent.VK_SHIFT; import java.util.List; @@ -40,6 +42,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.LinkedBlockingQueue; +import lc.kra.system.GlobalHookMode; import lc.kra.system.LibraryLoader; import lc.kra.system.keyboard.event.GlobalKeyEvent; import lc.kra.system.keyboard.event.GlobalKeyListener; @@ -95,11 +98,22 @@ public void run() { * @throws UnsatisfiedLinkError Thrown if loading the native library failed * @throws RuntimeException Thrown if registering the low-level keyboard hook failed */ - public GlobalKeyboardHook(boolean raw) throws UnsatisfiedLinkError { + public GlobalKeyboardHook(boolean raw) throws UnsatisfiedLinkError { this(raw?RAW:DEFAULT); } + + /** + * Instantiate a new GlobalKeyboardHook. + * + * @see #GlobalKeyboardHook() + * + * @param mode The mode to capture the input + * @throws UnsatisfiedLinkError Thrown if loading the native library failed + * @throws RuntimeException Thrown if registering the low-level keyboard hook failed + */ + public GlobalKeyboardHook(GlobalHookMode mode) throws UnsatisfiedLinkError { LibraryLoader.loadLibrary(); // load the library, in case it's not already loaded // register a keyboard hook (throws a RuntimeException in case something goes wrong) - keyboardHook = new NativeKeyboardHook(raw) { + keyboardHook = new NativeKeyboardHook(mode) { /** * Handle the input virtualKeyCode and transitionState, create event and add it to the inputBuffer */ @@ -178,13 +192,13 @@ public static Map listKeyboards() throws UnsatisfiedLinkError { private static abstract class NativeKeyboardHook extends Thread { private int status; - private boolean raw; + private GlobalHookMode mode; - public NativeKeyboardHook(boolean raw) { + public NativeKeyboardHook(GlobalHookMode mode) { super("Global Keyboard Hook Thread"); setDaemon(false); setPriority(MAX_PRIORITY); synchronized(this) { - this.raw = raw; + this.mode = mode; try { start(); wait(); } catch (InterruptedException e) { throw new RuntimeException(e); @@ -196,12 +210,12 @@ public NativeKeyboardHook(boolean raw) { } @Override public void run() { - status = registerHook(raw); + status = registerHook(mode.ordinal()); synchronized(this) { notifyAll(); } } - public native final int registerHook(boolean raw); + public native final int registerHook(int mode); public native final void unregisterHook(); public static native final Map listDevices(); diff --git a/src/main/java/lc/kra/system/mouse/GlobalMouseHook.java b/src/main/java/lc/kra/system/mouse/GlobalMouseHook.java index a5125b1..99d44f0 100644 --- a/src/main/java/lc/kra/system/mouse/GlobalMouseHook.java +++ b/src/main/java/lc/kra/system/mouse/GlobalMouseHook.java @@ -21,6 +21,8 @@ */ package lc.kra.system.mouse; +import static lc.kra.system.GlobalHookMode.DEFAULT; +import static lc.kra.system.GlobalHookMode.RAW; import static lc.kra.system.mouse.event.GlobalMouseEvent.BUTTON_NO; import static lc.kra.system.mouse.event.GlobalMouseEvent.TS_DOWN; import static lc.kra.system.mouse.event.GlobalMouseEvent.TS_MOVE; @@ -33,6 +35,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.LinkedBlockingQueue; +import lc.kra.system.GlobalHookMode; import lc.kra.system.LibraryLoader; import lc.kra.system.mouse.event.GlobalMouseEvent; import lc.kra.system.mouse.event.GlobalMouseListener; @@ -99,11 +102,22 @@ public void run() { * @throws UnsatisfiedLinkError Thrown if loading the native library failed * @throws RuntimeException Thrown if registering the low-level keyboard hook failed */ - public GlobalMouseHook(boolean raw) throws UnsatisfiedLinkError { + public GlobalMouseHook(boolean raw) throws UnsatisfiedLinkError { this(raw?RAW:DEFAULT); } + + /** + * Instantiate a new GlobalMouseHook. + * + * @see #GlobalMouseHook() + * + * @param mode The mode to capture the input + * @throws UnsatisfiedLinkError Thrown if loading the native library failed + * @throws RuntimeException Thrown if registering the low-level keyboard hook failed + */ + public GlobalMouseHook(GlobalHookMode mode) throws UnsatisfiedLinkError { LibraryLoader.loadLibrary(); // load the library, in case it's not already loaded // register a mouse hook (throws a RuntimeException in case something goes wrong) - mouseHook = new NativeMouseHook(raw) { + mouseHook = new NativeMouseHook(mode) { /** * Handle the input transitionState create event and add it to the inputBuffer */ @@ -199,13 +213,13 @@ public static Map listMice() throws UnsatisfiedLinkError { private static abstract class NativeMouseHook extends Thread { private int status; - private boolean raw; + private GlobalHookMode mode; - public NativeMouseHook(boolean raw) { + public NativeMouseHook(GlobalHookMode mode) { super("Global Mouse Hook Thread"); setDaemon(false); setPriority(MAX_PRIORITY); synchronized(this) { - this.raw = raw; + this.mode = mode; try { start(); wait(); } catch (InterruptedException e) { throw new RuntimeException(e); @@ -217,12 +231,12 @@ public NativeMouseHook(boolean raw) { } @Override public void run() { - status = registerHook(raw); + status = registerHook(mode.ordinal()); synchronized(this) { notifyAll(); } } - public native final int registerHook(boolean raw); + public native final int registerHook(int mode); public native final void unregisterHook(); public static native final Map listDevices(); diff --git a/src/main/native/windows/SystemHook.c b/src/main/native/windows/SystemHook.c index d39a1e0..1ef7512 100644 --- a/src/main/native/windows/SystemHook.c +++ b/src/main/native/windows/SystemHook.c @@ -68,7 +68,7 @@ DWORD hookThreadId[2] = { 0, 0 }; BYTE keyState[256]; WCHAR buffer[4]; -jint lOldX = (jint)SHRT_MIN, lOldY = (jint)SHRT_MIN; +jint lMode = 0, lOldX = (jint)SHRT_MIN, lOldY = (jint)SHRT_MIN; BOOL APIENTRY DllMain(HINSTANCE _hInst, DWORD reason, LPVOID reserved) { switch(reason) { @@ -112,7 +112,7 @@ LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) handleKey("LowLevelKeyboardProc", wParam, pStruct->vkCode, pStruct->scanCode, 0); - return CallNextHookEx(NULL, nCode, wParam, lParam); + return nCode<0 || lMode != MODE_FINAL ? CallNextHookEx(NULL, nCode, wParam, lParam) : -1; } LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) { if(nCode==HC_ACTION) { @@ -163,7 +163,7 @@ LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) { } else DEBUG_PRINT(("NATIVE: LowLevelMouseProc - Error on the attach current thread.\n")); } - return CallNextHookEx(NULL, nCode, wParam, lParam); + return nCode<0 || lMode != MODE_FINAL ? CallNextHookEx(NULL, nCode, wParam, lParam) : -1; } LRESULT CALLBACK WndProc(HWND hWndMain, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg){ @@ -291,7 +291,7 @@ static inline _Bool notifyHookObj(JNIEnv *env, size_t hook) { return TRUE; } -static inline jint registerHook(JNIEnv *env, jobject thisObj, size_t hook, const char *handleName, const char *handleSig, jboolean raw) { +static inline jint registerHook(JNIEnv *env, jobject thisObj, size_t hook, const char *handleName, const char *handleSig, jint mode) { DEBUG_PRINT(("NATIVE: registerHook - Hook start\n")); if(jvm==NULL) (*env)->GetJavaVM(env, &jvm); @@ -306,8 +306,8 @@ static inline jint registerHook(JNIEnv *env, jobject thisObj, size_t hook, const } HHOOK hHook; HWND hWnd; - switch(raw) { - case JNI_FALSE: + switch(lMode=mode) { + case MODE_DEFAULT: case MODE_FINAL: switch(hook) { case HOOK_KEYBOARD: hHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hInst, 0); @@ -318,7 +318,7 @@ static inline jint registerHook(JNIEnv *env, jobject thisObj, size_t hook, const } break; - case JNI_TRUE: { + case MODE_RAW: { WNDCLASS wndCls = {0}; wndCls.lpfnWndProc = WndProc; wndCls.hInstance = hInst; @@ -334,7 +334,7 @@ static inline jint registerHook(JNIEnv *env, jobject thisObj, size_t hook, const if(hHook==NULL&&hWnd==NULL) { debugPrintLastError("NATIVE: registerHook - Hook failed"); return (jint)E_HOOK_FAILED; - } else DEBUG_PRINT(("NATIVE: registerHook - %sHook success\n", raw?"Raw ":"")); + } else DEBUG_PRINT(("NATIVE: registerHook - %sHook success\n", lMode==MODE_RAW?"Raw ":"")); if(!notifyHookObj(env, hook)) { (*env)->ExceptionClear(env); @@ -357,11 +357,11 @@ static inline jint registerHook(JNIEnv *env, jobject thisObj, size_t hook, const return (jint)E_UNHOOK_FAILED; } } -JNIEXPORT jint JNICALL Java_lc_kra_system_keyboard_GlobalKeyboardHook_00024NativeKeyboardHook_registerHook(JNIEnv *env, jobject thisObj, jboolean raw) { - return registerHook(env, thisObj, HOOK_KEYBOARD, "handleKey", "(IICJ)V", raw); +JNIEXPORT jint JNICALL Java_lc_kra_system_keyboard_GlobalKeyboardHook_00024NativeKeyboardHook_registerHook(JNIEnv *env, jobject thisObj, jint mode) { + return registerHook(env, thisObj, HOOK_KEYBOARD, "handleKey", "(IICJ)V", mode); } -JNIEXPORT jint JNICALL Java_lc_kra_system_mouse_GlobalMouseHook_00024NativeMouseHook_registerHook(JNIEnv *env, jobject thisObj, jboolean raw) { - return registerHook(env, thisObj, HOOK_MOUSE, "handleMouse", "(IIIIIJ)V", raw); +JNIEXPORT jint JNICALL Java_lc_kra_system_mouse_GlobalMouseHook_00024NativeMouseHook_registerHook(JNIEnv *env, jobject thisObj, jint mode) { + return registerHook(env, thisObj, HOOK_MOUSE, "handleMouse", "(IIIIIJ)V", mode); } static inline void unregisterHook(size_t hook) { diff --git a/src/main/native/windows/SystemHook.h b/src/main/native/windows/SystemHook.h index ae2e975..f97ef19 100644 --- a/src/main/native/windows/SystemHook.h +++ b/src/main/native/windows/SystemHook.h @@ -36,6 +36,12 @@ typedef enum { E_NOTIFY_FAILED = -4 } GlobalHookError; +typedef enum { + MODE_DEFAULT = 0, + MODE_FINAL = 1, + MODE_RAW = 2 +} GlobalHookMode; + typedef enum { TS_UP = 0, TS_DOWN = 1, @@ -48,7 +54,7 @@ typedef enum { * Method: registerHook * Signature: (Z)I */ -JNIEXPORT jint JNICALL Java_lc_kra_system_keyboard_GlobalKeyboardHook_00024NativeKeyboardHook_registerHook(JNIEnv *,jobject,jboolean); +JNIEXPORT jint JNICALL Java_lc_kra_system_keyboard_GlobalKeyboardHook_00024NativeKeyboardHook_registerHook(JNIEnv *,jobject,jint); /* * Class: GlobalKeyboardHook$NativeKeyboardHook * Method: unregisterHook @@ -67,7 +73,7 @@ JNIEXPORT jobject JNICALL Java_lc_kra_system_keyboard_GlobalKeyboardHook_00024Na * Method: registerHook * Signature: (Z)I */ -JNIEXPORT jint JNICALL Java_lc_kra_system_mouse_GlobalMouseHook_00024NativeMouseHook_registerHook(JNIEnv *,jobject,jboolean); +JNIEXPORT jint JNICALL Java_lc_kra_system_mouse_GlobalMouseHook_00024NativeMouseHook_registerHook(JNIEnv *,jobject,jint); /* * Class: GlobalMouseHook$NativeMouseHook * Method: unregisterHook