在Java中监听没有焦点的input

我使用Robot类在Java中制作一个小程序。 程序接pipe了鼠标。 而在debugging的过程中,如果它开始行动,我不希望它很难退出程序,因为我不能移动鼠标到eclipse中的终止button,我不能使用热键打它,因为鼠标是不断点击另一个窗口,而不是重点窗口。

我想要做的就是挂上一个keylistener,这样当我打q时,我可以退出程序,但是我知道如何做到这一点的唯一方法就是创build一个窗口,并且该窗口需要重点来捕获input。 有没有办法从任何地方听取键盘或鼠标input,无论焦点是什么?

这不是一个微不足道的问题,Java并没有给你一个优雅的方法。 您可以使用像banjollitybuild议的解决scheme,但即使这不会一直工作,如果你错误的鼠标点击打开另一个目前在任务栏中打开的全尺寸的窗口。

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

所以要回答你的问题,我想你想要什么是你的程序在全球范围内监听按键的某种行为,而不仅仅是在你的应用程序中。 像这样的东西需要你访问你所select的操作系统所提供的function,并且要用Java来访问它,你需要通过Java Native Interface(JNI)层来完成。

所以你想要做的是:

  1. 在C语言中实现一个程序,在你的操作系统上监听全局按键,如果这个操作系统是Windows,而不是在Windows和Windows上查找文档,那么在Web和其他地方就可以很好的通过微软和MSDN的文档了解。 如果您的操作系统是Linux或Mac OS X,那么您将需要使用X11开发库来监听全局按键。 这可以根据我在http://ubuntuforums.org/showthread.php?t=864566上写的Howto在ubunutu linux distro上完成

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

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

有一个图书馆为你做了很多努力: https : //github.com/kwhat/jnativehook

有同样的问题。 在我的情况下,机器人只是控制一个单一的Windows应用程序,这是最大化。 我把这些线放在驱动机器人的主循环的顶部:

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

如果(iconCenterColor.equals(robot.getPixelColor(10,15)))抛出新的IllegalStateException(“机器人不与正确的应用程序交互”);

要取消机器人,只需alt-tab到另一个应用程序。 适用于一款简单的应用程序驱动机器人。

让程序打开第二个窗口,它显示在主窗口下方,但是被最大化了,然后你的错误的鼠标点击将全部被最大化的窗口接收,并且它可以接收你的键盘input。

下面是一个纯Java的方法来解决你所描述的问题(而不是KeyListener问题…在使用机器人问题时早期退出testing):

在整个testing过程中,将鼠标位置与您的testing最近设置的位置进行比较。 如果不匹配,退出testing。 注意:这段代码的重要部分是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(px != x2 || py != y2) throw new ExitEarlyException(); } 

从terminal的命令行启动程序,并使用Ctrl-C来终止它。