java - 在线程中运行消息循环
问题描述
我想使用 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)
在这种情况下也不起作用。
解决方案
我发现该解决方案实际上已经由 JNA 平台在User32Util.MessageLoopThread中提供
推荐阅读
- android - 某些三星设备的屏幕录制输出失真
- express - res.status 在 promise 函数中未定义
- amazon-web-services - AWS ARN 的最大长度是多少?
- java - 在注册码中加入一层密码校验码
- machine-learning - 如何将长句子分解为 5 到 10 个单词的句子并使用 LSTM 取得良好的效果?
- python - 如何按指定标准对 zip 对象列表进行排序?
- python - 使用 python ElementTree 我想找到所有标题
- angular - 使用角度路由器无法显示页面顶部
- java - 了解 HotSpot 中的通知方法
- go - 在 go 中将切片长度与 uint32 进行比较的最佳方法(用于对抗性上下文)