Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.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 Swing应用程序线程被JNA锁定_Java_Multithreading_Swing_Awt_Jna - Fatal编程技术网

Java Swing应用程序线程被JNA锁定

Java Swing应用程序线程被JNA锁定,java,multithreading,swing,awt,jna,Java,Multithreading,Swing,Awt,Jna,我在Windows10上安装了Swing应用程序。此外,我还添加了低级键盘挂钩,它应该拦截键盘事件,并将例如“z”重新映射到“s”按钮 这是挂接java应用程序外部的键盘事件所必需的。我已经使用JNA版本5.6.0和JNA平台版本5.6.0实现了它。它工作正常,但在我的Swing应用程序中不起作用 我的问题是,当挂钩打开时,swing应用程序会被锁定。我不能按任何Jbutton,甚至根本不能关闭Jframe 我的猜测是它与线程有关,但我在线程和多线程方面非常弱 可复制示例。 TestFrame类

我在Windows10上安装了Swing应用程序。此外,我还添加了低级键盘挂钩,它应该拦截键盘事件,并将例如“z”重新映射到“s”按钮

这是挂接java应用程序外部的键盘事件所必需的。我已经使用JNA版本5.6.0和JNA平台版本5.6.0实现了它。它工作正常,但在我的Swing应用程序中不起作用

我的问题是,当挂钩打开时,swing应用程序会被锁定。我不能按任何Jbutton,甚至根本不能关闭Jframe

我的猜测是它与线程有关,但我在线程和多线程方面非常弱

可复制示例。

TestFrame类:

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class TestFrame extends JFrame {

    public static void main(String [] args) {
        TestFrame frame = new TestFrame();

        JTextField textField=new JTextField();
        textField.setBounds(50,50, 150,20);

        JButton button=new JButton("Click Here");
        button.setBounds(50,100,95,30);

        button.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                ReMapper reMapper = new ReMapper();
                reMapper.reMapOn();
                textField.setText("Is my frame locked?");
            }
        });
        frame.add(button);
        frame.add(textField);
        frame.setSize(400,400);
        frame.setLayout(null);
        frame.setVisible(true);
    }
}
重新映射类:

import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.*;

public class ReMapper {

    private static WinUser.HHOOK hHook;
    final User32 user32Library = User32.INSTANCE;
    WinDef.HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null);
    static WinUser.INPUT input = new WinUser.INPUT();
    
    public void reMapOn() {
        WinUser.LowLevelKeyboardProc keyboardHook = new WinUser.LowLevelKeyboardProc() {

            @Override
            public WinDef.LRESULT callback(int nCode, WinDef.WPARAM wParam, WinUser.KBDLLHOOKSTRUCT kbDllHookStruct) {
                if (nCode >= 0) {
                    if (wParam.intValue() == WinUser.WM_KEYDOWN) {
                        if (kbDllHookStruct.vkCode == 90) { // 90 is key code = z
                            sendKey(83);            // 83 is key code = s
                            return new WinDef.LRESULT(1);
                        }
                    }
                }
                Pointer ptr = kbDllHookStruct.getPointer();
                long peer = Pointer.nativeValue(ptr);
                return user32Library.CallNextHookEx(hHook, nCode, wParam, new WinDef.LPARAM(peer));
            }
        };

        hHook = user32Library.SetWindowsHookEx(WinUser.WH_KEYBOARD_LL, keyboardHook, hMod, 0);

        int result;
        WinUser.MSG msg = new WinUser.MSG();
        while ((result = user32Library.GetMessage(msg, null, 0, 0)) != 0) {
            if (result == -1) {
                break;
            } else {
                user32Library.TranslateMessage(msg);
                user32Library.DispatchMessage(msg);
            }
        }
    }

    static void sendKey(int keyCode) {
        input.type = new WinDef.DWORD(WinUser.INPUT.INPUT_KEYBOARD);
        input.input.setType("ki"); // Because setting INPUT_INPUT_KEYBOARD is not enough: https://groups.google.com/d/msg/jna-users/NDBGwC1VZbU/cjYCQ1CjBwAJ
        input.input.ki.wScan = new WinDef.WORD(0);
        input.input.ki.time = new WinDef.DWORD(0);
        input.input.ki.dwExtraInfo = new BaseTSD.ULONG_PTR(0);
// Press
        input.input.ki.wVk = new WinDef.WORD(keyCode); // 0x41
        input.input.ki.dwFlags = new WinDef.DWORD(0);  // keydown

        User32.INSTANCE.SendInput(new WinDef.DWORD(1), (WinUser.INPUT[]) input.toArray(1), input.size());

// Release
        input.input.ki.wVk = new WinDef.WORD(keyCode); // 0x41
        input.input.ki.dwFlags = new WinDef.DWORD(2);  // keyup

        User32.INSTANCE.SendInput(new WinDef.DWORD(1), (WinUser.INPUT[]) input.toArray(1), input.size());
    }
}
以下是单击“单击此处”按钮后锁定Jframe的屏幕:

重新映射类与Swing应用程序分开运行时效果良好

reMapOn()
允许将“z”重新映射到“s”。但我需要它在我的Swing应用程序中工作,而不是阻止它


有人知道问题可能是什么以及如何解决吗?

查看您的
reMapOn
代码,它有一个while循环,这表明它可能无限期运行并阻塞应用程序UI

只需在
addActionListener
方法中调用自己线程上的
reMapOn
方法。这可以使用简单的或:

Swing Worker示例(首选解决方案,因为当重新映射结束时,您可以覆盖
done
并在该方法中根据需要操作Swing组件):

其他几点是:

  • 不要使用
    null
    /
    绝对布局
    而是使用适当的
  • 不要在组件上调用
    setBounds()
    setSize()
    ,如果您使用正确的布局管理器,这将为您处理
  • 调用
    JFrame#pack()
    ,然后使用
    LayoutManager将框架设置为可见
  • 不要不必要地扩展
    JFrame
  • 所有Swing组件都应该在via
    SwingUtilities.invokeLater上调用

  • 谢谢你的帮助。现在它就像一个符咒:)很高兴帮助人类!
    new SwingWorker<Void, Void>() {
        @Override
        protected Void doInBackground() throws Exception {
            ReMapper reMapper = new ReMapper();
            reMapper.reMapOn();
            return null;
        }
        
    }.execute();
    textField.setText("Is my frame locked?");
    
    new Thread(() -> {
        ReMapper reMapper = new ReMapper();
        reMapper.reMapOn();
    }).start();
    textField.setText("Is my frame locked?");