Search code examples
c#sendinput

Moving mouse by delta causes cursor movement to be "jittery"


I am writing a piece of software that takes an analog input from a POT in the form of a double with a range from -1 to +1 and am in turn trying to use this as mouse cursor delta. Everything works, but the iteration/speed is too slow and forces me to multiply the value of the input causing the cursor to movement to not be as fluid as I would like.

class myApp
{
    double remX = 0;
    double remY = 0;
    double rateX = 0;
    double rateY = 0;

    private void mouseDeltaThread()
    {
        while (!Global.IsShuttingDown)
        {
            System.Threading.Thread.Sleep(1);
            if (rateX != 0 || rateY !=0)
                setMouseDelta(rateX,rateY);
        }

    }

    private void setMouseDelta(double dX, double dY)
    {
        remX += (dX);
        remY += (dY);

        int moveX = (int)Math.Truncate(remX);
        int moveY = (int)Math.Truncate(remY);

        remX -= moveX;
        remY -= moveY;

        Shared.MoveCursorBy(moveX, moveY);
    }

}

internal static class Shared
{
    internal const uint INPUT_MOUSE = 0, INPUT_KEYBOARD = 1, INPUT_HARDWARE = 2;
    private static INPUT[] sendInputs = new INPUT[2]; // will allow for keyboard + mouse/tablet input within one SendInput call, or two mouse events
    private static object lockob = new object();
    public static void MoveCursorBy(int x, int y)
    {
        lock (lockob)
        {
            if (x != 0 || y != 0)
            {
                sendInputs[0].type = INPUT_MOUSE;
                sendInputs[0].data.mi.dwExtraInfo = IntPtr.Zero;
                sendInputs[0].data.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_MOVE;
                sendInputs[0].data.mi.mouseData = 0;
                sendInputs[0].data.mi.time = 0;
                sendInputs[0].data.mi.dx = x;
                sendInputs[0].data.mi.dy = y;
                uint result = SendInput(1, sendInputs, Marshal.SizeOf(sendInputs[0]));
            }
        }
    }
}

I am using SendInput since it allows for relative cursor movement, but I wonder if SetCursorPos and keeping track of the x,y relative to screen is more efficient.

Is there a better way of doing this?


Solution

  • Better, but still spending too many cycles on my waitHandle. I know infinite loops are typically bad, but I simply cannot see any other way to get decent performance out of this as timers seem to iterate slower.

    class MyApp
    {
        double remX = 0;
        double remY = 0;
        double rateX = 0;
        double rateY = 0;
    
        private void mouseDeltaThread()
        {
            EventWaitHandle MyEventWaitHandle = new EventWaitHandle(false,EventResetMode.AutoReset);
            while (!Global.IsShuttingDown)
            {
                MyEventWaitHandle.WaitOne(1);
                if (rateX != 0 || rateY !=0)
                    setMouseDelta(rateX,rateY);
            }
    
        }
    
        private void setMouseDelta(double dX, double dY)
        {
            remX += (dX);
            remY += (dY);
    
            int moveX = (int)remX;
            int moveY = (int)remY;
    
            remX -= moveX;
            remY -= moveY;
    
            Shared.MoveCursorBy(moveX, moveY);
        }
    
    }
    
    internal static class Shared
    {
        public static void MoveCursorBy(int x, int y)
        {
            POINT p = new POINT();
            GetCursorPos(out p);
            p.x += x;
            p.y += y;
            SetCursorPos(p.x, p.y);
        }
    }
    

    Changes from top to bottom.

    Using EventWaitHandle. Definitely like this and will be using it more often, however no noticeable performance differences from Sleep(1).

    Casting double remX and remY to int rather than truncating it. Seems to have slight performance boost.

    Using GetCursorPos and SetCursorPos in place of SendInput. Seems to perform better, would be better still if I maintained my own running x and y coords instead of calling GetCursorPos every iteration, but I wanted to maintain out of app mouse usage as well.

    This still needs some tuning thoug. As I said, I am still spending too many cycles on the EventWaitHandle and I do not know how to make that run any better.