skip to Main Content

So, I have a strange problem. I’m making a WPF app that moves the mouse around. I have the following bit of code for this:

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

        public static implicit operator Point(POINT point)
        {
            return new Point(point.X, point.Y);
        }
    }

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

[DllImport("user32.dll", EntryPoint = "SetCursorPos")]
private static extern void SetCursorPos(int X, int Y);

private static Random random = new Random(DateTime.Now.Millisecond);

public static Point GetMousePosition()
    {
        GetCursorPos(out POINT lpPoint);
        return lpPoint;
    }

public static void MoveMouse(int x, int y, int tolerance = 10)
    {
        tolerance = Math.Max(0, tolerance);
        int startX = GetMousePosition().X;
        int startY = GetMousePosition().Y;
        int finalX = random.Next(x - tolerance, x + tolerance + 1);
        int finalY = random.Next(y - tolerance, y + tolerance + 1);
        int diffX = finalX - startX;
        int diffY = finalY - startY;
        double time = Math.Max(1, Math.Max(Math.Abs(diffX), Math.Abs(diffY)) / (5 + random.NextDouble()));
        double deltaX = diffX / time;
        double deltaY = diffY / time;
        for (int i = 1; i <= time; i++)
        {
            SetCursorPos((int)(startX + deltaX * i), (int)(startY + deltaY * i));
        }
    }

Basically long story short, call MoveMouse() with an x,y coordinate and it’ll move the mouse to that point on screen ± [tolerance] pixels.

If I run it out of visual studio directly, with debugger attached, everything works as expected. However, if ran without the debugger, the mouse actually moves 2-3 times slower. I’d have to throw in a Thread.Sleep(1); inside the for loop just to match what it does in release mode. And then, if I leave the delay in there, it actually goes even slower in production! If I run the app stand-alone, observing its usual slowness, and then manually attach the debugger to it later, it suddenly becomes fast.

What gives? How can I make it go as fast in "production" as it does in debug?

To clarify: the "debug" vs "release" configuration doesn’t actually make a difference. It’s only different when the debugger is attached.

2

Answers


  1. Chosen as BEST ANSWER

    A-HA! I figured it out. On a wild hunch, I decided to dig up some time period shenanigans that I had some vague experience using a long time ago.

    I added

    [DllImport("winmm.dll", EntryPoint = "timeBeginPeriod", SetLastError = true)]
    public static extern uint TimeBeginPeriod(uint uMilliseconds);
    
    [DllImport("winmm.dll", EntryPoint = "timeEndPeriod", SetLastError = true)]
    public static extern uint TimeEndPeriod(uint uMilliseconds);
    

    and then wrapped the mouse moving code in

    TimeBeginPeriod(1);
    

    and

    TimeEndPeriod(1);
    

    This normalized the speeds across all possible run modes, solving my problem. Though now I'm also left confused as to why the debugger is interfering with this stuff. :/ Oh well, for the time being I'm satisfied and that can be another adventure for another time I guess, if it ever becomes relevant again.


  2. If I remember correctly, I observed similar issue when I made a console app that runs some function in a while(true) loop. Because no sleep was done in between every cycle, that means the function is being called again and again, making the application CPU usage peaks in an instant, and keeps on that. It made the whole system slow down, so the cursor gets laggy too.

    No proof at all, but I guess because debugger needs to follow things, it essentially adds delay, indirectly lowering the CPU usage. Not educated about debugger so any explanation about that is welcomed.

    My fix was like yours exactly, putting sleep in-between.

            for (int i = 1; i <= time; i++)
            {
                SetCursorPos((int)(startX + deltaX * i), (int)(startY + deltaY * i));
                Thread.Sleep(100); // 0.1s, might be a little clunky.
            }
    

    The sleep time depends on your actual requirement, but usually a movie has 24fps, that’s like ~40ms per sleep.

    Surely, 1ms smooth movement that fixes the stuck while being extra smooth sounds magnificent, but you should definitely consider balancing between performance cost and visual effect.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search