0
votes

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;
}
2
What do you mean by "harder"? When the robot is working, you may have a hard time trying to press another button manually. Some stackoverflow.com/help/mcve would be very helpful here.Marco13
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
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
I used the constructor to invoke the robot action. I may have to change something in that aspectbltzrrr
It should not have to do anything with the constructor. You should probably really post some code.Marco13

2 Answers

1
votes

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);
      }    
}
0
votes

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.