1
public static class SampleMouseMove
{

    static Random random = new Random();
    static int mouseSpeed = 15;

    public static void MoveMouse(int x, int y, int rx, int ry)
    {
        Point c = new Point();
        GetCursorPos(out c);

        x += random.Next(rx);
        y += random.Next(ry);

        double randomSpeed = Math.Max((random.Next(mouseSpeed) / 2.0 + mouseSpeed) / 10.0, 0.1);

        WindMouse(c.X, c.Y, x, y, 9.0, 3.0, 10.0 / randomSpeed,
            15.0 / randomSpeed, 10.0 * randomSpeed, 10.0 * randomSpeed);
    }

    static void WindMouse(double xs, double ys, double xe, double ye,
        double gravity, double wind, double minWait, double maxWait,
        double maxStep, double targetArea)
    {

        double dist, windX = 0, windY = 0, veloX = 0, veloY = 0, randomDist, veloMag, step;
        int oldX, oldY, newX = (int)Math.Round(xs), newY = (int)Math.Round(ys);

        double waitDiff = maxWait - minWait;
        double sqrt2 = Math.Sqrt(2.0);
        double sqrt3 = Math.Sqrt(3.0);
        double sqrt5 = Math.Sqrt(5.0);

        dist = Hypot(xe - xs, ye - ys);

        while (dist > 1.0)
        {

            wind = Math.Min(wind, dist);

            if (dist >= targetArea)
            {
                int w = random.Next((int)Math.Round(wind) * 2 + 1);
                windX = windX / sqrt3 + (w - wind) / sqrt5;
                windY = windY / sqrt3 + (w - wind) / sqrt5;
            }
            else
            {
                windX = windX / sqrt2;
                windY = windY / sqrt2;
                if (maxStep < 3)
                    maxStep = random.Next(3) + 3.0;
                else
                    maxStep = maxStep / sqrt5;
            }

            veloX += windX;
            veloY += windY;
            veloX = veloX + gravity * (xe - xs) / dist;
            veloY = veloY + gravity * (ye - ys) / dist;

            if (Hypot(veloX, veloY) > maxStep)
            {
                randomDist = maxStep / 2.0 + random.Next((int)Math.Round(maxStep) / 2);
                veloMag = Hypot(veloX, veloY);
                veloX = (veloX / veloMag) * randomDist;
                veloY = (veloY / veloMag) * randomDist;
            }

            oldX = (int)Math.Round(xs);
            oldY = (int)Math.Round(ys);
            xs += veloX;
            ys += veloY;
            dist = Hypot(xe - xs, ye - ys);
            newX = (int)Math.Round(xs);
            newY = (int)Math.Round(ys);

            if (oldX != newX || oldY != newY)
                SetCursorPos(newX, newY);

            step = Hypot(xs - oldX, ys - oldY);
            int wait = (int)Math.Round(waitDiff * (step / maxStep) + minWait);

            Thread.Sleep(wait); //<---
        }

        int endX = (int)Math.Round(xe);
        int endY = (int)Math.Round(ye);
        if (endX != newX || endY != newY)
            SetCursorPos(endX, endY);
    }

    static double Hypot(double dx, double dy)
    {
        return Math.Sqrt(dx * dx + dy * dy);
    }

    [DllImport("user32.dll")]
    static extern bool SetCursorPos(int X, int Y);

    [DllImport("user32.dll")]
    public static extern bool GetCursorPos(out Point p);
}

这是我将鼠标光标移动到某个点的代码。

我想Thread.Sleep(wait)用不会使 UI 线程冻结的异步替换上面的内容。我想出了如何制作计时器,但我不确定如何在上面的示例中使用它。

var timer = new System.Windows.Forms.Timer();
timer.Interval = wait; 
timer.Tick += (sender, args) => { /* do stuff */ };
timer.Start();
4

3 回答 3

2
  1. 将方法的签名更改为:private static async Task WindMouse()

  2. 替换Thread.Sleep(wait);await Task.Delay(wait);

于 2013-08-08T20:18:34.643 回答
2

您正在让 UI 线程直接进入睡眠状态。如果你想做你所问的,你需要把你的while循环放到它自己的线程中,然后让那个线程进入睡眠状态而不是UI线程。

要么,要么把你的整个 WindMouse 方法放到它自己的后台线程中。

于 2013-08-08T20:04:15.237 回答
1

请记住,您的应用程序的主线程将是处理来自窗口的消息的线程。这包括响应键盘和鼠标事件以及重绘屏幕的能力。如果你让你的主线程进入睡眠状态(或者只是让它做一堆同步工作),你的 UI 将看起来“冻结”,直到线程可以恢复处理来自消息泵的事件。

Timer 对象在这样的场景中很有用,但曾经存在内存使用问题和长时间运行的计时器。类的一种内存泄漏问题。老实说,我不知道这是否已修复。

也就是说,您可以编写一个单独的线程来为您完成这项工作而没有太大困难。

  1. 首先,使您的课程非静态。
  2. 其次,在您的类中添加一个布尔字段,使您能够“杀死开关”您的线程。还有一种方法可以让您的班级启用翻转此开关。
  3. 然后你会想要添加一个方法来“启动”这个辅助线程。使用命名约定“BeginMoveMouse”是一种很好的做法。“begin”前缀在 .NET 中经常使用,表示非阻塞异步操作,它会让任何其他尝试使用您的库的人更清楚地看到它。
  4. 您需要创建一个委托来“启动”您的线程,并在您的“开始”方法中对该委托调用开始调用。

