Browse Source

Fix mouse position backward compatibility with new SDL2 versions.

Clamp the mouse coordinates to the window's dimensions.
Sasha Szpakowski 2 years ago
parent
commit
e582677344

+ 18 - 0
src/modules/event/sdl/Event.cpp

@@ -51,6 +51,13 @@ static void windowToDPICoords(double *x, double *y)
 		window->windowToDPICoords(x, y);
 }
 
+static void clampToWindow(double *x, double *y)
+{
+	auto window = Module::getInstance<window::Window>(Module::M_WINDOW);
+	if (window)
+		window->clampPositionInWindow(x, y);
+}
+
 #ifndef LOVE_MACOSX
 static void normalizedToDPICoords(double *x, double *y)
 {
@@ -253,8 +260,16 @@ Message *Event::convert(const SDL_Event &e)
 			double y = (double) e.motion.y;
 			double xrel = (double) e.motion.xrel;
 			double yrel = (double) e.motion.yrel;
+
+			// SDL reports mouse coordinates outside the window bounds when click-and-
+			// dragging. For compatibility we clamp instead since user code may not be
+			// able to handle out-of-bounds coordinates. SDL has a hint to turn off
+			// auto capture, but it doesn't report the mouse's position at the edge of
+			// the window if the mouse moves fast enough when it's off.
+			clampToWindow(&x, &y);
 			windowToDPICoords(&x, &y);
 			windowToDPICoords(&xrel, &yrel);
+
 			vargs.emplace_back(x);
 			vargs.emplace_back(y);
 			vargs.emplace_back(xrel);
@@ -280,7 +295,10 @@ Message *Event::convert(const SDL_Event &e)
 
 			double px = (double) e.button.x;
 			double py = (double) e.button.y;
+
+			clampToWindow(&px, &py);
 			windowToDPICoords(&px, &py);
+
 			vargs.emplace_back(px);
 			vargs.emplace_back(py);
 			vargs.emplace_back((double) button);

+ 21 - 14
src/modules/mouse/sdl/Mouse.cpp

@@ -49,6 +49,13 @@ static void DPIToWindowCoords(double *x, double *y)
 		window->DPIToWindowCoords(x, y);
 }
 
+static void clampToWindow(double *x, double *y)
+{
+	auto window = Module::getInstance<window::Window>(Module::M_WINDOW);
+	if (window)
+		window->clampPositionInWindow(x, y);
+}
+
 const char *Mouse::getName() const
 {
 	return "love.mouse.sdl";
@@ -119,24 +126,16 @@ bool Mouse::isCursorSupported() const
 
 double Mouse::getX() const
 {
-	int x;
-	SDL_GetMouseState(&x, nullptr);
-
-	double dx = (double) x;
-	windowToDPICoords(&dx, nullptr);
-
-	return dx;
+	double x, y;
+	getPosition(x, y);
+	return x;
 }
 
 double Mouse::getY() const
 {
-	int y;
-	SDL_GetMouseState(nullptr, &y);
-
-	double dy = (double) y;
-	windowToDPICoords(nullptr, &dy);
-
-	return dy;
+	double x, y;
+	getPosition(x, y);
+	return y;
 }
 
 void Mouse::getPosition(double &x, double &y) const
@@ -146,6 +145,14 @@ void Mouse::getPosition(double &x, double &y) const
 
 	x = (double) mx;
 	y = (double) my;
+
+	// SDL reports mouse coordinates outside the window bounds when click-and-
+	// dragging. For compatibility we clamp instead since user code may not be
+	// able to handle out-of-bounds coordinates. SDL has a hint to turn off
+	// auto capture, but it doesn't report the mouse's position at the edge of
+	// the window if the mouse moves fast enough when it's off.
+	clampToWindow(&x, &y);
+
 	windowToDPICoords(&x, &y);
 }
 

+ 2 - 0
src/modules/window/Window.h

@@ -193,6 +193,8 @@ public:
 	virtual int getPixelWidth() const = 0;
 	virtual int getPixelHeight() const = 0;
 
+	virtual void clampPositionInWindow(double *wx, double *wy) const = 0;
+
 	// Note: window-space coordinates are not necessarily the same as
 	// density-independent units (which toPixels and fromPixels use.)
 	virtual void windowToPixelCoords(double *x, double *y) const = 0;

+ 7 - 0
src/modules/window/sdl/Window.cpp

@@ -1124,6 +1124,13 @@ int Window::getPixelHeight() const
 	return pixelHeight;
 }
 
+void Window::clampPositionInWindow(double *wx, double *wy) const
+{
+	if (wx != nullptr)
+		*wx = std::min(std::max(0.0, *wx), (double) getWidth() - 1);
+	if (wy != nullptr)
+		*wy = std::min(std::max(0.0, *wy), (double) getHeight() - 1);
+}
 
 void Window::windowToPixelCoords(double *x, double *y) const
 {

+ 2 - 0
src/modules/window/sdl/Window.h

@@ -104,6 +104,8 @@ public:
 	int getPixelWidth() const override;
 	int getPixelHeight() const override;
 
+	void clampPositionInWindow(double *wx, double *wy) const override;
+
 	void windowToPixelCoords(double *x, double *y) const override;
 	void pixelToWindowCoords(double *x, double *y) const override;