Capturar combinaciones de teclas fuera de mí programa

¿Cómo estás?, espero que muy bien.
Estoy desarrollando una aplicación en java y una de sus funciones es capturar el contenido del portapapeles.
Ya hice pruebas del portapapeles(Clipboard) y reconocimiento de combinaciones de teclas(KeyStrokes, map, Actionmap) con éxito, pero lo que yo quiero es que pueda reconocer las combinaciones de teclas(CTRL + C) en todo momento, no solo cuando la aplicación tiene el enfoque. El propósito de esta aplicación de prueba es pegar en la aplicación todo lo que el usuario copie desde cualquier lugar del sistema.
¿Cómo hago para que reconozca las combinaciones de teclas en cualquier parte del sistema?
Nota: Un ejemplo de lo que digo es jdownloader(¿lo conoces?, te lo recomiendo) que puede capturar los enlaces de descarga que el usuario copia.

1 respuesta

Respuesta
1
Ya te traigo la solución, me está quedando de maravilla.
Sinceramente si deseas ver lo es copiado me parece mejor que vigiles al Clipboard (Portapaleles), ya que no siempre se copia con Crtl + C, por ejemplo Clic derecho - copiar, etc.
Otra razón es que JAVA no puede normalmente capturas las teclas fuera de sus ventanas, se puede pero requiere del lenguaje nativo que se basa en otros lenguajes y es más complicado.
Lo que hice fue crear una clases que actúe como Listener. Cuando creas una instancia puedes sobreescribir el método actualizaTexto, permitiendo facilidades de implementación (no es una interfaz).
Primero va la clase del listener:
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.FlavorEvent;
import java.awt.datatransfer.FlavorListener;
import java.awt.datatransfer.Transferable;
/**
 *
 * @author Rodrigo Chaves
 *
 */
public class ClipboardTextListener {
    public void comienzaAEscuchar () {
        Owner owner = new Owner();
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        clipboard.addFlavorListener(new CentinelaFlavor (clipboard) );
        Transferable contents = clipboard.getContents(owner);
        clipboard.setContents(contents, owner);
    }
    class Owner implements ClipboardOwner{
        @Override
        public void lostOwnership(Clipboard clipboard, Transferable contents) {
            try {Transferable newContents = clipboard.getContents(this);
            if (contents.getTransferData(DataFlavor.stringFlavor).
                    equals(newContents.getTransferData(DataFlavor.stringFlavor)))
                return;
            clipboard.setContents(newContents, this);
            textoHaCambiado ( (String) clipboard.getData(DataFlavor.stringFlavor));
            } catch (Exception e) {
                System.out.println ("No fue texto"); //Puedes borrar esto
            }
        }
    }
    class CentinelaFlavor implements FlavorListener {
        private Clipboard c;
        public CentinelaFlavor (Clipboard c) {
            this.c = c;
        }
        public void flavorsChanged(FlavorEvent e) {
            try {
                Owner o = new Owner();
                String nuevaString = (String) c.getContents(o).getTransferData(DataFlavor.stringFlavor);
                c.setContents(c.getContents(o), new Owner() );
                textoHaCambiado ( nuevaString);
            } catch (Exception ex) {System.out.println ("No fue texto 2");/*Puedes borrar este*/ }
        }
    }
    protected void textoHaCambiado(String nuevoTexto) {
    }
}
Ejemplo de implementación:
Tienes un JTextField que se llama campoTexto:
1-Creas el texto : JTextField campoTexto = new JTextField ();
2-Creas el listener y sobreescribes el método textoHaCambiado:
ClipboardTextListener ctl = new ClipboardTextListener () {
            @Override
            protected void textoHaCambiado(String nuevoTexto) {
                campoTexto.setText (nuevoTexto);
            }
        };
3- Le dices al listener que comience a escuchar por si cambian el contenido del Portapapeles.
ctl.comienzaAEscuchar();
Me avisas si tienes dudas.
Finalmente, quiero mostrarte como lo implementé en un proyecto de prueba.
Si ves código extraño es por el Netbeans, el IDE que uso, que genera los textos y los posiciones según quiero.
Lo más importante está en el constructor.
Nota: Si te da algún tipo de error extraño trata de ejecutarlo fuera del IDE. A veces en el IDE da problemas por el Clipboard. Si el problema persiste, me avisas.
public class NewJFrame extends javax.swing.JFrame {
    /** Creates new form NewJFrame */
    public NewJFrame() {
        initComponents();
        ClipboardTextListener ctl = new ClipboardTextListener () {
            @Override
            protected void textoHaCambiado(String nuevoTexto) {
                System.out.println (nuevoTexto);
                actualizaTexto (nuevoTexto);
            }
        };
        ctl.comienzaAEscuchar();
    }
    public void actualizaTexto (String nuevoTexto) {
        if (jTextField1.getText().trim().isEmpty() && nuevoTexto.startsWith("http://"))
                jTextField1.setText(nuevoTexto);
    }
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {
        jTextField1 = new javax.swing.JTextField();
        jLabel1 = new javax.swing.JLabel();
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        jLabel1.setText("Link de descarga");
        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        Layout. SetHorizontalGroup(
            Layout. CreateParallelGroup(javax. Swing. GroupLayout. Alignment. LEADING)
            .AddGroup(layout.createSequentialGroup()
                .addContainerGap()
                .AddGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .AddComponent(jTextField1, javax. Swing. GroupLayout.DEFAULT_SIZE, 506, Short.MAX_VALUE)
                    .AddComponent(jLabel1))
                .addContainerGap())
        );
        Layout. SetVerticalGroup(
            Layout. CreateParallelGroup(javax. Swing. GroupLayout. Alignment. LEADING)
            .AddGroup(layout.createSequentialGroup()
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .AddComponent(jTextField1, javax. Swing. GroupLayout.PREFERRED_SIZE, 30, javax. Swing. GroupLayout.PREFERRED_SIZE)
                .AddPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel1))
        );
        pack();
    }// </editor-fold>
    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new NewJFrame().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify
    private javax.swing.JLabel jLabel1;
    private javax.swing.JTextField jTextField1;
    // End of variables declaration
}
¡Gracias!, ¡Es perfecto!
Yo creía que debía monitorizar(escuchar) el teclado, no sabía que podía monitorizar el porta-papeles. Ahora podré continuar con mí pequeño proyecto, sí quieres ver cómo va visita mí sitio en Google Code.
htttp://code.google.com/p/jlistentome
El nombre no es la gran cosa(todos los nombres buenos estaban ocupados) pero el software es decente. Lo mejor, es software libre.
En algunos días estará lista la siguiente versión.
Nuevamente Gracias por la ayuda.

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas