Search code examples
pythonpython-3.xmousepyautoguimousemove

How do I achieve smooth mouse movement on turns in Pyautogui?


How to achieve smooth mouse movement instead of teleportation between points on turns in pyautogui? How to setup paths for your mouse to move instead of it just teleporting unless you try to manually interpolate it for hours?


Solution

  • You can't (kind of)

    Pyautogui is a library meant for automation and isn't meant to be used for smooth movement, you can consider other libraries for this if you can find one.

    Except you can

    This is a bit of a workaround

    Curves

    To achieve proper smooth motion especially with curves we use mathematical functions to determine our path and loops to increment our x cordinate (in my example the x cordinate is "a" and the y cordinate is "b").

    Use Desmos, or a different graphical calcualtor for visualizing the graph of the function before making it in code. Might seem like extra effort but this is vital.

    Important: the y cordinate is inversed in pyautogui, account for that.

    I used "x" and "y" variables as center's of the screen on respective axis but you can start wherever you want by replacing them.

    Workaround

    Then we set pyautogui.pause to 0 so there's no pause between movements. It's quite frankly broken, duration values above 0.2 yield slow speeds, and <= 0.2 offer very high speed, this is not meant to be used for this but it just works. By setting the duration to 0.2 we can edit our step (the incrementation of the function) to achieve the necessary speed. And it is smooth.

    Here's a functional example: it draws an infinity symbol with your mouse. Make sure that you are able to stop it in your IDE, it's ctrl+F2 in Pycharm.

    import pyautogui
    import time
    
    screenSize = pyautogui.size()
    
    x = screenSize[0]/2
    y = screenSize[1]/2
    
    time.sleep(3)
    
    # SETTINGS
    
    pyautogui.PAUSE = 0
    
    # Multiplier
    size = 100
    # Duration
    speed = 0.2
    # Incrementation
    step = 0.0001
    
    pyautogui.moveTo(x, y, 0)
    
    a = step
    
    loopStart = True
    
    while True:
        if loopStart:
            while True:
                a += step
                b = -(a - 2) * 0.5 - 1
    
                pyautogui.moveTo(x + a * size, y + b * size, speed * 0.5, pyautogui.linear)
                if a >= 2:
                    break
    
        while True:
            a += step
            b = (((a - 2) ** 4) * 0.8) - 1
    
            pyautogui.moveTo(x + a * size, y + b * size, speed * 0.5, pyautogui.linear)
            if a >= 3:
                a += step
                break
    
        while True:
            a -= step
            b = -(((a - 2) ** 4) * 0.8) + 1
    
            pyautogui.moveTo(x + a * size, y + b * size, speed * 0.5, pyautogui.linear)
            if a <= 2:
                a -= step * 2
                break
    
        while True:
            a -= step
            b = a * 0.5
    
            pyautogui.moveTo(x + a * size, y + b * size, speed * 0.5, pyautogui.linear)
            if a <= -2:
                a += step
                break
    
        # Side 2
    
        while True:
            a -= step
            b = (((a + 2) ** 4) * 0.8) - 1
    
            pyautogui.moveTo(x + a * size, y + b * size, speed * 0.5, pyautogui.linear)
            if a <= -3:
                a -= step
                break
    
        while True:
            a += step
            b = -(((a + 2) ** 4) * 0.8) + 1
    
            pyautogui.moveTo(x + a * size, y + b * size, speed * 0.5, pyautogui.linear)
            if a >= -2:
                a += step*2
                break
    
        while True:
            a += step
            b = -(a + 2) * 0.5 + 1
    
            pyautogui.moveTo(x + a * size, y + b * size, speed * 0.5, pyautogui.linear)
            if a >= 2:
                loopStart = False
                break
    
    # I think this is also accomplishable by running code in parallel, but this weird method is better anyway.
    # Ideally you want to use a proper library like the currently broken (as of August 2023) Autopy for this.
    
    

    I know this is a highly requested question but I haven't found a single proper answer which weirded me out a lot and resulted in the creation of this QnA-ish post. Hope someone finds this useful <3