Browse Source

Implemented assignment of cursor position for Cacao when in full-screen, adapting to pixel scaling, and returning false when the cursor could not be moved.

David Piuva 7 months ago
parent
commit
90b037fbf5

+ 3 - 2
Source/DFPSR/api/guiAPI.cpp

@@ -196,9 +196,10 @@ bool dsr::window_getCursorVisibility(const Window& window) {
 	return window->backend->visibleCursor;
 }
 
-void dsr::window_setCursorPosition(const Window& window, int x, int y) {
+bool dsr::window_setCursorPosition(const Window& window, int x, int y) {
 	MUST_EXIST(window, window_setCursorPosition);
-	window->backend->setCursorPosition(x, y);
+	int pixelScale = window->getPixelScale();
+	return window->backend->setCursorPosition(x * pixelScale, y * pixelScale);
 }
 
 void dsr::window_setFullScreen(const Window& window, bool enabled) {

+ 4 - 1
Source/DFPSR/api/guiAPI.h

@@ -181,6 +181,8 @@ namespace dsr {
 	//   0 <= x < width
 	//   0 <= y < height
 	//   Moving the mouse outside of the window's region may cause undefined behavior between platforms.
+	// Post-condition:
+	//   Returns true on success and false on failure.
 	// WARNING!
 	//   Only set the cursor location if you know for sure that the cursor is controlled using relative input devices, such as a mouse or track-pad.
 	//   If an absolute input method is used, such as a stylus-pen, touch-screen or eye-tracker, the cursor will shake quickly.
@@ -190,9 +192,10 @@ namespace dsr {
 	// WARNING!
 	//   On MS-Windows the cursor will always move, but on X11 the cursor must be within the window's region.
 	//   Only use this in full-screen mode to prevent getting stuck outside of the window.
+	//   On MacOS, the call will always fail if fullscreen is not active.
 	// WARNING!
 	//   Due to potential race-conditions, you can not assume that the next mouse move event is generated by this call.
-	void window_setCursorPosition(const Window& window, int x, int y);
+	bool window_setCursorPosition(const Window& window, int x, int y);
 
 // Full screen
 	void window_setFullScreen(const Window& window, bool enabled);

+ 1 - 1
Source/DFPSR/implementation/gui/BackendWindow.h

@@ -92,7 +92,7 @@ public:
 	// Cursor interface
 	bool visibleCursor = true; // Written to by setCursorVisibility on success.
 	virtual bool setCursorVisibility(bool visible) { return false; } // Returns true on success.
-	virtual void setCursorPosition(int x, int y) {} // Does nothing unless implemented.
+	virtual bool setCursorPosition(int x, int y) { return false; } // Returns true on success.
 public:
 	// Clipboard interface
 	//   If none is replaced, both default implementations will use an internal variable.

+ 12 - 5
Source/SDK/camera/main.cpp

@@ -1,4 +1,7 @@
 
+// TODO:
+// Test with multiple displays and high DPI mode.
+
 #include "../../DFPSR/includeFramework.h"
 
 using namespace dsr;
@@ -89,9 +92,11 @@ void dsrMain(List<String> args) {
 		DsrKey key = event.dsrKey;
 		if (event.keyboardEventType == KeyboardEventType::KeyDown) {
 			if (key >= DsrKey_1 && key <= DsrKey_9) {
+				// TODO: Create a smooth transition between resolutions.
 				window_setPixelScale(window, key - DsrKey_0);
 			} else if (key == DsrKey_F11) {
 				window_setFullScreen(window, !window_isFullScreen(window));
+				window_setCursorVisibility(window, !window_isFullScreen(window));
 			} else if (key == DsrKey_Escape) {
 				running = false;
 			} else if (key == DsrKey_C) {
@@ -145,15 +150,17 @@ void dsrMain(List<String> args) {
 				cursorWasReset = false;
 			} else {
 				// TODO: Adjust mouse sensitivity somehow.
-				cameraYaw   += double(movement.x) * 0.005;
-				cameraPitch -= double(movement.y) * 0.005;
+				double radiansPerCanvasPixel = 0.005 * double(window_getPixelScale(window));
+				cameraYaw   += double(movement.x) * radiansPerCanvasPixel;
+				cameraPitch -= double(movement.y) * radiansPerCanvasPixel;
 				if (cameraPitch > maxPitch) cameraPitch = maxPitch;
 				if (cameraPitch < -maxPitch) cameraPitch = -maxPitch;
 				if (offset.x < -cursorLimitX || offset.y < -cursorLimitY || offset.x > cursorLimitX || offset.y > cursorLimitY) {
 					// The cursor traveled outside of the box, so it is moved to the center.
-					window_setCursorPosition(window, cursorOrigin.x, cursorOrigin.y);
-					// Remember that the cursor was reset, so that the next mouse move event going to the center can be ignored.
-					cursorWasReset = true;
+					if (window_setCursorPosition(window, cursorOrigin.x, cursorOrigin.y)) {
+						// If successful, remember that the cursor was reset, so that the next mouse move event going to the center can be ignored.
+						cursorWasReset = true;
+					}
 				}
 			}
 		}

+ 17 - 3
Source/windowManagers/CocoaWindow.mm

@@ -5,8 +5,6 @@
 //   * Make sure that the manual full screen does not collide with programmatical triggering of full screen.
 //   * Minimizing the window
 //     It just bounces back instantly.
-//   * Setting cursor position.
-//     Not yet implemented.
 
 // Potential optimizations:
 // * Double buffering is disabled for safety by assigining bufferCount to 1 instead of 2 and copying presented pixel data to delayedCanvas.
@@ -73,7 +71,7 @@ private:
 	bool setCursorVisibility(bool visible) override;
 
 	// Place the cursor within the window
-	//void setCursorPosition(int x, int y) override;
+	bool setCursorPosition(int x, int y) override;
 private:
 	// Helper methods specific to calling XLib
 	void updateTitle();
@@ -151,6 +149,22 @@ bool CocoaWindow::setCursorVisibility(bool visible) {
 	return true;
 }
 
+bool CocoaWindow::setCursorPosition(int x, int y) {
+	if (this->windowState == 2) {
+		NSRect viewBounds = [this->view bounds];
+		NSRect viewInWindow = [this->view convertRect:viewBounds toView:nil];
+		CGWarpMouseCursorPosition(CGPointMake(viewInWindow.origin.x + x, viewInWindow.origin.y + y));
+		// Prevent stalling after the move.
+		CGAssociateMouseAndMouseCursorPosition(true);
+		// TODO: How can the mouse move event be sent in the correct order in case of already having move events waiting?
+		this->receivedMouseEvent(dsr::MouseEventType::MouseMove, dsr::MouseKeyEnum::NoKey, dsr::IVector2D(x, y));
+		return true;
+	} else {
+		// Setting the cursor position is not reliable in windowed mode, because the fetching the window location often returns outdated coordinates.
+		return false;
+	}
+}
+
 void CocoaWindow::setDecorations(bool decorated) {
 	// NSWindowStyleMaskFullScreen has to be preserved, because it may only be changed by full screen transitions.
 	static const SInt flags = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;

+ 3 - 2
Source/windowManagers/Win32Window.cpp

@@ -69,7 +69,7 @@ private:
 	bool setCursorVisibility(bool visible) override;
 
 	// Place the cursor within the window
-	void setCursorPosition(int x, int y) override;
+	bool setCursorPosition(int x, int y) override;
 private:
 	// Helper methods specific to calling XLib
 	void updateTitle_locked();
@@ -168,12 +168,13 @@ void Win32Window::updateTitle_locked() {
 }
 
 // The method can be seen as locked, but it overrides a virtual method that is independent of threading.
-void Win32Window::setCursorPosition(int x, int y) {
+bool Win32Window::setCursorPosition(int x, int y) {
 	lockWindow();
 		POINT point; point.x = x; point.y = y;
 		ClientToScreen(this->hwnd, &point);
 		SetCursorPos(point.x, point.y);
 	unlockWindow();
+	return true;
 }
 
 bool Win32Window::setCursorVisibility(bool visible) {

+ 3 - 2
Source/windowManagers/X11Window.cpp

@@ -70,7 +70,7 @@ private:
 	bool setCursorVisibility(bool visible) override;
 
 	// Place the cursor within the window
-	void setCursorPosition(int x, int y) override;
+	bool setCursorPosition(int x, int y) override;
 
 	// Color format
 	dsr::PackOrderIndex packOrderIndex = dsr::PackOrderIndex::RGBA;
@@ -153,10 +153,11 @@ void X11Window::saveToClipboard(const dsr::ReadableString &text, double timeoutI
 	this->listContentInClipboard();
 }
 
-void X11Window::setCursorPosition(int x, int y) {
+bool X11Window::setCursorPosition(int x, int y) {
 	lockWindow();
 		XWarpPointer(this->display, this->window, this->window, 0, 0, this->windowWidth, this->windowHeight, x, y);
 	unlockWindow();
+	return true;
 }
 
 void X11Window::applyCursorVisibility_locked() {