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

1.1k views Asked by At

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?

2

There are 2 answers

1
Maksiks On BEST ANSWER

You can't (kind of)

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

Except you can

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 a piece of paper or a different graphical calcualtor for visualizing the graph of the function before making it in code.

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.

Smooth motion

Then we set pyautogui.pause to 0 so there's no pause between movements. After this make note of that it is broken, duration values above 0.2 yield slow speeds and <= 0.2 offer very high speed, this is clearly not meant to be used for this but it 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 stuff in parallel but this weird method is better anyway.
# Ideally you want to use a proper library like now broken Autopy for this.

I know this is a highly requested question but 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

0
Dwaynediddy On

You can use duration

    pyautogui.moveTo(x, y, duration=0.3)