// NOTE: This function executes on the hook thread! If you need to block // please do so on another thread via your own event dispatcher. void jni_EventDispatcher(uiohook_event * const event) { jobject NativeInputEvent_object = NULL; switch (event->type) { /* The following start and stop functions are less than ideal for attaching JNI. * TODO Consider moving threads out of the lib and into Java. */ case EVENT_THREAD_STARTED: if ((*jvm)->GetEnv(jvm, (void **)(&env), jvm_attach_args.version) == JNI_EDETACHED) { (*jvm)->AttachCurrentThread(jvm, (void **)(&env), &jvm_attach_args); } break; case EVENT_THREAD_STOPPED: // NOTE This callback may note be called from Windows under some circumstances. if ((*jvm)->GetEnv(jvm, (void **)(&env), jvm_attach_args.version) == JNI_OK) { if ((*jvm)->DetachCurrentThread(jvm) == JNI_OK) { env = NULL; } } break; case EVENT_HOOK_ENABLED: case EVENT_HOOK_DISABLED: break; case EVENT_KEY_PRESSED: if (env != NULL) { jint location; if (jni_ConvertToJavaLocation(event->data.keyboard.keycode, &location) == JNI_OK) { NativeInputEvent_object = (*env)->NewObject( env, org_jnativehook_keyboard_NativeKeyEvent->cls, org_jnativehook_keyboard_NativeKeyEvent->init, org_jnativehook_keyboard_NativeKeyEvent_NATIVE_KEY_PRESSED, (jlong) event->time, (jint) event->mask, (jint) event->data.keyboard.rawcode, (jint) event->data.keyboard.keycode, (jchar) org_jnativehook_keyboard_NativeKeyEvent_CHAR_UNDEFINED, location); } } break; case EVENT_KEY_RELEASED: if (env != NULL) { jint location; if (jni_ConvertToJavaLocation(event->data.keyboard.keycode, &location) == JNI_OK) { NativeInputEvent_object = (*env)->NewObject( env, org_jnativehook_keyboard_NativeKeyEvent->cls, org_jnativehook_keyboard_NativeKeyEvent->init, org_jnativehook_keyboard_NativeKeyEvent_NATIVE_KEY_RELEASED, (jlong) event->time, (jint) event->mask, (jint) event->data.keyboard.rawcode, (jint) event->data.keyboard.keycode, (jchar) org_jnativehook_keyboard_NativeKeyEvent_CHAR_UNDEFINED, location); } } break; case EVENT_KEY_TYPED: if (env != NULL) { jint location; if (jni_ConvertToJavaLocation(event->data.keyboard.keycode, &location) == JNI_OK) { NativeInputEvent_object = (*env)->NewObject( env, org_jnativehook_keyboard_NativeKeyEvent->cls, org_jnativehook_keyboard_NativeKeyEvent->init, org_jnativehook_keyboard_NativeKeyEvent_NATIVE_KEY_TYPED, (jlong) event->time, (jint) event->mask, (jint) event->data.keyboard.rawcode, (jint) org_jnativehook_keyboard_NativeKeyEvent_VK_UNDEFINED, (jchar) event->data.keyboard.keychar, location); } } break; case EVENT_MOUSE_PRESSED: if (env != NULL) { NativeInputEvent_object = (*env)->NewObject( env, org_jnativehook_mouse_NativeMouseEvent->cls, org_jnativehook_mouse_NativeMouseEvent->init, org_jnativehook_mouse_NativeMouseEvent_NATIVE_MOUSE_PRESSED, (jlong) event->time, (jint) event->mask, (jint) event->data.mouse.x, (jint) event->data.mouse.y, (jint) event->data.mouse.clicks, (jint) event->data.mouse.button); } break; case EVENT_MOUSE_RELEASED: if (env != NULL) { NativeInputEvent_object = (*env)->NewObject( env, org_jnativehook_mouse_NativeMouseEvent->cls, org_jnativehook_mouse_NativeMouseEvent->init, org_jnativehook_mouse_NativeMouseEvent_NATIVE_MOUSE_RELEASED, (jlong) event->time, (jint) event->mask, (jint) event->data.mouse.x, (jint) event->data.mouse.y, (jint) event->data.mouse.clicks, (jint) event->data.mouse.button); } break; case EVENT_MOUSE_CLICKED: if (env != NULL) { NativeInputEvent_object = (*env)->NewObject( env, org_jnativehook_mouse_NativeMouseEvent->cls, org_jnativehook_mouse_NativeMouseEvent->init, org_jnativehook_mouse_NativeMouseEvent_NATIVE_MOUSE_CLICKED, (jlong) event->time, (jint) event->mask, (jint) event->data.mouse.x, (jint) event->data.mouse.y, (jint) event->data.mouse.clicks, (jint) event->data.mouse.button); } break; case EVENT_MOUSE_MOVED: if (env != NULL) { NativeInputEvent_object = (*env)->NewObject( env, org_jnativehook_mouse_NativeMouseEvent->cls, org_jnativehook_mouse_NativeMouseEvent->init, org_jnativehook_mouse_NativeMouseEvent_NATIVE_MOUSE_MOVED, (jlong) event->time, (jint) event->mask, (jint) event->data.mouse.x, (jint) event->data.mouse.y, (jint) event->data.mouse.clicks, (jint) event->data.mouse.button); } break; case EVENT_MOUSE_DRAGGED: if (env != NULL) { NativeInputEvent_object = (*env)->NewObject( env, org_jnativehook_mouse_NativeMouseEvent->cls, org_jnativehook_mouse_NativeMouseEvent->init, org_jnativehook_mouse_NativeMouseEvent_NATIVE_MOUSE_DRAGGED, (jlong) event->time, (jint) event->mask, (jint) event->data.mouse.x, (jint) event->data.mouse.y, (jint) event->data.mouse.clicks, (jint) event->data.mouse.button); } break; case EVENT_MOUSE_WHEEL: if (env != NULL) { NativeInputEvent_object = (*env)->NewObject( env, org_jnativehook_mouse_NativeMouseWheelEvent->cls, org_jnativehook_mouse_NativeMouseWheelEvent->init, org_jnativehook_mouse_NativeMouseEvent_NATIVE_MOUSE_WHEEL, (jlong) event->time, (jint) event->mask, (jint) event->data.wheel.x, (jint) event->data.wheel.y, (jint) event->data.wheel.clicks, (jint) event->data.wheel.type, (jint) event->data.wheel.amount, (jint) event->data.wheel.rotation); } break; } // NOTE It is assumed that we do not need to check env* for null because NativeInputEvent_object // cannot be assigned if env* is NULL. if (NativeInputEvent_object != NULL) { // Create the global screen references up front to save time in the callback. jobject GlobalScreen_object = (*env)->CallStaticObjectMethod( env, org_jnativehook_GlobalScreen->cls, org_jnativehook_GlobalScreen->getInstance); if (GlobalScreen_object != NULL) { (*env)->CallVoidMethod( env, GlobalScreen_object, org_jnativehook_GlobalScreen->dispatchEvent, NativeInputEvent_object); // Set the propagate flag from java. event->reserved = (unsigned short) (*env)->GetShortField( env, NativeInputEvent_object, org_jnativehook_NativeInputEvent->reserved); (*env)->DeleteLocalRef(env, GlobalScreen_object); } else { jni_Logger(env, LOG_LEVEL_ERROR, "%s [%u]: Failed to acquire GlobalScreen singleton!\n", __FUNCTION__, __LINE__); jni_ThrowException(env, "java/lang/NullPointerException", "GlobalScreen singleton is null."); } (*env)->DeleteLocalRef(env, NativeInputEvent_object); } }
// NOTE: This function executes on the hook thread! If you need to block // please do so on another thread via your own event dispatcher. void jni_EventDispatcher(uiohook_event * const event) { JNIEnv *env; if ((*jvm)->GetEnv(jvm, (void **)(&env), jvm_attach_args.version) == JNI_OK) { jobject NativeInputEvent_obj = NULL; jint location = org_jnativehook_keyboard_NativeKeyEvent_LOCATION_UNKNOWN; switch (event->type) { case EVENT_HOOK_DISABLED: case EVENT_HOOK_ENABLED: notifyHookThread(env); return; case EVENT_KEY_PRESSED: if (jni_ConvertToJavaLocation(event->data.keyboard.keycode, &location) == JNI_OK) { NativeInputEvent_obj = (*env)->NewObject( env, org_jnativehook_keyboard_NativeKeyEvent->cls, org_jnativehook_keyboard_NativeKeyEvent->init, org_jnativehook_keyboard_NativeKeyEvent_NATIVE_KEY_PRESSED, (jint) event->mask, (jint) event->data.keyboard.rawcode, (jint) event->data.keyboard.keycode, (jchar) org_jnativehook_keyboard_NativeKeyEvent_CHAR_UNDEFINED, location); } break; case EVENT_KEY_RELEASED: if (jni_ConvertToJavaLocation(event->data.keyboard.keycode, &location) == JNI_OK) { NativeInputEvent_obj = (*env)->NewObject( env, org_jnativehook_keyboard_NativeKeyEvent->cls, org_jnativehook_keyboard_NativeKeyEvent->init, org_jnativehook_keyboard_NativeKeyEvent_NATIVE_KEY_RELEASED, (jint) event->mask, (jint) event->data.keyboard.rawcode, (jint) event->data.keyboard.keycode, (jchar) org_jnativehook_keyboard_NativeKeyEvent_CHAR_UNDEFINED, location); } break; case EVENT_KEY_TYPED: NativeInputEvent_obj = (*env)->NewObject( env, org_jnativehook_keyboard_NativeKeyEvent->cls, org_jnativehook_keyboard_NativeKeyEvent->init, org_jnativehook_keyboard_NativeKeyEvent_NATIVE_KEY_TYPED, (jint) event->mask, (jint) event->data.keyboard.rawcode, (jint) org_jnativehook_keyboard_NativeKeyEvent_VC_UNDEFINED, (jchar) event->data.keyboard.keychar, location); break; case EVENT_MOUSE_PRESSED: NativeInputEvent_obj = (*env)->NewObject( env, org_jnativehook_mouse_NativeMouseEvent->cls, org_jnativehook_mouse_NativeMouseEvent->init, org_jnativehook_mouse_NativeMouseEvent_NATIVE_MOUSE_PRESSED, (jint) event->mask, (jint) event->data.mouse.x, (jint) event->data.mouse.y, (jint) event->data.mouse.clicks, (jint) event->data.mouse.button); break; case EVENT_MOUSE_RELEASED: NativeInputEvent_obj = (*env)->NewObject( env, org_jnativehook_mouse_NativeMouseEvent->cls, org_jnativehook_mouse_NativeMouseEvent->init, org_jnativehook_mouse_NativeMouseEvent_NATIVE_MOUSE_RELEASED, (jint) event->mask, (jint) event->data.mouse.x, (jint) event->data.mouse.y, (jint) event->data.mouse.clicks, (jint) event->data.mouse.button); break; case EVENT_MOUSE_CLICKED: NativeInputEvent_obj = (*env)->NewObject( env, org_jnativehook_mouse_NativeMouseEvent->cls, org_jnativehook_mouse_NativeMouseEvent->init, org_jnativehook_mouse_NativeMouseEvent_NATIVE_MOUSE_CLICKED, (jint) event->mask, (jint) event->data.mouse.x, (jint) event->data.mouse.y, (jint) event->data.mouse.clicks, (jint) event->data.mouse.button); break; case EVENT_MOUSE_MOVED: NativeInputEvent_obj = (*env)->NewObject( env, org_jnativehook_mouse_NativeMouseEvent->cls, org_jnativehook_mouse_NativeMouseEvent->init, org_jnativehook_mouse_NativeMouseEvent_NATIVE_MOUSE_MOVED, (jint) event->mask, (jint) event->data.mouse.x, (jint) event->data.mouse.y, (jint) event->data.mouse.clicks, (jint) event->data.mouse.button); break; case EVENT_MOUSE_DRAGGED: NativeInputEvent_obj = (*env)->NewObject( env, org_jnativehook_mouse_NativeMouseEvent->cls, org_jnativehook_mouse_NativeMouseEvent->init, org_jnativehook_mouse_NativeMouseEvent_NATIVE_MOUSE_DRAGGED, (jint) event->mask, (jint) event->data.mouse.x, (jint) event->data.mouse.y, (jint) event->data.mouse.clicks, (jint) event->data.mouse.button); break; case EVENT_MOUSE_WHEEL: NativeInputEvent_obj = (*env)->NewObject( env, org_jnativehook_mouse_NativeMouseWheelEvent->cls, org_jnativehook_mouse_NativeMouseWheelEvent->init, org_jnativehook_mouse_NativeMouseEvent_NATIVE_MOUSE_WHEEL, (jint) event->mask, (jint) event->data.wheel.x, (jint) event->data.wheel.y, (jint) event->data.wheel.clicks, (jint) event->data.wheel.type, (jint) event->data.wheel.amount, (jint) event->data.wheel.rotation, (jint) event->data.wheel.direction); break; default: jni_Logger(env, LOG_LEVEL_WARN, "%s [%u]: Unknown native event type: %#X\n", __FUNCTION__, __LINE__, event->type); break; } if (NativeInputEvent_obj != NULL) { // Set the private when field to the native event time. (*env)->SetShortField( env, NativeInputEvent_obj, org_jnativehook_NativeInputEvent->when, (jlong) event->time); // Dispatch the event. (*env)->CallStaticVoidMethod( env, org_jnativehook_GlobalScreen->cls, org_jnativehook_GlobalScreen->dispatchEvent, NativeInputEvent_obj); // Set the propagate flag from java. event->reserved = (unsigned short) (*env)->GetShortField( env, NativeInputEvent_obj, org_jnativehook_NativeInputEvent->reserved); // Make sure our object is garbage collected. (*env)->DeleteLocalRef(env, NativeInputEvent_obj); } } }