'Windows: SetCursorPos over RDP sometimes results in wrong position

I am connected to a Windows VM via RDP. The host system is also Windows. On the VM, I run an application that uses SetCursorPos to change the position of the mouse cursor. I have observed that the call sometimes causes the mouse cursor to arrive at a completely different location.

If I run the application on the host system, it runs without errors. So it seems to be related to RDP.

Consider the following C# demo application. Basically, it calls SetCursorPos a thousand times with random positions and checks with GetCursorPos whether the mouse cursor has landed at the specified position.

using System;
using System.Runtime.InteropServices;
using System.Threading;

namespace CursorDemoApp
{
    class Program
    {
        static void Main()
        {
            var random = new Random(1);
            var displayWidth = GetDisplayWidth();
            var displayHeight = GetDisplayHeight();

            for (var run = 1; run <= 1000; run++)
            {
                SetAndCheckCursorPosition(0, 0);

                var x = random.Next(displayWidth);
                var y = random.Next(displayHeight);
                SetAndCheckCursorPosition(x, y);

                Thread.Sleep(10);
            }
        }

        private static void SetAndCheckCursorPosition(int x, int y)
        {
            SetCursorPosition(x, y);
            var currentPosition = GetCursorPosition();
            if (currentPosition.X != x || currentPosition.Y != y)
            {
                Console.WriteLine("Failed! Expected: ({0},{1}) - Got: ({2},{3})", x, y, currentPosition.X, currentPosition.Y);
            }
        }

        private static void SetCursorPosition(int x, int y)
        {
            Console.WriteLine("SetCursorPosition({0},{1})", x, y);
            SetCursorPos(x, y);
        }

        [DllImport("user32.dll")]
        private static extern bool SetCursorPos(int x, int y);

        private static Point GetCursorPosition()
        {
            GetCursorPos(out var point);
            Console.WriteLine("GetCursorPosition() == ({0},{1})", point.X, point.Y);
            return point;
        }

        [DllImport("user32.dll")]
        private static extern bool GetCursorPos(out Point point);

        private static int GetDisplayWidth()
        {
            return GetSystemMetrics(16 /* SM_CXFULLSCREEN */);
        }

        private static int GetDisplayHeight()
        {
            return GetSystemMetrics(17 /* SM_CYFULLSCREEN */);
        }

        [DllImport("user32.dll")]
        private static extern int GetSystemMetrics(int index);

        [StructLayout(LayoutKind.Sequential)]
        private struct Point
        {
            public int X;
            public int Y;
        }
    }
}

When I run this in the VM, I get as output, for example:

...
SetCursorPosition(0,0)
GetCursorPosition() == (0,0)
SetCursorPosition(1330,269)
GetCursorPosition() == (1330,269)
SetCursorPosition(0,0)
GetCursorPosition() == (0,0)
SetCursorPosition(18,10)
GetCursorPosition() == (1330,269)
Failed! Expected: (18,10) - Got: (1330,269)
SetCursorPosition(0,0)
GetCursorPosition() == (0,0)
SetCursorPosition(973,392)
GetCursorPosition() == (973,392)
...

Can anyone explain this behavior or provide a solution?

(Originally, I noticed this when using Eclipse SWT and Display.setCursorLocation(..). Since that also uses SetCursorPos under the hood, I wanted to leave this as a hint for search engines.)



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source