Windows 低级键挂钩停止工作 - 不是超时问题
Windows low level key hook stops working - not a timeout issue
问题
我正在实施一个 Java 程序,该程序通过 JNA 使用低级键挂钩。前几次运行一切正常,但在一些运行后挂钩停止工作,只有在我重新启动计算机时才能再次工作。
- 额外的细节:'stops working' 在这种情况下意味着挂钩检测到第一个按键事件而不是其他事件(甚至是相应的按键事件)
已经尝试过潜在的根本原因
1 - 挂钩超时 -> 显然,有一些无法解释的 Windows 7 行为 Windows 删除了一个挂钩。如果是这种情况,重新启动应用程序和挂钩将 'ressurect' 它 - 但事实并非如此。
2 - 钩子过多 -> 起初,我没有从之前的运行中删除我的钩子。现在我只是在删除钩子后才结束应用程序,但问题仍然存在。
代码
[...]
public static void start() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
lib = User32.INSTANCE;
HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null);
ll = new MyLowLevelKeyboardProc();
hook = lib.SetWindowsHookEx(WinUser.WH_KEYBOARD_LL, ll, hMod, 0);
// We must maintain this code to keep the listener thread alive
MSG msg = new MSG();
while (lib.GetMessage(msg, null, 0, 0) != 0) {
System.out.println("cycle");
}
finish();
}
});
}
[...]
static class MyLowLevelKeyboardProc implements LowLevelKeyboardProc {
@Override
public LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT info) {
if (nCode >= 0) {
switch (wParam.intValue()) {
case WinUser.WM_SYSKEYUP:
case WinUser.WM_KEYUP:
System.out.println("KEY_UP");
if (AppConfig.DEBUG_MODE) {
if (info.vkCode == WindowsKeys.WK_Q.value()) {
finish();
System.exit(0);
}
}
default:
break;
}
}
return lib.CallNextHookEx(hook, nCode, wParam, info.getPointer());
}
public static void finish() {
if (lib != null) {
lib.UnhookWindowsHookEx(hook);
}
}
关键是钩子尽量少做。设置一个标志,然后在另一个线程上执行 System.exit()
调用。
问题
我正在实施一个 Java 程序,该程序通过 JNA 使用低级键挂钩。前几次运行一切正常,但在一些运行后挂钩停止工作,只有在我重新启动计算机时才能再次工作。
- 额外的细节:'stops working' 在这种情况下意味着挂钩检测到第一个按键事件而不是其他事件(甚至是相应的按键事件)
已经尝试过潜在的根本原因
1 - 挂钩超时 -> 显然,有一些无法解释的 Windows 7 行为 Windows 删除了一个挂钩。如果是这种情况,重新启动应用程序和挂钩将 'ressurect' 它 - 但事实并非如此。
2 - 钩子过多 -> 起初,我没有从之前的运行中删除我的钩子。现在我只是在删除钩子后才结束应用程序,但问题仍然存在。
代码
[...]
public static void start() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
lib = User32.INSTANCE;
HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null);
ll = new MyLowLevelKeyboardProc();
hook = lib.SetWindowsHookEx(WinUser.WH_KEYBOARD_LL, ll, hMod, 0);
// We must maintain this code to keep the listener thread alive
MSG msg = new MSG();
while (lib.GetMessage(msg, null, 0, 0) != 0) {
System.out.println("cycle");
}
finish();
}
});
}
[...]
static class MyLowLevelKeyboardProc implements LowLevelKeyboardProc {
@Override
public LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT info) {
if (nCode >= 0) {
switch (wParam.intValue()) {
case WinUser.WM_SYSKEYUP:
case WinUser.WM_KEYUP:
System.out.println("KEY_UP");
if (AppConfig.DEBUG_MODE) {
if (info.vkCode == WindowsKeys.WK_Q.value()) {
finish();
System.exit(0);
}
}
default:
break;
}
}
return lib.CallNextHookEx(hook, nCode, wParam, info.getPointer());
}
public static void finish() {
if (lib != null) {
lib.UnhookWindowsHookEx(hook);
}
}
关键是钩子尽量少做。设置一个标志,然后在另一个线程上执行 System.exit()
调用。