Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Windows低级密钥挂钩停止工作-不是超时问题_Java_Hook_Jna - Fatal编程技术网

Java Windows低级密钥挂钩停止工作-不是超时问题

Java Windows低级密钥挂钩停止工作-不是超时问题,java,hook,jna,Java,Hook,Jna,问题 我正在实现一个Java程序,它通过JNA使用一个低级键钩子。在最初的几次运行中,一切正常,但在一些运行之后,挂钩停止工作,只有在我重新启动计算机时才能再次工作。 -附加细节:在这种情况下,“停止工作”意味着钩子检测到第一个按键下降事件,而没有其他事件(甚至是相应的按键上升事件) 已尝试的潜在根本原因 1-钩子超时->显然,Windows 7存在一些无法解释的行为,Windows通过这些行为删除钩子。如果是这样的话,重启应用程序和钩子会“压迫”它,但事实并非如此。 2-钩子过多->起初,我没

问题
我正在实现一个Java程序,它通过JNA使用一个低级键钩子。在最初的几次运行中,一切正常,但在一些运行之后,挂钩停止工作,只有在我重新启动计算机时才能再次工作。
-附加细节:在这种情况下,“停止工作”意味着钩子检测到第一个按键下降事件,而没有其他事件(甚至是相应的按键上升事件)

已尝试的潜在根本原因
1-钩子超时->显然,Windows 7存在一些无法解释的行为,Windows通过这些行为删除钩子。如果是这样的话,重启应用程序和钩子会“压迫”它,但事实并非如此。
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()
调用。

在JNA中,安装新的钩子时,通常应该调用以前的钩子。我怀疑这是您的问题的原因,但建议您这样做。包括您的注销代码。这可能就是你的问题所在。非常感谢你的快速回复,Technomage。我已经在打下一个钩子了(我怀疑这是否是你所说的“前一个钩子”,如果我误解了你,请纠正我)。我包括了下一个钩子调用和注销过程的代码。从钩子中调用
System.exit()
可能是不可取的(或者除了存储数据之外,执行很多其他操作)。您可以尝试简单地设置一个标志,让另一个线程处理钩子的移除和清理。如果您担心钩子在此期间被调用,它可以保存一个内部
禁用
标志。谢谢,Technomage!现在它工作得很好!我更改了您指出的内容和其他细节(例如,使用Thread.start()而不是SwingUtilities.invokeLater()),以使代码更接近您提供的示例。