Saturday, December 31, 2016

Making Humanistic Mouse Clicks with Java Robot Class

Preface: Java's Robot class allows you to send mouse and keyboard signals to the operating system through APIs designed for indirect interaction with the PC. By using this Java class, we can perform actions like scrolling, clicking, and typing without actually doing so.

Problem: While experimenting with the Robot class for an Arduino gamepad I was making, I discovered a problem with clicking the virtual mouse. Let's look at the code.

This is how it is explained in Java examples, and how other users have taken to using the mouse click:
Robot robot = new Robot();
    
    robot.mousePress(InputEvent.BUTTON1_MASK);
    robot.mouseRelease(InputEvent.BUTTON1_MASK);
The button is pressed and immediately released. Even adding a delay by way of a Thread.Sleep will still result in the same problem. What if I have a function that detects an event and presses the mouse button? This certainly works for that case, but what if I am holding the mouse button down? Instead, this code will simulate a set of rapid clicks for as long as the button is held. That's not the behavior I wanted. Furthermore, the right click code was verbatim with the mask changed to account for the different button. Right clicking did not work at all since it opened and close any context menus far too fast to be useable.

Solution: Using some extra state information, we can track whether or not the mouse button should be held down, or if it should be released. Assuming the event triggers occur often enough, the user should not notice whether the mouse is only clicked or held for any period of time.

int currentLeftClickState = 0;
...
if(trigger == 0 && currentLeftClickState == 1){
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
this.currentLeftClickState = 0;
}
else if(trigger == 1 && currentLeftClickState == 0){
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
this.currentLeftClickState = 1;
}
In my example, I declare a simple flag using an int that will represent the current state.  When I receive the literal 'trigger' my function code will validate the trigger against the current state. Only if there is a difference between them, do we need to change the mouse behavior.

This code allows you to now select windows, drag objects, open context menus correctly, and even select multiple lines. Cool stuff right?

To see the project this code was written for, please check out my GITHUB.

No comments:

Post a Comment