我已经包含了如下所述的代码。注意 while 循环的变化,以及“StopMoveMouse”方法的添加。我还添加了一个 ManualResetEvent 字段,它可以让您在用户请求停止移动鼠标时“打破”睡眠状态,而无需等待超时到期。如果等待时间很短,这确实没有必要,但我添加了它,例如,以防万一。我还添加了一个布尔字段,它允许我检查线程是否已经在运行,以防止在不先停止的情况下再次调用 BeginMoveMouse。这个检查可以很容易地修改为简单地返回并且什么都不做。

public class SampleMouseMove
{
    delegate void BeginMoveMouseDelegate(int x, int y, int rx, int ry);
    Random random = new Random();
    int mouseSpeed = 15;
    bool killMove = false;
    bool running = false;
    ManualResetEvent mre = new ManualResetEvent(false);

    public SampleMouseMove()
    { }

    public void BeginMoveMouse(int x, int y, int rx, int ry)
    {
        if (running)
            throw new Exception("Mouse is already being moved.");

        BeginMoveMouseDelegate del = new BeginMoveMouseDelegate(MoveMouse);
        del.BeginInvoke(x, y, rx, ry, new AsyncCallback(BeginMoveMouseCallback), del);
        running = true;
    }

    public void StopMoveMouse()
    {
        killMove = true;
        mre.Set();
    }

    void BeginMoveMouseCallback(IAsyncResult state)
    {  
        BeginMoveMouseDelegate del = (BeginMoveMouseDelegate)state.AsyncState;
        del.EndInvoke(state);
        mre.Reset();
        killMove = false;
        running = false;
    }

    public void MoveMouse(int x, int y, int rx, int ry)
    {
        Point c = new Point();
        GetCursorPos(out c);

        x += random.Next(rx);
        y += random.Next(ry);

        double randomSpeed = Math.Max((random.Next(mouseSpeed) / 2.0 + mouseSpeed) / 10.0, 0.1);

        WindMouse(c.X, c.Y, x, y, 9.0, 3.0, 10.0 / randomSpeed,
            15.0 / randomSpeed, 10.0 * randomSpeed, 10.0 * randomSpeed);
    }

    void WindMouse(double xs, double ys, double xe, double ye,
        double gravity, double wind, double minWait, double maxWait,
        double maxStep, double targetArea)
    {

        double dist, windX = 0, windY = 0, veloX = 0, veloY = 0, randomDist, veloMag, step;
        int oldX, oldY, newX = (int)Math.Round(xs), newY = (int)Math.Round(ys);

        double waitDiff = maxWait - minWait;
        double sqrt2 = Math.Sqrt(2.0);
        double sqrt3 = Math.Sqrt(3.0);
        double sqrt5 = Math.Sqrt(5.0);

        dist = Hypot(xe - xs, ye - ys);

        while (dist > 1.0 && !killMove)
        {

            wind = Math.Min(wind, dist);

            if (dist >= targetArea)
            {
                int w = random.Next((int)Math.Round(wind) * 2 + 1);
                windX = windX / sqrt3 + (w - wind) / sqrt5;
                windY = windY / sqrt3 + (w - wind) / sqrt5;
            }
            else
            {
                windX = windX / sqrt2;
                windY = windY / sqrt2;
                if (maxStep < 3)
                    maxStep = random.Next(3) + 3.0;
                else
                    maxStep = maxStep / sqrt5;
            }

            veloX += windX;
            veloY += windY;
            veloX = veloX + gravity * (xe - xs) / dist;
            veloY = veloY + gravity * (ye - ys) / dist;

            if (Hypot(veloX, veloY) > maxStep)
            {
                randomDist = maxStep / 2.0 + random.Next((int)Math.Round(maxStep) / 2);
                veloMag = Hypot(veloX, veloY);
                veloX = (veloX / veloMag) * randomDist;
                veloY = (veloY / veloMag) * randomDist;
            }

            oldX = (int)Math.Round(xs);
            oldY = (int)Math.Round(ys);
            xs += veloX;
            ys += veloY;
            dist = Hypot(xe - xs, ye - ys);
            newX = (int)Math.Round(xs);
            newY = (int)Math.Round(ys);

            if (oldX != newX || oldY != newY)
                SetCursorPos(newX, newY);

            step = Hypot(xs - oldX, ys - oldY);
            int wait = (int)Math.Round(waitDiff * (step / maxStep) + minWait);

            mre.WaitOne(wait);  // <-- this works like Thread.Sleep(), but we can cancel the "wait" by calling mre.Set();
        }

        int endX = (int)Math.Round(xe);
        int endY = (int)Math.Round(ye);
        if (endX != newX || endY != newY)
            SetCursorPos(endX, endY);
    }

    double Hypot(double dx, double dy)
    {
        return Math.Sqrt(dx * dx + dy * dy);
    }

    [DllImport("user32.dll")]
    static extern bool SetCursorPos(int X, int Y);

    [DllImport("user32.dll")]
    public static extern bool GetCursorPos(out Point p);
}
于 2013-08-08T20:25:54.883 回答