asweigart / pyautogui

A cross-platform GUI automation Python module for human beings. Used to programmatically control the mouse & keyboard.
BSD 3-Clause "New" or "Revised" License
10.45k stars 1.26k forks source link

pyautogui.move(None,None) doubles the X,Y coordinates #690

Open JayRizzo opened 2 years ago

JayRizzo commented 2 years ago

Now in my research & fix for #684.

I discovered another odd behaviour that needs to be addressed. If you Run the following:

import pyautogui
pyautogui.position()  # Point(x=110, y=125)
pyautogui.move(None, None)
pyautogui.position()  # Point(x=220, y=250)
pyautogui.move(None, None)
pyautogui.position()  # Point(x=440, y=500)
pyautogui.move(None, None)
pyautogui.position()  # Point(x=880, y=1000)
pyautogui.move(None, None)
pyautogui.position()  # Point(x=1760, y=2000)
pyautogui.move(None, None)
pyautogui.position()  # Point(x=3520, y=4000)
pyautogui.move(None, None)
pyautogui.position()  # Point(x=7040, y=8000)
pyautogui.move(None, None)
pyautogui.position()  # Point(x=14080, y=16000)

# and so on....  even though it is all off the screen.

You will get behaviour that is strange. Where, instead of "not moving" It double the x, y coordinates, potentially unexpected by most users.

The Culprit

I believe to be is:

int(None)
# Traceback (most recent call last):
#  File "<stdin>", line 1, in <module>
# TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'

This behaviour changed after 3.10 None values do not behave the same as it once used to.
As you can no longer run int(None).
Which throws the [Type Conversion Error] (https://docs.python.org/3.10/library/functions.html#int).

Return an integer object constructed from a number or string x, or return 0 if no arguments are given.

But it should not as it hasn't even been updated yet in the main documentation. int(None) ""used"" to return Zero, hence why we are seeing this complain.

Jarno-de-Wit commented 2 years ago

The culprit of this issue is not the use of int(None) (which has been removed in this commit already), which isn't ever performed in the .move() function chain. The reason behind this behaviour is the use of _normalizeXYArgs where it shouldn't be used (here).

In the moveRel function, the code following this line expects the returned values to be the offsets the cursor should be moved by. '_normalizeXYArgs' on the other hand is made to return absolute coordinates, and not relative coordinates. Therefore, any case where no number is passed in, and _normalizeXYArgs has to "find" a value, it will return the current coordinate of your cursor. MoveRel will then take this coordinate as an offset from the current location, and happily move it by this distance, effectively doubling the coordinate in this direction.

Fix

The most logical fix would be to make a new function _normalizeXYOffsetArgs, which returns 0 if None is passed in. This function should then be called inside moveRel, instead of _normalizeXYArgs.