0

Is there a way to stop Java Robot execution once it's started? I have a program that simulates left mouse button clicks, but i also have an unused JButton named STOP that was supposed to stop this clicking that i started using the Robot class. I noticed that Robot is fairly harder than the Thread class. Any ideas?

import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.util.Random;

public class Click{
Robot robot = new Robot();

private void leftClick(){
    int no = new Random().nextInt(6) + 1;
    robot.mousePress(InputEvent.BUTTON1_MASK);
    robot.delay(50 * no);
    robot.mouseRelease(InputEvent.BUTTON1_MASK);
    robot.delay(220 * no);
  }

public Click() throws AWTException{
    while (true) {
        leftClick();
        System.out.println("Click");            
    }       
  } 
}

And in the GUI class i have a JButton that looks something like this:

private JButton getBtnStart() {
    if (btnStart == null) {
        btnStart = new JButton("Start");
        btnStart.setBackground(Color.WHITE);
        btnStart.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    c = new Click();
                } catch (AWTException e1) {
                    e1.printStackTrace();
                }
            }
        });
    }
    return btnStart;
}
bltzrrr
  • 789
  • 1
  • 8
  • 14
  • What do you mean by "harder"? When the robot is working, you may have a hard time trying to press another button manually. Some http://stackoverflow.com/help/mcve would be very helpful here. – Marco13 Jul 06 '14 at 15:39
  • Sorry, I meant to say that the Robot class is way harder than the Thread class, as far as control is concerned. The problem is that as soon the Robot is executed, i no longer have control over my program, and don't have a clue how to stop it, except of course using the 'terminate' button in Eclipse. – bltzrrr Jul 06 '14 at 15:53
  • If your robot actions are performed on an own thread, you either be able to inerrupt this thread, or to create a flag that is checked regularly (to see whether the thread should stop). – Marco13 Jul 06 '14 at 15:58
  • I used the constructor to invoke the robot action. I may have to change something in that aspect – bltzrrr Jul 06 '14 at 16:11
  • It should not have to do anything with the constructor. You should probably really post some code. – Marco13 Jul 06 '14 at 17:13
  • I added some code to the original post, do you have any ideas what next? – bltzrrr Jul 06 '14 at 18:56
  • `while (true) {` replace true with a flag. – Marco Acierno Jul 06 '14 at 19:02
  • Can you clarify,please? I made a boolean named flag that equals true, and swapped that with true. Sorry – bltzrrr Jul 06 '14 at 19:20

2 Answers2

1

There are several issues. An unconditional loop in a constructor is a no-go. Apart from that, you are blocking the EDT, so I wonder whether this can work at all.

It's not even clear to me how you want to stop this clicking, given that you can hardly do anything while the robot is doing its job.

However, here is a sketch of how this could probably be solved, based on the information that you provided so far:

import java.awt.AWTException;
import java.awt.GridLayout;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class RobotControlTest
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final RobotControl robotControl = new RobotControl();

        f.getContentPane().setLayout(new GridLayout(1,2));

        final JButton startButton = new JButton("Start");
        f.getContentPane().add(startButton);

        final JButton stopButton = new JButton("Stop");
        stopButton.setEnabled(false);
        f.getContentPane().add(stopButton);

        startButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                startButton.setEnabled(false);
                stopButton.setEnabled(true);
                robotControl.startClicking();
            }
        });

        stopButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                robotControl.stopClicking();
                startButton.setEnabled(true);
                stopButton.setEnabled(false);
            }
        });

        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

class RobotControl
{
    private final Random random = new Random();
    private final Robot robot;
    private volatile boolean running = false;

    RobotControl()
    {
        try
        {
            robot = new Robot();
        }
        catch (AWTException e)
        {
            e.printStackTrace();
            throw new RuntimeException(e);
        }        
    }

    void startClicking()
    {
        Thread thread = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                running = true;
                performClicks();
            }
        });
        thread.start();
    }

    void stopClicking()
    {
        System.out.println("Stopping");
        running = false;
    }

    private void performClicks()
    {
        System.out.println("Starting");
        while (running)
        {
            leftClick();
            System.out.println("Clicked");
        }
    }

    private void leftClick()
    {
        int no = random.nextInt(6) + 1;
        robot.mousePress(InputEvent.BUTTON1_MASK);
        robot.delay(50 * no);
        robot.mouseRelease(InputEvent.BUTTON1_MASK);
        robot.delay(220 * no);
      }    
}

