在 Java 中没有焦点地监听输入

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/901224/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 20:50:29  来源:igfitidea点击:

Listening for input without focus in Java

javakeylistener

提问by Alex

I'm making a small program in Java using the Robot class. The program takes over the mouse. while in the course of debugging if it starts acting in a way that I don't want it's hard to quit the program, since I can't move the mouse over to the terminate button in eclipse, and I can't use hotkeys to hit it because the mouse is constant clicking in another window, giving that window focus instead.

我正在使用 Robot 类在 Java 中制作一个小程序。该程序接管鼠标。在调试过程中,如果它开始以我不希望的方式运行,则很难退出程序,因为我无法将鼠标移到 eclipse 中的终止按钮上,并且我无法使用热键击中它是因为鼠标在另一个窗口中不断点击,而不是让该窗口获得焦点。

What I'd like to do is just hook up a keylistener so that when I hit q I can quit the program, but the only way I know how to do this involves making a window, and that window needs focus to capture the input. Is there a way to listen for keyboard or mouse input from anywhere, regardless of what has focus?

我想要做的只是连接一个键侦听器,这样当我点击 q 时我就可以退出程序,但我知道如何做到这一点的唯一方法是创建一个窗口,而该窗口需要焦点来捕获输入。有没有办法从任何地方监听键盘或鼠标输入,而不管什么有焦点?

采纳答案by ldog

This is not a trivial problem and Java doesn't give you a way to do it elegantly. You can use a solution like banjollity suggested but even that won't work all the time if your errant mouse clicks open another fullsized window currently open in your taskbar for example.

这不是一个微不足道的问题,Java 没有给你优雅的方法。您可以使用建议的 banjollity 之类的解决方案,但如果您错误的鼠标点击打开另一个当前在任务栏中打开的全尺寸窗口,即使这样也不会一直有效。

The fact is, Java by default gives developers very little control over the OS. This is due to 2 main reasons: security (as citied by java documentation) and the fact that different operating systems handle events completely differently and making one unified model to represent all of these would probably not make a whole lot of sense.

事实是,默认情况下,Java 给开发人员很少的操作系统控制权。这是由于两个主要原因:安全性(如 java 文档所引用)以及不同操作系统处理事件的方式完全不同的事实,并且制作一个统一模型来表示所有这些可能没有多大意义。

So to answer your question, I imagine what you want is some kind of behaviour for your program where it listens for keypresses globally, not just in your application. Something like this will require that you access the functionality offered by your OS of choice, and to access it in Java you are going to need to do it through a Java Native Interface (JNI) layer.

所以为了回答你的问题,我想你想要的是你的程序的某种行为,它在全球范围内侦听按键,而不仅仅是在你的应用程序中。像这样的事情将要求您访问您选择的操作系统提供的功能,而要在 Java 中访问它,您将需要通过 Java 本机接口 (JNI) 层来完成。

So what you want to do is:

所以你想做的是:

  1. Implement a program in C that will listen for global keypresses on your OS, if this OS is Windows than look for documentation on windows hooks which is well docuemented by Microsoft and MSDN on the web and other places. If your OS is Linux or Mac OS X then you will need to listen for global keypresses using the X11 development libraries. This can be done on an ubunutu linux distro according to a Howto that I wrote at http://ubuntuforums.org/showthread.php?t=864566

  2. Hook up your C code to your Java code through JNI. This step is actually the easier step. Follow the procedure that I use in my tutorial at http://ubuntuforums.org/showthread.php?t=864566under both windows and linux as the procedure for hooking up your C code to your Java code will be identical on both OSes.

  1. 在 C 中实现一个程序,该程序将在您的操作系统上侦听全局按键,如果该操作系统是 Windows,那么请查找有关 Windows 挂钩的文档,该文档由 Microsoft 和 MSDN 在网络和其他地方提供了很好的文档。如果您的操作系统是 Linux 或 Mac OS X,那么您将需要使用 X11 开发库监听全局按键。这可以根据我在http://ubuntuforums.org/showthread.php?t=864566 上写的 Howto 在 ubunutu linux 发行版上完成

  2. 通过 JNI 将 C 代码连接到 Java 代码。这一步其实是比较简单的一步。按照我在http://ubuntuforums.org/showthread.php?t=864566 的教程中使用的过程,在 windows 和 linux 下,将 C 代码连接到 Java 代码的过程在两个操作系统上都是相同的。

