| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573 |
- # Windows implementation of PyAutoGUI functions.
- # BSD license
- # Al Sweigart al@inventwithpython.com
- import ctypes
- import ctypes.wintypes
- import pyautogui
- from pyautogui import LEFT, MIDDLE, RIGHT
- import sys
- if sys.platform != 'win32':
- raise Exception('The pyautogui_win module should only be loaded on a Windows system.')
- # Fixes the scaling issues where PyAutoGUI was reporting the wrong resolution:
- try:
- ctypes.windll.user32.SetProcessDPIAware()
- except AttributeError:
- pass # Windows XP doesn't support this, so just do nothing.
- """
- A lot of this code is probably repeated from win32 extensions module, but I didn't want to have that dependency.
- Note: According to http://msdn.microsoft.com/en-us/library/windows/desktop/ms646260(v=vs.85).aspx
- the ctypes.windll.user32.mouse_event() function has been superseded by SendInput.
- SendInput() is documented here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx
- UPDATE: SendInput() doesn't seem to be working for me. I've switched back to mouse_event()."""
- # Event codes to be passed to the mouse_event() win32 function.
- # Documented here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms646273(v=vs.85).aspx
- MOUSEEVENTF_MOVE = 0x0001
- MOUSEEVENTF_LEFTDOWN = 0x0002
- MOUSEEVENTF_LEFTUP = 0x0004
- MOUSEEVENTF_LEFTCLICK = MOUSEEVENTF_LEFTDOWN + MOUSEEVENTF_LEFTUP
- MOUSEEVENTF_RIGHTDOWN = 0x0008
- MOUSEEVENTF_RIGHTUP = 0x0010
- MOUSEEVENTF_RIGHTCLICK = MOUSEEVENTF_RIGHTDOWN + MOUSEEVENTF_RIGHTUP
- MOUSEEVENTF_MIDDLEDOWN = 0x0020
- MOUSEEVENTF_MIDDLEUP = 0x0040
- MOUSEEVENTF_MIDDLECLICK = MOUSEEVENTF_MIDDLEDOWN + MOUSEEVENTF_MIDDLEUP
- MOUSEEVENTF_ABSOLUTE = 0x8000
- MOUSEEVENTF_WHEEL = 0x0800
- MOUSEEVENTF_HWHEEL = 0x01000
- # Documented here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms646304(v=vs.85).aspx
- KEYEVENTF_KEYDOWN = 0x0000 # Technically this constant doesn't exist in the MS documentation. It's the lack of KEYEVENTF_KEYUP that means pressing the key down.
- KEYEVENTF_KEYUP = 0x0002
- # Documented here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx
- INPUT_MOUSE = 0
- INPUT_KEYBOARD = 1
- # These ctypes structures are for Win32 INPUT, MOUSEINPUT, KEYBDINPUT, and HARDWAREINPUT structures,
- # used by SendInput and documented here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx
- # Thanks to BSH for this StackOverflow answer: https://stackoverflow.com/questions/18566289/how-would-you-recreate-this-windows-api-structure-with-ctypes
- class MOUSEINPUT(ctypes.Structure):
- _fields_ = [
- ('dx', ctypes.wintypes.LONG),
- ('dy', ctypes.wintypes.LONG),
- ('mouseData', ctypes.wintypes.DWORD),
- ('dwFlags', ctypes.wintypes.DWORD),
- ('time', ctypes.wintypes.DWORD),
- ('dwExtraInfo', ctypes.POINTER(ctypes.wintypes.ULONG)),
- ]
- class KEYBDINPUT(ctypes.Structure):
- _fields_ = [
- ('wVk', ctypes.wintypes.WORD),
- ('wScan', ctypes.wintypes.WORD),
- ('dwFlags', ctypes.wintypes.DWORD),
- ('time', ctypes.wintypes.DWORD),
- ('dwExtraInfo', ctypes.POINTER(ctypes.wintypes.ULONG)),
- ]
- class HARDWAREINPUT(ctypes.Structure):
- _fields_ = [
- ('uMsg', ctypes.wintypes.DWORD),
- ('wParamL', ctypes.wintypes.WORD),
- ('wParamH', ctypes.wintypes.DWORD)
- ]
- class INPUT(ctypes.Structure):
- class _I(ctypes.Union):
- _fields_ = [
- ('mi', MOUSEINPUT),
- ('ki', KEYBDINPUT),
- ('hi', HARDWAREINPUT),
- ]
- _anonymous_ = ('i', )
- _fields_ = [
- ('type', ctypes.wintypes.DWORD),
- ('i', _I),
- ]
- # End of the SendInput win32 data structures.
- """ Keyboard key mapping for pyautogui:
- Documented at http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
- The *KB dictionaries in pyautogui map a string that can be passed to keyDown(),
- keyUp(), or press() into the code used for the OS-specific keyboard function.
- They should always be lowercase, and the same keys should be used across all OSes."""
- keyboardMapping = dict([(key, None) for key in pyautogui.KEY_NAMES])
- keyboardMapping.update({
- 'backspace': 0x08, # VK_BACK
- '\b': 0x08, # VK_BACK
- 'super': 0x5B, #VK_LWIN
- 'tab': 0x09, # VK_TAB
- '\t': 0x09, # VK_TAB
- 'clear': 0x0c, # VK_CLEAR
- 'enter': 0x0d, # VK_RETURN
- '\n': 0x0d, # VK_RETURN
- 'return': 0x0d, # VK_RETURN
- 'shift': 0x10, # VK_SHIFT
- 'ctrl': 0x11, # VK_CONTROL
- 'alt': 0x12, # VK_MENU
- 'pause': 0x13, # VK_PAUSE
- 'capslock': 0x14, # VK_CAPITAL
- 'kana': 0x15, # VK_KANA
- 'hanguel': 0x15, # VK_HANGUEL
- 'hangul': 0x15, # VK_HANGUL
- 'junja': 0x17, # VK_JUNJA
- 'final': 0x18, # VK_FINAL
- 'hanja': 0x19, # VK_HANJA
- 'kanji': 0x19, # VK_KANJI
- 'esc': 0x1b, # VK_ESCAPE
- 'escape': 0x1b, # VK_ESCAPE
- 'convert': 0x1c, # VK_CONVERT
- 'nonconvert': 0x1d, # VK_NONCONVERT
- 'accept': 0x1e, # VK_ACCEPT
- 'modechange': 0x1f, # VK_MODECHANGE
- ' ': 0x20, # VK_SPACE
- 'space': 0x20, # VK_SPACE
- 'pgup': 0x21, # VK_PRIOR
- 'pgdn': 0x22, # VK_NEXT
- 'pageup': 0x21, # VK_PRIOR
- 'pagedown': 0x22, # VK_NEXT
- 'end': 0x23, # VK_END
- 'home': 0x24, # VK_HOME
- 'left': 0x25, # VK_LEFT
- 'up': 0x26, # VK_UP
- 'right': 0x27, # VK_RIGHT
- 'down': 0x28, # VK_DOWN
- 'select': 0x29, # VK_SELECT
- 'print': 0x2a, # VK_PRINT
- 'execute': 0x2b, # VK_EXECUTE
- 'prtsc': 0x2c, # VK_SNAPSHOT
- 'prtscr': 0x2c, # VK_SNAPSHOT
- 'prntscrn': 0x2c, # VK_SNAPSHOT
- 'printscreen': 0x2c, # VK_SNAPSHOT
- 'insert': 0x2d, # VK_INSERT
- 'del': 0x2e, # VK_DELETE
- 'delete': 0x2e, # VK_DELETE
- 'help': 0x2f, # VK_HELP
- 'win': 0x5b, # VK_LWIN
- 'winleft': 0x5b, # VK_LWIN
- 'winright': 0x5c, # VK_RWIN
- 'apps': 0x5d, # VK_APPS
- 'sleep': 0x5f, # VK_SLEEP
- 'num0': 0x60, # VK_NUMPAD0
- 'num1': 0x61, # VK_NUMPAD1
- 'num2': 0x62, # VK_NUMPAD2
- 'num3': 0x63, # VK_NUMPAD3
- 'num4': 0x64, # VK_NUMPAD4
- 'num5': 0x65, # VK_NUMPAD5
- 'num6': 0x66, # VK_NUMPAD6
- 'num7': 0x67, # VK_NUMPAD7
- 'num8': 0x68, # VK_NUMPAD8
- 'num9': 0x69, # VK_NUMPAD9
- 'multiply': 0x6a, # VK_MULTIPLY ??? Is this the numpad *?
- 'add': 0x6b, # VK_ADD ??? Is this the numpad +?
- 'separator': 0x6c, # VK_SEPARATOR ??? Is this the numpad enter?
- 'subtract': 0x6d, # VK_SUBTRACT ??? Is this the numpad -?
- 'decimal': 0x6e, # VK_DECIMAL
- 'divide': 0x6f, # VK_DIVIDE
- 'f1': 0x70, # VK_F1
- 'f2': 0x71, # VK_F2
- 'f3': 0x72, # VK_F3
- 'f4': 0x73, # VK_F4
- 'f5': 0x74, # VK_F5
- 'f6': 0x75, # VK_F6
- 'f7': 0x76, # VK_F7
- 'f8': 0x77, # VK_F8
- 'f9': 0x78, # VK_F9
- 'f10': 0x79, # VK_F10
- 'f11': 0x7a, # VK_F11
- 'f12': 0x7b, # VK_F12
- 'f13': 0x7c, # VK_F13
- 'f14': 0x7d, # VK_F14
- 'f15': 0x7e, # VK_F15
- 'f16': 0x7f, # VK_F16
- 'f17': 0x80, # VK_F17
- 'f18': 0x81, # VK_F18
- 'f19': 0x82, # VK_F19
- 'f20': 0x83, # VK_F20
- 'f21': 0x84, # VK_F21
- 'f22': 0x85, # VK_F22
- 'f23': 0x86, # VK_F23
- 'f24': 0x87, # VK_F24
- 'numlock': 0x90, # VK_NUMLOCK
- 'scrolllock': 0x91, # VK_SCROLL
- 'shiftleft': 0xa0, # VK_LSHIFT
- 'shiftright': 0xa1, # VK_RSHIFT
- 'ctrlleft': 0xa2, # VK_LCONTROL
- 'ctrlright': 0xa3, # VK_RCONTROL
- 'altleft': 0xa4, # VK_LMENU
- 'altright': 0xa5, # VK_RMENU
- 'browserback': 0xa6, # VK_BROWSER_BACK
- 'browserforward': 0xa7, # VK_BROWSER_FORWARD
- 'browserrefresh': 0xa8, # VK_BROWSER_REFRESH
- 'browserstop': 0xa9, # VK_BROWSER_STOP
- 'browsersearch': 0xaa, # VK_BROWSER_SEARCH
- 'browserfavorites': 0xab, # VK_BROWSER_FAVORITES
- 'browserhome': 0xac, # VK_BROWSER_HOME
- 'volumemute': 0xad, # VK_VOLUME_MUTE
- 'volumedown': 0xae, # VK_VOLUME_DOWN
- 'volumeup': 0xaf, # VK_VOLUME_UP
- 'nexttrack': 0xb0, # VK_MEDIA_NEXT_TRACK
- 'prevtrack': 0xb1, # VK_MEDIA_PREV_TRACK
- 'stop': 0xb2, # VK_MEDIA_STOP
- 'playpause': 0xb3, # VK_MEDIA_PLAY_PAUSE
- 'launchmail': 0xb4, # VK_LAUNCH_MAIL
- 'launchmediaselect': 0xb5, # VK_LAUNCH_MEDIA_SELECT
- 'launchapp1': 0xb6, # VK_LAUNCH_APP1
- 'launchapp2': 0xb7, # VK_LAUNCH_APP2
- })
- # There are other virtual key constants that are not used here because the printable ascii keys are
- # handled in the following `for` loop.
- # The virtual key constants that aren't used are:
- # VK_OEM_1, VK_OEM_PLUS, VK_OEM_COMMA, VK_OEM_MINUS, VK_OEM_PERIOD, VK_OEM_2, VK_OEM_3, VK_OEM_4,
- # VK_OEM_5, VK_OEM_6, VK_OEM_7, VK_OEM_8, VK_PACKET, VK_ATTN, VK_CRSEL, VK_EXSEL, VK_EREOF,
- # VK_PLAY, VK_ZOOM, VK_NONAME, VK_PA1, VK_OEM_CLEAR
- # Populate the basic printable ascii characters.
- # https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-vkkeyscana
- for c in range(32, 128):
- keyboardMapping[chr(c)] = ctypes.windll.user32.VkKeyScanA(ctypes.wintypes.WCHAR(chr(c)))
- def _keyDown(key):
- """Performs a keyboard key press without the release. This will put that
- key in a held down state.
- NOTE: For some reason, this does not seem to cause key repeats like would
- happen if a keyboard key was held down on a text field.
- Args:
- key (str): The key to be pressed down. The valid names are listed in
- pyautogui.KEY_NAMES.
- Returns:
- None
- """
- if key not in keyboardMapping or keyboardMapping[key] is None:
- return
- needsShift = pyautogui.isShiftCharacter(key)
- """
- # OLD CODE: The new code relies on having all keys be loaded in keyboardMapping from the start.
- if key in keyboardMapping.keys():
- vkCode = keyboardMapping[key]
- elif len(key) == 1:
- # note: I could use this case to update keyboardMapping to cache the VkKeyScan results, but I've decided not to just to make any possible bugs easier to reproduce.
- vkCode = ctypes.windll.user32.VkKeyScanW(ctypes.wintypes.WCHAR(key))
- if vkCode == -1:
- raise ValueError('There is no VK code for key "%s"' % (key))
- if vkCode > 0x100: # the vk code will be > 0x100 if it needs shift
- vkCode -= 0x100
- needsShift = True
- """
- mods, vkCode = divmod(keyboardMapping[key], 0x100)
- for apply_mod, vk_mod in [(mods & 4, 0x12), (mods & 2, 0x11),
- (mods & 1 or needsShift, 0x10)]: #HANKAKU not supported! mods & 8
- if apply_mod:
- ctypes.windll.user32.keybd_event(vk_mod, 0, KEYEVENTF_KEYDOWN, 0) #
- ctypes.windll.user32.keybd_event(vkCode, 0, KEYEVENTF_KEYDOWN, 0)
- for apply_mod, vk_mod in [(mods & 1 or needsShift, 0x10), (mods & 2, 0x11),
- (mods & 4, 0x12)]: #HANKAKU not supported! mods & 8
- if apply_mod:
- ctypes.windll.user32.keybd_event(vk_mod, 0, KEYEVENTF_KEYUP, 0) #
- def _keyUp(key):
- """Performs a keyboard key release (without the press down beforehand).
- Args:
- key (str): The key to be released up. The valid names are listed in
- pyautogui.KEY_NAMES.
- Returns:
- None
- """
- if key not in keyboardMapping or keyboardMapping[key] is None:
- return
- needsShift = pyautogui.isShiftCharacter(key)
- """
- # OLD CODE: The new code relies on having all keys be loaded in keyboardMapping from the start.
- if key in keyboardMapping.keys():
- vkCode = keyboardMapping[key]
- elif len(key) == 1:
- # note: I could use this case to update keyboardMapping to cache the VkKeyScan results, but I've decided not to just to make any possible bugs easier to reproduce.
- vkCode = ctypes.windll.user32.VkKeyScanW(ctypes.wintypes.WCHAR(key))
- if vkCode == -1:
- raise ValueError('There is no VK code for key "%s"' % (key))
- if vkCode > 0x100: # the vk code will be > 0x100 if it needs shift
- vkCode -= 0x100
- needsShift = True
- """
- mods, vkCode = divmod(keyboardMapping[key], 0x100)
- for apply_mod, vk_mod in [(mods & 4, 0x12), (mods & 2, 0x11),
- (mods & 1 or needsShift, 0x10)]: #HANKAKU not supported! mods & 8
- if apply_mod:
- ctypes.windll.user32.keybd_event(vk_mod, 0, 0, 0) #
- ctypes.windll.user32.keybd_event(vkCode, 0, KEYEVENTF_KEYUP, 0)
- for apply_mod, vk_mod in [(mods & 1 or needsShift, 0x10), (mods & 2, 0x11),
- (mods & 4, 0x12)]: #HANKAKU not supported! mods & 8
- if apply_mod:
- ctypes.windll.user32.keybd_event(vk_mod, 0, KEYEVENTF_KEYUP, 0) #
- def _position():
- """Returns the current xy coordinates of the mouse cursor as a two-integer
- tuple by calling the GetCursorPos() win32 function.
- Returns:
- (x, y) tuple of the current xy coordinates of the mouse cursor.
- """
- cursor = ctypes.wintypes.POINT()
- ctypes.windll.user32.GetCursorPos(ctypes.byref(cursor))
- return (cursor.x, cursor.y)
- def _size():
- """Returns the width and height of the screen as a two-integer tuple.
- Returns:
- (width, height) tuple of the screen size, in pixels.
- """
- return (ctypes.windll.user32.GetSystemMetrics(0), ctypes.windll.user32.GetSystemMetrics(1))
- def _moveTo(x, y):
- """Send the mouse move event to Windows by calling SetCursorPos() win32
- function.
- Args:
- button (str): The mouse button, either 'left', 'middle', or 'right'
- x (int): The x position of the mouse event.
- y (int): The y position of the mouse event.
- Returns:
- None
- """
- ctypes.windll.user32.SetCursorPos(x, y)
- # This was a possible solution to issue #314 https://github.com/asweigart/pyautogui/issues/314
- # but I'd like to hang on to SetCursorPos because mouse_event() has been superseded.
- #_sendMouseEvent(MOUSEEVENTF_MOVE + MOUSEEVENTF_ABSOLUTE, x, y)
- def _mouseDown(x, y, button):
- """Send the mouse down event to Windows by calling the mouse_event() win32
- function.
- Args:
- x (int): The x position of the mouse event.
- y (int): The y position of the mouse event.
- button (str): The mouse button, either 'left', 'middle', or 'right'
- Returns:
- None
- """
- if button not in (LEFT, MIDDLE, RIGHT):
- raise ValueError('button arg to _click() must be one of "left", "middle", or "right", not %s' % button)
- if button == LEFT:
- EV = MOUSEEVENTF_LEFTDOWN
- elif button == MIDDLE:
- EV = MOUSEEVENTF_MIDDLEDOWN
- elif button == RIGHT:
- EV = MOUSEEVENTF_RIGHTDOWN
- try:
- _sendMouseEvent(EV, x, y)
- except (PermissionError, OSError):
- # TODO: We need to figure out how to prevent these errors, see https://github.com/asweigart/pyautogui/issues/60
- pass
- def _mouseUp(x, y, button):
- """Send the mouse up event to Windows by calling the mouse_event() win32
- function.
- Args:
- x (int): The x position of the mouse event.
- y (int): The y position of the mouse event.
- button (str): The mouse button, either 'left', 'middle', or 'right'
- Returns:
- None
- """
- if button not in (LEFT, MIDDLE, RIGHT):
- raise ValueError('button arg to _click() must be one of "left", "middle", or "right", not %s' % button)
- if button == LEFT:
- EV = MOUSEEVENTF_LEFTUP
- elif button == MIDDLE:
- EV = MOUSEEVENTF_MIDDLEUP
- elif button == RIGHT:
- EV = MOUSEEVENTF_RIGHTUP
- try:
- _sendMouseEvent(EV, x, y)
- except (PermissionError, OSError): # TODO: We need to figure out how to prevent these errors, see https://github.com/asweigart/pyautogui/issues/60
- pass
- def _click(x, y, button):
- """Send the mouse click event to Windows by calling the mouse_event() win32
- function.
- Args:
- button (str): The mouse button, either 'left', 'middle', or 'right'
- x (int): The x position of the mouse event.
- y (int): The y position of the mouse event.
- Returns:
- None
- """
- if button not in (LEFT, MIDDLE, RIGHT):
- raise ValueError('button arg to _click() must be one of "left", "middle", or "right", not %s' % button)
- if button == LEFT:
- EV = MOUSEEVENTF_LEFTCLICK
- elif button == MIDDLE:
- EV = MOUSEEVENTF_MIDDLECLICK
- elif button ==RIGHT:
- EV = MOUSEEVENTF_RIGHTCLICK
- try:
- _sendMouseEvent(EV, x, y)
- except (PermissionError, OSError):
- # TODO: We need to figure out how to prevent these errors, see https://github.com/asweigart/pyautogui/issues/60
- pass
- def _mouse_is_swapped():
- # TODO - measure the performance of checking this setting for each click.
- # 23 is SM_SWAPBUTTON: "Nonzero if the meanings of the left and right mouse buttons are swapped; otherwise, 0."
- return ctypes.windll.user32.GetSystemMetrics(23) != 0
- def _sendMouseEvent(ev, x, y, dwData=0):
- """The helper function that actually makes the call to the mouse_event()
- win32 function.
- Args:
- ev (int): The win32 code for the mouse event. Use one of the MOUSEEVENTF_*
- constants for this argument.
- x (int): The x position of the mouse event.
- y (int): The y position of the mouse event.
- dwData (int): The argument for mouse_event()'s dwData parameter. So far
- this is only used by mouse scrolling.
- Returns:
- None
- """
- assert x != None and y != None, 'x and y cannot be set to None'
- # TODO: ARG! For some reason, SendInput isn't working for mouse events. I'm switching to using the older mouse_event win32 function.
- #mouseStruct = MOUSEINPUT()
- #mouseStruct.dx = x
- #mouseStruct.dy = y
- #mouseStruct.mouseData = ev
- #mouseStruct.time = 0
- #mouseStruct.dwExtraInfo = ctypes.pointer(ctypes.c_ulong(0)) # according to https://stackoverflow.com/questions/13564851/generate-keyboard-events I can just set this. I don't really care about this value.
- #inputStruct = INPUT()
- #inputStruct.mi = mouseStruct
- #inputStruct.type = INPUT_MOUSE
- #ctypes.windll.user32.SendInput(1, ctypes.pointer(inputStruct), ctypes.sizeof(inputStruct))
- # TODO Note: We need to handle additional buttons, which I believe is documented here:
- # https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-mouse_event
- width, height = _size()
- convertedX = 65536 * x // width + 1
- convertedY = 65536 * y // height + 1
- ctypes.windll.user32.mouse_event(ev, ctypes.c_long(convertedX), ctypes.c_long(convertedY), dwData, 0)
- # TODO: Too many false positives with this code: See: https://github.com/asweigart/pyautogui/issues/108
- #if ctypes.windll.kernel32.GetLastError() != 0:
- # raise ctypes.WinError()
- def _scroll(clicks, x=None, y=None):
- """Send the mouse vertical scroll event to Windows by calling the
- mouse_event() win32 function.
- Args:
- clicks (int): The amount of scrolling to do. A positive value is the mouse
- wheel moving forward (scrolling up), a negative value is backwards (down).
- x (int): The x position of the mouse event.
- y (int): The y position of the mouse event.
- Returns:
- None
- """
- startx, starty = _position()
- width, height = _size()
- if x is None:
- x = startx
- else:
- if x < 0:
- x = 0
- elif x >= width:
- x = width - 1
- if y is None:
- y = starty
- else:
- if y < 0:
- y = 0
- elif y >= height:
- y = height - 1
- try:
- _sendMouseEvent(MOUSEEVENTF_WHEEL, x, y, dwData=clicks)
- except (PermissionError, OSError): # TODO: We need to figure out how to prevent these errors, see https://github.com/asweigart/pyautogui/issues/60
- pass
- def _hscroll(clicks, x, y):
- """Send the mouse horizontal scroll event to Windows by calling the
- mouse_event() win32 function.
- Args:
- clicks (int): The amount of scrolling to do. A positive value is the mouse
- wheel moving right, a negative value is moving left.
- x (int): The x position of the mouse event.
- y (int): The y position of the mouse event.
- Returns:
- None
- """
- return _scroll(clicks, x, y)
- def _vscroll(clicks, x, y):
- """A wrapper for _scroll(), which does vertical scrolling.
- Args:
- clicks (int): The amount of scrolling to do. A positive value is the mouse
- wheel moving forward (scrolling up), a negative value is backwards (down).
- x (int): The x position of the mouse event.
- y (int): The y position of the mouse event.
- Returns:
- None
- """
- return _scroll(clicks, x, y)
|