将 Thread.Sleep() 替换为 System.Windows.Forms.Timer()

本文关键字:Windows Forms Timer System 替换 Thread Sleep | 更新日期: 2023-09-27 18:26:52

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);
}

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

我想用不会

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

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

将 Thread.Sleep() 替换为 System.Windows.Forms.Timer()

您直接将 UI 线程置于睡眠状态。如果你想做你所问的,你需要把你的 while 循环放到它自己的线程中,并将该线程置于睡眠状态,而不是 UI 线程。

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

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

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

请记住

,应用程序的主要线程将是处理来自Windows的消息的线程。 这包括响应键盘和鼠标事件以及重绘屏幕的功能。 如果将主线程置于睡眠状态(或只是让它执行一系列同步工作(,则 UI 将显示为"冻结",直到线程可以恢复处理来自消息泵的事件。

Timer 对象在此类方案中可能很有用,但过去存在长时间运行的计时器的内存使用问题。 类的一种内存泄漏问题。 老实说,我不知道这是否已解决。

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

  1. 首先,使你的类是非静态的。
  2. Seceond,向类添加一个布尔字段,使您能够"终止开关"您的线程。 以及您的类启用翻转此开关的方法。
  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);
}