repeatedly simulating clicks while physically holding mouse button - java

So my problem is that i want to simulate mouse clicks while the mouse is held down. But the Robot library cant execute the click while the physical button is held down.
This is my code for the click:
public static void click() {
Runnable runnable = () -> {
try {
Robot robot = new Robot();
while (clicking) {
System.out.println("Clicking! " + System.currentTimeMillis());
robot.mousePress(mouseButton ? InputEvent.BUTTON1_DOWN_MASK : InputEvent.BUTTON2_DOWN_MASK);
Thread.sleep(300);
robot.mouseRelease(mouseButton ? InputEvent.BUTTON1_DOWN_MASK : InputEvent.BUTTON2_DOWN_MASK);
}
} catch (Exception ignored) {
System.out.println("Couldn't click");
}
};
new Thread(runnable).start();
}
This is my mouse event listener code:
public class MouseListener implements NativeMouseInputListener {
public void nativeMousePressed(NativeMouseEvent e) {
if (active && !focused && !clicking && e.getButton() == (mouseButton ? 1 : 2)) {
clicking = true;
click();
}
}
public void nativeMouseReleased(NativeMouseEvent e) {
if (active && !focused && e.getButton() == (mouseButton ? 1 : 2)) {
clicking = false;
}
}
}
The print gets executed normally and if i switch the clicks so a left click gets executed when i do a rightclick and that also works but i want it with the same button.
I appreciate your help.

Related

(How to) .setOnMouseClicked overwrite former event and return to old event?

