I was attempting to create a GLFW infinite mouse mode for Swing and here's my progress so far
package javax.swing.extras;
// AWT Imports
import java.awt.AWTException;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
// Swing Imports
import javax.swing.JFrame;
/**
* An extension class that allows JFrames to have infinite input as seen in most
* 3D games.
*/
public class InfiniteMouse {
/** Image for the blank cursor */
private static final BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
/** Blank cursor */
private static final Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(cursorImg, new Point(0, 0),
"blank cursor");
/** Mouse X */
private int x;
/** Mouse Y */
private int y;
/** Previous Mouse X */
private int previousX;
/** Previous Mouse Y */
private int previousY;
/** Center X */
private int centerX;
/** Center Y */
private int centerY;
/**
* Create a InfiniteMouse extension for a JFrame
*
* @param f - The JFrame to add the extension
* @param c - The Container to detect mouse motion
* @return an instance of InfiniteMouse containing the x and y
* @throws AWTException if the platform configuration does not allowlow-level
* input control. This exception is always thrown
* whenGraphicsEnvironment.isHeadless() returns true
*/
public static InfiniteMouse addExtension(JFrame f, Container c) throws AWTException {
// Create a new instance
InfiniteMouse infiniteMouse = new InfiniteMouse();
// Create a final Robot class to later move the mouse to the center
final Robot robot = new Robot();
// Store the on-screen center x of the window
infiniteMouse.centerX = f.getX() + f.getWidth() / 2;
// Store the on-screen center y of the window
infiniteMouse.centerY = f.getY() + f.getHeight() / 2;
// Add a resize listener
f.addComponentListener(new ComponentAdapter() {
// If the frame is resized
public void componentResized(ComponentEvent e) {
// Update the X position
infiniteMouse.centerX = f.getX() + f.getWidth() / 2;
// Update the Y position
infiniteMouse.centerY = f.getY() + f.getHeight() / 2;
}
});
// Make the cursor invisible
f.setCursor(blankCursor);
// Add a mouse listener
c.addMouseMotionListener(new MouseMotionListener() {
// If the mouse is moved
public void mouseMoved(MouseEvent e) {
// Get the current X
int currentX = e.getX();
// Get the current Y
int currentY = e.getY();
System.out.println(infiniteMouse.x);
// Get the mouse X position delta
infiniteMouse.x += currentX - infiniteMouse.previousX;
// Get the mouse Y position delta
infiniteMouse.y += currentY - infiniteMouse.previousY;
// Remove the listener when moving to the center
c.removeMouseMotionListener(this);
// Move the mouse to the center
robot.mouseMove(infiniteMouse.centerX, infiniteMouse.centerY);
// Add the listener back
c.addMouseMotionListener(this);
// Update the previous X
infiniteMouse.previousX = currentX;
// Update the previous Y
infiniteMouse.previousY = currentY;
}
@Override
public void mouseDragged(MouseEvent e) {
}
});
// Return the newly created instance
return infiniteMouse;
}
/**
* Get the X position
*
* @return the X position
*/
public int getX() {
return x;
}
/**
* Get the Y position
*
* @return the Y position
*/
public int getY() {
return y;
}
}
Used in this code
package javax.swing.extras;
import java.awt.AWTException;
import java.awt.Color;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) throws AWTException {
JFrame jf = new JFrame();
JPanel panel1 = new JPanel();
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setTitle("Window");
jf.setSize(800,600);
jf.setLocationRelativeTo(null);
jf.add(panel1);
panel1.grabFocus();
InfiniteMouse.addExtension(jf, panel1);
jf.setVisible(true);
}
}
However the issue I face with this code is that the mouse X being debugged in the console is really not increasing, and I suspect it to be the issue with these lines
c.removeMouseMotionListener(this);
robot.mouseMove(infiniteMouse.centerX, infiniteMouse.centerY);
c.addMouseMotionListener(this);
As it stays around the same value unless I tab out and move the JFrame
around and move it back into the window. Well, the purpose of this line is to suspend the mouse motion listener so that I can move the mouse back and then resume the listener. Is there a working alternative to this method that I can use? or is it some other issue?
Thanks to gthanop's answer I was able to figure out a solution to the issue. Here is the updated code
// Add a mouse listener
c.addMouseMotionListener(new MouseAdapter() {
// If the mouse is moved
public void mouseMoved(MouseEvent e) {
// Get the current X
int currentX = e.getX();
// Get the current Y
int currentY = e.getY();
// Get the current X on screen
int currentXOnScreen = f.getX() + currentX;
// Get the current Y on screen
int currentYOnScreen = f.getY() + currentY;
// Get the mouse X position delta
infiniteMouse.x += (currentXOnScreen - infiniteMouse.centerX) + 8;
// Get the mouse Y position delta
infiniteMouse.y += (currentYOnScreen - infiniteMouse.centerY) + 32;
// Move the mouse to the center
robot.mouseMove(infiniteMouse.centerX, infiniteMouse.centerY);
}
});
I believe that Robot.moveMouse
infact does not move the pointer to the specified location but sets the center of the pointer to the specified location maybe something like that. That is why I add 8 to the difference on the X and 32 on the Y. However I am not sure as to what the reason could be but since it works I will just leave it like that.
This answer provides a solution to the problem in the question. However gthanop's answer provides a lot more detail I highly recommend reading that