用System.Windows.Forms.Timer()替换Thread.Sleep()

时间:2013-08-08 19:59:32

标签: c#

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线程冻结的async替换上面的Thread.Sleep(wait)。我想出了如何制作计时器,但我不确定如何在上面的示例中使用它。

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

3 个答案:

答案 0 :(得分:2)

您正在将UI线程直接置于休眠状态。如果你想做你要问的事情,你需要将你的while循环放入它自己的线程中,并将THAT线程置于休眠状态而不是UI线程。

或者将你的整个WindMouse方法放入它自己的后台线程中。

答案 1 :(得分:2)

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

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

答案 2 :(得分:1)

请记住,您的应用程序的主要线程将是处理来自Windows的消息的主线程。这包括响应键盘和鼠标事件以及重新绘制屏幕的功能。如果你让你的主线程处于休眠状态(或只是让它做一堆同步工作),你的UI似乎会“冻结”,直到线程可以继续处理来自消息泵的事件。

Timer对象在这样的场景中很有用,但过去常常会出现长时间运行的内存使用问题。类中的一种内存泄漏问题。老实说,我不知道是否已修复。

那就是说,你可以写一个单独的线程为你做这项工作没有太大困难。

  1. 首先,让你的课程非静态。
  2. Seceond,在您的班级中添加一个布尔字段,以便您使用 “杀死开关”你的线程。还有一种方法让您的班级能够翻转此开关。
  3. 然后你想要添加一个方法来“启动”这个辅助线程。 使用命名约定“BeginMoveMouse”是一种很好的做法。 .NET中经常使用“begin”前缀来表示a 非阻塞异步操作,它会使它更多 对于试图使用你的图书馆的任何人都很明显。
  4. 您需要创建一个委托来“启动”您的线程,然后调用 在“begin”方法中开始调用该委托。
  5. 我已经包含了如下所述的代码。注意对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);
    }