我正在编写一个使用SendInput功能来模拟鼠标事件以播放PC水果忍者的程序。但是当我调用SendInput时,鼠标移动了,但是游戏屏幕上什么也没有发生。谁能告诉我为什么它不起作用并提供一些解决方案?我在C#上编程,并使用[dllimport]调用SendInput函数。
谢谢。

最佳答案

我建议您仅模拟mouse move。您应该模拟mouse drag。首先执行mouse down-> mouse move-> mouse up

这是我旧项目中的一些代码:

namespace Clicker.Enums
{
    public enum MouseEvents
    {
        MOVE = 0x0001, /* mouse move */
        LEFTDOWN = 0x0002, /* left button down */
        LEFTUP = 0x0004, /* left button up */
        RIGHTDOWN = 0x0008, /* right button down */
        RIGHTUP = 0x0010, /* right button up */
        MIDDLEDOWN = 0x0020, /* middle button down */
        MIDDLEUP = 0x0040, /* middle button up */
        XDOWN = 0x0080, /* x button down */
        XUP = 0x0100, /* x button down */
        WHEEL = 0x0800, /* wheel button rolled */
        VIRTUALDESK = 0x4000, /* map to entire virtual desktop */
        ABSOLUTE = 0x8000 /* absolute move */
    }
}

namespace Clicker.Actions
{
    public class Action
    {
        protected int x;
        protected int y;

        ...

        [DllImport("user32")]
        protected static extern int SetCursorPos(int x, int y);

        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        protected static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);

        ...

        public int X { get { return x; } set { x = value; } }
        public int Y { get { return y; } set { y = value; } }

        ...

        public vritual void PerformAction()
        {

        }

        ...
    }
}

namespace Clicker.Actions
{
    public class Drag : Action
    {
        public int To_X { get; set; }
        public int To_Y { get; set; }

        ...

        public override void PerformAction()
        {
            SetCursorPos(X, Y);
            Thread.Sleep(100);
            mouse_event((int)MouseEvents.LEFTDOWN, 0, 0, 0, 0);
            SetCursorPos(To_X, To_Y);
            Thread.Sleep(100);
            mouse_event((int)MouseEvents.LEFTUP, 0, 0, 0, 0);
        }

        ...
    }
}


使用方法:

Action sliseFruit = new Drag(){
    X = 0, // from (X=0, Y=0)
    Y = 0, // from (X=0, Y=0)
    To_X = 100, // to (X=100, Y=100)
    To_Y = 100, // to (X=100, Y=100)
};

sliseFruit.PerformAction();


这里有一些更多建议:如果您想在应用程序的主要形式之外单击,问题也可能出在SynchronizationContext和/或线程中。可能的解决方案:

namespace Clicker.Actions
    {
        public class Action
        {
            protected int x;
            protected int y;

            // Add this fields
            private static SynchronizationContext _context = null;
            public static SynchronizationContext Context { get { return _context; } set { _context = value; } }

            ...

            [DllImport("user32")]
            protected static extern int SetCursorPos(int x, int y);

            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
            protected static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);

            ...

            public int X { get { return x; } set { x = value; } }
            public int Y { get { return y; } set { y = value; } }

            ...

            // ... and this method
            internal virtual void InnerPerformAction(object state)
            {
                 return;
            }

            // change PerformAction like this
            public void PerformAction()
            {
                InnerPerformAction(new object());
            }

            ...
        }
    }


现在编辑Drag动作类:

namespace Clicker.Actions
    {
        public class Drag : Action
        {
            public int To_X { get; set; }
            public int To_Y { get; set; }

            ...

            internal override void InnerPerformAction(object state)
            {
               try
               {
                   Context.Send(new SendOrPostCallback(delegate
                       {
                           SetCursorPos(X, Y);
                           Thread.Sleep(100);
                           mouse_event((int)MouseEvents.LEFTDOWN, 0, 0, 0, 0);
                           SetCursorPos(To_X, To_Y);
                           Thread.Sleep(100);
                           mouse_event((int)MouseEvents.LEFTUP, 0, 0, 0, 0);
                       }), state);

               }
               catch
               {
                   //Aaaaahh... what ever...
               }
            }

            ...
        }
    }


差点忘了:

// You have to do this in your main form constructor
Action.Context = SynchronizationContext.Current;


我刚刚用此代码创建了简单的解决方案,并且效果很好。如果您愿意,我可以通过电子邮件或其他方式将其发送给您。

关于c# - SendInput在PC的水果忍者中被阻止,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18405990/

10-16 15:28