I have a stack of (game) cards. Three of them are displayed (gui), horizontal as rectangle objects,javaFx. At default i can go through the cards by clicking the left or the right card. The single rectangles are setOnMouseClicked in my FXML file. Each of them has is own ID -> (fstCard,scdCard,trdCard). Next to the rectangles is a button "Choose Card". Now, if i press this button i had to choose one of these displayed cards and i want activate a method and return to the default setOnMouseClicked. To activate the "Choose button" :
public void switchChooseDevCard(MouseEvent event) {
if(event.getSource().equals(chooseButton)){
fstDeve.setOnMouseClicked(event1 -> System.out.print("hello"));
**----->> how can i return to the default ?**
}
if (event.getSource().equals(fstCard)) {
ba = devCardStack.size() - 1;
if (devCardStack.size() <= 3) {
giveTooltip();
} else if (devCardStack.size() > 3) {
int passages = devCardStack.size();
fstDeve.setFill(scdDeve.getFill());
scdDeve.setFill(trdDeve.getFill());
if (a >= 3 && a < passages) {
trdDeve.setFill(devCardStack.get(a));
a++;
giveTooltip();
} else if (a == passages) {
a = 0;
trdDeve.setFill(devCardStack.get(a));
a++;
giveTooltip();
} else {
trdDeve.setFill(devCardStack.get(a));
a++;
giveTooltip();
}
}
} *rest of the code*
Thanks!!
You can store the handler in a temporary variable and restore it later when needed:
Button btn = new Button("Test");
//default event handler
btn.setOnMouseClicked(new EventHandler<Event>() {
#Override
public void handle(Event event) {
System.out.println("hello");
}
});
//store default event handler
EventHandler<Event> oldHandler = (EventHandler<Event>) btn.getOnMouseClicked();
//set new event handler
btn.setOnMouseClicked(new EventHandler<Event>() {
#Override
public void handle(Event event) {
System.out.println("test");
}
});
//restore default event handler
btn.setOnMouseClicked(oldHandler);
fixed it:
Just call the default method..
fstDeve.setOnMouseClicked(event1 -> switchChooseDevCard(event1));

How to make an event for left & right click at the same time?

I know how to deal with left or right click separately, dragging, double-clicking, but I can't figure out how to do something if the user clicks left and right mouse buttons at the same time without interfering/causing other events to fire.
#Override
public void handle(Event event) {
if (event.getSource() instanceof Tile) {
Tile tile = (Tile) event.getSource();
if (event.getEventType().equals(MouseEvent.MOUSE_CLICKED)) {
if (((MouseEvent) event).getButton().equals(MouseButton.SECONDARY))
tile.toggleFlag();
else if (((MouseEvent) event).getClickCount() == 2)
mineField.massClick(tile);
}
if (event.getEventType().equals(MouseEvent.DRAG_DETECTED))
if (!((MouseEvent) event).getButton().equals(MouseButton.SECONDARY))
tile.startFullDrag();
if (event.getEventType().equals(MouseDragEvent.MOUSE_DRAG_ENTERED))
tile.arm();
if (event.getEventType().equals(MouseDragEvent.MOUSE_DRAG_EXITED))
tile.disarm();
if (event.getEventType().equals(MouseDragEvent.MOUSE_DRAG_RELEASED))
mineField.clickedTile(tile);
if (event.getEventType().equals(ActionEvent.ANY))
mineField.clickedTile(tile);
}
}
Also, if you see a problem with my code feel free to point it out, always looking to improve.
The simple version is this:
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
StackPane root = new StackPane();
root.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> {
if( e.isPrimaryButtonDown() && e.isSecondaryButtonDown()) {
System.out.println( "Both down");
} else if( e.isPrimaryButtonDown()) {
System.out.println( "Primary down");
} else if( e.isSecondaryButtonDown()) {
System.out.println( "Secondary down");
}
});
Scene scene = new Scene(root,400,400);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
If you prefer your own event happening when both buttons are pressed, you could try it this way:
public class Main extends Application {
BooleanProperty primaryMouseButtonDown = new SimpleBooleanProperty();
BooleanProperty secondaryMouseButtonDown = new SimpleBooleanProperty();
#Override
public void start(Stage primaryStage) {
try {
StackPane root = new StackPane();
root.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> {
primaryMouseButtonDown.setValue( e.isPrimaryButtonDown());
secondaryMouseButtonDown.setValue( e.isSecondaryButtonDown());
});
root.addEventFilter(MouseEvent.MOUSE_RELEASED, e -> {
primaryMouseButtonDown.setValue( e.isPrimaryButtonDown());
secondaryMouseButtonDown.setValue( e.isSecondaryButtonDown());
});
BooleanBinding binding = Bindings.and(primaryMouseButtonDown, secondaryMouseButtonDown);
binding.addListener( new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
System.out.println( "Mouse Button Event: " + oldValue + " -> " + newValue);
}
});
Scene scene = new Scene(root,400,400);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
There are 2 boolean properties, one for the primary button down and one for the secondary button down. Both properties are connected via a BooleanBinding. Whenever one of the properties change via the mouse event, an event is fired. So what's left to do is for you to check if newValue is true and fire your handling code.
Do something more along the lines of, watch for mouse presses, and set a boolean to true when a mousePressed event is called for left/right mouse button. Then later in the event look to see if both booleans for left and right are true. If they are, act on it as if both were pressed at the same time.
boolean mouse_1, mouse_2 = false;
public void mousePressed(MouseEvent e){
//The numbers are just made up I don't remember the actual codes for the buttons but it's simple enough to figure out.
if(e.getButton()==1){
mouse_1 = true;
}
if(e.getButton()==2){
mouse_2 = true;
}
if(mouse_1&&mouse_2){
//Your code here
}
}
public void mouseReleased(MouseEvent e){
if(e.getButton() == 1){
mouse_1 = false;
}
if(e.getButton() == 2){
mouse_2 = false;
}
}
Assume this is some sort of handler class... But this is the short for how to implement it.
I'm probably late to answer this question, but I'm going to post my solution in order to demonstrate how to handle single-button clicks separately from both buttons being clicked at the same time
Existing answers already explained how to detect both mouse buttons being clicked at the same time. But mouse events (click, press, and release) are still triggered by individual buttons and previous posters didn't address how to avoid these events from interfering with each other.
My solution is to track both buttons being pressed on mouse press and detect mouse clicks of any kind on mouse release:
//flag to track both buttons being pressed
private boolean wereBothButtonsPressed = false;
private void onMousePressed(MouseEvent e) {
//single button press sets flag to false
wereBothButtonsPressed = e.isPrimaryButtonDown() && e.isSecondaryButtonDown();
}
private void onMouseReleased(MouseEvent e) {
if (e.isPrimaryButtonDown() || e.isSecondaryButtonDown()) {
//do nothing if user is still holding the button
return;
}
if (wereBothButtonsPressed) {
System.out.prinln("Both buttons");
} else if (e.getButton() == MouseButton.PRIMARY) {
System.out.prinln("Only primary");
} else if (e.getButton() == MouseButton.SECONDARY) {
System.out.prinln("Only secondary");
}
}
You can set these handlers for specific events on specific controls or fit them into your method:
private boolean wereBothButtonsPressed = false;
#Override
public void handle(Event event) {
...
if (event.getEventType().equals(MouseEvent.MOUSE_PRESSED)) {
MouseEvent me = (MouseEvent) event;
wereBothButtonsPressed = me.isPrimaryButtonDown() && me.isSecondaryButtonDown();
} else if (event.getEventType().equals(MouseEvent.MOUSE_RELEASED)) {
MouseEvent me = (MouseEvent) event;
if (!me.isPrimaryButtonDown() && !me.isSecondaryButtonDown()) {
if(wereBothButtonsPressed) {
mineField.massClick(tile);
} else if(me.getButton() == MouseButton.PRIMARY) {
mineField.clickedTile(tile);
} else if(me.getButton() == MouseButton.SECONDARY) {
tile.toggleFlag();
}
}
...

manipulating time in java swing

I was trying to manipulate an amateur animation using Swing in Java. The goal was to start an animation if I hover over a certain button. That was easy. But the problem is, I want to manipulate the speed of the timer of the animation according to the coordinates of the button.
For example, the more right I go on the button the more speedy the animation gets (delay time decreases) and vice-versa. The code I wrote works if I move the arrow out of the button then enter again. Then the delay changes according to co-ordinates. But not if I move the arrow within the region of the button. I used mouseEntered here. That may cause cause the problem. But the mouseMove function seems not to work too.
Here's my code:
private void jButton1MouseEntered(java.awt.event.MouseEvent evt)
{
// TODO add your handling code here:
PointerInfo inf = MouseInfo.getPointerInfo();
Point a = inf.getLocation();
double x = a.getX();
final int n = (int) (x - 161);
//String str=""+x;
//Output.setText(str);
ActionListener taskPerformer = null;
taskPerformer = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent evt)
{
//...Perform a task...
//if(t>0)timer.setDelay(1000);
if (t > 0)
{
timer.setDelay(500 + 50 * n);
}
if (label1 == 0)
{
jTextField1.setText(" A");
}
else if (label1 == 1)
{
jTextField1.setText(" B");
}
else if (label1 == 2)
{
jTextField1.setText(" C");
}
else if (label1 == 3)
{
jTextField1.setText(" D");
}
else if (label1 == 4)
{
jTextField1.setText(" E");
}
else if (label1 == 5)
{
jTextField1.setText(" F");
}
else if (label1 == 6)
{
jTextField1.setText(" G");
}
if (label1 >= 7)
{
label1 = 0;
}
else
{
label1++;
}
t++;
//System.out.printf("Reading SMTP Info. %d\n",x);
//System.out.printf("Reading SMTP Info. %d\n",label1t);
//jLabel3.setText("fsd");
}
private Object getContentPane()
{
throw new UnsupportedOperationException("Not supported yet.");
}
};
timer = new Timer(500, taskPerformer);
timer.start();
//timer.setRepeats(false);
try
{
Thread.sleep(10);
}
catch (InterruptedException ex)
{
Logger.getLogger(Keyboard_Gui.class.getName()).log(Level.SEVERE, null, ex);
}
}
But the mouseMove function seems not to work too.
The mouseMoved event is generated by a MouseMotionListener (not a MouseListener) so you will also need to implement that listener to manipulate the Timer interval.