EDIT based on the comment:

Of course it is possible to detect mouse movements, and pause the clicking for a while after each mouse movement. However, I don't like the direction where this is going. The first part of the answer was just a quick sketch to illustrate the idea that you could have developed on your own when reading a bit about threads. Any extensions to this sketch are inappropriate. And my gut feeling is that this will end in a chain of further requirements that could, somehow, be kludged into the original answer, but should have been stated right from the beginning.

But I see your problem: "Develop a program that does what I need" is not a valid question.

But to at least anwswer the "implicit" question of "How can I detect a mouse movement?":

You can use MouseInfo.getPointerInfo().getLocation() to obtain the mouse position, and regularly check this point to see whether it is different from the previous point.

Kludged into the original program:

import java.awt.AWTException;
import java.awt.GridLayout;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class ExtendedRobotControlTest
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final RobotControl robotControl = new RobotControl();

        f.getContentPane().setLayout(new GridLayout(1,2));

        final JButton startButton = new JButton("Start");
        f.getContentPane().add(startButton);

        final JButton stopButton = new JButton("Stop");
        stopButton.setEnabled(false);
        f.getContentPane().add(stopButton);

        startButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                startButton.setEnabled(false);
                stopButton.setEnabled(true);
                robotControl.startControl();
            }
        });

        stopButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                robotControl.stopControl();
                startButton.setEnabled(true);
                stopButton.setEnabled(false);
            }
        });

        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

class RobotControl
{
    private final Random random = new Random();
    private final Robot robot;

    private Thread clickingThread;
    private Thread observingThread;

    private long lastMovementMillis = -1;
    private Point lastMousePosition = null;

    private volatile boolean running = false;

    RobotControl()
    {
        try
        {
            robot = new Robot();
        }
        catch (AWTException e)
        {
            e.printStackTrace();
            throw new RuntimeException(e);
        }        
    }

    void startObserver()
    {
        observingThread = new Thread(new Runnable(){

            @Override
            public void run()
            {
                observeMovement();
            }
        });
        observingThread.start();
    }

    private void observeMovement()
    {
        while (running)
        {
            Point p = MouseInfo.getPointerInfo().getLocation();
            if (!p.equals(lastMousePosition))
            {
                System.out.println("Movement detected");
                lastMovementMillis = System.currentTimeMillis();
                lastMousePosition = p;
            }
            try
            {
                Thread.sleep(50);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
                Thread.currentThread().interrupt();
                return;
            }
        }
    }


    void startControl()
    {
        stopControl();
        System.out.println("Starting");
        lastMovementMillis = System.currentTimeMillis();
        lastMousePosition = MouseInfo.getPointerInfo().getLocation();
        running = true;
        startClicking();
        startObserver();
    }    

    private void startClicking()
    {
        clickingThread = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                performClicks();
            }
        });
        clickingThread.start();
    }

    void stopControl()
    {
        if (running)
        {
            System.out.println("Stopping");
            running = false;
            try
            {
                clickingThread.join(5000);
                observingThread.join(5000);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
                Thread.currentThread().interrupt();
            }
        }
    }

    private void performClicks()
    {
        System.out.println("Starting");
        while (running)
        {
            long t = System.currentTimeMillis();
            if (t > lastMovementMillis + 1000)
            {
                leftClick();
                System.out.println("Clicked");
            }
            else
            {
                System.out.println("Waiting before clicks...");
                try
                {
                    Thread.sleep(50);
                }
                catch (InterruptedException e)
                {
                    e.printStackTrace();
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        }
    }

    private void leftClick()
    {
        int no = random.nextInt(6) + 1;
        robot.mousePress(InputEvent.BUTTON1_MASK);
        robot.delay(50 * no);
        robot.mouseRelease(InputEvent.BUTTON1_MASK);
        robot.delay(220 * no);
      }    
}
Marco13
  • 53,703
  • 9
  • 80
  • 159
  • That was great, works like a charm! Do you think that it's possible to only click when the mouse cursor is not moving? – bltzrrr Jul 07 '14 at 11:06
  • Sure, but what does "not moving" mean exactly? When it has not been moving for, as an example, 1 second? – Marco13 Jul 07 '14 at 12:08
0

I'd just put the following condition after each robot action: if Esc is pressed then sleep. And at that moment I'd pop up a JOptionPane to the user decide if he wants to abort or continue the process.

I think it's an easier way to do what you want to.