Secuestrar una tecla con java

619 views
Skip to first unread message

Foex

unread,
Jul 26, 2007, 12:54:34 PM7/26/07
to JavaSOS
Buenas... Primero que nada contarles que soy nuevo aqui. Les cuento
que soy muy nuevo con java asi que estoy recien aprendiendo pero de
todos modos tratare de colaborar en todo lo que pueda :D


Mi consulta es la siguiente:

Tengo una aplicacion que genera un evento cuado se presiona una tecla.
El problema es que para que genere el evento cuando presiono dicha
tecla, tengo que tener seleccionada la aplicacion (ventana), pero
necesito que reaccione ahun cuando la tenga deseleccionada.... se
entiende??

Por ejemplo: la aplicacion cuando presiono la tecla f11, ejecuta un
evento de un modulo separado que emite un sonido. Esto funciona
siempre en cuando la tenga seleccionada.

Yo necesito que si tengo cualquier otra ventana seleccionada como un
notepad por ejemplo, y presiono f11, mi aplicacion tambien emita un
sonido, osea que a pesar de no tener seleccionada mi aplicacion, esta
de todos modos escuche la tecla f11.

Les dejo el codigo para que vean que es lo que tengo andando. Les
reitero que funciona perfectamente cuando selecciono la aplicacion.

Desde ya mil gracias por las respuestas.
Saludos.


----------------------------------------------------------------------------------------------------------------------
Codigo:
----------------------------------------------------------------------------------------------------------------------

package sc.keyImpulse;

import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JFrame;

public class KeyListener {

private JFrame parent;
private IPulseListenerKey parentI;

public KeyListener(IPulseListenerKey parent){
this.parent = (JFrame)parent;
parentI = parent;
initiate();
}

private void initiate(){
parent.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == 121) {
parentI.actionMade();
}
}
});

parent.addFocusListener(new FocusAdapter() {
public void focusLost(FocusEvent arg0) {
parent.requestFocus();
}
});
}
}

----------------------------------------------------------------------------------------------------------------------

Esteban Cabezudo

unread,
Jul 27, 2007, 5:38:17 AM7/27/07
to jav...@googlegroups.com
En los entornos de ventanas que conozco siempre tiene que estar
seleccionada la ventana para que esta responda al evento. Por otro lado
los eventos se propagan en la jerarquía de objetos. Esto quiere decir
que si presionas una tecla el objeto que tiene el foco la procesa y la
propaga al superior. Para que lo que quieres funcione tienes que
capturar el evento en un objeto superior a el que tiene el foco (siempre
y cuando este o alguno en el camino no impida la propagación del
evento). Lamentablemente esto solo lo podrías hacer programando sobre el
sistema de ventanas donde tu aplicación Java está funcionando y eso se
escapa a Java y al objetivo de esta lista.
Como una solución te diré que podrías hacer que el entorno de ventanas
ejecute una aplicación Java al presionar la tecla y esta se puede
conectar a tu aplicación para que le transfiera el evento.
No me parece una buena solución pero creo que no hay mas que hacer si lo
quieres programar en Java.
Puedas también utilizar procesos nativos y hacer que la aplicación
cuando arranque capture mediante la API del entorno de ventanas el
evento para procesarlo, pero eso ya no sería multiplataforma y tienes
que conocer la API del entorno de ventanas utilizado. Todo depende del
tiempo que que quieras perder estudiando.
Saludos.


--
http://www.java.cabezudo.net

Dream Tangerine

unread,
Jul 27, 2007, 10:37:47 AM7/27/07
to jav...@googlegroups.com
Una pista para windows

mirate la función SetWindowsHookEx, con lso flags WH_KEYBOARD y WH_KEYBOARD_LL

Un saludo.

Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to build bigger and better idiots. So far, the universe is winning. Robert Cringley (columnist, author, host of "Triumph of the Nerds")

> Date: Fri, 27 Jul 2007 04:38:17 -0500
> From: est...@cabezudo.net
> To: jav...@googlegroups.com
> Subject: [JavaSOS] Re: Secuestrar una tecla con java

Foex

unread,
Jul 28, 2007, 10:11:14 AM7/28/07
to JavaSOS
Bueno... les cuento como resolvi.

