簡體   English   中英

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

[英]Replace Thread.Sleep() with System.Windows.Forms.Timer()

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

您正在使UI線程直接進入睡眠狀態。 如果您想做您想做的事情,則需要將while循環放入它自己的線程中,並使THAT線程進入睡眠狀態,而不是UI線程進入睡眠狀態。

要么,要么將整個WindMouse方法放到它自己的后台線程中。

  1. 將該方法的簽名更改為: private static async Task WindMouse()

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

請記住,應用程序的主線程將是處理來自Windows的消息的線程。 這包括響應鍵盤和鼠標事件以及重畫屏幕的能力。 如果您將主線程置於睡眠狀態(或只是使其進行大量同步工作),則UI似乎“凍結”,直到該線程可以繼續處理來自消息泵的事件為止。

在這樣的情況下,Timer對象可能很有用,但是過去,長時間運行的計時器在內存使用方面存在問題。 類的一種內存泄漏問題。 老實說,我不知道是否已解決。

也就是說,您可以編寫一個單獨的線程為您輕松完成此工作。

  1. 首先,使您的課程成為非靜態課程。
  2. 第二,在您的課程中添加一個布爾字段,使您可以“殺死”線程。 類中的一種方法,可以啟用此開關。
  3. 然后,您需要添加一個方法來“啟動”該輔助線程。 最好使用命名約定“ BeginMoveMouse”。 .NET中經常使用“開始”前綴來表示非阻塞異步操作,這將使其他嘗試使用您的庫的人更加清楚。
  4. 您將需要創建一個委托來“啟動”線程,並在“開始”方法中對該委托調用begin invoke。

我已經包含了如下所述的代碼。 還請注意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);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM