Escuchando por entrada sin foco en Java

Estoy haciendo un pequeño progtwig en Java usando la clase Robot. El progtwig toma el control del mouse. mientras estoy depurando si comienza a actuar de una manera que no quiero que sea difícil salir del progtwig, ya que no puedo mover el mouse hasta el botón de terminar en eclipse, y no puedo usar las teclas rápidas para golpéelo porque el mouse está constantemente haciendo clic en otra ventana, dando ese foco de ventana en su lugar.

Lo que me gustaría hacer es simplemente conectar un keylistener para que cuando presiono q pueda salir del progtwig, pero la única forma en que sé cómo hacer esto implica hacer una ventana, y esa ventana necesita enfoque para capturar la entrada. ¿Hay alguna manera de escuchar la entrada del teclado o el mouse desde cualquier lugar, independientemente de lo que tenga foco?

Este no es un problema trivial y Java no te da una manera de hacerlo elegantemente. Puede utilizar una solución como banjollity sugerida, pero incluso eso no funcionará todo el tiempo si su mouse errante hace clic para abrir otra ventana de tamaño completo actualmente abierta en su barra de tareas, por ejemplo.

El hecho es que Java por defecto le da a los desarrolladores muy poco control sobre el sistema operativo. Esto se debe a dos razones principales: la seguridad (como lo indica la documentación de Java) y el hecho de que diferentes sistemas operativos manejan los eventos de forma completamente diferente y hacer que un modelo unificado para representar todos estos no tenga mucho sentido.

Entonces, para responder a su pregunta, me imagino que lo que desea es algún tipo de comportamiento para su progtwig en el que escucha las pulsaciones de teclas de forma global, no solo en su aplicación. Algo así requerirá que acceda a la funcionalidad ofrecida por su sistema operativo de su elección, y para acceder a ella en Java necesitará hacerlo a través de una capa Java Native Interface (JNI).

Entonces, lo que quieres hacer es:

  1. Implemente un progtwig en C que escuche las pulsaciones de teclas globales en su sistema operativo, si este sistema operativo es Windows, en lugar de buscar la documentación en Windows hooks, que está bien documentado por Microsoft y MSDN en la web y en otros lugares. Si su sistema operativo es Linux o Mac OS X, tendrá que escuchar las pulsaciones de tecla globales utilizando las bibliotecas de desarrollo X11. Esto se puede hacer en una distribución ubunutu linux según un Howto que escribí en http://ubuntuforums.org/showthread.php?t=864566

  2. Conecta tu código C a tu código Java a través de JNI. Este paso es realmente el paso más fácil. Siga el procedimiento que uso en mi tutorial en http://ubuntuforums.org/showthread.php?t=864566 bajo Windows y Linux, ya que el procedimiento para conectar su código C a su código Java será idéntico en ambos sistemas operativos.

Lo importante a recordar es que es mucho más fácil hacer funcionar su código JNI si primero codifica y depura su código C / C ++ y se asegura de que esté funcionando. Entonces, integrarlo con Java es fácil.

Hay una biblioteca que hace el trabajo duro por usted: https://github.com/kwhat/jnativehook

Tenía el mismo problema. En mi caso, el robot solo controló una sola aplicación de Windows, que se maximizó. Coloqué estas líneas en la parte superior del lazo principal manejando el robot:

Color iconCenterColor = new Color (255,0,0); // si el icono del progtwig es rojo

if (iconCenterColor.equals (robot.getPixelColor (10,15))) lanza una nueva IllegalStateException (“robot que no interactúa con la aplicación correcta”);

Para cancelar el robot, simplemente alt-tab a otra aplicación. Funciona muy bien para un simple robot de manejo de una aplicación.

Inicie el progtwig desde una línea de comando en un terminal y use Ctrl-C para terminarlo.

Haga que su progtwig abra una segunda ventana que se muestra debajo de su ventana principal, pero que está maximizada, luego sus clics erróneos con el mouse serán recibidos por la ventana maximizada, y puede recibir su entrada de teclado.

Aquí hay una forma pura de Java de hacerlo para resolver el problema que ha descrito (no el problema de KeyListener … la prueba de abandono temprano cuando se usa el problema del robot):

A lo largo de su prueba, compare la posición del mouse con una que su prueba haya establecido recientemente. Si no coincide, abandone la prueba. Nota: la parte importante de este código es el método testPosition . Aquí está el código que utilicé recientemente:

 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(); }