Resulta que la solucion no la tiene java. Lo que necesitaba yo es una
solucion de mas bajo nivel para lo cual java no esta diseñado.
Entonces me acorde de los famosos y odiosos (en algunos casos)
KeyLoggers. Todos me imagino los conocen. Son esos programitas que te
escuchan el teclado todo el tiempo y guardan contraseñas y eso. Y eso
es lo que necesitaba yo, escuchar el teclado hasta que se precione lo
que preciso y en ese momento ejecutar una accion....
Busque entonces como hacer KeyLoggers en inet. No importaba la
tecnologia, solo que se pudiera hacer y encontre un par de codigos
para c++. Note que estos codigos no hacen mas que llamar a la dll
user32.dll de windows. Esta tiene un metodo que se llama
GetAsyncKeyState que lo que hace es informar acerca del estado de una
tecla, si esta presionada o no...
Aqui es donde se resuelve todo. Lo unico que hice fue empezar a llamar
a esta dll desde Java en un thread independiente y cuando esta me
informa que se presiono la tecla emito un evento...

Asi de sensillo.

Lo unico malo es que pierdo la posibilidad de instalar el soft en
linux por ejemplo ya que para que funciones es concicion necesaria que
llame a esta dll pero eso se arregla con un modulo para linux y listo.

ahora no tengo el codigo de lo que resolvi en esta pc pero en cuanto
lo tenga lo posteo para que lo vean. a alguien quizas le pueda
resultar util.

saludos y gracias por las respuestas.

Bruno Bonanno

unread,
Jul 28, 2007, 8:25:31 PM7/28/07
to jav...@googlegroups.com
No genera eso una espera activa, con la consecuente perdida de rendimiento?

--
ATTE
Bruno Bonanno
15-5462-3775
-

Foex

unread,
Jul 29, 2007, 8:35:37 PM7/29/07
to JavaSOS
el modulo que espera que se presione la tecla es un thread
independiente. es un if que esta llamando a la dll constantemente. si
puede que se pierda un podo el rendimiento pero no es significativo en
comparacion en el tamaño del modulo...

Daniel

unread,
Jul 30, 2007, 8:19:11 AM7/30/07
to JavaSOS
muy buena la solucion que obtuviste!
nos podrias compartir el codigo cuando lo tengas?
Gracias!

Bruno Bonanno

unread,
Jul 29, 2007, 11:03:55 PM7/29/07
to jav...@googlegroups.com
estube googleando un poco y veo q la forma es justamente al reves, hay formas de crear clases en c++ y registrarlas en la API de windows para q cuando presionas una "global hot key" se dispare un evento q llame a esa clase, luego en esa clase deberias llamar por JNI a tu aplicacion java, de esta forma usas el modelo de eventos tradicional y te evitas esa espera activa, q es una de las cosas q debe uno intentar evitar, ya q por mas q no parezca, el consumo de sistema q se genera ante el thread-swich genera siempre overhead
espero haberte ayudado

saludos

Bruce

Foex

unread,
Jul 30, 2007, 9:08:14 AM7/30/07
to JavaSOS
Aqui les dejo el codigo de un ejemplo que implemente para testear si
funcionaba la idea. Utilizo una api que se llama NativeCall, que me
permite invocar dll's del sistema operativo sin necesidad de utilizar
JNI. El diseñador de esta api es Johann Burkard, un tipo muy amable
que me contesto unas consultas por email en unos minutos, la verdad
que de primera... y la api resulta de verdad muuuuy util. Tambien les
dejo el link al site de este joven...

http://johannburkard.de/software/nativecall/

Aqui las dos clases del ejemplo. Este lo unico que hace es mostrales
una ventanita con un boton que cuando lo presionan ejecuta el thread
que espera el pulso de la tecla. Cuando la app detecta que se presiono
la tecla que pidieron muestra un mensaje de "tecla presionada" en el
cuadro de texo de la app y en la consola de java.
Al ejemplo le tenemos que decir el codigo de la tecla que
escucharemos. Es un long y lo podemos obtener con un ejemplo de
keylistener que nos da java en este link:
http://java.sun.com/docs/books/tutorial/uiswing/events/keylistener.html

Cualquier consulta no duden en postearla.
Mil gracias a todos los que sugirieron soluciones.
Saludos.


