我想使用JNA运行低级键盘挂钩。我改编了一个在JNA contrib文件夹中找到的示例
private static HHOOK keyHook;
private static LowLevelKeyboardProc keyCallback;
public static void main(String[] args) {
final User32 U32 = User32.INSTANCE;
final Kernel32 K32 = Kernel32.INSTANCE;
HMODULE module = K32.GetModuleHandle(null);
keyCallback = (int code, WPARAM wParam, KBDLLHOOKSTRUCT info) -> {
if (code >= 0) {
System.err.println("Key=" + info.vkCode);
if (info.vkCode == 81) {
U32.PostQuitMessage(0);
}
}
long peer = Pointer.nativeValue(info.getPointer());
return U32.CallNextHookEx(keyHook, code, wParam, new LPARAM(peer));
};
keyHook = U32.SetWindowsHookEx(WH_KEYBOARD_LL, keyCallback, module, 0);
System.out.println("Hook installed, type anywhere, 'q' to quit");
MSG msg = new MSG();
while (U32.GetMessage(msg, null, 0, 0) > 0) {
U32.TranslateMessage(msg);
U32.DispatchMessage(msg);
}
U32.UnhookWindowsHookEx(keyHook);
}
这按预期工作。但是现在,我想在线程中运行消息循环,以避免阻塞我的应用程序。天真的方法是
Executor thread = Executors.newSingleThreadExecutor();
thread.execute(() -> {
int result;
MSG msg = new MSG();
while ((result = U32.GetMessage(msg, null, 0, 0)) > 0) {
U32.TranslateMessage(msg);
U32.DispatchMessage(msg);
}
U32.UnhookWindowsHookEx(keyHook);
});
不幸的是,这不起作用。回调不再被调用,系统上的键盘输入开始大量滞后。如何正确处理我的消息循环?我想我需要找到线程ID并将其传递给SetWindowsHookEx
而不是0,但是如何获取该ID?
编辑:我通过将整个钩子注册和消息循环封装在一个线程中,尝试了一种不同的方法。回调现在可以正常工作,但是PostQuitMessage
似乎没有将消息发布到正确的队列,并且无法停止线程。 PostThreadMessage(0, User32.WM_QUIT, null, null)
在这种情况下也不起作用。