The important thing to remember is that its much easier to get your JNI code working if you first code and debug your C/C++ code and make sure that it is working. Then integrating it with Java is easy.

要记住的重要一点是,如果您首先编写和调试 C/C++ 代码并确保它正常工作,那么让 JNI 代码工作要容易得多。然后将它与 Java 集成很容易。

回答by Glenn

Start the program from a command line in a terminal and use Ctrl-C to terminate it.

从终端中的命令行启动程序并使用 Ctrl-C 终止它。

回答by banjollity

Have your program open a second window which displays underneath your main window but is maximised, then your errant mouse clicks will all be received by the maximised window, and it can receive your keyboard input.

让您的程序打开第二个窗口,该窗口显示在您的主窗口下方但已最大化,然后您错误的鼠标点击都将被最大化的窗口接收,并且它可以接收您的键盘输入。

回答by user467317

Had same problem. In my case, robot just controlled a single Windows App, that was maximized. I placed these lines at top of main loop driving the robot:

有同样的问题。就我而言,机器人只控制了一个最大化的 Windows 应用程序。我将这些线放在驱动机器人的主循环的顶部:

Color iconCenterColor = new Color(255,0,0); // if program icon is red

颜色 iconCenterColor = 新颜色(255,0,0); // 如果程序图标是红色的

if (iconCenterColor.equals(robot.getPixelColor(10,15))) throw new IllegalStateException("robot not interacting with the right app.");

if (iconCenterColor.equals(robot.getPixelColor(10,15))) throw new IllegalStateException("机器人没有与正确的应用程序交互。");

To cancel the robot, just alt-tab to another app. Works great for a simple one app driving robot.

要取消机器人,只需 alt-tab 到另一个应用程序。非常适合一个简单的应用程序驾驶机器人。

回答by MasterID

There is a library that does the hard work for you: https://github.com/kwhat/jnativehook

有一个库可以为您完成繁重的工作:https: //github.com/kwhat/jnativehook

回答by durron597

Here's a pure Java way to do it to solve the problem you've described (not the KeyListener problem... the quit test early when using robot problem):

这是一种纯 Java 方法来解决您所描述的问题(不是 KeyListener 问题......使用机器人问题时的早期退出测试):

Throughout your test, compare the mouse position with one that your test has recently set it to. If it doesn't match, quit the test. Note: the importantpart of this code is the testPositionmethod. Here's code that I used recently:

在整个测试过程中,将鼠标位置与测试最近设置的位置进行比较。如果不匹配,请退出测试。注意:这段代码的重要部分是testPosition方法。这是我最近使用的代码:

public void testSomething() throws Exception {
    try {
        // snip

        // you can even extract this into a method "clickAndTest" or something
        robot.mouseMove(x2, y2);
        click();
        testPosition(x2, y2);

        // snip
    } catch (ExitEarlyException e) {
        // handle early exit
    }
}

private static void click() throws InterruptedException {
    r.mousePress(InputEvent.BUTTON1_DOWN_MASK);
    Thread.sleep(30 + rand.nextInt(50));
    r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
    Thread.sleep(30 + rand.nextInt(50));
}

private static void testPosition(int x2, int y2) throws ExitEarlyException {
    Point p = MouseInfo.getPointerInfo().getLocation();
    if(p.x != x2 || p.y != y2) throw new ExitEarlyException();
}