------------------------------------------------------------------------------------------------------------------------------------
El codigo:
------------------------------------------------------------------------------------------------------------------------------------

package test;

import java.io.IOException;
import javax.swing.JTextField;
import com.eaio.nativecall.IntCall;
import com.eaio.nativecall.NativeCall;

public class Procces implements Runnable{

private JTextField salida;

public Procces(JTextField pSalida){
salida = pSalida;
}

public void run() {
comienzo();
}

public void comienzo (){

System.out.println ("...1");
try {
NativeCall.init();
} catch (UnsupportedOperationException ex) {
ex.printStackTrace();
} catch (UnsatisfiedLinkError ex) {
ex.printStackTrace();
} catch (SecurityException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
} catch (sun.misc.ServiceConfigurationError ex) {
ex.printStackTrace();
}

System.out.println ("...2");

IntCall listen = new IntCall("user32.dll",
"GetAsyncKeyState");

System.out.println ("...3");
System.out.println ("");

boolean continuar = true;

while (continuar){
if (listen.executeCall(new Object[] {16}) != 0){
System.out.println("Tecla presionada");
this.salida.setText("Tecla presionada");
try{
Thread.currentThread().sleep(100);
}catch(InterruptedException e){
//no hago nada :P
}
this.salida.setText("");


}
}

listen.destroy();

System.out.println ("");
System.out.println ("finalizado");

}

}

------------------------------------------------------------------------------------------------------------------------------------

package test;

import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JTextField;
import javax.swing.WindowConstants;

public class Main {

private JFrame v;
private JButton b;
private JTextField text;
private JTextField resultado;
private Thread t = new Thread();

/** Creates a new instance of Main */
public Main() {
v = new JFrame("Nueva ventana de prueba");
v.getContentPane().setLayout(new FlowLayout());

b = new JButton("Presionar para comenzar escucha");
v.getContentPane().add(b);

text = new JTextField(15);
v.getContentPane().add(text);

resultado = new JTextField(15);
v.getContentPane().add(resultado);

b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
text.setText("Esperando tecla...");
System.out.println("Comienza escucha del teclado");
resultado.setText("");
test();
}
});

v.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
v.setBounds(520, 400, 300, 150);
v.setVisible(true);
}

public static void main(String[] args) {
new Main();
}

public void test(){
if (t.isAlive()){
t.stop();
}
t = new Thread(new Procces(this.resultado));
t.start();
}
}

------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------

Foex

unread,
Jul 30, 2007, 9:08:14 AM7/30/07
to JavaSOS

Bruno Bonanno

unread,
Jul 29, 2007, 11:03:55 PM7/29/07
to jav...@googlegroups.com
estube googleando un poco y veo q la forma es justamente al reves, hay formas de crear clases en c++ y registrarlas en la API de windows para q cuando presionas una "global hot key" se dispare un evento q llame a esa clase, luego en esa clase deberias llamar por JNI a tu aplicacion java, de esta forma usas el modelo de eventos tradicional y te evitas esa espera activa, q es una de las cosas q debe uno intentar evitar, ya q por mas q no parezca, el consumo de sistema q se genera ante el thread-swich genera siempre overhead
espero haberte ayudado

saludos

Bruce

On 7/29/07, Foex <fo...@montevideo.com.uy> wrote:

Daniel

unread,
Jul 30, 2007, 3:21:22 PM7/30/07
to JavaSOS
Foex, muchas gracias 5 estrellas!

Foex

unread,
Jul 30, 2007, 5:14:31 PM7/30/07
to JavaSOS
Es tal cual como tu dices bruno, pero esta solucion es lo primero que
se me ocurrio y bueno... no estoy con los tiempos como para investigar
mucho mas, jejeje, ademas de que soy bastante novato en esto de la
programacion y me llevaria mas tiempo del planeado poder agregar esa
funcionalidad a la api de windows.
Estuve repasando el codigo de todas formas y ese while que espera que
se presione la tecla es realmente poco performante. lo modifique un
poco y ahora consume la cuarta parte de los recursos que en un
principio. Ahora no tengo los codigos aqui pero cuando este en la
oficina mañana los posteare.
Saludos.

Reply all
Reply to author
Forward
0 new messages