How to know if it is mouse click or the Robot?

3

I wanted to know if you can differentiate the click from the java.awt.Robot of the mouse click ...

I need to know if it was the Robot that clicked or was the mouse.

    
asked by anonymous 19.02.2015 / 19:05

1 answer

4

I'm not sure about this, but the java.awt.Robot class must insert click events into the operating system queue. So much so that you can use it to click on other programs, drag-and-drop on the desktop or anything like that. With this, the only way to differentiate this would be if you fucked in the guts of the operating system, and therefore do not expect the code to be portable.

But can not you try anyway using only java code? Well, I tried and came to the conclusion that it does not, at least not 100% sure. Here is the code I tried:

import java.awt.AWTException;
import java.awt.EventQueue;
import java.awt.MouseInfo;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.JButton;
import javax.swing.JFrame;

/**
 * @author Victor
 */
public class DetectRobot {
    public static void main(String[] args) {
        EventQueue.invokeLater(DetectRobot::go);
    }

    private static void go() {
        try {
            Mouser m = new Mouser();
            Robot r = new Robot();
            JFrame jf = new JFrame("Teste");
            JButton jb = new JButton("Clique aqui");
            jb.addActionListener(DetectRobot::clicked);
            jb.addMouseListener(m);
            jb.addMouseWheelListener(m);
            jb.addMouseMotionListener(m);
            jf.add(jb);
            jf.setBounds(10, 10, 250, 250);
            jf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            jf.setVisible(true);
            Thread t = new Thread(() -> clicker(jf, r));
            t.start();
        } catch (AWTException e) {
            throw new RuntimeException(e);
        }
    }

    private static void clicker(JFrame jf, Robot r) {
        Thread t = Thread.currentThread();
        try {
            while (!Thread.interrupted()) {
                Thread.sleep(5000);
                System.out.println("Robo clicando");
                EventQueue.invokeAndWait(() -> {
                    if (jf.isDisplayable()) {
                        r.mouseMove(150, 150);
                        r.mousePress(InputEvent.BUTTON1_DOWN_MASK);
                    } else {
                        t.interrupt();
                    }
                });
                Thread.sleep(50);
                EventQueue.invokeAndWait(() -> {
                    r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
                    if (!jf.isDisplayable()) t.interrupt();
                });
                Thread.sleep(50);
                System.out.println("Robo terminou");
            }
        } catch (InterruptedException e) {
            // Ignora e deixa a Thread morrer naturalmente.
        } catch (InvocationTargetException ex) {
            ex.printStackTrace();
        }
    }

    private static void clicked(ActionEvent e) {
        log(e);
    }

    // Para simplificar a saída do log. Não precisamos mostrar no System.out qual foi o JButton clicado, apenas os eventos.
    private static void log(Object x) {
        String a = x.toString();
        int i = a.indexOf(" on javax.swing.JButton[");
        System.out.println(a.substring(0, i));
    }

    private static class Mouser implements MouseListener, MouseMotionListener, MouseWheelListener {

        @Override
        public void mouseClicked(MouseEvent e) {
            log(e);
        }

        @Override
        public void mousePressed(MouseEvent e) {
            log(e);
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            log(e);
        }

        @Override
        public void mouseEntered(MouseEvent e) {
            log(e);
        }

        @Override
        public void mouseExited(MouseEvent e) {
            log(e);
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            log(e);
        }

        @Override
        public void mouseMoved(MouseEvent e) {
            log(e);
        }

        @Override
        public void mouseWheelMoved(MouseWheelEvent e) {
            log(e);
        }
    }
}

Here's the result:

Robo clicando
java.awt.event.MouseEvent[MOUSE_ENTERED,(132,109),absolute(150,150),button=0,clickCount=0]
java.awt.event.MouseEvent[MOUSE_MOVED,(132,109),absolute(150,150),clickCount=0]
java.awt.event.MouseEvent[MOUSE_PRESSED,(132,109),absolute(150,150),button=1,modifiers=Button1,extModifiers=Button1,clickCount=1]
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Clique aqui,when=1424373236982,modifiers=Button1]
java.awt.event.MouseEvent[MOUSE_RELEASED,(132,109),absolute(150,150),button=1,modifiers=Button1,clickCount=1]
java.awt.event.MouseEvent[MOUSE_CLICKED,(132,109),absolute(150,150),button=1,modifiers=Button1,clickCount=1]
Robo terminou
Robo clicando
java.awt.event.MouseEvent[MOUSE_PRESSED,(132,109),absolute(150,150),button=1,modifiers=Button1,extModifiers=Button1,clickCount=1]
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Clique aqui,when=1424373242084,modifiers=Button1]
java.awt.event.MouseEvent[MOUSE_RELEASED,(132,109),absolute(150,150),button=1,modifiers=Button1,clickCount=1]
java.awt.event.MouseEvent[MOUSE_CLICKED,(132,109),absolute(150,150),button=1,modifiers=Button1,clickCount=1]
Robo terminou
Robo clicando
java.awt.event.MouseEvent[MOUSE_PRESSED,(132,109),absolute(150,150),button=1,modifiers=Button1,extModifiers=Button1,clickCount=1]
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Clique aqui,when=1424373247185,modifiers=Button1]
java.awt.event.MouseEvent[MOUSE_RELEASED,(132,109),absolute(150,150),button=1,modifiers=Button1,clickCount=1]
java.awt.event.MouseEvent[MOUSE_CLICKED,(132,109),absolute(150,150),button=1,modifiers=Button1,clickCount=1]
Robo terminou
java.awt.event.MouseEvent[MOUSE_MOVED,(132,108),absolute(150,149),clickCount=0]

