2
0
Эх сурвалжийг харах

Win 32: Fix disabled cursor mode when connected over RDP

Fixes #1276
Based on PR #1279 by @Pokechu22

Co-authored-by: Pokechu22 <[email protected]>
Hilderin 1 жил өмнө
parent
commit
c8521b7fda

+ 2 - 0
CONTRIBUTORS.md

@@ -279,6 +279,8 @@ video tutorials.
  - Jonas Ådahl
  - Lasse Öörni
  - Leonard König
+ - Pokechu22
+ - Guillaume Lebrun
  - All the unmentioned and anonymous contributors in the GLFW community, for bug
    reports, patches, feedback, testing and encouragement
 

+ 1 - 0
README.md

@@ -236,6 +236,7 @@ information on what to include when reporting a bug.
  - [Win32] Bugfix: `glfwWaitEventsTimeout` did not return for some sent messages (#2408)
  - [Win32] Bugfix: Fix pkg-config for dynamic library on Windows (#2386, #2420)
  - [Win32] Bugfix: XInput could reportedly provide invalid DPad bit masks (#2291)
+ - [Win32] Bugfix: Disabled cursor mode doesn't work right when connected over RDP (#1276)
  - [Win32] Bugfix: Rapid clipboard calls could fail due to Clipboard History
  - [Cocoa] Added support for `VK_EXT_metal_surface` (#1619)
  - [Cocoa] Added locating the Vulkan loader at runtime in an application bundle

+ 48 - 0
src/win32_init.c

@@ -430,6 +430,47 @@ static GLFWbool createHelperWindow(void)
    return GLFW_TRUE;
 }
 
+// Creates the blank cursor
+//
+static void createBlankCursor(void)
+{
+    // HACK: Create a transparent cursor as using the NULL cursor breaks
+    //       using SetCursorPos when connected over RDP
+    int cursorWidth = GetSystemMetrics(SM_CXCURSOR);
+    int cursorHeight = GetSystemMetrics(SM_CYCURSOR);
+    unsigned char* andMask = calloc(cursorWidth * cursorHeight / 8, sizeof(unsigned char));
+    unsigned char* xorMask = calloc(cursorWidth * cursorHeight / 8, sizeof(unsigned char));
+
+    if (andMask != NULL && xorMask != NULL) {
+
+        memset(andMask, 0xFF, (size_t)(cursorWidth * cursorHeight / 8));
+
+        // Cursor creation might fail, but that's fine as we get NULL in that case,
+        // which serves as an acceptable fallback blank cursor (other than on RDP)
+        _glfw.win32.blankCursor = CreateCursor(NULL, 0, 0, cursorWidth, cursorHeight, andMask, xorMask);
+
+        free(andMask);
+        free(xorMask);
+    }
+
+}
+
+// Initialize for remote sessions
+//
+static void initRemoteSession(void)
+{
+    //Check if the current progress was started with Remote Desktop.
+    _glfw.win32.isRemoteSession = GetSystemMetrics(SM_REMOTESESSION) > 0;
+
+    // With Remote desktop, we need to create a blank cursor because of the cursor is Set to NULL
+    // if cannot be moved to center in capture mode. If not Remote Desktop win32.blankCursor stays NULL
+    // and will perform has before (normal).
+    if (_glfw.win32.isRemoteSession)
+    {
+        createBlankCursor();
+    }
+
+}
 
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW internal API                      //////
@@ -699,12 +740,19 @@ int _glfwInitWin32(void)
     if (!createHelperWindow())
         return GLFW_FALSE;
 
+    //Some hacks are needed to support Remote Desktop...
+    initRemoteSession();
+
     _glfwPollMonitorsWin32();
     return GLFW_TRUE;
 }
 
 void _glfwTerminateWin32(void)
 {
+
+    if (_glfw.win32.blankCursor)
+        DestroyCursor(_glfw.win32.blankCursor);
+
     if (_glfw.win32.deviceNotificationHandle)
         UnregisterDeviceNotification(_glfw.win32.deviceNotificationHandle);
 

+ 5 - 0
src/win32_platform.h

@@ -430,6 +430,7 @@ typedef struct _GLFWwindowWin32
 
     // The last received cursor position, regardless of source
     int                 lastCursorPosX, lastCursorPosY;
+
     // The last received high surrogate when decoding pairs of UTF-16 messages
     WCHAR               highSurrogate;
 } _GLFWwindowWin32;
@@ -457,6 +458,10 @@ typedef struct _GLFWlibraryWin32
     RAWINPUT*           rawInput;
     int                 rawInputSize;
     UINT                mouseTrailSize;
+    // Indicate if the process was started behind Remote Destop
+    BOOL                isRemoteSession;
+    // An invisible cursor, needed for special cases (see WM_INPUT handler)
+    HCURSOR             blankCursor;
 
     struct {
         HINSTANCE                       instance;

+ 34 - 4
src/win32_window.c

@@ -232,7 +232,10 @@ static void updateCursorImage(_GLFWwindow* window)
             SetCursor(LoadCursorW(NULL, IDC_ARROW));
     }
     else
-        SetCursor(NULL);
+        //Connected via Remote Desktop, NULL cursor will present SetCursorPos the move the cursor.
+        //using a blank cursor fix that.
+        //When not via Remote Desktop, win32.blankCursor should be NULL
+        SetCursor(_glfw.win32.blankCursor);
 }
 
 // Sets the cursor clip rect to the window content area
@@ -897,6 +900,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
             HRAWINPUT ri = (HRAWINPUT) lParam;
             RAWINPUT* data = NULL;
             int dx, dy;
+            int width, height;
+            POINT pos;
 
             if (_glfw.win32.disabledCursorWindow != window)
                 break;
@@ -923,9 +928,30 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
 
             data = _glfw.win32.rawInput;
             if (data->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE)
-            {
-                dx = data->data.mouse.lLastX - window->win32.lastCursorPosX;
-                dy = data->data.mouse.lLastY - window->win32.lastCursorPosY;
+            {   
+                if (_glfw.win32.isRemoteSession)
+                {
+                    //Remote Desktop Mode...
+                    // As per https://github.com/Microsoft/DirectXTK/commit/ef56b63f3739381e451f7a5a5bd2c9779d2a7555
+                    // MOUSE_MOVE_ABSOLUTE is a range from 0 through 65535, based on the screen size.
+                    // As far as I can tell, absolute mode only occurs over RDP though.
+                    width = GetSystemMetrics((data->data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) ? SM_CXVIRTUALSCREEN : SM_CXSCREEN);
+                    height = GetSystemMetrics((data->data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) ? SM_CYVIRTUALSCREEN : SM_CYSCREEN);
+
+                    pos.x = (int)((data->data.mouse.lLastX / 65535.0f) * width);
+                    pos.y = (int)((data->data.mouse.lLastY / 65535.0f) * height);
+                    ScreenToClient(window->win32.handle, &pos);
+
+                    dx = pos.x - window->win32.lastCursorPosX;
+                    dy = pos.y - window->win32.lastCursorPosY;
+                }
+                else
+                {
+                    //Normal mode... We should have the right absolute coords in data.mouse
+                    dx = data->data.mouse.lLastX - window->win32.lastCursorPosX;
+                    dy = data->data.mouse.lLastY - window->win32.lastCursorPosY;
+                }
+
             }
             else
             {
@@ -1432,11 +1458,13 @@ static int createNativeWindow(_GLFWwindow* window,
         window->win32.transparent = GLFW_TRUE;
     }
 
+
     _glfwGetWindowSizeWin32(window, &window->win32.width, &window->win32.height);
 
     return GLFW_TRUE;
 }
 
+
 GLFWbool _glfwCreateWindowWin32(_GLFWwindow* window,
                                 const _GLFWwndconfig* wndconfig,
                                 const _GLFWctxconfig* ctxconfig,
@@ -1525,6 +1553,7 @@ void _glfwDestroyWindowWin32(_GLFWwindow* window)
 
     if (window->win32.smallIcon)
         DestroyIcon(window->win32.smallIcon);
+
 }
 
 void _glfwSetWindowTitleWin32(_GLFWwindow* window, const char* title)
@@ -2102,6 +2131,7 @@ void _glfwPollEventsWin32(void)
 
         // NOTE: Re-center the cursor only if it has moved since the last call,
         //       to avoid breaking glfwWaitEvents with WM_MOUSEMOVE
+        // The re-center is required in order to prevent the mouse cursor stopping at the edges of the screen.
         if (window->win32.lastCursorPosX != width / 2 ||
             window->win32.lastCursorPosY != height / 2)
         {