Is there a way to lock the mouse in one position in Java for a certain amount of time?
I've tried this:
while(timer == true){
Robot bot = new Robot();
bot.mouseMove(x, y);
}
But when the user moves the mouse it jumps unpleasantly back and forth (from the position the user is dragging to the position where it's supposed to be locked).
Any ideas if there is a better way to do this? Or can I completely disable user input for the mouse? Thanks in advance!
This is as far as you can go (at least with the standard libraries). The mouse "jumps" are system dependent, specifically on the "sampling rate" of the listener. I'm not aware of a JVM parameter affecting it, but wouldn't be surprised if there is something in that spirit. The jumps are in opposite relation to the mouse acceleration (the mouse can move a "long" distance between the samples).
public class Stop extends JFrame {
static Robot robot = null;
static Rectangle bounds = new Rectangle(300, 300, 300, 300);
static int lastX = 450; static int lastY = 450;
Stop() {
try {
robot = new Robot();
} catch (AWTException e) {
e.printStackTrace();
}
addMouseMotionListener(new MouseStop());
getContentPane().add(new JLabel("<html>A sticky situation<br>Hold SHIFT to get out of it", JLabel.CENTER));
setDefaultCloseOperation(EXIT_ON_CLOSE);
setBounds(bounds);
setVisible(true);
}
private static class MouseStop extends MouseAdapter {
#Override
public void mouseMoved(MouseEvent e) {
if(e.isShiftDown()) {
lastX = e.getXOnScreen();
lastY = e.getYOnScreen();
}
else
robot.mouseMove(lastX, lastY);
}
}
public static void main(String args[]) {
new Stop();
}
}
Edit: I have just gotten an idea involving painting of the cursor to appear as if the mouse is not moving at all. I'll add code if I get something working.
Related
I was playing around in Java and trying to make an autoclicker just as a challenge for myself. I was making key bindings to turn it on and off when I discovered that I needed to turn off a while loop from a different class. Normally I would think this to be easy but I am using actions, so the action keeps playing until it is broken. I thought about it for a little bit and came to the conclusion that I needed to ask for a keybind within an action, but I have no idea how to do this. Here is my code right now if you want to help me make some improvements
package autoclicker;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Autoclicker {
JFrame frame;
JLabel label;
boolean endis;
Action enableAction;
public Autoclicker() {
frame = new JFrame("Autoclicker");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(420, 420);
frame.setLayout(null);
label = new JLabel();
label.setBackground(Color.red);
label.setBounds(100, 100, 100, 100);
label.setOpaque(true);
enableAction = new EnableAction();
label.getInputMap().put(KeyStroke.getKeyStroke("UP"), "enableAction");
label.getActionMap().put("enableAction", enableAction);
frame.add(label);
frame.setVisible(true);
}
public class EnableAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
endis = true;
try {
Robot robot = new Robot();
while(endis) {
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
}
} catch (AWTException e1) {
e1.printStackTrace();
}
}
}
}
Assuming you want to use your autoclicker on other programs besides the java application, this isn't an easy thing to do. Java Swing was only designed to get events (such as keyboard presses) from the window that's currently focused on.
However, according to MasterID on this stack overflow post, it is possible with this library: https://github.com/kwhat/jnativehook. I haven't used this library myself though.
I've made my own auto clicker a long time ago, and here's how I dealt with exiting the loop. Mouse Position is something that is easy to get in Java. MouseInfo.getPointerInfo().getLocation(); So, rather than breaking on a keypress (requiring JFrame focus in Swing), you can break on if the mouse has been moved. In your loop, if the mouse is ever not in the same position, that means it has been moved, so exit the loop.
Perhaps something like this:
public void mainLoop() {
// Sleep for an amount of time to get mouse into proper position
Thread.sleep(4000);
...
Point p = MouseInfo.getPointerInfo().getLocation();
int lastX = (int)p.getX();
int lastY = (int)p.getY();
while(!isMoved(lastX, lastY)) {
// Do Click or other Stuff...
}
}
/** Returns true if the last x and y position don't match the current mouse x and y position on the screen. False if same position. */
public boolean isMoved(int lastX, int lastY){
Point p = MouseInfo.getPointerInfo().getLocation();
return (int)p.getX() != lastX || (int)p.getY() != lastY;
}
This breaks out of the loop if the mouse is ever moved. And if you want to use Robot.mouseMove(), you could make a simple wrapper class for Robot to handle updating the last position for you.
I am working on a swing application which run on a touch screen linux tablet. I want to implement a module in which i find that in which direction user swipe its finger on the screen. I am using MouseMotionListener to find the position of the mouse. But confusing now that how i can find the exact direction of the mouse movement. I only interested to find upward and downward movement on jframe. Can someone give me idea about that
I am using MouseMotionListener to find the position of the mouse.
I would guess you need to keep track of two MouseEvents:
the previous event (or maybe the mousePressed event which started the swipe?)
the current event.
so that you have access to the two points generated by each event.
Then you compare the two points using basic math. If the current y value is greater you are swiping down, otherwise up.
I wanted to add this example code illustrating #camickr's answer since it might help - as it got rejected as an edit, and I don't have enough points to add comments, here it is:
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class DragDirectionDemo {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Drag Direction Demo");
frame.setSize(500, 500);
frame.setVisible(true);
frame.addMouseListener(new MouseListener() {
float lastY = 0;
public void mouseReleased(MouseEvent e) {
System.out.println("Mouse released at " + e.getY());
if (e.getY() < lastY) {
System.out.println("Upward swipe");
} else if (e.getY() > lastY) {
System.out.println("Downward swipe");
} else {
System.out.println("No movement");
}
;
}
public void mousePressed(MouseEvent e) {
System.out.println("Mouse clicked at " + e.getY());
lastY = e.getY();
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
}
});
}
});
}
}
It is just a toy example illustrating the approach explained in #camickr's answer: tracking the y coordinate when the motion starts (the mouse button being depressed, in my example); then, comparing it to the y coordinate when the motion finishes (mouse button released, in my example - may need tweaking for touch, I don't know).
Observe the console output indicating what the motion has been picked up as. Good luck!
This is a little mouse hook application that I wrote a few years ago and I just was wondering why it makes my mouse lag whenever I run it.
I remember reading somewhere that I have to call some method to manually dispose of resources or something with the MouseListener. It will make my mouse lag whenever I drag any window around the screen, and this doesn't happen when it's not running. Any idea why? (I know I'm running a while loop on the EDT and my variable names for the 2 JLabels are J and C, sue me)
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class MouseLocation {
Point p;
int x,y;
MouseLocation() throws AWTException {
}
public String printLocation(){
p = MouseInfo.getPointerInfo().getLocation();
x = p.x;
y = p.y;
String location = (x + " - " + y);
return location;
}
public Color getMouseColor() throws AWTException{
Robot r = new Robot();
return r.getPixelColor(x, y);
}
public static void main(String[] args) throws AWTException {
MouseLocation m = new MouseLocation();
JFrame frame = new JFrame("Mouse Location Display");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(450,110);
frame.setLayout(new FlowLayout());
JLabel j = new JLabel();
JLabel c = new JLabel();
j.setFont (j.getFont ().deriveFont (24.0f));
c.setForeground(Color.red);
frame.add(j);
frame.add(c);
frame.setVisible(true);
while (true){
j.setText("Current Mouse Location: " + m.printLocation());
c.setText(String.valueOf(m.getMouseColor()));
}
}
}
You are requesting the mouse position at a very fast rate.
Try adding a Thread.sleep(time) in your loop:
while (true){
j.setText("Current Mouse Location: " + m.printLocation());
c.setText(String.valueOf(m.getMouseColor()));
// waiting a few milliseconds
Thread.sleep(200);
}
Also, it's best practice to reuse objects to avoid reallocation.
You could improve your method getMouseColor like this:
// Global var
Robot robot;
MouseLocation() throws AWTException {
robot = new Robot();
}
public Color getMouseColor() {
return robot.getPixelColor(x, y);
}
EDIT:
Following the suggestion by #cricket_007, use a timer to avoid using a Thread.sleep in the main thread (and inside a while-loop):
new Timer().schedule(new TimerTask() {
#Override
public void run() {
j.setText("Current Mouse Location: " + m.printLocation());
c.setText(String.valueOf(m.getMouseColor()));
}
}, 0, 200); // 200 milliseconds
This question may be a simple matter of me lacking a fundamental understanding of Java Swing or Graphics, and if so, I apologize.
I'm trying to develop a GUI application using Java Swing that can be controlled by an external device that sends pitch, yaw, and roll values via bluetooth to the Application. My idea is to create a cursor (perhaps an empty circle) that moves around when the external device moves around. I have no problems with receiving the data from the device, just the part where I need to actually paint something over all of my components.
I figured that a GlassPane was the easiest way to show a cursor over the entire application, and have it move around when the external device is moved around. I use a Thread to capture the data, and I'm trying to call repaint() afterwards, but it doesn't seem to be triggering.
Here is the relevant code:
JFrame:
public class Frame extends JFrame {
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
//Thread myoHandlerThread = new Thread(myoHandler);
//myoHandlerThread.start();
Frame frame = new Frame();
GlassPane glassPane = new GlassPane();
glassPane.setVisible(true);
frame.setGlassPane(glassPane);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Frame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(50, 50, 1000, 650);
/* Code to add and place components */
}
}
And my GlassPane:
public class GlassPane extends JComponent {
private static double pitch;
private static double yaw;
private static double roll;
Point point;
public void setPoint(Point p) {
this.point = p;
}
public void paintComponent(Graphics g) {
if (point != null) {
System.out.println("Test print statement");
g.setColor(Color.red);
g.fillOval(point.x - 10, point.y - 10, 20, 20);
}
}
public GlassPane() {
Thread handler = new Thread(deviceHandler);
handler.start();
}
private Runnable deviceHandler = new Runnable() {
#Override
public void run() {
Hub hub = new Hub("com.garbage");
System.out.println("Attempting to find device...");
Device externalDevice = hub.waitForDevice(10000);
if (externalDevice == null) {
throw new RuntimeException("Unable to find device!");
}
System.out.println("Connected");
DataCollector dataCollector = new DataCollector();
hub.addListener(dataCollector);
while (true) {
hub.run(1000/20); //gathers data and stores in dataCollector
roll = dataCollector.getRoll();
pitch = dataCollector.getPitch();
yaw = dataCollector.getYaw();
Point p = new Point();
p.setLocation(Math.abs(pitch) * 10, Math.abs(yaw) * 10);
setPoint(p);
repaint();
}
}
};
}
What I would like to happen is for a red circle to be drawn somewhere on the GUI depending on the orientation of the external device. At this point, my "test print statement" doesn't fire even once.
My guess is that I'm lacking some sort of basic understanding of Java's GlassPane or even how paint, paintComponent, and repaint even works. Could anyone point out what I'm doing wrong?
The likely cause of your frustration is trying to set the glass pane visible (Swing components are visible by default), before setting it as the frames GlassPane.
The JFrame is likely resetting the glass pane to be invisible, meaning that it won't be painted (no point painting something that's not visible)
Try setting the glass pane visible AFTER you apply it to the frame
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
public class dots extends JPanel implements KeyListener, ComponentListener{ //JPanel extended so that we can overwrite paintComponent and draw the dots, KeyListener so that we can capture keypresses
Random rand = new Random();
JFrame frame;
boolean haveSize = false; //this is used to tell paintComponent whether or not we have the size of the drawable area
int[] x = new int[18],y = new int[18]; //used to store x and y coordinates of the dots so that they don't change position every time paintComponent is called, which is unpredictable
final int OVALDIAM = 40;
public dots() {
frame = new JFrame("Dots");
frame.setSize(new Dimension(800,600)); //So that when we minimize, we don't get a little bar
frame.setExtendedState(Frame.MAXIMIZED_BOTH); //Maximize the window
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Hiding the window is a dumb default close behavior. Oh well.
frame.getContentPane().add(this); //put the JPanel in the JFrame
frame.addComponentListener(this);
addKeyListener(this); //The next three lines allow the JPanel to capture key presses and subsequently move the dots when a key is pressed
setFocusable(true);
requestFocusInWindow();
frame.setVisible(true);
try { //for whatever reason, the JPanel (this) doesn't know it's height, which we need to accuratly place dots, immediately after calling setVisible, so we wait for a bit to let it figure things out
Thread.sleep(50);
}
catch (Exception e) {}
newPos();
System.out.println("Press any button to rearrange the dots");
}
public void paintComponent(Graphics g) {
super.paintComponent(g); //draw background using the supers method
if (haveSize) { //if we have the size of the window, then newPos has run and we can paint the dots
for (int i = 0; i < 18; i++) { //loop to draw the dots
g.setColor(i < 12 ? Color.YELLOW : Color.BLUE); //if we have drawn fewer than 12 dots, color them yellow, else, color them blue
g.fillOval(x[i],y[i],OVALDIAM,OVALDIAM);
//System.out.println((i < 12 ? "Yellow":"Blue") + " oval drawn at " + x[i] + "," + y[i]); //Debugging that gave location of dots (some where getting lost)
}
}
}
public void newPos() { //this method generates new and random locations for the dots
for (int i = 0; i < 18; i++) {
x[i] = rand.nextInt(getSize().getWidth() > OVALDIAM ? (int)getSize().getWidth() - OVALDIAM : (int)getSize().getWidth()); // we subtract OVALDIAM so that the entire dot fits in the screen. We also check to make sure that the area is >OVALDIAM
y[i] = rand.nextInt(getSize().getHeight() > OVALDIAM ? (int)getSize().getHeight() - OVALDIAM : (int)getSize().getHeight());
}
if (!haveSize) { //if this method has run, then we can run paintComponent
haveSize = true; //we have locations for dots so we can start drawing dots
frame.repaint(); //ensure dots get painted
}
}
public void componentResized(ComponentEvent e){
newPos();
frame.repaint();
}
public void keyPressed(KeyEvent e) { //when a button is pressed, move the dots
newPos();
frame.repaint();
}
//interface methods we don't need
public void componentMoved(ComponentEvent e) {}
public void componentShown(ComponentEvent e) {}
public void componentHidden(ComponentEvent e) {}
public void keyReleased(KeyEvent e){}
public void keyTyped(KeyEvent e) {}
public static void main(String[] args) {
new dots();
}
}
So I have this code, and it works fine. However, if you comment out
try { //for whatever reason, the JPanel (this) doesn't know it's height, which we need to accuratly place dots, immediately after calling setVisible, so we wait for a bit to let it figure things out
Thread.sleep(50);
}
catch (Exception e) {}
you get an error. Works fine if you press a key, which updates everything, but otherwise it is weird. Any ideas why?
On an unrelated note, this code is going to help get me a job, so if any of you see anything wrong, please feel free to speak up.
All drawing should be executed under the AWT thread as shown here and here you might want to get your painting code under dots() method to run under invokeLater() so it will manage to finish painting before querying for height or width.