... Mais um monte de eventos MOUSE_MOVED disparados praticamente ao mesmo tempo, a medida que eu ia movendo o mouse ...

java.awt.event.MouseEvent[MOUSE_MOVED,(192,21),absolute(210,62),clickCount=0]
java.awt.event.MouseEvent[MOUSE_PRESSED,(192,21),absolute(210,62),button=1,modifiers=Button1,extModifiers=Button1,clickCount=1]
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Clique aqui,when=1424373250075,modifiers=Button1]
java.awt.event.MouseEvent[MOUSE_RELEASED,(192,21),absolute(210,62),button=1,modifiers=Button1,clickCount=1]
java.awt.event.MouseEvent[MOUSE_CLICKED,(192,21),absolute(210,62),button=1,modifiers=Button1,clickCount=1]
java.awt.event.MouseEvent[MOUSE_MOVED,(191,25),absolute(209,66),clickCount=0]

... Mais um monte de eventos MOUSE_MOVED disparados praticamente ao mesmo tempo, a medida que eu ia movendo o mouse ...

java.awt.event.MouseEvent[MOUSE_MOVED,(159,67),absolute(177,108),clickCount=0]
java.awt.event.MouseEvent[MOUSE_PRESSED,(159,67),absolute(177,108),button=1,modifiers=Button1,extModifiers=Button1,clickCount=1]
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Clique aqui,when=1424373250629,modifiers=Button1]
java.awt.event.MouseEvent[MOUSE_RELEASED,(159,67),absolute(177,108),button=1,modifiers=Button1,clickCount=1]
java.awt.event.MouseEvent[MOUSE_CLICKED,(159,67),absolute(177,108),button=1,modifiers=Button1,clickCount=1]
java.awt.event.MouseEvent[MOUSE_PRESSED,(159,67),absolute(177,108),button=1,modifiers=Button1,extModifiers=Button1,clickCount=2]
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Clique aqui,when=1424373251059,modifiers=Button1]
java.awt.event.MouseEvent[MOUSE_RELEASED,(159,67),absolute(177,108),button=1,modifiers=Button1,clickCount=2]
java.awt.event.MouseEvent[MOUSE_CLICKED,(159,67),absolute(177,108),button=1,modifiers=Button1,clickCount=2]
java.awt.event.MouseEvent[MOUSE_PRESSED,(159,67),absolute(177,108),button=1,modifiers=Button1,extModifiers=Button1,clickCount=3]
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Clique aqui,when=1424373251309,modifiers=Button1]
java.awt.event.MouseEvent[MOUSE_RELEASED,(159,67),absolute(177,108),button=1,modifiers=Button1,clickCount=3]
java.awt.event.MouseEvent[MOUSE_CLICKED,(159,67),absolute(177,108),button=1,modifiers=Button1,clickCount=3]
java.awt.event.MouseEvent[MOUSE_MOVED,(160,66),absolute(178,107),clickCount=0]

... Mais um monte de eventos MOUSE_MOVED disparados praticamente ao mesmo tempo, a medida que eu ia movendo o mouse ...

java.awt.event.MouseEvent[MOUSE_MOVED,(228,0),absolute(246,41),clickCount=0]
java.awt.event.MouseEvent[MOUSE_EXITED,(230,-1),absolute(248,40),button=0,clickCount=0]
Robo clicando
java.awt.event.MouseEvent[MOUSE_ENTERED,(132,109),absolute(150,150),button=0,modifiers=Button1,extModifiers=Button1,clickCount=0]
java.awt.event.MouseEvent[MOUSE_MOVED,(132,109),absolute(150,150),clickCount=0]
java.awt.event.MouseEvent[MOUSE_RELEASED,(132,109),absolute(150,150),button=1,modifiers=Button1,clickCount=3]
Robo terminou
java.awt.event.MouseEvent[MOUSE_MOVED,(131,109),absolute(149,150),clickCount=0]

... Mais um monte de eventos MOUSE_MOVED disparados praticamente ao mesmo tempo, a medida que eu ia movendo o mouse ...

java.awt.event.MouseEvent[MOUSE_MOVED,(198,1),absolute(216,42),clickCount=0]
java.awt.event.MouseEvent[MOUSE_EXITED,(199,-1),absolute(217,40),button=0,clickCount=0]

Note that there is no simple way to distinguish events from Robot of user events. The best I think I can do is to check if the mouse is "jumping" and not "walking". To do this, you can track the position of the mouse by using java.awt.MouseInfo.getPointerInfo().getLocation() , which provides the mouse position on the graphical device where it is and java.awt.MouseInfo.getPointerInfo().getDevice() to tell which graphic device it is on (important if there is more than one monitor). Thus, it is not difficult to detect whether the mouse is "jumping" and not "walking" and if it clicks right after the jump, it was probably Robot . But of course this does not directly solve the problem, as it can be bypassed by a Robot that causes the mouse to walk and not jump and does not resolve the case of the mouse being clicked without being moved.

You can also search for other behavior patterns typical of robots, such as always clicking in the exact same position, always moving the mouse to the same pattern, always having the same range or length of clicks, or anything like that. But just by using java, without getting inside the guts of the operating system, I do not think what you want is possible with 100% guarantee.

The main problem here is that the intention of Robot is exactly that of passing through the user using the computer. That is, one of the purposes of it is exactly that of being indistinguishable from that of a user operating the system, but what you need is exactly distinguish them!

However, if you have access to the code of Robot (or to be more precise, of the class that controls Robot ), then the problem becomes easy. Look at those System.out.println("Robo clicando"); and System.out.println("Robo terminou"); , if your controller of Robot somehow warns your app that it will click, then your application will know that the next click is from Robot e not the user.

    
19.02.2015 / 20:45