0

当我这样做时;

Point startpoint = Cursor.Position;
startpoint.Y -= 1;
DoMouse(MOUSEEVENTF.MOVE | MOUSEEVENTF.ABSOLUTE, startpoint);

鼠标不仅向上移动.. 它也向左移动一点。但是如果我在一个循环中执行它,它只会在第一次迭代时向左移动。

这是一个完全工作的控制台程序,它提出了这个问题。你必须Add Reference -> .NET -> System.DrawingSystem.Windows.Forms让它编译。

启动程序时键入start将鼠标向上移动 5 像素一次或键入start X(X 是数字)将鼠标向上移动 5 像素 X 次。你会看到每一个新的循环鼠标都会向左移动一点;它根本不应该那样做。

using System;
using System.Text.RegularExpressions;
using System.Threading;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace mousemove_temp
{
    class Program
    {
        //Capture user input
        static void Main(string[] args)
        {
            while (true)
            {
                string s = Console.ReadLine();

                switch (s)
                {
                    case("start"):
                        moveMouseTest(1);
                        break;
                    default:
                        //Get # of times to run function
                        Match match = Regex.Match(s, @"start (.+)", RegexOptions.IgnoreCase);
                        if (!match.Success || match.Groups.Count != 2) break;

                        //Copy # to int
                        int amnt = -1;
                        try
                        {
                            amnt = Int32.Parse(match.Groups[1].Value);
                        }
                        catch (Exception) { break; } //fail
                        if (amnt <= -1) break; //fail
                        moveMouseTest(amnt); //aaaawww yeah

                        break;
                }

                Thread.Sleep(10);
            }
        }

        //Move the mouse
        static void moveMouseTest(int repeat)
        {
            int countrepeat = 0;

            //Loop entire function X times
            while (countrepeat < repeat)
            {
                Point startpoint = Cursor.Position;
                int amount = 5; //Move 5 pixels
                int counter = 0;

                //Move 1 pixel up each loop
                while (counter < amount)
                {
                    startpoint.Y -= 1;
                    DoMouse(MOUSEEVENTF.MOVE | MOUSEEVENTF.ABSOLUTE, startpoint);

                    counter++;
                    Thread.Sleep(100); //Slow down so you can see it only jumps left the first time
                }

                countrepeat++;
                Console.WriteLine(String.Format("{0}/{1}", countrepeat, repeat));
                Thread.Sleep(1000); //Wait a second before next loop
            }
        }

        /*
         * Function stuff 
        */

        //Control the Mouse
        private static object mouselock = new object(); //For use with multithreading
        public static void DoMouse(MOUSEEVENTF flags, Point newPoint)
        {
            lock (mouselock)
            {
                INPUT input = new INPUT();
                MOUSEINPUT mi = new MOUSEINPUT();
                input.dwType = InputType.Mouse;
                input.mi = mi;
                input.mi.dwExtraInfo = IntPtr.Zero;
                // mouse co-ords: top left is (0,0), bottom right is (65535, 65535)
                // convert screen co-ord to mouse co-ords...
                input.mi.dx = newPoint.X * (65535 / Screen.PrimaryScreen.Bounds.Width);
                input.mi.dy = newPoint.Y * (65535 / Screen.PrimaryScreen.Bounds.Height);
                input.mi.time = 0;
                input.mi.mouseData = 0;
                // can be used for WHEEL event see msdn
                input.mi.dwFlags = flags;
                int cbSize = Marshal.SizeOf(typeof(INPUT));
                int result = SendInput(1, ref input, cbSize);
                if (result == 0)
                    Console.WriteLine("DoMouse Error:" + Marshal.GetLastWin32Error());
            }
        }

        /*
         * Native Methods 
        */

        [DllImport("user32.dll", SetLastError = true)]
        static internal extern Int32 SendInput(Int32 cInputs, ref INPUT pInputs, Int32 cbSize);

        [DllImport("user32.dll")]
        public static extern bool GetAsyncKeyState(Int32 vKey);

        [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 28)]
        internal struct INPUT
        {
            [FieldOffset(0)]
            public InputType dwType;
            [FieldOffset(4)]
            public MOUSEINPUT mi;
            [FieldOffset(4)]
            public KEYBDINPUT ki;
            [FieldOffset(4)]
            public HARDWAREINPUT hi;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct MOUSEINPUT
        {
            public Int32 dx;
            public Int32 dy;
            public Int32 mouseData;
            public MOUSEEVENTF dwFlags;
            public Int32 time;
            public IntPtr dwExtraInfo;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct KEYBDINPUT
        {
            public Int16 wVk;
            public Int16 wScan;
            public KEYEVENTF dwFlags;
            public Int32 time;
            public IntPtr dwExtraInfo;
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct HARDWAREINPUT
        {
            public Int32 uMsg;
            public Int16 wParamL;
            public Int16 wParamH;
        }

        internal enum InputType : int
        {
            Mouse = 0,
            Keyboard = 1,
            Hardware = 2
        }

        [Flags()]
        internal enum MOUSEEVENTF : int
        {
            MOVE = 0x1,
            LEFTDOWN = 0x2,
            LEFTUP = 0x4,
            RIGHTDOWN = 0x8,
            RIGHTUP = 0x10,
            MIDDLEDOWN = 0x20,
            MIDDLEUP = 0x40,
            XDOWN = 0x80,
            XUP = 0x100,
            VIRTUALDESK = 0x400,
            WHEEL = 0x800,
            ABSOLUTE = 0x8000
        }

        [Flags()]
        internal enum KEYEVENTF : int
        {
            EXTENDEDKEY = 1,
            KEYUP = 2,
            UNICODE = 4,
            SCANCODE = 8
        }
    }
}

谁能告诉我出了什么问题?

4

2 回答 2

1

你做错了数学,结果是舍入错误。

例如,65535 / 1920 = 34.1328125。但是截断(因为您将 int 除以 int)得到 34。因此,如果在 1920x1080 的屏幕上,您将鼠标一直放在右侧,您将得到 1920 * (65535 / 1920) = 1920 * 34 = 65280。

这将为您带来更好的结果:

            input.mi.dx = (int)((65535.0f * (newPoint.X / (float)Screen.PrimaryScreen.Bounds.Width)) + 0.5f);
            input.mi.dy = (int)((65535.0f * (newPoint.Y / (float)Screen.PrimaryScreen.Bounds.Height)) + 0.5f);

虽然如果你决定使用 P/Invoke 而不是仅仅说

Cursor.Position = new Point(newPoint.X, newPoint.Y);

那么你真的应该使用 SetCursorPos - http://msdn.microsoft.com/en-us/library/windows/desktop/ms648394(v=vs.85).aspx - 因为它(连同 GetCursorPos)是 . NET 用于通过 Cursor.Position 获取和设置光标位置。

于 2012-07-14T10:51:56.143 回答
0

对您的项目而言,最简单的方法是在 codeplex 上使用有用的开源库Windows 输入模拟器(C# SendInput Wrapper - 模拟键盘和鼠标) 。用它!

于 2012-07-14T10:22:51.397 回答