Re: SetWindowsHookEx not notifing me on key pressed, using JNI and C++ dll
Here is a very simple yet complete working sample of a
low level Windows keyboard hook within a Swing application.
Please try it.
//
// FrameTest.java
//
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FrameTest extends JFrame {
private JPanel mainPanel;
private JTextArea mainTextArea;
private HookTest hook;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new FrameTest().setVisible(true);
}
});
}
FrameTest() {
super("FrameTest");
setSize(200, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
mainTextArea = new JTextArea();
mainPanel.add(mainTextArea, BorderLayout.CENTER);
getContentPane().add(mainPanel);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent event) {
hook.unRegisterHook();
}
});
new Thread() {
public void run() {
hook = new HookTest();
hook.registerHook();
}
}.start();
}
}
//
// HookTest.java
//
public class HookTest {
static {
System.loadLibrary("HookTest");
}
void processKey(int key, boolean pressed) {
System.out.println("Java: HookTest.processKey - key = " + key +
(pressed ? " pressed" : " released"));
}
native void registerHook();
native void unRegisterHook();
}
//
// HookTest.h
//
#ifndef _Included_HookTest
#define _Included_HookTest
#include <jni.h>
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_HookTest_registerHook(JNIEnv * env, jobject
obj);
JNIEXPORT void JNICALL Java_HookTest_unRegisterHook(JNIEnv * env,
jobject obj);
#ifdef __cplusplus
}
#endif
#endif /* _Included_HookTest */
//
// HookTest.cpp
//
#include <windows.h>
#include "HookTest.h"
HINSTANCE hInst = NULL;
JavaVM * jvm = NULL;
jobject hookObj = NULL;
jmethodID processKeyID = NULL;
DWORD hookThreadId = 0;
extern "C" BOOL APIENTRY DllMain(HINSTANCE _hInst, DWORD reason, LPVOID
reserved) {
switch (reason) {
case DLL_PROCESS_ATTACH:
printf("C++: DllMain - DLL_PROCESS_ATTACH.\n");
hInst = _hInst;
break;
default:
break;
}
return TRUE;
}
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM
lParam) {
JNIEnv * env;
KBDLLHOOKSTRUCT * p = (KBDLLHOOKSTRUCT *)lParam;
if (jvm->AttachCurrentThread((void **)&env, NULL) >= 0) {
switch (wParam) {
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
printf("C++: LowLevelKeyboardProc - Key pressed\n");
env->CallVoidMethod(hookObj, processKeyID, p->vkCode,
true);
break;
case WM_KEYUP:
case WM_SYSKEYUP:
printf("C++: LowLevelKeyboardProc - Key released\n");
env->CallVoidMethod(hookObj, processKeyID, p->vkCode,
false);
break;
default:
break;
}
}
else {
printf("C++: LowLevelKeyboardProc - Error on the attach current
thread.\n");
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
void MsgLoop() {
MSG message;
while (GetMessage(&message, NULL, 0, 0)) {
TranslateMessage(&message);
DispatchMessage(&message);
}
}
JNIEXPORT void JNICALL Java_HookTest_registerHook(JNIEnv * env, jobject
obj) {
HHOOK hookHandle = SetWindowsHookEx(WH_KEYBOARD_LL,
LowLevelKeyboardProc, hInst, 0);
if (hookHandle == NULL) {
printf("C++: Java_HookTest_registerHook - Hook failed!\n");
return;
}
else {
printf("C++: Java_HookTest_registerHook - Hook successful\n");
}
hookObj = env->NewGlobalRef(obj);
jclass cls = env->GetObjectClass(hookObj);
processKeyID = env->GetMethodID(cls, "processKey", "(IZ)V");
env->GetJavaVM(&jvm);
hookThreadId = GetCurrentThreadId();
MsgLoop();
if (!UnhookWindowsHookEx(hookHandle))
printf("C++: Java_HookTest_registerHook - Unhook failed\n");
else
printf("C++: Java_HookTest_registerHook - Unhook
successful\n");
}
JNIEXPORT void JNICALL Java_HookTest_unRegisterHook(JNIEnv *env,
jobject object) {
if (hookThreadId == 0)
return;
printf("C++: Java_HookTest_unRegisterHook - call
PostThreadMessage.\n");
PostThreadMessage(hookThreadId, WM_QUIT, 0, 0L);
}
Regards