How to check if displayMessage() is no longer on screen

I made my displayMessage() clickable this way (thanks stackoverflow!):
public class Tray {
private static class ShowMessageListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
trayIcon.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (openBrowser == 1) {
Desktop desktop = Desktop.isDesktopSupported() ? Desktop
.getDesktop() : null;
if (desktop != null
&& desktop.isSupported(Desktop.Action.BROWSE)) {
try {
desktop.browse(URI.create(link));
} catch (Exception e2) {
LogError.get(e2);
}
}
}
openBrowser = 0;
}
});
trayIcon.displayMessage("Finished", link,
TrayIcon.MessageType.INFO);
}
} //ShowMessageListener class end
invisibleItem.addActionListener(new ShowMessageListener());
}
and I'm dispatching event to show the message:
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(new ActionEvent(Tray.invisibleItem, ActionEvent.ACTION_PERFORMED, "asd", 1, 0));
Everything works great, the message is clickable. It was perfect until I realized that ActionListener is listening to TrayIcon too. If the user doesn't click on the message, TrayIcon will take the event on the next click and open the website.
Here's my question: how can I check if displayMessage() is gone?

MultiThread handling and stopping midway

i'm having trouble stopping a thread in the middle. This is part of my code, in the StoplightThread class I have problems on the first if statement. What it is supposed to do is wait at least 10 secs then allow the user to press the button so they can change the light, if the button is pressed it should stop the running thread in this case Thread.sleep(40000). What happens is when I press the button it changes the light but does not stop the thread. If I press the button while there is still 20secs left it will add 20secs to the 10secs for the yellow light, making it yellow for 30 secs.
Edit: if you are wondering, stoplightCanvas.x == 3 is green, stoplightCanvas.x == 2 is yellow, and stoplightCanvas.x == 1 is red.
class StoplightCanvas extends Canvas implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == cross) {
isPressed = true;
if (x == 3 && canCross)
x = 2;
}
repaint();
}
}
class StoplightThread extends Thread
{
StoplightCanvas stoplightCanvas;
StoplightThread(StoplightCanvas stoplightCanvas) {
this.stoplightCanvas = stoplightCanvas;
}
public void run()
{
if (stoplightCanvas.x == 3){
Thread.sleep(10000);
stoplightCanvas.canCross = true;
Thread.sleep(40000);
if(stoplightCanvas.isPressed)
StoplightThread.interrupt();
} else if (stoplightCanvas.x == 2) {
Thread.sleep(10000);
} else if (stoplightCanvas.x == 1) {
Thread.sleep(60000);
}
} catch (InterruptedException e){}
stoplightCanvas.toggleColor();
stoplightCanvas.repaint();
}
}
}
The way your code is written, the thread is sleeping for 40 seconds; then wakes up and checks for stoplightCanvas.isPressed and sets the interrupt flag...
If you want to interrupt the thread while it's sleeping, you need to interrupt from another thread. The EventDispatchThread is a fine place to do that, so you can either modify your current ActionListener, or create another one that does it.
public void actionPerformed(ActionEvent e)
{
...
stopLightThread.interrupt();
}
If you don't want to expose the button outside stopLightCanvas, then you can roll your own listener support in StopLightCanvas:
class StopLightCanvas extends Canvas implements ActionEventListener {
public static interface StopLightListener extends EventListener {
public void stopLightChanged(int state);
}
// watch out, you may need this to be threadsafe depending on your usage
List<ActionEventListener> myListeners = new LinkedList<StopLightListener>();
public void addStopLightListener(StopLightListener lst) {
myListeners.add(lst);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == cross) {
isPressed = true;
if (x == 3 && canCross)
x = 2;
}
repaint();
for(StopLightListener lst: myListeners) {
lst.stopLightChanged(x);
}
}
...
}
public class StopLightThread extends Thread implements {
StoplightThread(StoplightCanvas stoplightCanvas) {
this.stoplightCanvas = stoplightCanvas;
stopLightCanvas.addStopLightListener(this);
}
...
#Override public void stopLightChanged(int state) {
this.interrupt();
}
}

Categories