pydirectinput
Partial implementation of DirectInput function calls to simulate mouse and keyboard inputs.
1""" 2Partial implementation of DirectInput function calls to simulate 3mouse and keyboard inputs. 4""" 5 6from __future__ import annotations 7 8# native imports 9import functools 10import inspect 11import os 12import sys 13import time 14from collections.abc import Generator 15from collections.abc import Sequence 16from contextlib import contextmanager 17from ctypes import POINTER 18from ctypes import Array 19from ctypes import LibraryLoader 20from ctypes import Structure 21from ctypes import Union 22from ctypes import WinDLL 23from ctypes import pointer 24from ctypes import sizeof 25from ctypes.wintypes import BOOL 26from ctypes.wintypes import DWORD 27from ctypes.wintypes import HMONITOR 28from ctypes.wintypes import INT 29from ctypes.wintypes import LONG 30from ctypes.wintypes import LPCVOID 31from ctypes.wintypes import PULONG 32from ctypes.wintypes import UINT 33from ctypes.wintypes import ULONG 34from ctypes.wintypes import WORD 35from math import ceil 36from math import floor 37from math import log10 38from struct import unpack 39from threading import Lock 40 41 42# Windows-only 43if sys.platform != "win32": 44 raise ImportError( 45 "This module makes Windows API calls and is thereby only available " 46 "on that plattform!" 47 ) 48 49# Python 3.7 or higher 50if sys.version_info >= (3, 7): 51 # native imports 52 from typing import TYPE_CHECKING 53 from typing import Any 54 from typing import Callable 55 from typing import TypeVar 56 from typing import cast as hint_cast # prevent confusion with ctypes.cast 57 from typing import overload 58else: 59 raise ImportError( 60 "This module is strictly typed and can't be used in Python <3.7!" 61 ) 62 63# Python 3.8 or higher 64if sys.version_info >= (3, 8): 65 # native imports 66 from typing import ClassVar 67 from typing import Final 68 from typing import Literal 69 from typing import Protocol 70else: 71 # pip imports 72 from typing_extensions import ClassVar 73 from typing_extensions import Final 74 from typing_extensions import Literal 75 from typing_extensions import Protocol 76 77# Python 3.9 or higher 78if sys.version_info >= (3, 9): 79 List = list 80else: 81 # native imports 82 from typing import List 83 84# Python 3.10 or higher 85if sys.version_info >= (3, 10): 86 # native imports 87 from typing import ParamSpec 88 from typing import TypeAlias 89else: 90 # pip imports 91 from typing_extensions import ParamSpec 92 from typing_extensions import TypeAlias 93 94# # Python 3.11 or higher 95# if sys.version_info >= (3, 11): 96# pass 97# else: 98# pass 99 100# ------------------------------------------------------------------------------ 101# https://github.com/python/mypy/issues/7540#issuecomment-845741357 102if TYPE_CHECKING: 103 # We have to get the private Pointer type from typeshed to make 104 # the type checker shut up about the "incompatible types" error. 105 # native imports 106 from ctypes import _Pointer # pyright: ignore[reportPrivateUsage] 107 108 _POINTER_TYPE = _Pointer 109else: 110 111 class __pointer: 112 """ 113 Create pointer proxy class that translates square bracket notation 114 __pointer[type] into POINTER(type). 115 """ 116 117 @classmethod 118 def __class_getitem__(cls, item): 119 return POINTER(item) 120 121 _POINTER_TYPE = __pointer 122# ------------------------------------------------------------------------------ 123 124 125# ============================================================================== 126# ===== Internal WinDLL instance =============================================== 127# ============================================================================== 128# Importing the cached WinDLL instance from ctypes directly would cause 129# conflicts with other packages that also use ctypes (notably pyautogui). 130# Therefore we create our own WinDLL instance and use that instead. 131windll: LibraryLoader[WinDLL] = LibraryLoader(WinDLL) 132 133 134# ============================================================================== 135# ===== Internal time source =================================================== 136# ============================================================================== 137_time: Callable[[], float] = time.perf_counter 138_time_ns: Callable[[], int] = time.perf_counter_ns 139_sleep: Callable[[float], None] = time.sleep 140 141 142# ============================================================================== 143# ===== External "constants" =================================================== 144# ============================================================================== 145 146# ----- "Constants" for failsafe check and pause ------------------------------- 147# Intendend to be modified by callers 148FAILSAFE: bool = True 149""" 150Stop execution if mouse is moved into one of `FAILSAFE_POINTS`. 151Change to disable failsafe behaviour. 152""" 153FAILSAFE_POINTS: list[tuple[int, int]] = [(0, 0)] 154""" 155List of coordinates that trigger failafe exception. (default: top left corner) 156""" 157PAUSE: float | None = 0.01 # 1/100 second pause by default 158""" 159Default pause interval in seconds if _pause argument isn't set to False. 1601/100 second pause by default. 161 162Set to None to disable automatic pauses entirely. 163""" 164MINIMUM_SLEEP_IDEAL: float = 1e-6 165""" 166Extremely small timer interval greater than 0 that still causes the system to 167sleep. This is the ideal value, the system may not be able to sleep for this 168short of a time. See `MINIMUM_SLEEP_ACTUAL` and `calibrate_real_sleep_minimum`. 169""" 170MINIMUM_SLEEP_ACTUAL: float = 0.002 171""" 172Actual time spent on sleeping with MINIMUM_SLEEP_IDEAL, rounded up for safety. 173Determined ahead of time by `calibrate_real_sleep_minimum`. The `MINIMUM_SLEEP_` 174values may differ between systems. If you're unsure, run the calibration 175and correct this value after importing the module. 176""" 177# ------------------------------------------------------------------------------ 178 179 180# ----- Constants for the mouse button names ----------------------------------- 181MOUSE_LEFT: str = "left" 182"""Name of left mouse button""" 183MOUSE_MIDDLE: str = "middle" 184"""Name of middle mouse button""" 185MOUSE_RIGHT: str = "right" 186"""Name of right mouse button""" 187MOUSE_PRIMARY: str = "primary" 188"""Name of primary mouse button (left mouse button unless swapped)""" 189MOUSE_SECONDARY: str = "secondary" 190"""Name of secondary mouse button (right mouse button unless swapped)""" 191MOUSE_BUTTON4: str = "mouse4" 192"""Name of first additional mouse button (usually a side button)""" 193MOUSE_X1: str = "x1" 194"""Name of first additional mouse button (usually a side button)""" 195MOUSE_BUTTON5: str = "mouse5" 196"""Name of second additional mouse button (usually a side button)""" 197MOUSE_X2: str = "x2" 198"""Name of second additional mouse button (usually a side button)""" 199# ------------------------------------------------------------------------------ 200 201 202# ============================================================================== 203# ===== External setup functions =============================================== 204# ============================================================================== 205 206 207# ----- automatically measure minimum sleep time ------------------------------- 208def calibrate_real_sleep_minimum( 209 runs: int = 10, *, verbose: bool = False 210) -> None: 211 """ 212 Measure your system's minimum sleep duration and calibrate 213 `MINIMUM_SLEEP_ACTUAL` accordingly. 214 215 Will try to sleep for `MINIMUM_SLEEP_IDEAL` seconds and measure actual time 216 difference. Repeat for `runs` amount of times, take the highest measurement 217 and round it up to the next higher value in the same order of magnitude. 218 219 Example: [0.001874, 0.001721, 0.001806] would round up to 0.002 220 """ 221 222 def round_up_same_magnitude(x: float) -> float: 223 mag: float = 10 ** floor(log10(x)) 224 return ceil(x / mag) * mag 225 226 def stopwatch(duration: float) -> float: 227 t1: int = _time_ns() 228 _sleep(duration) 229 t2: int = _time_ns() 230 return (t2 - t1) * 1e-9 231 232 if verbose: 233 print("Calibrating real sleep minimum...") 234 235 measurements = [stopwatch(MINIMUM_SLEEP_IDEAL) for _ in range(runs)] 236 if verbose: 237 print(f"Real measurements: {measurements}") 238 239 new_sleep_minimum = round_up_same_magnitude(max(measurements)) 240 if verbose: 241 print( 242 "Rounding max measurement to next higher value in same order of " 243 f"magnitude: {new_sleep_minimum}" 244 ) 245 246 global MINIMUM_SLEEP_ACTUAL 247 if verbose: 248 print( 249 f"Changing MINIMUM_SLEEP_ACTUAL from {MINIMUM_SLEEP_ACTUAL} to " 250 f"{new_sleep_minimum}" 251 ) 252 MINIMUM_SLEEP_ACTUAL = ( # pyright: ignore[reportConstantRedefinition] 253 new_sleep_minimum 254 ) 255 # -------------------------------------------------------------------------- 256 257 258# ============================================================================== 259# ===== Internal constants ===================================================== 260# ============================================================================== 261 262 263# ----- INPUT.type constants --------------------------------------------------- 264_INPUT_MOUSE: Final = 0x0000 # c_ulong(0x0000) 265"""The event is a mouse event. Use the mi structure of the union.""" 266_INPUT_KEYBOARD: Final = 0x0001 # c_ulong(0x0001) 267"""The event is a keyboard event. Use the ki structure of the union.""" 268_INPUT_HARDWARE: Final = 0x0002 # c_ulong(0x0002) 269"""The event is a hardware event. Use the hi structure of the union.""" 270# ------------------------------------------------------------------------------ 271 272 273# ----- MOUSEINPUT.mouseData constants ----------------------------------------- 274_XBUTTON1: Final = 0x0001 # c_ulong(0x0001) 275"""Set if the first X button is pressed or released.""" 276_XBUTTON2: Final = 0x0002 # c_ulong(0x0002) 277"""Set if the second X button is pressed or released.""" 278# ------------------------------------------------------------------------------ 279 280 281# ----- MOUSEINPUT.dwFlags constants ------------------------------------------- 282_MOUSEEVENTF_MOVE: Final = 0x0001 # c_ulong(0x0001) 283"""Movement occurred.""" 284 285_MOUSEEVENTF_LEFTDOWN: Final = 0x0002 # c_ulong(0x0002) 286"""The left button was pressed.""" 287_MOUSEEVENTF_LEFTUP: Final = 0x0004 # c_ulong(0x0004) 288"""The left button was released.""" 289_MOUSEEVENTF_LEFTCLICK: Final = ( 290 _MOUSEEVENTF_LEFTDOWN + _MOUSEEVENTF_LEFTUP # c_ulong(0x0006) 291) 292"""Combined event: Left button was clicked.""" 293 294_MOUSEEVENTF_RIGHTDOWN: Final = 0x0008 # c_ulong(0x0008) 295"""The right button was pressed.""" 296_MOUSEEVENTF_RIGHTUP: Final = 0x0010 # c_ulong(0x0010) 297"""The right button was released.""" 298_MOUSEEVENTF_RIGHTCLICK: Final = ( 299 _MOUSEEVENTF_RIGHTDOWN + _MOUSEEVENTF_RIGHTUP # c_ulong(0x0018) 300) 301"""Combined event: Right button was clicked.""" 302 303_MOUSEEVENTF_MIDDLEDOWN: Final = 0x0020 # c_ulong(0x0020) 304"""The middle button was pressed.""" 305_MOUSEEVENTF_MIDDLEUP: Final = 0x0040 # c_ulong(0x0040) 306"""The middle button was released.""" 307_MOUSEEVENTF_MIDDLECLICK: Final = ( 308 _MOUSEEVENTF_MIDDLEDOWN + _MOUSEEVENTF_MIDDLEUP # c_ulong(0x0060) 309) 310"""Combined event: Middle button was clicked.""" 311 312_MOUSEEVENTF_XDOWN: Final = 0x0080 # c_ulong(0x0080) 313"""An X button was pressed.""" 314_MOUSEEVENTF_XUP: Final = 0x0100 # c_ulong(0x0100) 315"""An X button was released.""" 316_MOUSEEVENTF_XCLICK: Final = ( 317 _MOUSEEVENTF_XDOWN + _MOUSEEVENTF_XUP # c_ulong(0x0180) 318) 319"""Combined event: Side button was clicked.""" 320 321_MOUSEEVENTF_WHEEL: Final = 0x0800 # c_ulong(0x0800) 322""" 323The wheel was moved, if the mouse has a wheel. 324The amount of movement is specified in mouseData. 325""" 326_MOUSEEVENTF_HWHEEL: Final = 0x1000 # c_ulong(0x1000) 327""" 328The wheel was moved horizontally, if the mouse has a wheel. The amount of 329movement is specified in mouseData. 330Windows XP/2000: This value is not supported. 331""" 332 333_MOUSEEVENTF_MOVE_NOCOALESCE: Final = 0x2000 # c_ulong(0x2000) 334""" 335The WM_MOUSEMOVE messages will not be coalesced. The default behavior is to 336coalesce WM_MOUSEMOVE messages. 337Windows XP/2000: This value is not supported. 338""" 339_MOUSEEVENTF_VIRTUALDESK: Final = 0x4000 # c_ulong(0x4000) 340""" 341Maps coordinates to the entire desktop. Must be used with MOUSEEVENTF_ABSOLUTE. 342""" 343_MOUSEEVENTF_ABSOLUTE: Final = 0x8000 # c_ulong(0x8000) 344""" 345The dx and dy members contain normalized absolute coordinates. If the flag is 346not set, dx and dy contain relative data (the change in position since the last 347reported position). This flag can be set, or not set, regardless of what kind of 348mouse or other pointing device, if any, is connected to the system. For further 349information about relative mouse motion, see the following Remarks section. 350""" 351# ------------------------------------------------------------------------------ 352 353 354# ----- MOUSEINPUT Remarks ----------------------------------------------------- 355""" 356https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-mouseinput#remarks 357 358----- Remarks ----- 359 360If the mouse has moved, indicated by MOUSEEVENTF_MOVE, dx and dy specify 361information about that movement. The information is specified as absolute or 362relative integer values. 363 364If MOUSEEVENTF_ABSOLUTE value is specified, dx and dy contain normalized 365absolute coordinates between 0 and 65,535. The event procedure maps these 366coordinates onto the display surface. Coordinate (0,0) maps onto the upper-left 367corner of the display surface; coordinate (65535,65535) maps onto the 368lower-right corner. In a multimonitor system, the coordinates map to the 369primary monitor. 370 371If MOUSEEVENTF_VIRTUALDESK is specified, the coordinates map to the entire 372virtual desktop. 373 374If the MOUSEEVENTF_ABSOLUTE value is not specified, dx and dy specify movement 375relative to the previous mouse event (the last reported position). Positive 376values mean the mouse moved right (or down); negative values mean the mouse 377moved left (or up). 378 379Relative mouse motion is subject to the effects of the mouse speed and the 380two-mouse threshold values. A user sets these three values with the 381Pointer Speed slider of the Control Panel's Mouse Properties sheet. You can 382obtain and set these values using the SystemParametersInfo[1] function. 383 384The system applies two tests to the specified relative mouse movement. If the 385specified distance along either the x or y axis is greater than the first 386mouse threshold value, and the mouse speed is not zero, the system doubles the 387distance. If the specified distance along either the x or y axis is greater 388than the second mouse threshold value, and the mouse speed is equal to two, 389the system doubles the distance that resulted from applying the first 390threshold test. It is thus possible for the system to multiply specified 391relative mouse movement along the x or y axis by up to four times. 392 393[1] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfoa 394""" 395# ------------------------------------------------------------------------------ 396 397 398# ----- Scrolling distance ----------------------------------------------------- 399_WHEEL_DELTA: Final = 120 400""" 401The delta was set to 120 to allow Microsoft or other vendors to build 402finer-resolution wheels (a freely-rotating wheel with no notches) to send more 403messages per rotation, but with a smaller value in each message. 404 405https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mousewheel 406""" 407# ------------------------------------------------------------------------------ 408 409 410# ----- KEYBDINPUT.dwFlags Flags ------------------------------------------------ 411_KEYEVENTF_EXTENDEDKEY: Final = 0x0001 # c_ulong(0x0001) 412""" 413If specified, the scan code was preceded by a prefix byte that has the value 4140xE0 (224). 415""" 416_KEYEVENTF_KEYUP: Final = 0x0002 # c_ulong(0x0002) 417""" 418If specified, the key is being released. If not specified, the key is being 419pressed. 420""" 421_KEYEVENTF_UNICODE: Final = 0x0004 # c_ulong(0x0004) 422""" 423If specified, the system synthesizes a VK_PACKET keystroke. The wVk parameter 424must be zero. This flag can only be combined with the KEYEVENTF_KEYUP flag. 425For more information, see the Remarks section. 426""" 427_KEYEVENTF_SCANCODE: Final = 0x0008 # c_ulong(0x0008) 428"""If specified, wScan identifies the key and wVk is ignored.""" 429# ------------------------------------------------------------------------------ 430 431 432# ----- KEYBDINPUT Remarks ----------------------------------------------------- 433""" 434https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-keybdinput#remarks 435 436----- Remarks ----- 437 438INPUT_KEYBOARD supports nonkeyboard-input methods—such as handwriting 439recognition or voice recognition—as if it were text input by using the 440KEYEVENTF_UNICODE flag. If KEYEVENTF_UNICODE is specified, SendInput sends 441a WM_KEYDOWN or WM_KEYUP message to the foreground thread's message queue with 442wParam equal to VK_PACKET. Once GetMessage or PeekMessage obtains this message, 443passing the message to TranslateMessage posts a WM_CHAR message with the 444Unicode character originally specified by wScan. This Unicode character will 445automatically be converted to the appropriate ANSI value if it is posted to 446an ANSI window. 447 448Set the KEYEVENTF_SCANCODE flag to define keyboard input in terms of the scan 449code. This is useful for simulating a physical keystroke regardless of which 450keyboard is currently being used. You can also pass the KEYEVENTF_EXTENDEDKEY 451flag if the scan code is an extended key. The virtual key value of a key can 452change depending on the current keyboard layout or what other keys were pressed, 453but the scan code will always be the same. 454""" 455# ------------------------------------------------------------------------------ 456 457 458# ----- MapVirtualKey Map Types ------------------------------------------------ 459_MAPVK_VK_TO_VSC: Final = 0 # c_unit(0) 460""" 461The uCode parameter is a virtual-key code and is translated into a scan code. 462If it is a virtual-key code that does not distinguish between left- and 463right-hand keys, the left-hand scan code is returned. 464If there is no translation, the function returns 0. 465""" 466_MAPVK_VSC_TO_VK: Final = 1 # c_unit(1) 467""" 468The uCode parameter is a scan code and is translated into a virtual-key code 469that does not distinguish between left- and right-hand keys. 470If there is no translation, the function returns 0. 471""" 472_MAPVK_VK_TO_CHAR: Final = 2 # c_unit(2) 473""" 474The uCode parameter is a virtual-key code and is translated into an unshifted 475character value in the low order word of the return value. Dead keys 476(diacritics) are indicated by setting the top bit of the return value. 477If there is no translation, the function returns 0. 478""" 479_MAPVK_VSC_TO_VK_EX: Final = 3 # c_unit(3) 480""" 481The uCode parameter is a scan code and is translated into a virtual-key code 482that distinguishes between left- and right-hand keys. 483If there is no translation, the function returns 0. 484""" 485_MAPVK_VK_TO_VSC_EX: Final = 4 # c_unit(4) 486""" 487Windows Vista and later: The uCode parameter is a virtual-key code and is 488translated into a scan code. If it is a virtual-key code that does not 489distinguish between left- and right-hand keys, the left-hand scan code is 490returned. If the scan code is an extended scan code, the high byte of the uCode 491value can contain either 0xe0 or 0xe1 to specify the extended scan code. 492If there is no translation, the function returns 0. 493""" 494# ------------------------------------------------------------------------------ 495 496 497# ----- GetSystemMetrics nIndex arguments -------------------------------------- 498_SM_CXSCREEN: Final = 0 499""" 500The width of the screen of the primary display monitor, in pixels. This is the 501same value obtained by calling GetDeviceCaps[1] as follows: 502`GetDeviceCaps(hdcPrimaryMonitor, HORZRES)`. 503 504[1] https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getdevicecaps 505""" 506_SM_CYSCREEN: Final = 1 507""" 508The height of the screen of the primary display monitor, in pixels. This is 509the same value obtained by calling GetDeviceCaps[1] as follows: 510`GetDeviceCaps(hdcPrimaryMonitor, VERTRES)`. 511 512[1] https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getdevicecaps 513""" 514_SM_SWAPBUTTON: Final = 23 515""" 516Nonzero if the meanings of the left and right mouse buttons are swapped; 517otherwise, 0. 518""" 519_SM_XVIRTUALSCREEN: Final = 76 520""" 521The coordinates for the left side of the virtual screen. The virtual screen is 522the bounding rectangle of all display monitors. The SM_CXVIRTUALSCREEN metric 523is the width of the virtual screen. 524""" 525_SM_YVIRTUALSCREEN: Final = 77 526""" 527The coordinates for the top of the virtual screen. The virtual screen is the 528bounding rectangle of all display monitors. The SM_CYVIRTUALSCREEN metric is 529the height of the virtual screen. 530""" 531_SM_CXVIRTUALSCREEN: Final = 78 532""" 533The width of the virtual screen, in pixels. The virtual screen is the bounding 534rectangle of all display monitors. The SM_XVIRTUALSCREEN metric is the 535coordinates for the left side of the virtual screen. 536""" 537_SM_CYVIRTUALSCREEN: Final = 79 538""" 539The height of the virtual screen, in pixels. The virtual screen is the bounding 540rectangle of all display monitors. The SM_YVIRTUALSCREEN metric is the 541coordinates for the top of the virtual screen. 542""" 543# ------------------------------------------------------------------------------ 544 545 546# ----- SystemParametersInfoW uiAction arguments ------------------------------- 547_SPI_GETMOUSE: Final = 0x0003 # c_uint 548""" 549Retrieves the two mouse threshold values and the mouse acceleration. The 550pvParam parameter must point to an array of three integers that receives these 551values. See mouse_event[1] for further information. 552 553https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mouse_event 554""" 555_SPI_SETMOUSE: Final = 0x0004 # c_uint 556""" 557Sets the two mouse threshold values and the mouse acceleration. The pvParam 558parameter must point to an array of three integers that specifies these values. 559See mouse_event[1] for further information. 560 561https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mouse_event 562""" 563_SPI_GETMOUSESPEED: Final = 0x0070 # c_uint 564""" 565Retrieves the current mouse speed. The mouse speed determines how far the 566pointer will move based on the distance the mouse moves. The pvParam parameter 567must point to an integer that receives a value which ranges between 1 (slowest) 568and 20 (fastest). A value of 10 is the default. The value can be set by an 569end-user using the mouse control panel application or by an application using 570SPI_SETMOUSESPEED. 571""" 572_SPI_SETMOUSESPEED: Final = 0x0071 # c_uint 573""" 574Sets the current mouse speed. The pvParam parameter is an integer between 5751 (slowest) and 20 (fastest). A value of 10 is the default. This value is 576typically set using the mouse control panel application. 577""" 578# ------------------------------------------------------------------------------ 579 580 581# ----- MOUSEEVENTF Index constants -------------------------------------------- 582_MOUSE_PRESS: Final = 0 583_MOUSE_RELEASE: Final = 1 584_MOUSE_CLICK: Final = 2 585# ------------------------------------------------------------------------------ 586 587 588# ----- MOUSEEVENTF Lookup dicts ----------------------------------------------- 589_MOUSEEVENTF_LEFT: tuple[int, int, int] = ( 590 _MOUSEEVENTF_LEFTDOWN, 591 _MOUSEEVENTF_LEFTUP, 592 _MOUSEEVENTF_LEFTCLICK, 593) 594_MOUSEEVENTF_MIDDLE: tuple[int, int, int] = ( 595 _MOUSEEVENTF_MIDDLEDOWN, 596 _MOUSEEVENTF_MIDDLEUP, 597 _MOUSEEVENTF_MIDDLECLICK, 598) 599_MOUSEEVENTF_RIGHT: tuple[int, int, int] = ( 600 _MOUSEEVENTF_RIGHTDOWN, 601 _MOUSEEVENTF_RIGHTUP, 602 _MOUSEEVENTF_RIGHTCLICK, 603) 604_MOUSEEVENTF_X: tuple[int, int, int] = ( 605 _MOUSEEVENTF_XDOWN, 606 _MOUSEEVENTF_XUP, 607 _MOUSEEVENTF_XCLICK, 608) 609_MOUSE_MAPPING_EVENTF: dict[str, tuple[int, int, int]] = {} 610_MOUSE_MAPPING_DATA: dict[str, int] = {} 611 612 613def update_MOUSEEVENT_mappings() -> None: 614 """ 615 Update the MOUSEEVENT mappings if you change the name of the button name 616 constants. 617 618 This function MUST be called every time one of the `MOUSE_*` constants 619 has been changed! 620 """ 621 _MOUSE_MAPPING_EVENTF.update( 622 { 623 MOUSE_LEFT: _MOUSEEVENTF_LEFT, 624 MOUSE_MIDDLE: _MOUSEEVENTF_MIDDLE, 625 MOUSE_RIGHT: _MOUSEEVENTF_RIGHT, 626 MOUSE_BUTTON4: _MOUSEEVENTF_X, 627 MOUSE_X1: _MOUSEEVENTF_X, 628 MOUSE_BUTTON5: _MOUSEEVENTF_X, 629 MOUSE_X2: _MOUSEEVENTF_X, 630 } 631 ) 632 _MOUSE_MAPPING_DATA.update( 633 { 634 MOUSE_LEFT: 0, 635 MOUSE_MIDDLE: 0, 636 MOUSE_RIGHT: 0, 637 MOUSE_BUTTON4: _XBUTTON1, 638 MOUSE_X1: _XBUTTON1, 639 MOUSE_BUTTON5: _XBUTTON2, 640 MOUSE_X2: _XBUTTON2, 641 } 642 ) 643 644 645update_MOUSEEVENT_mappings() # call the function on import to set mappings. 646# ------------------------------------------------------------------------------ 647 648 649# ----- MonitorFromPoint dwFlags constants ------------------------------------- 650_MONITOR_DEFAULTTONULL: Final = 0x00000000 # c_ulong 651"""Returns NULL.""" 652_MONITOR_DEFAULTTOPRIMARY: Final = 0x00000001 # c_ulong 653"""Returns a handle to the primary display monitor.""" 654_MONITOR_DEFAULTTONEAREST: Final = 0x00000002 # c_ulong 655"""Returns a handle to the display monitor that is nearest to the point.""" 656# ------------------------------------------------------------------------------ 657 658 659# ============================================================================== 660# ===== C struct redefinitions ================================================= 661# ============================================================================== 662 663 664# ----- MOUSEINPUT ------------------------------------------------------------- 665class _MOUSEINPUT(Structure): 666 """ 667 MOUSEINPUT structure (winuser.h) 668 669 Contains information about a simulated mouse event. 670 671 https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-mouseinput 672 """ 673 674 # Python side type hinting 675 dx: int # LONG 676 """ 677 The absolute position of the mouse, or the amount of motion since the last 678 mouse event was generated, depending on the value of the dwFlags member. 679 Absolute data is specified as the x coordinate of the mouse; relative data 680 is specified as the number of pixels moved. 681 """ 682 dy: int # LONG 683 """ 684 The absolute position of the mouse, or the amount of motion since the last 685 mouse event was generated, depending on the value of the dwFlags member. 686 Absolute data is specified as the y coordinate of the mouse; relative data 687 is specified as the number of pixels moved. 688 """ 689 mouseData: int # DWORD 690 """ 691 If dwFlags contains MOUSEEVENTF_WHEEL, then mouseData specifies the amount 692 of wheel movement. A positive value indicates that the wheel was rotated 693 forward, away from the user; a negative value indicates that the wheel was 694 rotated backward, toward the user. One wheel click is defined as 695 WHEEL_DELTA, which is 120. 696 697 Windows Vista: If dwFlags contains MOUSEEVENTF_HWHEEL, then dwData 698 specifies the amount of wheel movement. A positive value indicates that 699 the wheel was rotated to the right; a negative value indicates that the 700 wheel was rotated to the left. One wheel click is defined as WHEEL_DELTA, 701 which is 120. 702 703 If dwFlags does not contain MOUSEEVENTF_WHEEL, MOUSEEVENTF_XDOWN, or 704 MOUSEEVENTF_XUP, then mouseData should be zero. 705 706 If dwFlags contains MOUSEEVENTF_XDOWN or MOUSEEVENTF_XUP, then mouseData 707 specifies which X buttons were pressed or released. This value may be any 708 combination of the following flags. (See _XBUTTON* constants) 709 """ 710 dwFlags: int # DWORD 711 """ 712 A set of bit flags that specify various aspects of mouse motion and button 713 clicks. The bits in this member can be any reasonable combination of the 714 following values. 715 716 The bit flags that specify mouse button status are set to indicate changes 717 in status, not ongoing conditions. For example, if the left mouse button is 718 pressed and held down, MOUSEEVENTF_LEFTDOWN is set when the left button is 719 first pressed, but not for subsequent motions. Similarly MOUSEEVENTF_LEFTUP 720 is set only when the button is first released. 721 722 You cannot specify both the MOUSEEVENTF_WHEEL flag and either 723 MOUSEEVENTF_XDOWN or MOUSEEVENTF_XUP flags simultaneously in the dwFlags 724 parameter, because they both require use of the mouseData field. 725 (See _MOUSEEVENTF_* constants) 726 """ 727 time: int # DWORD 728 """ 729 The time stamp for the event, in milliseconds. If this parameter is 0, the 730 system will provide its own time stamp. 731 """ 732 dwExtraInfo: ULONG # ULONG_PTR 733 """ 734 An additional value associated with the keystroke. Use the 735 GetMessageExtraInfo[1] function to obtain this information. 736 737 [1] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessageextrainfo 738 """ 739 # ctypes side struct definition 740 _fields_ = [ 741 ("dx", LONG), 742 ("dy", LONG), 743 ("mouseData", DWORD), 744 ("dwFlags", DWORD), 745 ("time", DWORD), 746 ("dwExtraInfo", PULONG), 747 ] 748 # -------------------------------------------------------------------------- 749 750 751# ----- KEYBDINPUT ------------------------------------------------------------- 752class _KEYBDINPUT(Structure): 753 """ 754 KEYBDINPUT structure (winuser.h) 755 756 Contains information about a simulated keyboard event. 757 758 https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-keybdinput 759 """ 760 761 # Python side type hinting 762 wVk: int # WORD 763 """ 764 A virtual-key code. The code must be a value in the range 1 to 254. If the 765 dwFlags member specifies KEYEVENTF_UNICODE, wVk must be 0. 766 """ 767 wScan: int # WORD 768 """ 769 A hardware scan code for the key. If dwFlags specifies KEYEVENTF_UNICODE, 770 wScan specifies a Unicode character which is to be sent to the foreground 771 application. 772 """ 773 dwFlags: int # DWORD 774 """ 775 Specifies various aspects of a keystroke. This member can be certain 776 combinations of the following values. (See _KEYEVENTF_* constants) 777 """ 778 time: int # DWORD 779 """ 780 The time stamp for the event, in milliseconds. If this parameter is zero, 781 the system will provide its own time stamp. 782 """ 783 dwExtraInfo: ULONG # ULONG_PTR 784 """ 785 An additional value associated with the keystroke. Use the 786 GetMessageExtraInfo[1] function to obtain this information. 787 788 [1] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessageextrainfo 789 """ 790 # ctypes side struct definition 791 _fields_ = [ 792 ("wVk", WORD), 793 ("wScan", WORD), 794 ("dwFlags", DWORD), 795 ("time", DWORD), 796 ("dwExtraInfo", PULONG), 797 ] 798 # -------------------------------------------------------------------------- 799 800 801# ----- HARDWAREINPUT ---------------------------------------------------------- 802class _HARDWAREINPUT(Structure): 803 """ 804 HARDWAREINPUT structure (winuser.h) 805 806 Contains information about a simulated message generated by an input 807 device other than a keyboard or mouse. 808 809 https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-hardwareinput 810 """ 811 812 # Python side type hinting 813 uMsg: int # DWORD 814 """The message generated by the input hardware.""" 815 wParamL: int # WORD 816 """The low-order word of the lParam parameter for uMsg.""" 817 wParamH: int # WORD 818 """The high-order word of the lParam parameter for uMsg.""" 819 # ctypes side struct definition 820 _fields_ = [ 821 ("uMsg", DWORD), 822 ("wParamL", WORD), 823 ("wParamH", WORD), 824 ] 825 # -------------------------------------------------------------------------- 826 827 828# ----- POINT ------------------------------------------------------------------ 829class _POINT(Structure): 830 """ 831 POINT structure 832 833 The POINT structure defines the x- and y- coordinates of a point. 834 835 https://docs.microsoft.com/en-us/previous-versions/dd162805(v=vs.85) 836 """ 837 838 # Python side type hinting 839 x: int # LONG 840 """The x-coordinate of the point.""" 841 y: int # LONG 842 """The y-coordinate of the point.""" 843 # ctypes side struct definition 844 _fields_ = [("x", LONG), ("y", LONG)] 845 # -------------------------------------------------------------------------- 846 847 848# ----- INPUT ------------------------------------------------------------------ 849class _INPUT_UNION(Union): 850 """ 851 https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-input 852 """ 853 854 # Python side type hinting 855 mi: _MOUSEINPUT 856 ki: _KEYBDINPUT 857 hi: _HARDWAREINPUT 858 # ctypes side struct definition 859 _fields_ = [ 860 ("mi", _MOUSEINPUT), 861 ("ki", _KEYBDINPUT), 862 ("hi", _HARDWAREINPUT), 863 ] 864 865 866class _INPUT(Structure): 867 """ 868 INPUT structure (winuser.h) 869 870 Used by SendInput to store information for synthesizing input events such 871 as keystrokes, mouse movement, and mouse clicks. 872 873 https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-input 874 """ 875 876 # Python side type hinting 877 type: Literal[0, 1, 2] # DWORD 878 """ 879 The type of the input event. This member can be one of the following 880 values. (See _INPUT_* constants) 881 """ 882 ii: _INPUT_UNION 883 mi: _MOUSEINPUT # part of _INPUT_UNION ii 884 """The information about a simulated mouse event.""" 885 ki: _KEYBDINPUT # part of _INPUT_UNION ii 886 """The information about a simulated keyboard event.""" 887 hi: _HARDWAREINPUT # part of _INPUT_UNION ii 888 """The information about a simulated hardware event.""" 889 # ctypes side struct definition 890 _anonymous_ = ("ii",) 891 _fields_ = [ 892 ("type", DWORD), 893 ("ii", _INPUT_UNION), 894 ] 895 # -------------------------------------------------------------------------- 896 897 898# ============================================================================== 899# ===== C struct factory functions ============================================= 900# ============================================================================== 901 902 903# ----- _create_mouse_input ---------------------------------------------------- 904def _create_mouse_input( 905 dx: int = 0, # c_long 906 dy: int = 0, # c_long 907 mouseData: int = 0, # c_ulong 908 dwFlags: int = 0, # c_ulong 909 time: int = 0, # c_ulong 910) -> _INPUT: 911 """Create INPUT structure for mouse input""" 912 dwExtraInfo: ULONG = ULONG(0) 913 input_struct: _INPUT = _INPUT(_INPUT_MOUSE) 914 input_struct.mi = _MOUSEINPUT( 915 dx, dy, mouseData, dwFlags, time, pointer(dwExtraInfo) 916 ) 917 return input_struct 918 # -------------------------------------------------------------------------- 919 920 921# ----- _create_keyboard_input ------------------------------------------------- 922def _create_keyboard_input( 923 wVk: int = 0, # c_ushort 924 wScan: int = 0, # c_ushort 925 dwFlags: int = 0, # c_ulong 926 time: int = 0, # c_ulong 927) -> _INPUT: 928 """Create INPUT structure for keyboard input""" 929 dwExtraInfo: ULONG = ULONG(0) 930 input_struct: _INPUT = _INPUT(_INPUT_KEYBOARD) 931 input_struct.ki = _KEYBDINPUT( 932 wVk, wScan, dwFlags, time, pointer(dwExtraInfo) 933 ) 934 return input_struct 935 # -------------------------------------------------------------------------- 936 937 938# ----- _create_hardware_input ------------------------------------------------- 939def _create_hardware_input( # pyright: ignore[reportUnusedFunction] 940 uMsg: int = 0, # c_ulong 941 wParamL: int = 0, # c_short 942 wParamH: int = 0, # c_ushort 943) -> _INPUT: 944 """Create INPUT structure for hardware input""" 945 input_struct: _INPUT = _INPUT(_INPUT_HARDWARE) 946 input_struct.hi = _HARDWAREINPUT(uMsg, wParamL, wParamH) 947 return input_struct 948 # -------------------------------------------------------------------------- 949 950 951# ============================================================================== 952# ==== User32 functions ======================================================== 953# ============================================================================== 954 955# ----- user32.dll ------------------------------------------------------------- 956_user32: WinDLL = windll.user32 957# ------------------------------------------------------------------------------ 958 959 960# ----- SendInput Declaration -------------------------------------------------- 961class _SendInputType(Protocol): 962 argtypes: tuple[type[UINT], type[_POINTER_TYPE[_INPUT]], type[INT]] 963 restype: type[UINT] 964 965 def __call__( 966 self, 967 cInputs: UINT | int, 968 pInputs: _POINTER_TYPE[_INPUT] | _INPUT | Array[_INPUT], 969 cbSize: INT | int, 970 ) -> int: # UINT 971 ... 972 973 974_SendInput: _SendInputType = hint_cast(_SendInputType, _user32.SendInput) 975""" 976----- SendInput function (winuser.h) ----- 977 978Synthesizes keystrokes, mouse motions, and button clicks. 979 980https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput 981 982----- Parameters ----- 983 984[in] cInputs 985 986Type: UINT 987 988The number of structures in the pInputs array. 989 990[in] pInputs 991 992Type: LPINPUT 993 994An array of INPUT structures. Each structure represents an event to be 995inserted into the keyboard or mouse input stream. 996 997[in] cbSize 998 999Type: int 1000 1001The size, in bytes, of an INPUT structure. If cbSize is not the size of an 1002INPUT structure, the function fails. 1003 1004----- Return value ----- 1005 1006Type: UINT 1007 1008The function returns the number of events that it successfully inserted into 1009the keyboard or mouse input stream. If the function returns zero, the input 1010was already blocked by another thread. To get extended error information, call 1011GetLastError. 1012 1013This function fails when it is blocked by UIPI. Note that neither GetLastError 1014nor the return value will indicate the failure was caused by UIPI blocking. 1015 1016----- Remarks ----- 1017 1018This function is subject to UIPI. Applications are permitted to inject input 1019only into applications that are at an equal or lesser integrity level. 1020 1021The SendInput function inserts the events in the INPUT structures serially 1022into the keyboard or mouse input stream. These events are not interspersed 1023with other keyboard or mouse input events inserted either by the user (with 1024the keyboard or mouse) or by calls to keybd_event, mouse_event, or other 1025calls to SendInput. 1026 1027This function does not reset the keyboard's current state. Any keys that are 1028already pressed when the function is called might interfere with the events 1029that this function generates. To avoid this problem, check the keyboard's 1030state with the GetAsyncKeyState function and correct as necessary. 1031 1032Because the touch keyboard uses the surrogate macros defined in winnls.h to 1033send input to the system, a listener on the keyboard event hook must decode 1034input originating from the touch keyboard. For more information, see Surrogates 1035and Supplementary Characters. 1036 1037An accessibility application can use SendInput to inject keystrokes 1038corresponding to application launch shortcut keys that are handled by the 1039shell. 1040This functionality is not guaranteed to work for other types of applications. 1041""" 1042_SendInput.argtypes = UINT, POINTER(_INPUT), INT 1043_SendInput.restype = UINT 1044 1045 1046def _send_input( 1047 inputs: _INPUT | Sequence[_INPUT], 1048) -> int: 1049 """ 1050 Abstraction layer over SendInput (winuser.h) 1051 1052 See https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput 1053 """ 1054 # prepare arguments 1055 cInputs: UINT 1056 inputs_array: Array[_INPUT] 1057 if isinstance(inputs, _INPUT): 1058 # -> single element array 1059 cInputs = UINT(1) 1060 inputs_array = (_INPUT * 1)(inputs) 1061 else: 1062 cInputs = UINT(len(inputs)) 1063 inputs_array = (_INPUT * len(inputs))(*inputs) 1064 cbSize: INT = INT(sizeof(_INPUT)) 1065 # execute function 1066 # inputs_array will be automatically be referenced by pointer 1067 return _SendInput(cInputs, inputs_array, cbSize) 1068 # -------------------------------------------------------------------------- 1069 1070 1071# ----- MapVirtualKeyW Declaration --------------------------------------------- 1072class _MapVirtualKeyWType(Protocol): 1073 argtypes: tuple[type[UINT], type[UINT]] 1074 restype: type[UINT] 1075 1076 def __call__( 1077 self, 1078 uCode: UINT | int, 1079 uMapType: UINT | int, 1080 ) -> int: # UINT 1081 ... 1082 1083 1084_MapVirtualKeyW: _MapVirtualKeyWType = hint_cast( 1085 _MapVirtualKeyWType, _user32.MapVirtualKeyW 1086) 1087""" 1088----- MapVirtualKeyW function (winuser.h) ----- 1089 1090Translates (maps) a virtual-key code into a scan code or character value, or 1091translates a scan code into a virtual-key code. 1092 1093To specify a handle to the keyboard layout to use for translating the specified 1094code, use the MapVirtualKeyEx function. 1095 1096https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mapvirtualkeyw 1097 1098----- Parameters ----- 1099 1100[in] uCode 1101 1102Type: UINT 1103 1104The virtual key code[1] or scan code for a key. How this value is interpreted 1105depends on the value of the uMapType parameter. 1106 1107Starting with Windows Vista, the high byte of the uCode value can contain 1108either 0xe0 or 0xe1 to specify the extended scan code. 1109 1110[in] uMapType 1111 1112Type: UINT 1113 1114The translation to be performed. The value of this parameter depends on the 1115value of the uCode parameter. (See _MAPVK_VK_TO_* constants) 1116 1117----- Return value ----- 1118 1119Type: UINT 1120 1121The return value is either a scan code, a virtual-key code, or a character 1122value, depending on the value of uCode and uMapType. If there is no 1123translation, the return value is zero. 1124 1125----- Remarks ----- 1126 1127An application can use MapVirtualKey to translate scan codes to the 1128virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU, and vice versa. 1129These translations do not distinguish between the left and right instances 1130of the SHIFT, CTRL, or ALT keys. 1131 1132An application can get the scan code corresponding to the left or right 1133instance of one of these keys by calling MapVirtualKey with uCode set to 1134one of the following virtual-key code constants: 1135 1136 VK_LSHIFT 1137 VK_RSHIFT 1138 VK_LCONTROL 1139 VK_RCONTROL 1140 VK_LMENU 1141 VK_RMENU 1142 1143These left- and right-distinguishing constants are available to an application 1144only through the GetKeyboardState[2], SetKeyboardState[3], GetAsyncKeyState[4], 1145GetKeyState, MapVirtualKey, and MapVirtualKeyEx functions. For list complete 1146table of virtual key codes, see Virtual Key Codes[1]. 1147 1148[1] https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes 1149 1150[2] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeyboardstate 1151 1152[3] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setkeyboardstate 1153 1154[4] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate 1155 1156[5] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeystate 1157""" 1158_MapVirtualKeyW.argtypes = UINT, UINT 1159_MapVirtualKeyW.restype = UINT 1160 1161 1162def _map_virtual_key( 1163 uCode: int, 1164 uMapType: Literal[0, 1, 2, 3, 4], # See _MAPVK_* constants 1165) -> int: 1166 """ 1167 Abstraction layer over MapVirtualKeyW (winuser.h) 1168 1169 Accepted values for uMapType are: 1170 - _MAPVK_VK_TO_VSC = 0 1171 - _MAPVK_VSC_TO_VK = 1 1172 - _MAPVK_VK_TO_CHAR = 2 1173 - _MAPVK_VSC_TO_VK_EX = 3 1174 - _MAPVK_VK_TO_VSC_EX = 4 1175 1176 See https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mapvirtualkeyw 1177 """ 1178 return _MapVirtualKeyW(UINT(uCode), UINT(uMapType)) 1179 # -------------------------------------------------------------------------- 1180 1181 1182# ----- GetSystemMetrics Declaration ------------------------------------------- 1183class _GetSystemMetricsType(Protocol): 1184 argtypes: tuple[type[INT]] 1185 restype: type[INT] 1186 1187 def __call__( 1188 self, 1189 nIndex: INT | int, 1190 ) -> int: # c_int 1191 ... 1192 1193 1194_GetSystemMetrics: _GetSystemMetricsType = hint_cast( 1195 _GetSystemMetricsType, _user32.GetSystemMetrics 1196) 1197""" 1198----- GetSystemMetrics function (winuser.h) ----- 1199 1200Retrieves the specified system metric or system configuration setting. 1201 1202Note that all dimensions retrieved by GetSystemMetrics are in pixels. 1203 1204https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemmetrics 1205 1206----- Parameters ----- 1207 1208[in] nIndex 1209 1210Type: int 1211 1212The system metric or configuration setting to be retrieved. This parameter can 1213be one of the following values. Note that all SM_CX* values are widths and all 1214SM_CY* values are heights. Also note that all settings designed to return 1215Boolean data represent TRUE as any nonzero value, and FALSE as a zero value. 1216(See _SM_* constants) 1217 1218----- Return value ----- 1219 1220Type: int 1221 1222If the function succeeds, the return value is the requested system metric or 1223configuration setting. 1224 1225If the function fails, the return value is 0. GetLastError does not provide 1226extended error information. 1227 1228----- Remarks ----- 1229 1230System metrics can vary from display to display. 1231 1232GetSystemMetrics(SM_CMONITORS) counts only visible display monitors. This is 1233different from EnumDisplayMonitors[1], which enumerates both visible display 1234monitors and invisible pseudo-monitors that are associated with mirroring 1235drivers. An invisible pseudo-monitor is associated with a pseudo-device used 1236to mirror application drawing for remoting or other purposes. 1237 1238This API is not DPI aware, and should not be used if the calling thread is 1239per-monitor DPI aware. For the DPI-aware version of this API, see 1240GetSystemMetricsForDPI[2]. For more information on DPI awareness, see the 1241Windows High DPI documentation[3]. 1242 1243[1] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumdisplaymonitors 1244 1245[2] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemmetricsfordpi 1246 1247[3] https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows 1248""" # noqa (URL too long) 1249_GetSystemMetrics.argtypes = (INT,) 1250_GetSystemMetrics.restype = INT 1251 1252 1253def _get_system_metrics(nIndex: int) -> int: 1254 """ 1255 Abstraction layer over GetSystemMetrics (winuser.h) 1256 1257 See the _SM_* constants for accepted values for the nIndex argument. 1258 1259 See https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemmetrics 1260 """ 1261 return _GetSystemMetrics(nIndex) 1262 # -------------------------------------------------------------------------- 1263 1264 1265# ----- MonitorFromPoint Declaration ----------------------------------------------- 1266class _MonitorFromPointType(Protocol): 1267 argtypes: tuple[type[_POINT], type[DWORD]] 1268 restype: type[HMONITOR] 1269 1270 def __call__( 1271 self, 1272 pt: _POINT, 1273 dwFlags: DWORD | int, 1274 ) -> int | None: # HMONITOR 1275 ... 1276 1277 1278_MonitorFromPoint: _MonitorFromPointType = hint_cast( 1279 _MonitorFromPointType, _user32.MonitorFromPoint 1280) 1281""" 1282----- MonitorFromPoint function (winuser.h) ----- 1283 1284Retrieves the position of the mouse cursor, in screen coordinates. 1285 1286https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-monitorfrompoint 1287 1288----- Parameters ----- 1289 1290[in] pt 1291 1292Type: POINT 1293 1294A POINT structure that specifies the point of interest in 1295virtual-screen coordinates. 1296 1297[in] dwFlags 1298 1299Type: DWORD 1300 1301Determines the function's return value if the point is not contained within 1302any display monitor. 1303 1304This parameter can be one of the following values. 1305 1306MONITOR_DEFAULTTONULL 0x00000000 Returns NULL. 1307MONITOR_DEFAULTTOPRIMARY 0x00000001 Returns a handle to the primary 1308 display monitor. 1309MONITOR_DEFAULTTONEAREST 0x00000002 Returns a handle to the display monitor 1310 that is nearest to the point. 1311 1312----- Return value ----- 1313 1314If the point is contained by a display monitor, the return value is an 1315HMONITOR handle to that display monitor. 1316 1317If the point is not contained by a display monitor, the return value depends 1318on the value of dwFlags. 1319""" 1320_MonitorFromPoint.argtypes = (_POINT, DWORD) 1321_MonitorFromPoint.restype = HMONITOR 1322 1323 1324def _monitor_from_point(x: int, y: int) -> int | None: 1325 """ 1326 Abstraction layer over MonitorFromPoint (winuser.h) 1327 1328 See https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-monitorfrompoint 1329 """ 1330 pt = _POINT() 1331 pt.x, pt.y = x, y 1332 return _MonitorFromPoint(pt, _MONITOR_DEFAULTTONULL) 1333 # -------------------------------------------------------------------------- 1334 1335 1336# ----- GetCursorPos Declaration ----------------------------------------------- 1337class _GetCursorPosType(Protocol): 1338 argtypes: tuple[type[_POINTER_TYPE[_POINT]]] 1339 restype: type[BOOL] 1340 1341 def __call__( 1342 self, 1343 lpPoint: _POINTER_TYPE[_POINT] | _POINT, 1344 ) -> bool: # BOOL 1345 ... 1346 1347 1348_GetCursorPos: _GetCursorPosType = hint_cast( 1349 _GetCursorPosType, _user32.GetCursorPos 1350) 1351""" 1352----- GetCursorPos function (winuser.h) ----- 1353 1354Retrieves the position of the mouse cursor, in screen coordinates. 1355 1356https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcursorpos 1357 1358----- Parameters ----- 1359 1360[out] lpPoint 1361 1362Type: LPPOINT 1363 1364A pointer to a POINT structure that receives the screen coordinates of the 1365cursor. 1366 1367----- Return value ----- 1368 1369Type: BOOL 1370 1371Returns nonzero if successful or zero otherwise. To get extended error 1372information, call GetLastError. 1373 1374----- Remarks ----- 1375 1376The cursor position is always specified in screen coordinates and is not 1377affected by the mapping mode of the window that contains the cursor. 1378 1379The calling process must have WINSTA_READATTRIBUTES access to the window 1380station. 1381 1382The input desktop must be the current desktop when you call GetCursorPos. Call 1383OpenInputDesktop[1] to determine whether the current desktop is the input 1384desktop. If it is not, call SetThreadDesktop[2] with the HDESK returned by 1385OpenInputDesktop to switch to that desktop. 1386 1387[1] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-openinputdesktop 1388 1389[2] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setthreaddesktop 1390""" 1391_GetCursorPos.argtypes = (POINTER(_POINT),) 1392_GetCursorPos.restype = BOOL 1393 1394 1395def _get_cursor_pos() -> _POINT: 1396 """ 1397 Abstraction layer over GetCursorPos (winuser.h) 1398 1399 See https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcursorpos 1400 """ 1401 cursor = _POINT() 1402 # cursor will be automatically be referenced by pointer 1403 _GetCursorPos(cursor) 1404 return cursor 1405 # -------------------------------------------------------------------------- 1406 1407 1408# ----- SystemParametersInfoW Declaration -------------------------------------- 1409class _SystemParametersInfoW_Type(Protocol): 1410 argtypes: tuple[type[UINT], type[UINT], type[LPCVOID], type[UINT]] 1411 restype: type[BOOL] 1412 1413 def __call__( 1414 self, 1415 uiAction: UINT | int, 1416 uiParam: UINT | int, 1417 pvParam: LPCVOID | Any, 1418 fWinIni: UINT | int, 1419 ) -> bool: # BOOL 1420 ... 1421 1422 1423_SystemParametersInfoW: _SystemParametersInfoW_Type = hint_cast( 1424 _SystemParametersInfoW_Type, _user32.SystemParametersInfoW 1425) 1426""" 1427----- SystemParametersInfoW function (winuser.h) ----- 1428 1429Retrieves or sets the value of one of the system-wide parameters. This 1430function can also update the user profile while setting a parameter. 1431 1432https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfow 1433 1434""" 1435_SystemParametersInfoW.argtypes = UINT, UINT, LPCVOID, UINT 1436_SystemParametersInfoW.restype = BOOL 1437 1438 1439# ----- Get system settings for mouse movement --------------------------------- 1440def _get_mouse_parameters() -> tuple[int, int, int]: 1441 """ 1442 Query system parameters for user's mouse settings. 1443 1444 Abstraction layer over SystemParametersInfoW (winuser.h) 1445 1446 https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfow 1447 1448 Information on _SPI_GETMOUSE 1449 1450 Retrieves the two mouse threshold values and the mouse acceleration. The 1451 pvParam parameter must point to an array of three integers that receives 1452 these values. See mouse_event[1] for further information. 1453 1454 https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mouse_event 1455 """ 1456 pvParam: Array[UINT] = (UINT * 3)() 1457 _SystemParametersInfoW(_SPI_GETMOUSE, 0, pointer(pvParam), 0) 1458 return (pvParam[0], pvParam[1], pvParam[2]) 1459 # -------------------------------------------------------------------------- 1460 1461 1462# ----- Set system settings for mouse movement --------------------------------- 1463def _set_mouse_parameters( 1464 threshold1: int, threshold2: int, enhanced_pointer_precision: int 1465) -> bool: 1466 """ 1467 Set system parameters for user's mouse settings. 1468 1469 Abstraction layer over SystemParametersInfoW (winuser.h) 1470 1471 https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfow 1472 1473 Information on _SPI_SETMOUSE 1474 1475 Sets the two mouse threshold values and the mouse acceleration. 1476 The pvParam parameter must point to an array of three integers that 1477 specifies these values. 1478 See mouse_event[1] for further information. 1479 1480 https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mouse_event 1481 """ 1482 pvParam: Final[Array[UINT]] = (UINT * 3)( 1483 threshold1, threshold2, enhanced_pointer_precision 1484 ) 1485 # leave last parameter as 0 to make changes non-permanent and restore 1486 # themselves upon reboot if something goes wrong and the wrong setting 1487 # was overwritten. 1488 return _SystemParametersInfoW(_SPI_SETMOUSE, 0, pointer(pvParam), 0) 1489 # -------------------------------------------------------------------------- 1490 1491 1492# ----- Get system settings for mouse speed ------------------------------------ 1493def _get_mouse_speed() -> int: 1494 """ 1495 Query system parameters for user's mouse settings. 1496 1497 Abstraction layer over SystemParametersInfoW (winuser.h) 1498 1499 https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfow 1500 1501 Information on SPI_GETMOUSESPEED 1502 1503 Retrieves the current mouse speed. The mouse speed determines how far the 1504 pointer will move based on the distance the mouse moves. The pvParam 1505 parameter must point to an integer that receives a value which ranges 1506 between 1 (slowest) and 20 (fastest). A value of 10 is the default. The 1507 value can be set by an end-user using the mouse control panel application 1508 or by an application using SPI_SETMOUSESPEED. 1509 """ 1510 pvParam: Array[UINT] = (UINT * 1)() 1511 _SystemParametersInfoW(_SPI_GETMOUSESPEED, 0, pointer(pvParam), 0) 1512 return pvParam[0] 1513 # -------------------------------------------------------------------------- 1514 1515 1516# ----- Set system settings for mouse movement --------------------------------- 1517def _set_mouse_speed(mouse_speed: int) -> bool: 1518 """ 1519 Set system parameters for user's mouse settings. 1520 1521 Abstraction layer over SystemParametersInfoW (winuser.h) 1522 1523 https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfow 1524 1525 Information on SPI_SETMOUSESPEED 1526 1527 Sets the current mouse speed. The pvParam parameter is an integer between 1528 1 (slowest) and 20 (fastest). A value of 10 is the default. This value is 1529 typically set using the mouse control panel application. 1530 """ 1531 pvParam: Final[Array[UINT]] = (UINT * 1)(mouse_speed) 1532 # leave last parameter as 0 to make changes non-permanent and restore 1533 # themselves upon reboot if something goes wrong and the wrong setting 1534 # was overwritten. 1535 return _SystemParametersInfoW(_SPI_SETMOUSESPEED, 0, pointer(pvParam), 0) 1536 # -------------------------------------------------------------------------- 1537 1538 1539# ============================================================================== 1540# ===== Keyboard Scan Code Mappings ============================================ 1541# ============================================================================== 1542 1543 1544# ----- Special class for key extended scancode sequences ---------------------- 1545class ScancodeSequence(List[int]): 1546 """ 1547 A special class with the sole purpose of representing extended scancode 1548 sequences that should be grouped together in a single INPUT array. 1549 1550 Inserting non-scancode elements is illegal, but no runtime checks exist 1551 to verify correct input! Violations could lead to unpredictable runtime 1552 behaviour. You've been warned. 1553 """ 1554 1555 pass 1556 # -------------------------------------------------------------------------- 1557 1558 1559# ----- TypeAlias for KEYBOARD_MAPPING values ---------------------------------- 1560ScancodeTypes: TypeAlias = "int | ScancodeSequence" # TODO 3.10: remove quotes 1561""" 1562Acceptable value types in KEYBOARD_MAPPING. 1563 1564Accepts single standalone scancode integer or multiple scancode integers 1565contained in a special class ScancodeSequence instance. 1566""" 1567# ------------------------------------------------------------------------------ 1568 1569 1570# ----- Offsets for values in KEYBOARD_MAPPING --------------------------------- 1571_OFFSET_EXTENDEDKEY: Final = 0xE000 1572_OFFSET_SHIFTKEY: Final = 0x10000 1573# ------------------------------------------------------------------------------ 1574 1575 1576# ----- KEYBOARD_MAPPING ------------------------------------------------------- 1577_SHIFT_SCANCODE: Final = 0x2A # Used in auto-shifting 1578# should be keyboard MAKE scancodes ( <0x80 ) 1579# some keys require the use of EXTENDEDKEY flags, they 1580US_QWERTY_MAPPING: Final[dict[str, ScancodeTypes]] = { 1581 "escape": 0x01, 1582 "esc": 0x01, 1583 "f1": 0x3B, 1584 "f2": 0x3C, 1585 "f3": 0x3D, 1586 "f4": 0x3E, 1587 "f5": 0x3F, 1588 "f6": 0x40, 1589 "f7": 0x41, 1590 "f8": 0x42, 1591 "f9": 0x43, 1592 "f10": 0x44, 1593 "f11": 0x57, 1594 "f12": 0x58, 1595 "printscreen": 0x54, # same result as ScancodeSequence([0xE02A, 0xE037]) 1596 "prntscrn": 0x54, # same result as ScancodeSequence([0xE02A, 0xE037]) 1597 "prtsc": 0x54, # same result as ScancodeSequence([0xE02A, 0xE037]) 1598 "prtscr": 0x54, # same result as ScancodeSequence([0xE02A, 0xE037]) 1599 "scrolllock": 0x46, 1600 "ctrlbreak": 0x46 + _OFFSET_EXTENDEDKEY, 1601 "pause": ScancodeSequence([0xE11D, 0x45, 0xE19D, 0xC5]), 1602 "`": 0x29, 1603 "1": 0x02, 1604 "2": 0x03, 1605 "3": 0x04, 1606 "4": 0x05, 1607 "5": 0x06, 1608 "6": 0x07, 1609 "7": 0x08, 1610 "8": 0x09, 1611 "9": 0x0A, 1612 "0": 0x0B, 1613 "-": 0x0C, 1614 "=": 0x0D, 1615 "~": 0x29 + _OFFSET_SHIFTKEY, 1616 "!": 0x02 + _OFFSET_SHIFTKEY, 1617 "@": 0x03 + _OFFSET_SHIFTKEY, 1618 "#": 0x04 + _OFFSET_SHIFTKEY, 1619 "$": 0x05 + _OFFSET_SHIFTKEY, 1620 "%": 0x06 + _OFFSET_SHIFTKEY, 1621 "^": 0x07 + _OFFSET_SHIFTKEY, 1622 "&": 0x08 + _OFFSET_SHIFTKEY, 1623 "*": 0x09 + _OFFSET_SHIFTKEY, 1624 "(": 0x0A + _OFFSET_SHIFTKEY, 1625 ")": 0x0B + _OFFSET_SHIFTKEY, 1626 "_": 0x0C + _OFFSET_SHIFTKEY, 1627 "+": 0x0D + _OFFSET_SHIFTKEY, 1628 "backspace": 0x0E, 1629 "\b": 0x0E, 1630 "insert": 0x52 + _OFFSET_EXTENDEDKEY, 1631 "home": 0x47 + _OFFSET_EXTENDEDKEY, 1632 "pageup": 0x49 + _OFFSET_EXTENDEDKEY, 1633 "pgup": 0x49 + _OFFSET_EXTENDEDKEY, 1634 "pagedown": 0x51 + _OFFSET_EXTENDEDKEY, 1635 "pgdn": 0x51 + _OFFSET_EXTENDEDKEY, 1636 # numpad 1637 "numlock": 0x45, 1638 "divide": 0x35 + _OFFSET_EXTENDEDKEY, 1639 "multiply": 0x37, 1640 "subtract": 0x4A, 1641 "add": 0x4E, 1642 "decimal": 0x53, 1643 "numperiod": 0x53, 1644 "numpadenter": 0x1C + _OFFSET_EXTENDEDKEY, 1645 "numpad1": 0x4F, 1646 "numpad2": 0x50, 1647 "numpad3": 0x51, 1648 "numpad4": 0x4B, 1649 "numpad5": 0x4C, 1650 "numpad6": 0x4D, 1651 "numpad7": 0x47, 1652 "numpad8": 0x48, 1653 "numpad9": 0x49, 1654 "num0": 0x52, 1655 "num1": 0x4F, 1656 "num2": 0x50, 1657 "num3": 0x51, 1658 "num4": 0x4B, 1659 "num5": 0x4C, 1660 "num6": 0x4D, 1661 "num7": 0x47, 1662 "num8": 0x48, 1663 "num9": 0x49, 1664 "clear": 0x4C, # name from pyautogui 1665 # end numpad 1666 "tab": 0x0F, 1667 "\t": 0x0F, 1668 "q": 0x10, 1669 "w": 0x11, 1670 "e": 0x12, 1671 "r": 0x13, 1672 "t": 0x14, 1673 "y": 0x15, 1674 "u": 0x16, 1675 "i": 0x17, 1676 "o": 0x18, 1677 "p": 0x19, 1678 "[": 0x1A, 1679 "]": 0x1B, 1680 "\\": 0x2B, 1681 "Q": 0x10 + _OFFSET_SHIFTKEY, 1682 "W": 0x11 + _OFFSET_SHIFTKEY, 1683 "E": 0x12 + _OFFSET_SHIFTKEY, 1684 "R": 0x13 + _OFFSET_SHIFTKEY, 1685 "T": 0x14 + _OFFSET_SHIFTKEY, 1686 "Y": 0x15 + _OFFSET_SHIFTKEY, 1687 "U": 0x16 + _OFFSET_SHIFTKEY, 1688 "I": 0x17 + _OFFSET_SHIFTKEY, 1689 "O": 0x18 + _OFFSET_SHIFTKEY, 1690 "P": 0x19 + _OFFSET_SHIFTKEY, 1691 "{": 0x1A + _OFFSET_SHIFTKEY, 1692 "}": 0x1B + _OFFSET_SHIFTKEY, 1693 "|": 0x2B + _OFFSET_SHIFTKEY, 1694 "del": 0x53 + _OFFSET_EXTENDEDKEY, 1695 "delete": 0x53 + _OFFSET_EXTENDEDKEY, 1696 "end": 0x4F + _OFFSET_EXTENDEDKEY, 1697 "capslock": 0x3A, 1698 "a": 0x1E, 1699 "s": 0x1F, 1700 "d": 0x20, 1701 "f": 0x21, 1702 "g": 0x22, 1703 "h": 0x23, 1704 "j": 0x24, 1705 "k": 0x25, 1706 "l": 0x26, 1707 ";": 0x27, 1708 "'": 0x28, 1709 "A": 0x1E + _OFFSET_SHIFTKEY, 1710 "S": 0x1F + _OFFSET_SHIFTKEY, 1711 "D": 0x20 + _OFFSET_SHIFTKEY, 1712 "F": 0x21 + _OFFSET_SHIFTKEY, 1713 "G": 0x22 + _OFFSET_SHIFTKEY, 1714 "H": 0x23 + _OFFSET_SHIFTKEY, 1715 "J": 0x24 + _OFFSET_SHIFTKEY, 1716 "K": 0x25 + _OFFSET_SHIFTKEY, 1717 "L": 0x26 + _OFFSET_SHIFTKEY, 1718 ":": 0x27 + _OFFSET_SHIFTKEY, 1719 '"': 0x28 + _OFFSET_SHIFTKEY, 1720 "enter": 0x1C, 1721 "return": 0x1C, 1722 "\n": 0x1C, 1723 "shift": _SHIFT_SCANCODE, 1724 "shiftleft": _SHIFT_SCANCODE, 1725 "z": 0x2C, 1726 "x": 0x2D, 1727 "c": 0x2E, 1728 "v": 0x2F, 1729 "b": 0x30, 1730 "n": 0x31, 1731 "m": 0x32, 1732 ",": 0x33, 1733 ".": 0x34, 1734 "/": 0x35, 1735 "Z": 0x2C + _OFFSET_SHIFTKEY, 1736 "X": 0x2D + _OFFSET_SHIFTKEY, 1737 "C": 0x2E + _OFFSET_SHIFTKEY, 1738 "V": 0x2F + _OFFSET_SHIFTKEY, 1739 "B": 0x30 + _OFFSET_SHIFTKEY, 1740 "N": 0x31 + _OFFSET_SHIFTKEY, 1741 "M": 0x32 + _OFFSET_SHIFTKEY, 1742 "<": 0x33 + _OFFSET_SHIFTKEY, 1743 ">": 0x34 + _OFFSET_SHIFTKEY, 1744 "?": 0x35 + _OFFSET_SHIFTKEY, 1745 "shiftright": 0x36, 1746 "ctrl": 0x1D, 1747 "ctrlleft": 0x1D, 1748 "win": 0x5B + _OFFSET_EXTENDEDKEY, 1749 "super": 0x5B + _OFFSET_EXTENDEDKEY, # name from pyautogui 1750 "winleft": 0x5B + _OFFSET_EXTENDEDKEY, 1751 "alt": 0x38, 1752 "altleft": 0x38, 1753 " ": 0x39, 1754 "space": 0x39, 1755 "altright": 0x38 + _OFFSET_EXTENDEDKEY, 1756 "winright": 0x5C + _OFFSET_EXTENDEDKEY, 1757 "apps": 0x5D + _OFFSET_EXTENDEDKEY, 1758 "context": 0x5D + _OFFSET_EXTENDEDKEY, 1759 "contextmenu": 0x5D + _OFFSET_EXTENDEDKEY, 1760 "ctrlright": 0x1D + _OFFSET_EXTENDEDKEY, 1761 # Originally from learncodebygaming/pydirectinput: 1762 # arrow key scancodes can be different depending on the hardware, 1763 # so I think the best solution is to look it up based on the virtual key 1764 # https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mapvirtualkeya 1765 "up": _map_virtual_key(0x26, _MAPVK_VK_TO_VSC) + _OFFSET_EXTENDEDKEY, 1766 "left": _map_virtual_key(0x25, _MAPVK_VK_TO_VSC) + _OFFSET_EXTENDEDKEY, 1767 "down": _map_virtual_key(0x28, _MAPVK_VK_TO_VSC) + _OFFSET_EXTENDEDKEY, 1768 "right": _map_virtual_key(0x27, _MAPVK_VK_TO_VSC) + _OFFSET_EXTENDEDKEY, 1769 # While forking the original repository and working on the code, 1770 # I'm starting to doubt this still holds true. 1771 # As far as I can see, arrow keys are just the Numpad scancodes for Num 1772 # 2, 4, 6, and 8 with EXTENDEDKEY flag. 1773 # In fact, looking up the virtual key codes will just return the very same 1774 # scancodes the Numpad keys occupy. 1775 "help": 0x63, 1776 "sleep": 0x5F + _OFFSET_EXTENDEDKEY, 1777 "medianext": 0x19 + _OFFSET_EXTENDEDKEY, 1778 "nexttrack": 0x19 + _OFFSET_EXTENDEDKEY, 1779 "mediaprevious": 0x10 + _OFFSET_EXTENDEDKEY, 1780 "prevtrack": 0x10 + _OFFSET_EXTENDEDKEY, 1781 "mediastop": 0x24 + _OFFSET_EXTENDEDKEY, 1782 "stop": 0x24 + _OFFSET_EXTENDEDKEY, 1783 "mediaplay": 0x22 + _OFFSET_EXTENDEDKEY, 1784 "mediapause": 0x22 + _OFFSET_EXTENDEDKEY, 1785 "playpause": 0x22 + _OFFSET_EXTENDEDKEY, 1786 "mute": 0x20 + _OFFSET_EXTENDEDKEY, 1787 "volumemute": 0x20 + _OFFSET_EXTENDEDKEY, 1788 "volumeup": 0x30 + _OFFSET_EXTENDEDKEY, 1789 "volup": 0x30 + _OFFSET_EXTENDEDKEY, 1790 "volumedown": 0x2E + _OFFSET_EXTENDEDKEY, 1791 "voldown": 0x2E + _OFFSET_EXTENDEDKEY, 1792 "media": 0x6D + _OFFSET_EXTENDEDKEY, 1793 "launchmediaselect": 0x6D + _OFFSET_EXTENDEDKEY, 1794 "email": 0x6C + _OFFSET_EXTENDEDKEY, 1795 "launchmail": 0x6C + _OFFSET_EXTENDEDKEY, 1796 "calculator": 0x21 + _OFFSET_EXTENDEDKEY, 1797 "calc": 0x21 + _OFFSET_EXTENDEDKEY, 1798 "launch1": 0x6B + _OFFSET_EXTENDEDKEY, 1799 "launchapp1": 0x6B + _OFFSET_EXTENDEDKEY, 1800 "launch2": 0x21 + _OFFSET_EXTENDEDKEY, 1801 "launchapp2": 0x21 + _OFFSET_EXTENDEDKEY, 1802 "browsersearch": 0x65 + _OFFSET_EXTENDEDKEY, 1803 "browserhome": 0x32 + _OFFSET_EXTENDEDKEY, 1804 "browserforward": 0x69 + _OFFSET_EXTENDEDKEY, 1805 "browserback": 0x6A + _OFFSET_EXTENDEDKEY, 1806 "browserstop": 0x68 + _OFFSET_EXTENDEDKEY, 1807 "browserrefresh": 0x67 + _OFFSET_EXTENDEDKEY, 1808 "browserfavorites": 0x66 + _OFFSET_EXTENDEDKEY, 1809 "f13": 0x64, 1810 "f14": 0x65, 1811 "f15": 0x66, 1812 "f16": 0x67, 1813 "f17": 0x68, 1814 "f18": 0x69, 1815 "f19": 0x6A, 1816 "f20": 0x6B, 1817 "f21": 0x6C, 1818 "f22": 0x6D, 1819 "f23": 0x6E, 1820 "f24": 0x76, 1821} 1822""" 1823Maps a string representation of keyboard keys to their corresponding hardware 1824scan code. Based on standard US QWERTY-Layout. 1825 1826Not intended to be changed at runtime! 1827 1828If you want to change the keyboard mapping to better reflect your own keyboard 1829layout, use `KEYBOARD_MAPPING.update(your_dict)` where `your_dict` is a dict 1830that maps keynames to scancodes. 1831""" 1832 1833KEYBOARD_MAPPING: dict[str, ScancodeTypes] = {} 1834""" 1835Maps a string representation of keyboard keys to their corresponding hardware 1836scan code. Based on standard US QWERTY-Layout by default. 1837 1838If you want to change the keyboard mapping to better reflect your own keyboard 1839layout, use `KEYBOARD_MAPPING.update(your_dict)`, where `your_dict` is a dict 1840that maps keynames to scancodes. 1841""" 1842KEYBOARD_MAPPING.update(US_QWERTY_MAPPING) # use US QWERTY by default 1843# ------------------------------------------------------------------------------ 1844 1845 1846# ============================================================================== 1847# ===== Fail Safe and Pause implementation ===================================== 1848# ============================================================================== 1849 1850 1851# ----- Exceptions ------------------------------------------------------------- 1852class FailSafeException(Exception): 1853 """Raised when _failSafeCheck detects failsafe mouse position.""" 1854 1855 pass 1856 1857 1858class PriorInputFailedException(Exception): 1859 """Raised in hold() context managers when raise_on_failure is set.""" 1860 1861 pass 1862 # -------------------------------------------------------------------------- 1863 1864 1865# ----- Failsafe Check --------------------------------------------------------- 1866def _failSafeCheck() -> None: 1867 """ 1868 Check if mouse has been moved into one of the defined failsafe points, 1869 indicated by global var `FAILSAFE_POINTS`, and raise `FailSafeException` 1870 if that's the case. 1871 1872 Set global var `FAILSAFE` to False to stop raising exceptions. 1873 """ 1874 if FAILSAFE and tuple(position()) in FAILSAFE_POINTS: 1875 raise FailSafeException( 1876 "PyDirectInput fail-safe triggered from mouse moving to a corner " 1877 "of the screen. " 1878 "To disable this fail-safe, set pydirectinput.FAILSAFE to False. " 1879 "DISABLING FAIL-SAFE IS NOT RECOMMENDED." 1880 ) 1881 # -------------------------------------------------------------------------- 1882 1883 1884# ----- handle pause for generic input checks ---------------------------------- 1885def _handlePause(_pause: Any) -> None: 1886 """ 1887 Pause the default amount of time if `_pause=True` in function arguments. 1888 """ 1889 if _pause and PAUSE: 1890 _sleep(PAUSE) 1891 # -------------------------------------------------------------------------- 1892 1893 1894# ----- generic input check decorator ------------------------------------------ 1895_PS = ParamSpec("_PS") # param spec 1896_RT = TypeVar("_RT") # return type 1897 1898 1899# direct copy of _genericPyAutoGUIChecks() 1900def _genericPyDirectInputChecks( 1901 wrappedFunction: Callable[_PS, _RT], 1902) -> Callable[_PS, _RT]: 1903 """ 1904 Decorator for wrapping input functions. 1905 1906 Performs failsafe checking and inserts artifical delay after input 1907 functions have been executed unless disabled. 1908 1909 The delay amount is set by global var `PAUSE`. 1910 """ 1911 1912 @functools.wraps(wrappedFunction) 1913 def wrapper(*args: _PS.args, **kwargs: _PS.kwargs) -> _RT: 1914 returnVal: _RT 1915 if PAUSE: # Skip _pause checks if PAUSE has been globally disabled. 1916 _pause: Any 1917 if "_pause" in kwargs: # Fast track, low cost lookup. 1918 _pause = kwargs[ 1919 "_pause" 1920 ] # pyrefly: ignore[unsupported-operation] 1921 else: # Slow track, inspect.getcallargs() is expensive. 1922 funcArgs: dict[str, Any] = inspect.getcallargs( 1923 wrappedFunction, 1924 *args, 1925 **kwargs, # pyrefly: ignore[bad-argument-type] 1926 ) 1927 _pause = funcArgs.get("_pause") 1928 _failSafeCheck() 1929 returnVal = wrappedFunction(*args, **kwargs) 1930 _handlePause(_pause) 1931 else: 1932 _failSafeCheck() 1933 returnVal = wrappedFunction(*args, **kwargs) 1934 return returnVal 1935 1936 return wrapper 1937 # -------------------------------------------------------------------------- 1938 1939 1940# ============================================================================== 1941# ===== Helper Functions ======================================================= 1942# ============================================================================== 1943# -------------------------------------------------------------------------- 1944def _calc_normalized_screen_coord(pixel_coord: int, display_total: int) -> int: 1945 """ 1946 Convert a pixel coordinate to normalized Windows screen coordinate value 1947 (range 0 - 65535) by taking the average of two neighboring pixels. 1948 """ 1949 # formula from this strange (probably machine translated) article 1950 # https://sourceexample.com/make-a-statement-in-the-source-code-of-the-coordinate-conversion-of-sendinput-(windows-api)-that-is-overflowing-in-the-streets-23df9/ 1951 # win_coord = (x * 65536 + width - 1) // width 1952 # This alone is not enough, but we can do better by taking the average of 1953 # this pixel plus the next pixel. 1954 # In my testing this perfectly reflected the real pixel that SendInput 1955 # moves to, down to the pixels that Windows itself can't resolve. 1956 this_pixel: Final[int] = ( 1957 pixel_coord * 65536 + display_total - 1 1958 ) // display_total 1959 next_pixel: Final[int] = ( 1960 (pixel_coord + 1) * 65536 + display_total - 1 1961 ) // display_total 1962 return (this_pixel + next_pixel) // 2 1963 # -------------------------------------------------------------------------- 1964 1965 1966# ----- translate pixels to normalized Windows coordinates --------------------- 1967def _to_windows_coordinates( 1968 x: int = 0, y: int = 0, *, virtual: bool = False 1969) -> tuple[int, int]: 1970 """ 1971 Convert x,y coordinates to normalized windows coordinates and return as 1972 tuple (x, y). 1973 """ 1974 display_width: int 1975 display_height: int 1976 offset_left: int 1977 offset_top: int 1978 1979 if virtual: 1980 display_width, display_height, offset_left, offset_top = virtual_size() 1981 else: 1982 display_width, display_height = size() 1983 offset_left, offset_top = 0, 0 1984 1985 windows_x: int = _calc_normalized_screen_coord( 1986 x - offset_left, display_width 1987 ) 1988 windows_y: int = _calc_normalized_screen_coord( 1989 y - offset_top, display_height 1990 ) 1991 1992 return windows_x, windows_y 1993 # -------------------------------------------------------------------------- 1994 1995 1996# ----- line coordinates based on Bresenham's line algorithm ------------------- 1997def _bresenham(x0: int, y0: int, x1: int, y1: int) -> list[tuple[int, int]]: 1998 """ 1999 Return a list of coordinates on the line from (x0, y0) to (x1, y1). 2000 Start and end point are included in the result. 2001 2002 Based on Bresenham's line algorithm. 2003 Using Petr Viktorin's implementation (MIT license) 2004 https://github.com/encukou/bresenham 2005 """ 2006 2007 def gen() -> Generator[tuple[int, int], None, None]: 2008 """ 2009 Yield integer coordinates on the line from (x0, y0) to (x1, y1). 2010 2011 Input coordinates should be integers. 2012 2013 The result will contain both the start and the end point. 2014 """ 2015 dx: int = x1 - x0 2016 dy: int = y1 - y0 2017 2018 xsign: Literal[1, -1] = 1 if dx > 0 else -1 2019 ysign: Literal[1, -1] = 1 if dy > 0 else -1 2020 2021 dx = abs(dx) 2022 dy = abs(dy) 2023 2024 xx: Literal[1, 0, -1] 2025 xy: Literal[1, 0, -1] 2026 yx: Literal[1, 0, -1] 2027 yy: Literal[1, 0, -1] 2028 2029 if dx > dy: 2030 xx, xy, yx, yy = xsign, 0, 0, ysign 2031 else: 2032 dx, dy = dy, dx 2033 xx, xy, yx, yy = 0, ysign, xsign, 0 2034 2035 d: int = 2 * dy - dx 2036 y = 0 2037 for x in range(dx + 1): 2038 yield x0 + x * xx + y * yx, y0 + x * xy + y * yy 2039 if d >= 0: 2040 y += 1 2041 d -= 2 * dx 2042 d += 2 * dy 2043 2044 return list(gen()) 2045 # -------------------------------------------------------------------------- 2046 2047 2048# ----- path function type alias ----------------------------------------------- 2049PathFunction: TypeAlias = ( 2050 "Callable[[int, int, int, int], list[tuple[int, int]]]" 2051) 2052# ------------------------------------------------------------------------------ 2053 2054 2055# ----- linear tweening function ----------------------------------------------- 2056def _linear(n: float) -> float: 2057 """ 2058 Linear tweening function that clamps n between 0.0 and 1.0. 2059 Otherwise returns n unchanged. 2060 """ 2061 if n >= 1.0: 2062 return 1.0 2063 if n <= 0.0: 2064 return 0.0 2065 return n 2066 # -------------------------------------------------------------------------- 2067 2068 2069# ----- get mouse position ----------------------------------------------------- 2070def position( 2071 x: int | float | None = None, y: int | float | None = None 2072) -> tuple[int, int]: 2073 """ 2074 Return a postion tuple `(x, y)`. 2075 2076 If x and/or y argument(s) are not given, use current mouse cursor coordinate 2077 instead. 2078 """ 2079 cursor: _POINT = _get_cursor_pos() 2080 return ( 2081 cursor.x if x is None else int(x), 2082 cursor.y if y is None else int(y), 2083 ) 2084 # -------------------------------------------------------------------------- 2085 2086 2087# ----- get primary screen resolution ------------------------------------------ 2088def size() -> tuple[int, int]: 2089 """ 2090 Return the size of the primary display as tuple `(width, height)`. 2091 """ 2092 return ( 2093 _get_system_metrics(_SM_CXSCREEN), 2094 _get_system_metrics(_SM_CYSCREEN), 2095 ) 2096 # -------------------------------------------------------------------------- 2097 2098 2099# ----- get resolution of multi monitor bounding box --------------------------- 2100def virtual_size() -> tuple[int, int, int, int]: 2101 """ 2102 Return the the display size of the complete virtual monitor bounding box 2103 rectangle as tuple `(width, height, left_offset, top_offset)`. 2104 2105 On a single monitor system, this function is equal to `(*size(), 0, 0)`. 2106 2107 `left_offset` and `top_offset` are measured from the top left pixel of the 2108 primary monitor. 2109 """ 2110 return ( 2111 _get_system_metrics(_SM_CXVIRTUALSCREEN), 2112 _get_system_metrics(_SM_CYVIRTUALSCREEN), 2113 _get_system_metrics(_SM_XVIRTUALSCREEN), 2114 _get_system_metrics(_SM_YVIRTUALSCREEN), 2115 ) 2116 # -------------------------------------------------------------------------- 2117 2118 2119# ----- are coordinates on primary monitor ------------------------------------- 2120@overload 2121def on_primary_monitor( 2122 x: int | None = None, 2123 y: int | None = None, 2124) -> bool: ... 2125 2126 2127@overload 2128def on_primary_monitor( 2129 x: tuple[int, int], 2130 y: None = None, 2131) -> bool: ... 2132 2133 2134def on_primary_monitor( 2135 x: int | tuple[int, int] | None = None, 2136 y: int | None = None, 2137) -> bool: 2138 """ 2139 Returns whether the given xy coordinates are on the primary screen or not. 2140 2141 If x and/or y argument(s) are not given, current mouse cursor coordinates 2142 will be used instead. 2143 """ 2144 _x: int | None 2145 _y: int | None 2146 if isinstance(x, Sequence): 2147 assert not isinstance(x, int) # remove int annotation, mypy needs this 2148 if y is not None: 2149 raise ValueError( 2150 "onScreen() does not accept Sequence-types as first argument " 2151 "if a second argument is also provided!" 2152 ) 2153 try: 2154 _x, _y = x[0], x[1] 2155 except IndexError as e: 2156 raise ValueError( 2157 "onScreen() does not accept single element sequences " 2158 "as first argument!" 2159 ) from e 2160 else: 2161 _x, _y = x, y 2162 2163 x, y = position(_x, _y) 2164 display_width: int 2165 display_height: int 2166 display_width, display_height = size() 2167 2168 return 0 <= x < display_width and 0 <= y < display_height 2169 2170 2171onScreen = on_primary_monitor 2172# ------------------------------------------------------------------------------ 2173 2174 2175# ----- are coordinates on any monitor ----------------------------------------- 2176@overload 2177def valid_screen_coordinates( 2178 x: int | None = None, 2179 y: int | None = None, 2180) -> bool: ... 2181 2182 2183@overload 2184def valid_screen_coordinates(x: tuple[int, int], y: None = None) -> bool: ... 2185 2186 2187def valid_screen_coordinates( 2188 x: int | tuple[int, int] | None = None, y: int | None = None 2189) -> bool: 2190 """ 2191 Returns whether the given xy coordinates are on a real monitor or not. 2192 2193 If x and/or y argument(s) are not given, current mouse cursor coordinates 2194 will be used instead. 2195 """ 2196 _x: int | None 2197 _y: int | None 2198 if isinstance(x, Sequence): 2199 assert not isinstance(x, int) # remove int annotation, mypy needs this 2200 if y is not None: 2201 raise ValueError( 2202 "onScreen() does not accept Sequence-types as first argument " 2203 "if a second argument is also provided!" 2204 ) 2205 try: 2206 _x, _y = x[0], x[1] 2207 except IndexError as e: 2208 raise ValueError( 2209 "onScreen() does not accept single element sequences " 2210 "as first argument!" 2211 ) from e 2212 else: 2213 _x, _y = x, y 2214 2215 x, y = position(_x, _y) 2216 return _monitor_from_point(x, y) is not None 2217 # -------------------------------------------------------------------------- 2218 2219 2220# ----- lookup function for MOUSEINPUT data ------------------------------------ 2221def _get_mouse_struct_data( 2222 button: str, method: Literal[0, 1, 2] 2223) -> tuple[int | None, int]: 2224 """ 2225 Translate a button string to INPUT struct data. 2226 2227 Automatically detect the correct button if `MOUSE_PRIMARY` or 2228 `MOUSE_SECONDARY` are given as the button argument. 2229 """ 2230 if not (0 <= method <= 2): 2231 raise ValueError(f"method index {method} is not a valid argument!") 2232 2233 buttons_swapped: bool 2234 if button == MOUSE_PRIMARY: 2235 buttons_swapped = _get_system_metrics(_SM_SWAPBUTTON) != 0 2236 button = MOUSE_RIGHT if buttons_swapped else MOUSE_LEFT 2237 elif button == MOUSE_SECONDARY: 2238 buttons_swapped = _get_system_metrics(_SM_SWAPBUTTON) != 0 2239 button = MOUSE_LEFT if buttons_swapped else MOUSE_RIGHT 2240 2241 event_value: int | None 2242 event_value = _MOUSE_MAPPING_EVENTF.get(button, (None, None, None))[method] 2243 mouseData: int = _MOUSE_MAPPING_DATA.get(button, 0) 2244 2245 return event_value, mouseData 2246 # -------------------------------------------------------------------------- 2247 2248 2249# ----- normalize key name to lower case if not shifiting ---------------------- 2250def _normalize_key(key: str, *, auto_shift: bool = False) -> str: 2251 """ 2252 return a lowercase representation of `key` if key is longer than one 2253 character or automatic shifting is disabled (default). 2254 """ 2255 return key.lower() if (len(key) > 1 or not auto_shift) else key 2256 # -------------------------------------------------------------------------- 2257 2258 2259# ------------------------------------------------------------------------------ 2260# ----- Mouse acceleration and Ehanced Pointer Precision storage singleton ----- 2261class __MouseSpeedSettings: 2262 """ 2263 Allows controlled storage of Windows Enhanced Pointer Precision and mouse 2264 speed settings. 2265 """ 2266 2267 __context_manager_epp: ClassVar[int | None] = None 2268 __context_manager_speed: ClassVar[int | None] = None 2269 __context_manager_count: ClassVar[int] = 0 2270 __context_manager_lock: ClassVar[Lock] = Lock() 2271 __manual_store_epp: ClassVar[int | None] = None 2272 __manual_store_speed: ClassVar[int | None] = None 2273 __manual_lock: ClassVar[Lock] = Lock() 2274 # -------------------------------------------------------------------------- 2275 2276 @classmethod 2277 def get_manual_mouse_settings(cls) -> tuple[int | None, int | None]: 2278 with cls.__manual_lock: 2279 return (cls.__manual_store_epp, cls.__manual_store_speed) 2280 # ---------------------------------------------------------------------- 2281 2282 @classmethod 2283 def set_manual_mouse_settings( 2284 cls, enhanced_pointer_precision_enabled: int, mouse_speed: int 2285 ) -> None: 2286 with cls.__manual_lock: 2287 cls.__manual_store_epp = enhanced_pointer_precision_enabled 2288 cls.__manual_store_speed = mouse_speed 2289 # ---------------------------------------------------------------------- 2290 2291 @classmethod 2292 def get_ctxtmgr_mouse_settings(cls) -> tuple[int | None, int | None]: 2293 with cls.__context_manager_lock: 2294 cls.__context_manager_count -= 1 2295 if cls.__context_manager_count > 0: 2296 # Don't retrieve stored value until last 2297 return (None, None) 2298 epp_enabled: int | None = cls.__context_manager_epp 2299 mouse_speed: int | None = cls.__context_manager_speed 2300 cls.__context_manager_epp = None 2301 cls.__context_manager_speed = None 2302 return (epp_enabled, mouse_speed) 2303 # ---------------------------------------------------------------------- 2304 2305 @classmethod 2306 def set_ctxtmgr_mouse_settings( 2307 cls, enhanced_pointer_precision_enabled: int, mouse_speed: int 2308 ) -> None: 2309 with cls.__context_manager_lock: 2310 cls.__context_manager_count += 1 2311 if cls.__context_manager_count > 1: 2312 # Don't allow changing the stored value if another value is 2313 # already stored 2314 return 2315 cls.__context_manager_epp = enhanced_pointer_precision_enabled 2316 cls.__context_manager_speed = mouse_speed 2317 # ---------------------------------------------------------------------- 2318 2319 2320# ----- Temporarily disable Enhanced Pointer Precision ------------------------- 2321@contextmanager 2322def _no_mouse_acceleration() -> Generator[None, None, None]: 2323 """ 2324 Context manager that allows temporarily disabling Windows Enhanced Pointer 2325 Precision on enter and restoring the previous setting on exit. 2326 """ 2327 th1: int 2328 th2: int 2329 precision: int | None 2330 # store mouse parameters (thresholds, enhanced pointer precision) 2331 th1, th2, precision = _get_mouse_parameters() 2332 speed: int | None = _get_mouse_speed() 2333 assert isinstance(precision, int) 2334 assert isinstance(speed, int) 2335 __MouseSpeedSettings.set_ctxtmgr_mouse_settings(precision, speed) 2336 try: 2337 # modify mouse parameters 2338 if precision != 0: 2339 _set_mouse_parameters(th1, th2, 0) 2340 if speed != 10: 2341 _set_mouse_speed(10) 2342 yield 2343 finally: 2344 # restore mouse parameters 2345 precision, speed = __MouseSpeedSettings.get_ctxtmgr_mouse_settings() 2346 if precision is not None: 2347 _set_mouse_parameters(th1, th2, precision) 2348 if speed is not None: 2349 _set_mouse_speed(speed) 2350 # -------------------------------------------------------------------------- 2351 2352 2353# ----- manually store current enhanced pointer precision setting -------------- 2354def store_mouse_acceleration_settings() -> None: 2355 """ 2356 Manually save the current Windows Enhanced Pointer Precision setting so 2357 that it can be restored later with `restore_mouse_acceleration_settings()`. 2358 """ 2359 precision: int 2360 _, _, precision = _get_mouse_parameters() 2361 speed: int = _get_mouse_speed() 2362 __MouseSpeedSettings.set_manual_mouse_settings(precision, speed) 2363 # -------------------------------------------------------------------------- 2364 2365 2366# ----- manually restore current enhanced pointer precision setting ------------ 2367def restore_mouse_acceleration_settings() -> None: 2368 """ 2369 Manually restore the current Windows Enhanced Pointer Precision setting to 2370 what it was beforehand when it was saved with 2371 `store_mouse_acceleration_settings()`. 2372 """ 2373 precision: int | None 2374 speed: int | None 2375 precision, speed = __MouseSpeedSettings.get_manual_mouse_settings() 2376 if precision is None or speed is None: 2377 raise ValueError( 2378 "Can't restore Enhanced Pointer Precision setting! " 2379 "Setting was not saved beforehand!" 2380 ) 2381 th1: int 2382 th2: int 2383 th1, th2, _ = _get_mouse_parameters() 2384 _set_mouse_parameters(th1, th2, precision) 2385 _set_mouse_speed(speed) 2386 # -------------------------------------------------------------------------- 2387 2388 2389# ============================================================================== 2390# ===== Main Mouse Functions =================================================== 2391# ============================================================================== 2392 2393 2394# ----- mouseDown -------------------------------------------------------------- 2395@_genericPyDirectInputChecks 2396def mouseDown( 2397 x: int | None = None, 2398 y: int | None = None, 2399 button: str = MOUSE_PRIMARY, 2400 duration: float = 0.0, 2401 tween: Callable[[float], float] | None = None, 2402 logScreenshot: bool = False, 2403 _pause: bool = True, 2404 *, 2405 relative: bool = False, 2406 virtual: bool = False, 2407 path_function: PathFunction | None = None, 2408 attempt_pixel_perfect: bool = False, 2409 disable_mouse_acceleration: bool = False, 2410) -> None: 2411 """ 2412 Press down mouse button `button`. 2413 2414 If `x` or `y` are given and not None, then the mouse will move the 2415 indicated postion before pressing the button. 2416 2417 `button` is the name of the button to press. Use the public `MOUSE_*` 2418 constants to get valid argument values. (If you change the constants, then 2419 you will have to call `update_MOUSEEVENT_mappings()` to resync the lookup 2420 functions) 2421 2422 If `_pause` is True (default), then an automatic sleep will be performed 2423 after the function finshes executing. The duration is set by the global 2424 variable `PAUSE`. 2425 2426 `duration`, `tween`, `relative`, `virtual`, `path_function`, 2427 `attempt_pixel_perfect`, `disable_mouse_acceleration` are only relevant 2428 if x or y are given. 2429 See `moveTo()` for further information. 2430 2431 Raises `ValueError` if `button` is not a valid mouse button name. 2432 2433 ---------------------------------------------------------------------------- 2434 2435 NOTE: `logScreenshot` is currently unsupported. 2436 """ 2437 # TODO: bounding box check for valid position 2438 if x is not None or y is not None: 2439 moveTo( 2440 x, 2441 y, 2442 duration=duration, 2443 tween=tween, 2444 logScreenshot=logScreenshot, 2445 _pause=False, # don't add an additional pause 2446 relative=relative, 2447 virtual=virtual, 2448 path_function=path_function, 2449 attempt_pixel_perfect=attempt_pixel_perfect, 2450 disable_mouse_acceleration=disable_mouse_acceleration, 2451 ) 2452 2453 event_value: int | None = None 2454 mouseData: int 2455 event_value, mouseData = _get_mouse_struct_data(button, _MOUSE_PRESS) 2456 2457 if not event_value: 2458 raise ValueError( 2459 f"Invalid button argument! " 2460 f'Expected "{MOUSE_LEFT}", "{MOUSE_RIGHT}", "{MOUSE_MIDDLE}", ' 2461 f'"{MOUSE_BUTTON4}", "{MOUSE_BUTTON5}", "{MOUSE_PRIMARY}" or ' 2462 f'"{MOUSE_SECONDARY}"; got "{button}" instead!' 2463 ) 2464 2465 _send_input(_create_mouse_input(mouseData=mouseData, dwFlags=event_value)) 2466 # -------------------------------------------------------------------------- 2467 2468 2469# ----- mouseUp ---------------------------------------------------------------- 2470@_genericPyDirectInputChecks 2471def mouseUp( 2472 x: int | None = None, 2473 y: int | None = None, 2474 button: str = MOUSE_PRIMARY, 2475 duration: float = 0.0, 2476 tween: Callable[[float], float] | None = None, 2477 logScreenshot: bool = False, 2478 _pause: bool = True, 2479 *, 2480 relative: bool = False, 2481 virtual: bool = False, 2482 path_function: PathFunction | None = None, 2483 attempt_pixel_perfect: bool = False, 2484 disable_mouse_acceleration: bool = False, 2485) -> None: 2486 """ 2487 Lift up mouse button `button`. 2488 2489 If `x` or `y` are given and not None, then the mouse will move the 2490 indicated postion before lifting the button. 2491 2492 `button` is the name of the button to press. Use the public `MOUSE_*` 2493 constants to get valid argument values. (If you change the constants, then 2494 you will have to call `update_MOUSEEVENT_mappings()` to resync the lookup 2495 functions) 2496 2497 If `_pause` is True (default), then an automatic sleep will be performed 2498 after the function finshes executing. The duration is set by the global 2499 variable `PAUSE`. 2500 2501 `duration`, `tween`, `relative`, `virtual`, `path_function`, 2502 `attempt_pixel_perfect`, `disable_mouse_acceleration` are only relevant 2503 if x or y are given. 2504 See `moveTo()` for further information. 2505 2506 Raises `ValueError` if `button` is not a valid mouse button name. 2507 2508 ---------------------------------------------------------------------------- 2509 2510 NOTE: `logScreenshot` is currently unsupported. 2511 """ 2512 # TODO: bounding box check for valid position 2513 if x is not None or y is not None: 2514 moveTo( 2515 x, 2516 y, 2517 duration=duration, 2518 tween=tween, 2519 logScreenshot=logScreenshot, 2520 _pause=False, # don't add an additional pause 2521 relative=relative, 2522 virtual=virtual, 2523 path_function=path_function, 2524 attempt_pixel_perfect=attempt_pixel_perfect, 2525 disable_mouse_acceleration=disable_mouse_acceleration, 2526 ) 2527 2528 event_value: int | None = None 2529 mouseData: int 2530 event_value, mouseData = _get_mouse_struct_data(button, _MOUSE_RELEASE) 2531 2532 if not event_value: 2533 raise ValueError( 2534 "Invalid button argument! " 2535 f'Expected "{MOUSE_LEFT}", "{MOUSE_RIGHT}", "{MOUSE_MIDDLE}", ' 2536 f'"{MOUSE_BUTTON4}", "{MOUSE_BUTTON5}", "{MOUSE_PRIMARY}" or ' 2537 f'"{MOUSE_SECONDARY}"; got "{button}" instead!' 2538 ) 2539 2540 _send_input(_create_mouse_input(mouseData=mouseData, dwFlags=event_value)) 2541 # -------------------------------------------------------------------------- 2542 2543 2544# ----- click ------------------------------------------------------------------ 2545@_genericPyDirectInputChecks 2546def click( 2547 x: int | None = None, 2548 y: int | None = None, 2549 clicks: int = 1, 2550 interval: float = 0.0, 2551 button: str = MOUSE_PRIMARY, 2552 duration: float = 0.0, 2553 tween: Callable[[float], float] | None = None, 2554 logScreenshot: bool = False, 2555 _pause: bool = True, 2556 *, 2557 relative: bool = False, 2558 virtual: bool = False, 2559 path_function: PathFunction | None = None, 2560 attempt_pixel_perfect: bool = False, 2561 disable_mouse_acceleration: bool = False, 2562) -> None: 2563 """ 2564 Click mouse button `button` (combining press down and lift up). 2565 2566 If `x` or `y` are given and not None, then the mouse will move the 2567 indicated postion before clicking the button. 2568 2569 `button` is the name of the button to press. Use the public `MOUSE_*` 2570 constants to get valid argument values. (If you change the constants, then 2571 you will have to call `update_MOUSEEVENT_mappings()` to resync the lookup 2572 functions) 2573 2574 `clicks` is an integer that determines the amount of times the button will 2575 be clicked. 2576 2577 `interval` is the wait time in seconds between clicks. 2578 2579 If `_pause` is True (default), then an automatic sleep will be performed 2580 after the function finshes executing. The duration is set by the global 2581 variable `PAUSE`. 2582 2583 `duration`, `tween`, `relative`, `virtual`, `path_function`, 2584 `attempt_pixel_perfect`, `disable_mouse_acceleration` are only relevant 2585 if x or y are given. 2586 See `moveTo()` for further information. 2587 2588 Raises `ValueError` if `button` is not a valid mouse button name. 2589 2590 ---------------------------------------------------------------------------- 2591 2592 NOTE: `logScreenshot` is currently unsupported. 2593 """ 2594 # TODO: bounding box check for valid position 2595 if x is not None or y is not None: 2596 moveTo( 2597 x, 2598 y, 2599 duration=duration, 2600 tween=tween, 2601 logScreenshot=logScreenshot, 2602 _pause=False, # don't add an additional pause 2603 relative=relative, 2604 virtual=virtual, 2605 path_function=path_function, 2606 attempt_pixel_perfect=attempt_pixel_perfect, 2607 disable_mouse_acceleration=disable_mouse_acceleration, 2608 ) 2609 2610 event_value: int | None = None 2611 mouseData: int 2612 event_value, mouseData = _get_mouse_struct_data(button, _MOUSE_CLICK) 2613 2614 if not event_value: 2615 raise ValueError( 2616 f"Invalid button argument! " 2617 f'Expected "{MOUSE_LEFT}", "{MOUSE_RIGHT}", "{MOUSE_MIDDLE}", ' 2618 f'"{MOUSE_BUTTON4}", "{MOUSE_BUTTON5}", "{MOUSE_PRIMARY}" or ' 2619 f'"{MOUSE_SECONDARY}"; got "{button}" instead!' 2620 ) 2621 2622 apply_interval: bool = False 2623 for _ in range(clicks): 2624 if apply_interval: # Don't delay first press 2625 _sleep(interval) 2626 apply_interval = True 2627 2628 _send_input( 2629 _create_mouse_input(mouseData=mouseData, dwFlags=event_value) 2630 ) 2631 # -------------------------------------------------------------------------- 2632 2633 2634# ----- leftClick -------------------------------------------------------------- 2635def leftClick( 2636 x: int | None = None, 2637 y: int | None = None, 2638 interval: float = 0.0, 2639 duration: float = 0.0, 2640 tween: Callable[[float], float] | None = None, 2641 logScreenshot: bool = False, 2642 _pause: bool = True, 2643 *, 2644 relative: bool = False, 2645 virtual: bool = False, 2646 path_function: PathFunction | None = None, 2647 attempt_pixel_perfect: bool = False, 2648 disable_mouse_acceleration: bool = False, 2649) -> None: 2650 """ 2651 Click Left Mouse button. 2652 2653 See `click()` for more information 2654 """ 2655 click( 2656 x, 2657 y, 2658 clicks=1, 2659 interval=interval, 2660 button=MOUSE_LEFT, 2661 duration=duration, 2662 tween=tween, 2663 logScreenshot=logScreenshot, 2664 _pause=_pause, # Keep _pause since this function has no input checks 2665 relative=relative, 2666 virtual=virtual, 2667 path_function=path_function, 2668 attempt_pixel_perfect=attempt_pixel_perfect, 2669 disable_mouse_acceleration=disable_mouse_acceleration, 2670 ) 2671 # -------------------------------------------------------------------------- 2672 2673 2674# ----- rightClick ------------------------------------------------------------- 2675def rightClick( 2676 x: int | None = None, 2677 y: int | None = None, 2678 interval: float = 0.0, 2679 duration: float = 0.0, 2680 tween: Callable[[float], float] | None = None, 2681 logScreenshot: bool = False, 2682 _pause: bool = True, 2683 *, 2684 relative: bool = False, 2685 virtual: bool = False, 2686 path_function: PathFunction | None = None, 2687 attempt_pixel_perfect: bool = False, 2688 disable_mouse_acceleration: bool = False, 2689) -> None: 2690 """ 2691 Click Right Mouse button. 2692 2693 See `click()` for more information 2694 """ 2695 click( 2696 x, 2697 y, 2698 clicks=1, 2699 interval=interval, 2700 button=MOUSE_RIGHT, 2701 duration=duration, 2702 tween=tween, 2703 logScreenshot=logScreenshot, 2704 _pause=_pause, # Keep _pause since this function has no input checks 2705 relative=relative, 2706 virtual=virtual, 2707 path_function=path_function, 2708 attempt_pixel_perfect=attempt_pixel_perfect, 2709 disable_mouse_acceleration=disable_mouse_acceleration, 2710 ) 2711 # -------------------------------------------------------------------------- 2712 2713 2714# ----- middleClick ------------------------------------------------------------ 2715def middleClick( 2716 x: int | None = None, 2717 y: int | None = None, 2718 interval: float = 0.0, 2719 duration: float = 0.0, 2720 tween: Callable[[float], float] | None = None, 2721 logScreenshot: bool = False, 2722 _pause: bool = True, 2723 *, 2724 relative: bool = False, 2725 virtual: bool = False, 2726 path_function: PathFunction | None = None, 2727 attempt_pixel_perfect: bool = False, 2728 disable_mouse_acceleration: bool = False, 2729) -> None: 2730 """ 2731 Click Middle Mouse button. 2732 2733 See `click()` for more information 2734 """ 2735 click( 2736 x, 2737 y, 2738 clicks=1, 2739 interval=interval, 2740 button=MOUSE_MIDDLE, 2741 duration=duration, 2742 tween=tween, 2743 logScreenshot=logScreenshot, 2744 _pause=_pause, # Keep _pause since this function has no input checks 2745 relative=relative, 2746 virtual=virtual, 2747 path_function=path_function, 2748 attempt_pixel_perfect=attempt_pixel_perfect, 2749 disable_mouse_acceleration=disable_mouse_acceleration, 2750 ) 2751 # -------------------------------------------------------------------------- 2752 2753 2754# ----- doubleClick ------------------------------------------------------------ 2755def doubleClick( 2756 x: int | None = None, 2757 y: int | None = None, 2758 interval: float = 0.0, 2759 button: str = MOUSE_LEFT, 2760 duration: float = 0.0, 2761 tween: Callable[[float], float] | None = None, 2762 logScreenshot: bool = False, 2763 _pause: bool = True, 2764 *, 2765 relative: bool = False, 2766 virtual: bool = False, 2767 path_function: PathFunction | None = None, 2768 attempt_pixel_perfect: bool = False, 2769 disable_mouse_acceleration: bool = False, 2770) -> None: 2771 """ 2772 Double click `button`. 2773 2774 See `click()` for more information 2775 """ 2776 click( 2777 x, 2778 y, 2779 clicks=2, 2780 interval=interval, 2781 button=button, 2782 duration=duration, 2783 tween=tween, 2784 logScreenshot=logScreenshot, 2785 _pause=_pause, # Keep _pause since this function has no input checks 2786 relative=relative, 2787 virtual=virtual, 2788 path_function=path_function, 2789 attempt_pixel_perfect=attempt_pixel_perfect, 2790 disable_mouse_acceleration=disable_mouse_acceleration, 2791 ) 2792 # -------------------------------------------------------------------------- 2793 2794 2795# ----- tripleClick ------------------------------------------------------------ 2796def tripleClick( 2797 x: int | None = None, 2798 y: int | None = None, 2799 interval: float = 0.0, 2800 button: str = MOUSE_LEFT, 2801 duration: float = 0.0, 2802 tween: Callable[[float], float] | None = None, 2803 logScreenshot: bool = False, 2804 _pause: bool = True, 2805 *, 2806 relative: bool = False, 2807 virtual: bool = False, 2808 path_function: PathFunction | None = None, 2809 attempt_pixel_perfect: bool = False, 2810 disable_mouse_acceleration: bool = False, 2811) -> None: 2812 """ 2813 Triple click `button`. 2814 2815 See `click()` for more information 2816 """ 2817 click( 2818 x, 2819 y, 2820 clicks=3, 2821 interval=interval, 2822 button=button, 2823 duration=duration, 2824 tween=tween, 2825 logScreenshot=logScreenshot, 2826 _pause=_pause, # Keep _pause since this function has no input checks 2827 relative=relative, 2828 virtual=virtual, 2829 path_function=path_function, 2830 attempt_pixel_perfect=attempt_pixel_perfect, 2831 disable_mouse_acceleration=disable_mouse_acceleration, 2832 ) 2833 # -------------------------------------------------------------------------- 2834 2835 2836# ----- scroll ----------------------------------------------------------------- 2837# Originally implemented by 2838# https://github.com/learncodebygaming/pydirectinput/pull/22 2839@_genericPyDirectInputChecks 2840def scroll( 2841 clicks: int = 0, 2842 x: Any = None, # x and y do absolutely nothing, still keeping the arguments 2843 y: Any = None, # to stay consistent with PyAutoGUI. 2844 logScreenshot: bool = False, 2845 _pause: bool = True, 2846 *, 2847 interval: float = 0.0, 2848) -> None: 2849 """ 2850 Vertically scroll mouse `clicks` number of times, waiting `interval` 2851 seconds between every scroll. 2852 2853 Negative values of `clicks` will scroll down, postive values will scroll 2854 up. 2855 2856 `x` and `y` are intentionally ignored and only exists to keep the call 2857 signature backwards-compatible with PyAutoGui. 2858 If you need to change the mouse position before scrolling use one of the 2859 `move()` functions. 2860 2861 If `_pause` is True (default), then an automatic sleep will be performed 2862 after the function finshes executing. The duration is set by the global 2863 variable `PAUSE`. 2864 2865 ---------------------------------------------------------------------------- 2866 2867 NOTE: `logScreenshot` is currently unsupported. 2868 """ 2869 direction: Literal[-1, 1] 2870 if clicks >= 0: 2871 direction = 1 2872 else: 2873 direction = -1 2874 clicks = abs(clicks) 2875 2876 apply_interval: bool = False 2877 for _ in range(clicks): 2878 if apply_interval: 2879 _sleep(interval) 2880 apply_interval = True 2881 2882 _send_input( 2883 _create_mouse_input( 2884 mouseData=(direction * _WHEEL_DELTA), dwFlags=_MOUSEEVENTF_WHEEL 2885 ) 2886 ) 2887 # -------------------------------------------------------------------------- 2888 2889 2890# ----- hscroll ---------------------------------------------------------------- 2891@_genericPyDirectInputChecks 2892def hscroll( 2893 clicks: int = 0, 2894 x: Any = None, # x and y do absolutely nothing, still keeping the arguments 2895 y: Any = None, # to stay consistent with PyAutoGUI. 2896 logScreenshot: bool = False, 2897 _pause: bool = True, 2898 *, 2899 interval: float = 0.0, 2900) -> None: 2901 """ 2902 Horizontally scroll mouse `clicks` number of times, waiting `interval` 2903 seconds between every scroll. 2904 2905 Negative values of `clicks` will scroll left, postive values will scroll 2906 right. 2907 2908 `x` and `y` are intentionally ignored and only exists to keep the call 2909 signature backwards-compatible with PyAutoGui. 2910 If you need to change the mouse position before scrolling use one of the 2911 `move()` functions. 2912 2913 If `_pause` is True (default), then an automatic sleep will be performed 2914 after the function finshes executing. The duration is set by the global 2915 variable `PAUSE`. 2916 2917 ---------------------------------------------------------------------------- 2918 2919 NOTE: `logScreenshot` is currently unsupported. 2920 """ 2921 direction: Literal[-1, 1] 2922 if clicks >= 0: 2923 direction = 1 2924 else: 2925 direction = -1 2926 clicks = abs(clicks) 2927 2928 apply_interval: bool = False 2929 for _ in range(clicks): 2930 if apply_interval: 2931 _sleep(interval) 2932 apply_interval = True 2933 2934 _send_input( 2935 _create_mouse_input( 2936 mouseData=(direction * _WHEEL_DELTA), 2937 dwFlags=_MOUSEEVENTF_HWHEEL, 2938 ) 2939 ) 2940 # -------------------------------------------------------------------------- 2941 2942 2943# ----- scroll alias ----------------------------------------------------------- 2944vscroll = scroll 2945# ------------------------------------------------------------------------------ 2946 2947 2948# ----- absolute_mouse_move ---------------------------------------------------- 2949def _absolute_mouse_move( 2950 x: int | None = None, 2951 y: int | None = None, 2952 duration: float = 0.0, 2953 tween: Callable[[float], float] | None = None, 2954 logScreenshot: bool = False, 2955 target_coords_relative: bool = False, 2956 *, 2957 virtual: bool = False, 2958 path_function: PathFunction | None = None, 2959 attempt_pixel_perfect: bool = False, 2960 disable_mouse_acceleration: bool = False, 2961) -> None: 2962 """ 2963 Move the mouse to an absolute(*) postion indicated by the arguments of 2964 `x` and `y`. The coordinates 0,0 represent the top left pixel of the 2965 primary monitor. 2966 2967 If `duration` is floating point number greater than 0, then this function 2968 will automatically split the movement into microsteps instead of moving 2969 straight to the target position. 2970 2971 `tween` is a function that takes a floating point number between 0.0 and 2972 1.0 and returns another floating point number between 0.0 and 1.0. The 2973 returned number will be used to calculate the next position of the 2974 mouse between the start and the end position based on the current duration. 2975 The default tweening function is linear, which will move the mouse at a 2976 constant speed. See the `pytweening` package for more tweening functions. 2977 2978 `path_function` is a function that takes the start and end coordinates of 2979 the mouse movement (4 integers) and returns a list of coordinates (list of 2980 tuples containting 2 integers each) that the mouse will move through. 2981 The default path function is Bresenham's line algorithm, which will move 2982 the mouse in a straight line. 2983 2984 (*) If `target_coords_relative` is set: Use absolute mouse movement to move 2985 the mouse cursor to the current mouse position offset by arguments 2986 `x` and `y`. 2987 2988 If `_pause` is True (default), then an automatic sleep will be performed 2989 after the function finshes executing. The duration is set by the global 2990 variable `PAUSE`. 2991 2992 Setting `virtual` to True (default: False) changes the way internal APIs 2993 handle coordinates and is intended for multi monitor systems. It should be 2994 pretty much unncessary even for multi monitor systems, since all the 2995 necessary internal calculations beyond the border of the primay monitor 2996 work without it. 2997 2998 The way that Windows calculates the target pixel coordinates internally 2999 unfortunately leads to inaccuracies and unreachable pixels, especially 3000 if the `virtual` option is used. 3001 3002 If you need the target position to be pixel perfect, you can try setting 3003 `attempt_pixel_perfect` to True, which will use tiny relative movements 3004 to correct the unreachable position. 3005 3006 Relative movement is influenced by mouse speed and Windows Enhanced Pointer 3007 Precision, which can be temporarily disabled by setting 3008 `disable_mouse_acceleration`. 3009 3010 ---------------------------------------------------------------------------- 3011 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 3012 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 3013 3014 If you you start a relative movement while another is already in progress 3015 than the second movement could overwrite the first setting and disable 3016 Enhanced Pointer Precision and change mouse speed. 3017 There are some measures in place to try to mitigate that risk, such as an 3018 internal counter that only allows storing and restoring the acceleration 3019 settings as long as no other movement is currently in progress. 3020 Additionally, the acceleration settings can be manually saved and 3021 restored with `store_mouse_acceleration_settings()` and 3022 `restore_mouse_acceleration_settings()`. For your convenience, the 3023 store function is automatically called during import to save your current 3024 setting. You can then call the restore function at any time. 3025 3026 If all fails, the setting is not written permanently to your Windows 3027 settings, so it should restore itself upon reboot. 3028 3029 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3030 this library in multiple threads / processes / programs at the same time! 3031 3032 ---------------------------------------------------------------------------- 3033 3034 NOTE: `logScreenshot` is currently unsupported. 3035 """ 3036 # TODO: bounding box check for valid position 3037 if tween is None: 3038 tween = _linear 3039 if path_function is None: 3040 path_function = _bresenham 3041 final_x: int 3042 final_y: int 3043 current_x: int = 0 3044 current_y: int = 0 3045 current_x, current_y = position() 3046 if target_coords_relative: 3047 final_x = current_x + (0 if x is None else x) 3048 final_y = current_y + (0 if y is None else y) 3049 else: 3050 # if only x or y is provided, will keep the current position for the 3051 # other axis 3052 final_x, final_y = position(x, y) 3053 3054 dwFlags: int = _MOUSEEVENTF_MOVE | _MOUSEEVENTF_ABSOLUTE 3055 if virtual: 3056 dwFlags |= _MOUSEEVENTF_VIRTUALDESK 3057 3058 if duration <= 0.0: 3059 # no duration -> move mouse instantly 3060 x, y = _to_windows_coordinates(final_x, final_y, virtual=virtual) 3061 _send_input(_create_mouse_input(dx=x, dy=y, dwFlags=dwFlags)) 3062 3063 else: 3064 start_time: Final[float] = _time() 3065 final_time: Final[float] = start_time + duration 3066 path: list[tuple[int, int]] = path_function( 3067 current_x, current_y, final_x, final_y 3068 ) 3069 path_length = len(path) 3070 keep_looping: bool = True 3071 sleep_duration: float = MINIMUM_SLEEP_IDEAL 3072 3073 apply_duration: bool = False 3074 while keep_looping: 3075 if apply_duration: 3076 _sleep(sleep_duration) # sleep between iterations 3077 else: 3078 apply_duration = True 3079 3080 _failSafeCheck() 3081 3082 current_time = _time() 3083 if current_time >= final_time: 3084 keep_looping = False 3085 segment_count = path_length - 1 3086 else: 3087 time_ratio = (current_time - start_time) / duration 3088 if time_ratio <= 0.0: 3089 time_ratio = 0.0 3090 if time_ratio >= 1.0: 3091 time_ratio = 1.0 3092 path_ratio = tween(time_ratio) 3093 segment_count = int(path_length * path_ratio) 3094 if segment_count >= path_length: 3095 segment_count = path_length - 1 3096 3097 current_x, current_y = position() 3098 x, y = path[segment_count] 3099 3100 if x == current_x and y == current_y: 3101 # no change in movement for current segment ->try again 3102 continue 3103 3104 x, y = _to_windows_coordinates(x, y, virtual=virtual) 3105 _send_input(_create_mouse_input(dx=x, dy=y, dwFlags=dwFlags)) 3106 3107 # After-care: Did Windows move the cursor correctly? 3108 # If not, attempt to fix off-by-one errors. 3109 if attempt_pixel_perfect: 3110 current_x, current_y = position() 3111 if current_x == final_x and current_y == final_y: 3112 return # We are already pixel perfect, great! 3113 _relative_mouse_move( 3114 x=final_x - current_x, 3115 y=final_y - current_y, 3116 duration=0.0, 3117 target_coords_relative=True, 3118 virtual=virtual, 3119 disable_mouse_acceleration=disable_mouse_acceleration, 3120 ) 3121 # -------------------------------------------------------------------------- 3122 3123 3124# ----- relative_mouse_move ---------------------------------------------------- 3125def _relative_mouse_move( 3126 x: int | None = None, 3127 y: int | None = None, 3128 duration: float = 0.0, 3129 tween: Callable[[float], float] | None = None, 3130 logScreenshot: bool = False, 3131 target_coords_relative: bool = True, 3132 *, 3133 virtual: bool = False, 3134 path_function: PathFunction | None = None, 3135 disable_mouse_acceleration: bool = False, 3136) -> None: 3137 """ 3138 Move the mouse a relative amount determined by `x` and `y`. 3139 3140 If `duration` is floating point number greater than 0, then this function 3141 will automatically split the movement into microsteps instead of moving the 3142 complete distance instantly. 3143 3144 `tween` is a function that takes a floating point number between 0.0 and 3145 1.0 and returns another floating point number between 0.0 and 1.0. The 3146 returned number will be used to calculate the next position of the 3147 mouse between the start and the end position based on the current duration. 3148 The default tweening function is linear, which will move the mouse at a 3149 constant speed. See the `pytweening` package for more tweening functions. 3150 3151 `path_function` is a function that takes the start and end coordinates of 3152 the mouse movement (4 integers) and returns a list of coordinates (list of 3153 tuples containting 2 integers each) that the mouse will move through. 3154 The default path function is Bresenham's line algorithm, which will move 3155 the mouse in a straight line. 3156 3157 `target_coords_relative` parameter decides how `x` and `y` are interpreted: 3158 3159 -> `False`: `x` and `y` are assumed to be absolute coordinates 3160 and the offset to move will be calculated based on the current mouse 3161 position. Movement is then performed using relative mouse movements 3162 (can be inconsistent). 3163 3164 -> `True`: `x` and `y` are assumed to be relative coordinates 3165 and the mouse will be moved by that amount. Movement is then performed 3166 using relative mouse movements (can be inconsistent). 3167 3168 The inconsistency issue can be solved by disabling Enhanced Pointer 3169 Precision and set Mouse speed to 10 in Windows mouse settings. Since users 3170 may not want to permanently change their input settings just for this 3171 library, the `disable_mouse_acceleration` argument can be used to 3172 temporarily disable Enhanced Pointer Precision and fix mouse speed at 10 3173 and restore it after the mouse movement. 3174 3175 If `_pause` is True (default), then an automatic sleep will be performed 3176 after the function finshes executing. The duration is set by the global 3177 variable `PAUSE`. 3178 3179 Setting `virtual` to True (default: False) changes the way internal APIs 3180 handle coordinates and is intended for multi monitor systems. It should be 3181 pretty much unncessary even for multi monitor systems, since all the 3182 necessary internal calculations beyond the border of the primay monitor 3183 work without it. 3184 3185 ---------------------------------------------------------------------------- 3186 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 3187 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 3188 3189 If you you start a relative movement while another is already in progress 3190 than the second movement could overwrite the first setting and disable 3191 Enhanced Pointer Precision and change mouse speed. 3192 There are some measures in place to try to mitigate that risk, such as an 3193 internal counter that only allows storing and restoring the acceleration 3194 settings as long as no other movement is currently in progress. 3195 Additionally, the acceleration settings can be manually saved and 3196 restored with `store_mouse_acceleration_settings()` and 3197 `restore_mouse_acceleration_settings()`. For your convinnience, the 3198 store function is automatically called during import to save your current 3199 setting. You can then call the restore function at any time. 3200 3201 If all fails, the setting is not written permanently to your Windows 3202 settings, so it should restore itself upon reboot. 3203 3204 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3205 this library in multiple threads / processes / programs at the same time! 3206 3207 ---------------------------------------------------------------------------- 3208 3209 NOTE: `logScreenshot` is are currently unsupported. 3210 """ 3211 # TODO: bounding box check for valid position 3212 if tween is None: 3213 tween = _linear 3214 if path_function is None: 3215 path_function = _bresenham 3216 x, y = _helper_relative_move_target_coords(x, y, target_coords_relative) 3217 3218 if duration <= 0.0: 3219 # no duration -> move mouse instantly 3220 _helper_relative_mouse_move(x, y, disable_mouse_acceleration) 3221 return 3222 3223 current_x: int = 0 3224 current_y: int = 0 3225 3226 next_x: int 3227 next_y: int 3228 3229 final_x: int = x 3230 final_y: int = y 3231 3232 start_time: Final[float] = _time() 3233 final_time: Final[float] = start_time + duration 3234 3235 path: list[tuple[int, int]] = path_function( 3236 current_x, current_y, final_x, final_y 3237 ) 3238 path_length: int = len(path) 3239 3240 keep_looping: bool = True 3241 sleep_duration: float = MINIMUM_SLEEP_IDEAL 3242 3243 apply_duration: bool = False 3244 while keep_looping: 3245 if apply_duration: 3246 _sleep(sleep_duration) # sleep between iterations 3247 else: 3248 apply_duration = True 3249 3250 _failSafeCheck() 3251 3252 current_time: float = _time() 3253 if current_time >= final_time: 3254 keep_looping = False 3255 segment_count: int = path_length - 1 3256 else: 3257 time_ratio: float = (current_time - start_time) / duration 3258 if time_ratio <= 0.0: 3259 time_ratio = 0.0 3260 if time_ratio >= 1.0: 3261 time_ratio = 1.0 3262 path_ratio: float = tween(time_ratio) 3263 segment_count = int(path_length * path_ratio) 3264 if segment_count >= path_length: 3265 segment_count = path_length - 1 3266 3267 next_x, next_y = path[segment_count] 3268 x = next_x - current_x 3269 y = next_y - current_y 3270 3271 if x == 0 and y == 0: 3272 # no change in movement for current segment ->try again 3273 continue 3274 3275 current_x = next_x 3276 current_y = next_y 3277 3278 _helper_relative_mouse_move(x, y, disable_mouse_acceleration) 3279 # -------------------------------------------------------------------------- 3280 3281 3282# ----- helper_relative_move_target_coords ------------------------------------- 3283def _helper_relative_move_target_coords( 3284 x: int | None, 3285 y: int | None, 3286 target_coords_relative: bool, 3287) -> tuple[int, int]: 3288 """ 3289 Calculate target coordinates for relative mouse movement. 3290 """ 3291 if target_coords_relative: 3292 if x is None: 3293 x = 0 3294 if y is None: 3295 y = 0 3296 else: 3297 if x is None and y is None: 3298 # Prevent unnecessary API calls 3299 return 0, 0 3300 current_x: int 3301 current_y: int 3302 current_x, current_y = position() 3303 if x is None: 3304 x = 0 3305 else: 3306 x = x - current_x 3307 if y is None: 3308 y = 0 3309 else: 3310 y = y - current_y 3311 return x, y 3312 # -------------------------------------------------------------------------- 3313 3314 3315# ----- helper_relative_mouse_move --------------------------------------------- 3316def _helper_relative_mouse_move( 3317 x: int, 3318 y: int, 3319 disable_mouse_acceleration: bool, 3320) -> None: 3321 """ 3322 When using MOUSEEVENTF_MOVE for relative movement the results may 3323 be inconsistent. "Relative mouse motion is subject to the effects 3324 of the mouse speed and the two-mouse threshold values. A user 3325 sets these three values with the Pointer Speed slider of the 3326 Control Panel's Mouse Properties sheet. You can obtain and set 3327 these values using the SystemParametersInfo function." 3328 3329 https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-mouseinput 3330 https://stackoverflow.com/questions/50601200/pyhon-directinput-mouse-relative-moving-act-not-as-expected 3331 3332 We can solve this issue by just disabling Enhanced Pointer 3333 Precision and forcing Mouse speed to neutral 10. 3334 Since that is a user setting that users may want to have 3335 enabled, use a optional keyword-only argument and a 3336 state-restoring context manager to give users the choice if they 3337 want this library messing around in their Windows settings. 3338 """ 3339 input_struct: _INPUT = _create_mouse_input( 3340 dx=x, dy=y, dwFlags=_MOUSEEVENTF_MOVE 3341 ) 3342 if disable_mouse_acceleration: 3343 # Use a context manager to temporarily disable enhanced pointer 3344 # precision 3345 with _no_mouse_acceleration(): 3346 _send_input(input_struct) 3347 else: 3348 _send_input(input_struct) 3349 # -------------------------------------------------------------------------- 3350 3351 3352# ----- moveTo ----------------------------------------------------------------- 3353@_genericPyDirectInputChecks 3354def moveTo( 3355 x: int | None = None, 3356 y: int | None = None, 3357 duration: float = 0.0, 3358 tween: Callable[[float], float] | None = None, 3359 logScreenshot: bool = False, 3360 _pause: bool = True, 3361 relative: bool = False, 3362 *, 3363 virtual: bool = False, 3364 path_function: PathFunction | None = None, 3365 attempt_pixel_perfect: bool = False, 3366 disable_mouse_acceleration: bool = False, 3367) -> None: 3368 """ 3369 Move the mouse to an absolute(*) postion indicated by the arguments of 3370 `x` and `y`. The coordinates 0,0 represent the top left pixel of the 3371 primary monitor. 3372 3373 If `duration` is floating point number greater than 0, then this function 3374 will automatically split the movement into microsteps instead of moving 3375 straight to the target position. 3376 3377 `tween` is a function that takes a floating point number between 0.0 and 3378 1.0 and returns another floating point number between 0.0 and 1.0. The 3379 returned number will be used to calculate the next position of the 3380 mouse between the start and the end position based on the current duration. 3381 The default tweening function is linear, which will move the mouse at a 3382 constant speed. See the `pytweening` package for more tweening functions. 3383 Be aware that tweening only controls to the timing of movement, not the 3384 path itself. If you need to non-linear movement (e.g. overshoot), then 3385 use the `path_function` argument. 3386 3387 `path_function` is a function that takes the start and end coordinates of 3388 the mouse movement (4 integers) and returns a list of coordinates (list of 3389 tuples, each containting 2 integers (x,y)) that the mouse will move 3390 through. The default path function is Bresenham's line algorithm, which 3391 will move the mouse in a straight line. 3392 3393 (*) `relative` parameter decides how the movement is executed: 3394 3395 -> `False`: Target postion is given and absolute movement is used. 3396 3397 -> `True`: Calculates target offset and uses relative movement API 3398 (can be inconsistent) 3399 3400 If `_pause` is True (default), then an automatic sleep will be performed 3401 after the function finshes executing. The duration is set by the global 3402 variable `PAUSE`. 3403 3404 Setting `virtual` to True (default: False) changes the way internal APIs 3405 handle coordinates and is intended for multi monitor systems. It should be 3406 pretty much unncessary even for multi monitor systems, since all the 3407 necessary internal calculations beyond the border of the primay monitor 3408 work without it. 3409 3410 The way that Windows calculates the target pixel coordinates internally 3411 unfortunately leads to inaccuracies and unreachable pixels, especially 3412 if the `virtual` option is used. 3413 3414 If you need the target position to be pixel perfect, you can try setting 3415 `attempt_pixel_perfect` to True, which will use tiny relative movements 3416 to correct the unreachable position. 3417 3418 Relative movement is influenced by mouse speed and Windows Enhanced Pointer 3419 Precision, which can be temporarily disabled by setting 3420 `disable_mouse_acceleration`. 3421 3422 ---------------------------------------------------------------------------- 3423 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 3424 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 3425 3426 If you you start a relative movement while another is already in progress 3427 than the second movement could overwrite the first setting and disable 3428 Enhanced Pointer Precision and change mouse speed. 3429 There are some measures in place to try to mitigate that risk, such as an 3430 internal counter that only allows storing and restoring the acceleration 3431 settings as long as no other movement is currently in progress. 3432 Additionally, the acceleration settings can be manually saved and 3433 restored with `store_mouse_acceleration_settings()` and 3434 `restore_mouse_acceleration_settings()`. For your convenience, the 3435 store function is automatically called during import to save your current 3436 setting. You can then call the restore function at any time. 3437 3438 If all fails, the setting is not written permanently to your Windows 3439 settings, so it should restore itself upon reboot. 3440 3441 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3442 this library in multiple threads / processes / programs at the same time! 3443 3444 ---------------------------------------------------------------------------- 3445 3446 NOTE: `logScreenshot` is currently unsupported. 3447 """ 3448 if relative: 3449 _relative_mouse_move( 3450 x=x, 3451 y=y, 3452 duration=duration, 3453 tween=tween, 3454 logScreenshot=logScreenshot, 3455 target_coords_relative=False, 3456 virtual=virtual, 3457 path_function=path_function, 3458 disable_mouse_acceleration=disable_mouse_acceleration, 3459 ) 3460 else: 3461 _absolute_mouse_move( 3462 x=x, 3463 y=y, 3464 duration=duration, 3465 tween=tween, 3466 logScreenshot=logScreenshot, 3467 target_coords_relative=False, 3468 virtual=virtual, 3469 path_function=path_function, 3470 attempt_pixel_perfect=attempt_pixel_perfect, 3471 disable_mouse_acceleration=disable_mouse_acceleration, 3472 ) 3473 # -------------------------------------------------------------------------- 3474 3475 3476# ----- moveRel ---------------------------------------------------------------- 3477@_genericPyDirectInputChecks 3478def moveRel( 3479 xOffset: int | None = None, 3480 yOffset: int | None = None, 3481 duration: float = 0.0, 3482 tween: Callable[[float], float] | None = None, 3483 logScreenshot: bool = False, 3484 _pause: bool = True, 3485 relative: bool = False, 3486 *, 3487 virtual: bool = False, 3488 path_function: PathFunction | None = None, 3489 attempt_pixel_perfect: bool = False, 3490 disable_mouse_acceleration: bool = False, 3491) -> None: 3492 """ 3493 Move the mouse a relative amount determined by `xOffset` and `yOffset`. 3494 3495 If `duration` is floating point number greater than 0, then this function 3496 will automatically split the movement into microsteps instead of moving the 3497 complete distance instantly. 3498 3499 `tween` is a function that takes a floating point number between 0.0 and 3500 1.0 and returns another floating point number between 0.0 and 1.0. The 3501 returned number will be used to calculate the next position of the 3502 mouse between the start and the end position based on the current duration. 3503 The default tweening function is linear, which will move the mouse at a 3504 constant speed. See the `pytweening` package for more tweening functions. 3505 Be aware that tweening only controls to the timing of movement, not the 3506 path itself. If you need to non-linear movement (e.g. overshoot), then 3507 use the `path_function` argument. 3508 3509 `path_function` is a function that takes the start and end coordinates of 3510 the mouse movement (4 integers) and returns a list of coordinates (list of 3511 tuples, each containting 2 integers (x,y)) that the mouse will move 3512 through. The default path function is Bresenham's line algorithm, which 3513 will move the mouse in a straight line. 3514 3515 `relative` parameter decides how the movement is executed: 3516 3517 -> `False`: Target postion is calculated and absolute movement is used. 3518 3519 -> `True`: Target offset is given and relative movement API is used 3520 (can be inconsistent) 3521 3522 The inconsistency issue can be solved by disabling Enhanced Pointer 3523 Precision and set Mouse speed to 10 in Windows mouse settings. Since users 3524 may not want to permanently change their input settings just for this 3525 library, the `disable_mouse_acceleration` argument can be used to 3526 temporarily disable Enhanced Pointer Precision and fix mouse speed at 10 3527 and restore it after the mouse movement. 3528 3529 If `_pause` is True (default), then an automatic sleep will be performed 3530 after the function finshes executing. The duration is set by the global 3531 variable `PAUSE`. 3532 3533 Setting `virtual` to True (default: False) changes the way internal APIs 3534 handle coordinates and is intended for multi monitor systems. It should be 3535 pretty much unncessary even for multi monitor systems, since all the 3536 necessary internal calculations beyond the border of the primay monitor 3537 work without it. 3538 3539 The way that Windows calculates the target pixel coordinates internally 3540 unfortunately leads to inaccuracies and unreachable pixels, especially 3541 if the `virtual` option is used. 3542 3543 If you need the target position to be pixel perfect, you can try setting 3544 `attempt_pixel_perfect` to True, which will use tiny relative movements 3545 to correct the unreachable position. 3546 3547 ---------------------------------------------------------------------------- 3548 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 3549 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 3550 3551 If you you start a relative movement while another is already in progress 3552 than the second movement could overwrite the first setting and disable 3553 Enhanced Pointer Precision and change mouse speed. 3554 There are some measures in place to try to mitigate that risk, such as an 3555 internal counter that only allows storing and restoring the acceleration 3556 settings as long as no other movement is currently in progress. 3557 Additionally, the acceleration settings can be manually saved and 3558 restored with `store_mouse_acceleration_settings()` and 3559 `restore_mouse_acceleration_settings()`. For your convinnience, the 3560 store function is automatically called during import to save your current 3561 setting. You can then call the restore function at any time. 3562 3563 If all fails, the setting is not written permanently to your Windows 3564 settings, so it should restore itself upon reboot. 3565 3566 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3567 this library in multiple threads / processes / programs at the same time! 3568 3569 ---------------------------------------------------------------------------- 3570 3571 NOTE: `logScreenshot` is are currently unsupported. 3572 """ 3573 if relative: 3574 _relative_mouse_move( 3575 x=xOffset, 3576 y=yOffset, 3577 duration=duration, 3578 tween=tween, 3579 logScreenshot=logScreenshot, 3580 target_coords_relative=True, 3581 virtual=virtual, 3582 path_function=path_function, 3583 disable_mouse_acceleration=disable_mouse_acceleration, 3584 ) 3585 else: 3586 _absolute_mouse_move( 3587 x=xOffset, 3588 y=yOffset, 3589 duration=duration, 3590 tween=tween, 3591 logScreenshot=logScreenshot, 3592 target_coords_relative=True, 3593 virtual=virtual, 3594 path_function=path_function, 3595 attempt_pixel_perfect=attempt_pixel_perfect, 3596 disable_mouse_acceleration=disable_mouse_acceleration, 3597 ) 3598 # -------------------------------------------------------------------------- 3599 3600 3601# ----- move alias ------------------------------------------------------------- 3602# move() and moveRel() are equivalent. 3603move = moveRel 3604# ------------------------------------------------------------------------------ 3605 3606 3607# ----- dragTo ----------------------------------------------------------------- 3608@_genericPyDirectInputChecks 3609def dragTo( 3610 x: int | None = None, 3611 y: int | None = None, 3612 duration: float = 0.0, 3613 tween: Callable[[float], float] | None = None, 3614 button: str | None = None, 3615 logScreenshot: bool = False, 3616 _pause: bool = True, 3617 mouseDownUp: bool = True, 3618 *, 3619 relative: bool = False, 3620 virtual: bool = False, 3621 path_function: PathFunction | None = None, 3622 attempt_pixel_perfect: bool = False, 3623 disable_mouse_acceleration: bool = False, 3624) -> None: 3625 """ 3626 Press and hold a mouse button while moving to the target coordinates. 3627 3628 See `moveTo` for more information on most arguments. 3629 3630 `button` is a string that is one of the following constants: 3631 MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, MOUSE_BUTTON4, MOUSE_BUTTON5, 3632 MOUSE_PRIMARY (default), MOUSE_SECONDARY. 3633 3634 If `mouseDownUp` (default: True) is manually set to False, then this 3635 function is basically the same as `moveTo`. Only exists to match PyAutoGUI. 3636 3637 If `_pause` is True (default), then an automatic sleep will be performed 3638 after the function finshes executing. The duration is set by the global 3639 variable `PAUSE`. 3640 3641 ---------------------------------------------------------------------------- 3642 3643 NOTE: `logScreenshot` is currently unsupported. 3644 """ 3645 # TODO: bounding box check for valid position 3646 if button is None: 3647 button = MOUSE_PRIMARY 3648 if mouseDownUp: 3649 mouseDown(button=button, _pause=False, virtual=virtual) 3650 moveTo( 3651 x, 3652 y, 3653 duration=duration, 3654 tween=tween, 3655 logScreenshot=logScreenshot, 3656 _pause=False, # don't add an additional pause 3657 relative=relative, 3658 virtual=virtual, 3659 path_function=path_function, 3660 attempt_pixel_perfect=attempt_pixel_perfect, 3661 disable_mouse_acceleration=disable_mouse_acceleration, 3662 ) 3663 if mouseDownUp: 3664 mouseUp(button=button, _pause=False, virtual=virtual) 3665 # -------------------------------------------------------------------------- 3666 3667 3668# ----- dragRel ---------------------------------------------------------------- 3669@_genericPyDirectInputChecks 3670def dragRel( 3671 xOffset: int | None = None, 3672 yOffset: int | None = None, 3673 duration: float = 0.0, 3674 tween: Callable[[float], float] | None = None, 3675 button: str | None = None, 3676 logScreenshot: bool = False, 3677 _pause: bool = True, 3678 mouseDownUp: bool = True, 3679 *, 3680 relative: bool = False, 3681 virtual: bool = False, 3682 path_function: PathFunction | None = None, 3683 disable_mouse_acceleration: bool = False, 3684) -> None: 3685 """ 3686 Press and hold a mouse button while moving a relative distance 3687 3688 See `moveRel` for more information on most arguments. 3689 3690 `button` is a string that is one of the following constants: 3691 MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, MOUSE_BUTTON4, MOUSE_BUTTON5, 3692 MOUSE_PRIMARY (default), MOUSE_SECONDARY. 3693 3694 If `mouseDownUp` (default: True) is manually set to False, then this 3695 function is basically the same as `moveTo`. Only exists to match PyAutoGUI. 3696 3697 If `_pause` is True (default), then an automatic sleep will be performed 3698 after the function finshes executing. The duration is set by the global 3699 variable `PAUSE`. 3700 3701 ---------------------------------------------------------------------------- 3702 3703 NOTE: `logScreenshot` is currently unsupported. 3704 """ 3705 # TODO: bounding box check for valid position 3706 if button is None: 3707 button = MOUSE_PRIMARY 3708 if mouseDownUp: 3709 mouseDown(button=button, _pause=False, virtual=virtual) 3710 moveRel( 3711 xOffset, 3712 yOffset, 3713 duration=duration, 3714 tween=tween, 3715 logScreenshot=logScreenshot, 3716 _pause=False, # don't add an additional pause 3717 relative=relative, 3718 virtual=virtual, 3719 path_function=path_function, 3720 disable_mouse_acceleration=disable_mouse_acceleration, 3721 ) 3722 if mouseDownUp: 3723 mouseUp(button=button, _pause=False, virtual=virtual) 3724 # -------------------------------------------------------------------------- 3725 3726 3727# ----- drag alias ------------------------------------------------------------- 3728drag = dragRel 3729# ------------------------------------------------------------------------------ 3730 3731 3732# ============================================================================== 3733# ===== Keyboard Functions ===================================================== 3734# ============================================================================== 3735 3736 3737# ----- is_valid_key ------------------------------------------------------------- 3738def is_valid_key(key: str) -> bool: 3739 """ 3740 Returns true if key name `key` can be translated into a valid scan code. 3741 """ 3742 return key in KEYBOARD_MAPPING 3743 3744 3745isValidKey = is_valid_key 3746# ------------------------------------------------------------------------------ 3747 3748 3749# ===== scancode functions ===================================================== 3750 3751 3752# ----- scancode_keyDown ------------------------------------------------------- 3753@_genericPyDirectInputChecks 3754def scancode_keyDown( 3755 scancodes: ScancodeTypes, 3756 logScreenshot: None = None, 3757 _pause: bool = True, 3758 *, 3759 auto_shift: bool = False, 3760) -> bool: 3761 """ 3762 Press down key corresponding to `scancodes`. 3763 3764 The actually pressed key will depend on your system keyboard layout. 3765 Limits the available character set but should provide the best 3766 compatibility. 3767 3768 If `_pause` is True (default), then an automatic sleep will be performed 3769 after the function finshes executing. The duration is set by the global 3770 variable `PAUSE`. 3771 3772 `auto_shift` is used internally by higher level functions to automatically 3773 press the shift key before supported scancodes (indicitated by a special 3774 bit outside the regular scancode range, while it technically can be used, 3775 it's not intended for public access). 3776 3777 ---------------------------------------------------------------------------- 3778 3779 NOTE: `logScreenshot` is currently unsupported. 3780 """ 3781 scancodes_sequence: ScancodeSequence 3782 if isinstance(scancodes, int): 3783 scancodes_sequence = ScancodeSequence([scancodes]) 3784 else: 3785 scancodes_sequence = scancodes 3786 3787 keybdFlags: int = _KEYEVENTF_SCANCODE 3788 input_structs: list[_INPUT] = [] 3789 extendedFlag: int 3790 3791 # Init event tracking 3792 insertedEvents: int = 0 3793 expectedEvents: int = 0 3794 3795 for scancode in scancodes_sequence: 3796 if auto_shift and scancode & _OFFSET_SHIFTKEY: 3797 input_structs += [ 3798 _create_keyboard_input( 3799 wScan=_SHIFT_SCANCODE, dwFlags=keybdFlags 3800 ) 3801 ] 3802 expectedEvents += 1 3803 3804 scancode = scancode & 0xFFFF 3805 3806 extendedFlag = _KEYEVENTF_EXTENDEDKEY if scancode >= 0xE000 else 0 3807 input_structs += [ 3808 _create_keyboard_input( 3809 wScan=scancode, dwFlags=keybdFlags | extendedFlag 3810 ) 3811 ] 3812 expectedEvents += 1 3813 3814 insertedEvents += _send_input(input_structs) 3815 3816 # SendInput returns the number of event successfully inserted into 3817 # input stream 3818 # https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput#return-value 3819 return insertedEvents == expectedEvents 3820 # -------------------------------------------------------------------------- 3821 3822 3823# ----- scancode_keyUp --------------------------------------------------------- 3824@_genericPyDirectInputChecks 3825def scancode_keyUp( 3826 scancodes: ScancodeTypes, 3827 logScreenshot: None = None, 3828 _pause: bool = True, 3829 *, 3830 auto_shift: bool = False, 3831) -> bool: 3832 """ 3833 Release key corresponding to `scancodes`. 3834 3835 The actually pressed key will depend on your system keyboard layout. 3836 Limits the available character set but should provide the best 3837 compatibility. 3838 3839 If `_pause` is True (default), then an automatic sleep will be performed 3840 after the function finshes executing. The duration is set by the global 3841 variable `PAUSE`. 3842 3843 `auto_shift` is used internally by higher level functions to automatically 3844 press the shift key before supported scancodes (indicitated by a special 3845 bit outside the regular scancode range, while it technically can be used, 3846 it's not intended for public access). 3847 3848 ---------------------------------------------------------------------------- 3849 3850 NOTE: `logScreenshot` is currently unsupported. 3851 """ 3852 scancodes_sequence: ScancodeSequence 3853 if isinstance(scancodes, int): 3854 scancodes_sequence = ScancodeSequence([scancodes]) 3855 else: 3856 scancodes_sequence = scancodes 3857 3858 keybdFlags: int = _KEYEVENTF_SCANCODE | _KEYEVENTF_KEYUP 3859 input_structs: list[_INPUT] = [] 3860 extendedFlag: int 3861 3862 # Init event tracking 3863 insertedEvents: int = 0 3864 expectedEvents: int = 0 3865 3866 for scancode in scancodes_sequence: 3867 if auto_shift and scancode & _OFFSET_SHIFTKEY: 3868 input_structs += [ 3869 _create_keyboard_input( 3870 wScan=_SHIFT_SCANCODE, dwFlags=keybdFlags 3871 ) 3872 ] 3873 expectedEvents += 1 3874 3875 scancode = scancode & 0xFFFF 3876 3877 extendedFlag = _KEYEVENTF_EXTENDEDKEY if scancode >= 0xE000 else 0 3878 input_structs += [ 3879 _create_keyboard_input( 3880 wScan=scancode & 0xFFFF, dwFlags=keybdFlags | extendedFlag 3881 ) 3882 ] 3883 expectedEvents += 1 3884 3885 insertedEvents += _send_input(input_structs) 3886 return insertedEvents == expectedEvents 3887 # -------------------------------------------------------------------------- 3888 3889 3890# ----- _helper_scancode_press ------------------------------------------------- 3891def _helper_scancode_press( 3892 scancodes: ScancodeTypes, 3893 duration: float = 0.0, 3894 _pause: bool = True, 3895 auto_shift: bool = False, 3896) -> bool: 3897 """ 3898 Press `scancode`, wait for `duration` seconds, release `scancode`. 3899 3900 Return `True` if complete press was successful. 3901 """ 3902 downed: bool = scancode_keyDown( 3903 scancodes, _pause=_pause, auto_shift=auto_shift 3904 ) 3905 _sleep(duration) 3906 upped: bool = scancode_keyUp( 3907 scancodes, _pause=_pause, auto_shift=auto_shift 3908 ) 3909 # Count key press as complete if key was "downed" and "upped" 3910 # successfully 3911 return bool(downed and upped) 3912 # -------------------------------------------------------------------------- 3913 3914 3915# ----- scancode_press --------------------------------------------------------- 3916# Ignored parameters: logScreenshot 3917@_genericPyDirectInputChecks 3918def scancode_press( 3919 scancodes: ScancodeTypes | Sequence[ScancodeTypes], 3920 presses: int = 1, 3921 interval: float = 0.0, 3922 logScreenshot: None = None, 3923 _pause: bool = True, 3924 *, 3925 auto_shift: bool = False, 3926 delay: float = 0.0, 3927 duration: float = 0.0, 3928) -> bool: 3929 """ 3930 Press the sequence of `keys` for `presses` amount of times. 3931 3932 The actually pressed key will depend on your system keyboard layout. 3933 Limits the available character set but should provide the best 3934 compatibility. 3935 3936 Explanation of time parameters (seconds as floating point numbers): 3937 3938 - `interval` is the time spent waiting between sequences. If `keys` is a 3939 str instance or single element list, then `interval` will be ignored. 3940 - `delay` is the time from one complete key (press+release) to the next one 3941 in the same sequence. If there is only a single key in a sequence, then 3942 `delay` will be ignored. 3943 - `duration` is the time spent on holding every key before releasing it 3944 again. 3945 3946 If `_pause` is True (default), then an automatic sleep will be performed 3947 after the function finshes executing. The duration is set by the global 3948 variable `PAUSE`. 3949 Be aware, that the global pause defined by the PAUSE `constant` only 3950 applies after every call to this function, not inbetween (no extra pause 3951 between pressing and releasing key, use the `duration` argument instead)! 3952 3953 `auto_shift` is used internally by higher level functions to automatically 3954 press the shift key before supported scancodes (indicitated by a special 3955 bit outside the regular scancode range, while it technically can be used, 3956 it's not intended for public access). 3957 3958 ---------------------------------------------------------------------------- 3959 3960 NOTE: `logScreenshot` is currently unsupported. 3961 """ 3962 scancodes_sequence: Sequence[ScancodeTypes] 3963 if isinstance(scancodes, int): 3964 scancodes_sequence = [ScancodeSequence([scancodes])] 3965 elif isinstance(scancodes, ScancodeSequence): 3966 scancodes_sequence = [scancodes] 3967 else: 3968 scancodes_sequence = scancodes 3969 3970 # We need to press x keys y times, which comes out to x*y presses in total 3971 expectedPresses: int = presses * len(scancodes_sequence) 3972 completedPresses: int = 0 3973 3974 apply_interval: bool = False 3975 for _ in range(presses): 3976 if apply_interval: # Don't delay first press 3977 _sleep(interval) 3978 apply_interval = True 3979 3980 apply_delay: bool = False 3981 for c in scancodes_sequence: 3982 if apply_delay: # Don't delay first press 3983 _sleep(delay) 3984 apply_delay = True 3985 3986 completedPresses += _helper_scancode_press( 3987 c, duration, _pause=False, auto_shift=auto_shift 3988 ) 3989 3990 return completedPresses == expectedPresses 3991 # -------------------------------------------------------------------------- 3992 3993 3994# ----- scancode_hold ---------------------------------------------------------- 3995@contextmanager 3996@_genericPyDirectInputChecks 3997def scancode_hold( 3998 scancodes: ScancodeTypes | Sequence[ScancodeTypes], 3999 logScreenshot: None = None, 4000 _pause: bool = True, 4001 *, 4002 auto_shift: bool = False, 4003 raise_on_failure: bool = False, 4004) -> Generator[None, None, None]: 4005 """ 4006 Hold the sequence of keys corresponding to `scancodes` as long as the 4007 context manager is in scope (press upon entry, release upon exit). 4008 4009 Keys will be released in reverse order (LIFO), but still practically 4010 instantenous. 4011 4012 The actually pressed key will depend on your system keyboard layout. 4013 Limits the available character set but should provide the best 4014 compatibility. 4015 4016 If `_pause` is True (default), then an automatic sleep will be performed 4017 after the function finshes executing. The duration is set by the global 4018 variable `PAUSE`. 4019 Be aware, that the global pause defined by the PAUSE `constant` only 4020 applies after every call to this function, not inbetween (no pause between 4021 press and releasing key)! 4022 4023 `auto_shift` is used internally by higher level functions to automatically 4024 press the shift key before supported scancodes (indicitated by a special 4025 bit outside the regular scancode range, while it technically can be used, 4026 it's not intended for public access). 4027 4028 If `raise_on_failure` is True, then `PriorInputFailedException` will be 4029 raised if not all keyboard inputs could be executed successfully. 4030 4031 ---------------------------------------------------------------------------- 4032 4033 NOTE: `logScreenshot` is currently unsupported. 4034 """ 4035 scancodes_sequence: Sequence[ScancodeTypes] 4036 if isinstance(scancodes, int): 4037 scancodes_sequence = [ScancodeSequence([scancodes])] 4038 elif isinstance(scancodes, ScancodeSequence): 4039 scancodes_sequence = [scancodes] 4040 else: 4041 scancodes_sequence = scancodes 4042 4043 expectedPresses: int = len(scancodes_sequence) 4044 downed: int = 0 4045 upped: int = 0 4046 4047 try: 4048 for c in scancodes_sequence: 4049 downed += scancode_keyDown(c, _pause=False, auto_shift=auto_shift) 4050 yield 4051 finally: 4052 for c in reversed(scancodes_sequence): 4053 upped += scancode_keyUp(c, _pause=False, auto_shift=auto_shift) 4054 if raise_on_failure and not (expectedPresses == downed == upped): 4055 raise PriorInputFailedException 4056 # -------------------------------------------------------------------------- 4057 4058 4059# ----- scancode_hotkey -------------------------------------------------------- 4060@_genericPyDirectInputChecks 4061def scancode_hotkey( 4062 *args: ScancodeTypes, 4063 interval: float = 0.0, 4064 wait: float = 0.0, 4065 logScreenshot: None = None, 4066 _pause: bool = True, 4067 auto_shift: bool = True, 4068) -> bool: 4069 """ 4070 Press down buttons in order they are specified as arguments, 4071 releasing them in reverse order, e.g. 0x1D, 0x2E will first press 4072 Control, then C and release C before releasing Control. 4073 4074 Use keyword-only argument `interval` to specify a delay between single 4075 keys when pressing and releasing and `wait` for delay between last press 4076 and first release. 4077 4078 If `_pause` is True (default), then an automatic sleep will be performed 4079 after the function finshes executing. The duration is set by the global 4080 variable `PAUSE`. 4081 Be aware, that the global pause defined by the PAUSE `constant` only 4082 applies after every call to this function, not inbetween (no pause between 4083 press and releasing key)! 4084 4085 `auto_shift` is used internally by higher level functions to automatically 4086 press the shift key before supported scancodes (indicitated by a special 4087 bit outside the regular scancode range, while it technically can be used, 4088 it's not intended for public access). 4089 4090 ---------------------------------------------------------------------------- 4091 4092 NOTE: `logScreenshot` is currently unsupported. 4093 """ 4094 expectedPresses: int = len(args) 4095 downed: int = 0 4096 upped: int = 0 4097 4098 apply_interval: bool = False 4099 for code in args: 4100 if apply_interval: 4101 _sleep(interval) # sleep between iterations 4102 apply_interval = True 4103 4104 downed += scancode_keyDown(code, _pause=False, auto_shift=auto_shift) 4105 4106 _sleep(wait) 4107 4108 apply_interval = False 4109 for code in reversed(args): 4110 if apply_interval: 4111 _sleep(interval) # sleep between iterations 4112 apply_interval = True 4113 4114 upped += scancode_keyUp(code, _pause=False, auto_shift=auto_shift) 4115 4116 return expectedPresses == downed == upped 4117 # -------------------------------------------------------------------------- 4118 4119 4120# ===== keyname functions ====================================================== 4121 4122 4123# ----- keyDown ---------------------------------------------------------------- 4124# Ignored parameters: logScreenshot 4125def keyDown( 4126 key: str, 4127 logScreenshot: None = None, 4128 _pause: bool = True, 4129 *, 4130 auto_shift: bool = False, 4131) -> bool: 4132 """ 4133 Press down key corresponding to key name `key`. 4134 4135 `key` will be interpreted as a keyboard key (US QWERTY). 4136 The actually pressed key will depend on your system keyboard layout. 4137 Limits the available character set but should provide the best 4138 compatibility. 4139 4140 If `_pause` is True (default), then an automatic sleep will be performed 4141 after the function finshes executing. The duration is set by the global 4142 variable `PAUSE`. 4143 4144 If `auto_shift` is True, then "shifted" characters like upper case letters 4145 and the symbols on the number row automatically insert a Shift scancode 4146 into the input sequence. 4147 4148 ---------------------------------------------------------------------------- 4149 4150 NOTE: `logScreenshot` is currently unsupported. 4151 """ 4152 scancode: ScancodeTypes | None = KEYBOARD_MAPPING.get(key) 4153 if scancode is None: 4154 return False 4155 return scancode_keyDown( 4156 scancode, logScreenshot, _pause=_pause, auto_shift=auto_shift 4157 ) 4158 # -------------------------------------------------------------------------- 4159 4160 4161# ----- keyUp ------------------------------------------------------------------ 4162# Ignored parameters: logScreenshot 4163def keyUp( 4164 key: str, 4165 logScreenshot: None = None, 4166 _pause: bool = True, 4167 *, 4168 auto_shift: bool = False, 4169) -> bool: 4170 """ 4171 Lift up key corresponding to key name `key`. 4172 4173 `key` will be interpreted as a keyboard key (US QWERTY). 4174 The actually lifted key will depend on your system keyboard layout. 4175 Limits the available character set but should provide the best 4176 compatibility. 4177 4178 If `_pause` is True (default), then an automatic sleep will be performed 4179 after the function finshes executing. The duration is set by the global 4180 variable `PAUSE`. 4181 4182 If `auto_shift` is True, then "shifted" characters like upper case letters 4183 and the symbols on the number row automatically insert a Shift scancode 4184 into the input sequence. 4185 4186 ---------------------------------------------------------------------------- 4187 4188 NOTE: `logScreenshot` is currently unsupported. 4189 """ 4190 scancode: ScancodeTypes | None = KEYBOARD_MAPPING.get(key) 4191 if scancode is None: 4192 return False 4193 return scancode_keyUp( 4194 scancode, logScreenshot, _pause=_pause, auto_shift=auto_shift 4195 ) 4196 # -------------------------------------------------------------------------- 4197 4198 4199# ----- _helper_press ---------------------------------------------------------- 4200def _helper_press( 4201 key: str, 4202 duration: float = 0.0, 4203 _pause: bool = True, 4204 auto_shift: bool = False, 4205) -> bool: 4206 """ 4207 Press `key`, wait for `duration` seconds, release `key`. 4208 4209 Return `True` if complete press was successful. 4210 """ 4211 downed: bool = keyDown(key, _pause=_pause, auto_shift=auto_shift) 4212 _sleep(duration) 4213 upped: bool = keyUp(key, _pause=_pause, auto_shift=auto_shift) 4214 # Count key press as complete if key was "downed" and "upped" 4215 # successfully 4216 return bool(downed and upped) 4217 # -------------------------------------------------------------------------- 4218 4219 4220# ----- press ------------------------------------------------------------------ 4221# Ignored parameters: logScreenshot 4222@_genericPyDirectInputChecks 4223def press( 4224 keys: str | Sequence[str], 4225 presses: int = 1, 4226 interval: float = 0.0, 4227 logScreenshot: None = None, 4228 _pause: bool = True, 4229 *, 4230 auto_shift: bool = False, 4231 delay: float = 0.0, 4232 duration: float = 0.0, 4233) -> bool: 4234 """ 4235 Press the sequence of `keys` for `presses` amount of times. 4236 4237 `keys` will be interpreted as sequence of keyboard keys (US QWERTY). 4238 The actually pressed key will depend on your system keyboard layout. 4239 Limits the available character set but should provide the best 4240 compatibility. 4241 4242 Explanation of time parameters (seconds as floating point numbers): 4243 4244 - `interval` is the time spent waiting between sequences. If `keys` is a 4245 str instance, single element list or presses equals 1 (the default), 4246 then `interval` will be ignored. 4247 - `delay` is the time from one complete key (press+release) to the next one 4248 in the same sequence. If there is only a single key in a sequence, then 4249 `delay` will be ignored. 4250 - `duration` is the time spent on holding every key before releasing it 4251 again. 4252 4253 If `_pause` is True (default), then an automatic sleep will be performed 4254 after the function finshes executing. The duration is set by the global 4255 variable `PAUSE`. 4256 Be aware, that the global pause defined by the `PAUSE` var only applies 4257 after every call to this function, not inbetween (no extra pause between 4258 pressing and releasing key, use the `duration` argument instead)! 4259 4260 If `auto_shift` is True, then "shifted" characters like upper case letters 4261 and the symbols on the number row automatically insert a Shift scancode 4262 into the input sequence. 4263 4264 ---------------------------------------------------------------------------- 4265 4266 NOTE: `logScreenshot` is currently unsupported. 4267 """ 4268 if isinstance(keys, str): 4269 keys = [keys] # If keys is 'enter', convert it to ['enter']. 4270 keys = [_normalize_key(key, auto_shift=auto_shift) for key in keys] 4271 4272 # We need to press x keys y times, which comes out to x*y presses in total 4273 expectedPresses: int = presses * len(keys) 4274 completedPresses: int = 0 4275 4276 apply_interval: bool = False 4277 for _ in range(presses): 4278 if apply_interval: # Don't delay first press 4279 _sleep(interval) 4280 apply_interval = True 4281 4282 apply_delay: bool = False 4283 for k in keys: 4284 if apply_delay: # Don't delay first press 4285 _sleep(delay) 4286 apply_delay = True 4287 4288 completedPresses += _helper_press( 4289 k, duration, _pause=False, auto_shift=auto_shift 4290 ) 4291 4292 return completedPresses == expectedPresses 4293 # -------------------------------------------------------------------------- 4294 4295 4296# ----- hold ------------------------------------------------------------------- 4297@contextmanager 4298@_genericPyDirectInputChecks 4299def hold( 4300 keys: str | Sequence[str], 4301 logScreenshot: None = None, 4302 _pause: bool = True, 4303 *, 4304 auto_shift: bool = False, 4305 raise_on_failure: bool = False, 4306) -> Generator[None, None, None]: 4307 """ 4308 Hold the sequence of keys corresponding to key names in `keys` as long as 4309 the context manager is in scope (press upon entry, release upon exit). 4310 4311 Keys will be released in reverse order (LIFO), but still practically 4312 instantenous. 4313 4314 `key` will be interpreted as a keyboard key (US QWERTY). 4315 The actually pressed key will depend on your system keyboard layout. 4316 Limits the available character set but should provide the best 4317 compatibility. 4318 4319 If `_pause` is True (default), then an automatic sleep will be performed 4320 after the function finshes executing. The duration is set by the global 4321 variable `PAUSE`. 4322 Be aware, that the global pause defined by the PAUSE `constant` only 4323 applies after every call to this function, not inbetween (no pause between 4324 press and releasing key)! 4325 4326 `auto_shift` is used internally by higher level functions to automatically 4327 press the shift key before supported scancodes (indicitated by a special 4328 bit outside the regular scancode range, while it technically can be used, 4329 it's not intended for public access). 4330 4331 If `raise_on_failure` is True, then `PriorInputFailedException` will be 4332 raised if not all keyboard inputs could be executed successfully. 4333 4334 ---------------------------------------------------------------------------- 4335 4336 NOTE: `logScreenshot` is currently unsupported. 4337 """ 4338 if isinstance(keys, str): 4339 keys = [keys] # make single element into iterable 4340 keys = [_normalize_key(key, auto_shift=auto_shift) for key in keys] 4341 4342 expectedPresses: int = len(keys) 4343 downed: int = 0 4344 upped: int = 0 4345 4346 try: 4347 for k in keys: 4348 downed += keyDown(k, auto_shift=auto_shift) 4349 yield 4350 finally: 4351 for k in reversed(keys): 4352 upped += keyUp(k, auto_shift=auto_shift) 4353 if raise_on_failure and not (expectedPresses == downed == upped): 4354 raise PriorInputFailedException 4355 # -------------------------------------------------------------------------- 4356 4357 4358# ----- typewrite -------------------------------------------------------------- 4359@_genericPyDirectInputChecks 4360def typewrite( 4361 message: str, 4362 interval: float = 0.0, 4363 logScreenshot: None = None, 4364 _pause: bool = True, 4365 *, 4366 auto_shift: bool = False, 4367 delay: float = 0.0, 4368 duration: float = 0.0, 4369) -> None: 4370 """ 4371 Break down `message` into a single character key sequence and press each 4372 key one by one. 4373 4374 `message` will be interpreted as sequence of keyboard keys (US QWERTY). 4375 The actually pressed keys will depend on your system keyboard layout. 4376 Limits the available character set but should provide the best 4377 compatibility. 4378 4379 Explanation of time parameters (seconds as floating point numbers): 4380 4381 - `interval` is the time spent waiting between sequences. If `message` is a 4382 single character string, then `interval` will be ignored. 4383 - `delay` is the time from one complete key (press+release) to the next one 4384 in the same sequence. If there is only a single key in a sequence, then 4385 `delay` will be ignored. 4386 - `duration` is the time spent on holding every key before releasing it 4387 again. 4388 4389 If `_pause` is True (default), then an automatic sleep will be performed 4390 after the function finshes executing. The duration is set by the global 4391 variable `PAUSE`. 4392 Be aware, that the global pause defined by the PAUSE `constant` only 4393 applies after every call to this function, not inbetween (no pause between 4394 press and releasing key)! 4395 4396 `auto_shift` is used internally by higher level functions to automatically 4397 press the shift key before supported scancodes (indicitated by a special 4398 bit outside the regular scancode range, while it technically can be used, 4399 it's not intended for public access). 4400 4401 ---------------------------------------------------------------------------- 4402 4403 NOTE: `logScreenshot` is currently unsupported. 4404 """ 4405 4406 apply_interval: bool = False 4407 for key in message: 4408 if apply_interval: # Don't delay first press 4409 _sleep(interval) 4410 apply_interval = True 4411 4412 press( 4413 key, 4414 _pause=False, 4415 auto_shift=auto_shift, 4416 delay=delay, 4417 duration=duration, 4418 ) 4419 # -------------------------------------------------------------------------- 4420 4421 4422# ----- typewrite alias -------------------------------------------------------- 4423write = typewrite 4424# ------------------------------------------------------------------------------ 4425 4426 4427# ----- hotkey ----------------------------------------------------------------- 4428# Originally implemented by 4429# https://github.com/learncodebygaming/pydirectinput/pull/30 4430@_genericPyDirectInputChecks 4431def hotkey( 4432 *args: str, 4433 interval: float = 0.0, 4434 wait: float = 0.0, 4435 logScreenshot: None = None, 4436 _pause: bool = True, 4437 auto_shift: bool = True, 4438) -> None: 4439 """ 4440 Press down buttons in order they are specified as arguments, 4441 releasing them in reverse order, e.g. 'ctrl', 'c' will first press 4442 Control, then C and release C before releasing Control. 4443 4444 Use keyword-only argument `interval` to specify a delay between single 4445 keys when pressing and releasing and `wait` for delay between last press 4446 and first release. 4447 4448 If `_pause` is True (default), then an automatic sleep will be performed 4449 after the function finshes executing. The duration is set by the global 4450 variable `PAUSE`. 4451 Be aware, that the global pause defined by the PAUSE `constant` only 4452 applies after every call to this function, not inbetween (no pause between 4453 press and releasing key)! 4454 4455 `auto_shift` is used internally by higher level functions to automatically 4456 press the shift key before supported scancodes (indicitated by a special 4457 bit outside the regular scancode range, while it technically can be used, 4458 it's not intended for public access). 4459 4460 ---------------------------------------------------------------------------- 4461 4462 NOTE: `logScreenshot` is currently unsupported. 4463 """ 4464 apply_interval: bool = False 4465 for key in args: 4466 if apply_interval: 4467 _sleep(interval) # sleep between iterations 4468 apply_interval = True 4469 4470 keyDown(key, _pause=False, auto_shift=auto_shift) 4471 4472 _sleep(wait) 4473 4474 apply_interval = False 4475 for key in reversed(args): 4476 if apply_interval: 4477 _sleep(interval) # sleep between iterations 4478 apply_interval = True 4479 4480 keyUp(key, _pause=False, auto_shift=auto_shift) 4481 # -------------------------------------------------------------------------- 4482 4483 4484# ===== unicode functions ====================================================== 4485 4486 4487# ----- unicode_charDown ------------------------------------------------------- 4488@_genericPyDirectInputChecks 4489def unicode_charDown( 4490 char: str, logScreenshot: None = None, _pause: bool = True 4491) -> bool: 4492 """ 4493 Send Unicode character(s) `char` to currently focused application as 4494 WM_KEYDOWN message. 4495 4496 `char` will be interpreted as a string of Unicode characters 4497 (independet from keyboard layout). Supports complete Unicode character set 4498 but may not be compatible with every application. 4499 4500 If `_pause` is True (default), then an automatic sleep will be performed 4501 after the function finshes executing. The duration is set by the global 4502 variable `PAUSE`. 4503 4504 ---------------------------------------------------------------------------- 4505 4506 NOTE: `logScreenshot` is currently unsupported. 4507 """ 4508 utf16surrogates: bytes = char.encode("utf-16be") 4509 codes: Sequence[int] = unpack( 4510 f">{len(utf16surrogates) // 2}H", utf16surrogates 4511 ) 4512 4513 keybdFlags: int = _KEYEVENTF_UNICODE 4514 4515 input_structs: list[_INPUT] = [ 4516 _create_keyboard_input(wVk=0, wScan=charcode, dwFlags=keybdFlags) 4517 for charcode in codes 4518 ] 4519 # Init event tracking 4520 expectedEvents: int = len(input_structs) 4521 insertedEvents: int = _send_input(input_structs) 4522 4523 return insertedEvents == expectedEvents 4524 # -------------------------------------------------------------------------- 4525 4526 4527# ----- unicode_charUp --------------------------------------------------------- 4528@_genericPyDirectInputChecks 4529def unicode_charUp( 4530 char: str, logScreenshot: None = None, _pause: bool = True 4531) -> bool: 4532 """ 4533 Send Unicode character(s) `char` to currently focused application as 4534 WM_KEYUP message. 4535 4536 `char` will be interpreted as a string of Unicode characters 4537 (independet from keyboard layout). Supports complete Unicode character set 4538 but may not be compatible with every application. 4539 4540 If `_pause` is True (default), then an automatic sleep will be performed 4541 after the function finshes executing. The duration is set by the global 4542 variable `PAUSE`. 4543 4544 ---------------------------------------------------------------------------- 4545 4546 NOTE: `logScreenshot` is currently unsupported. 4547 """ 4548 utf16surrogates: bytes = char.encode("utf-16be") 4549 codes: Sequence[int] = unpack( 4550 f">{len(utf16surrogates) // 2}H", utf16surrogates 4551 ) 4552 4553 keybdFlags: int = _KEYEVENTF_UNICODE | _KEYEVENTF_KEYUP 4554 4555 input_structs: list[_INPUT] = [ 4556 _create_keyboard_input(wVk=0, wScan=charcode, dwFlags=keybdFlags) 4557 for charcode in codes 4558 ] 4559 # Init event tracking 4560 expectedEvents: int = len(input_structs) 4561 insertedEvents: int = _send_input(input_structs) 4562 4563 return insertedEvents == expectedEvents 4564 # -------------------------------------------------------------------------- 4565 4566 4567# ----- _helper_unicode_press_char --------------------------------------------- 4568def _helper_unicode_press_char( 4569 char: str, 4570 duration: float = 0.0, 4571 _pause: bool = True, 4572) -> bool: 4573 """ 4574 Press `key`, wait for `duration` seconds, release `key`. 4575 4576 Return `True` if complete press was successful. 4577 """ 4578 downed: bool = unicode_charDown(char, _pause=_pause) 4579 _sleep(duration) 4580 upped: bool = unicode_charUp(char, _pause=_pause) 4581 # Count key press as complete if key was "downed" and "upped" 4582 # successfully 4583 return bool(downed and upped) 4584 # -------------------------------------------------------------------------- 4585 4586 4587# ----- unicode_press ---------------------------------------------------------- 4588@_genericPyDirectInputChecks 4589def unicode_press( 4590 chars: str | Sequence[str], 4591 presses: int = 1, 4592 interval: float = 0.0, 4593 logScreenshot: None = None, 4594 _pause: bool = True, 4595 *, 4596 delay: float = 0.0, 4597 duration: float = 0.0, 4598) -> bool: 4599 """ 4600 Press the sequence of `chars` for `presses` amount of times. 4601 4602 `chars` will be interpreted as a sequence of Unicode characters 4603 (independent from keyboard layout). Supports complete Unicode character set 4604 but may not be compatible with every application. 4605 4606 Explanation of time parameters (seconds as floating point numbers): 4607 4608 - `interval` is the time spent waiting between sequences. If `chars` is a 4609 str instance or single element list, then `interval` will be ignored. 4610 - `delay` is the time from one complete char (press+release) to the next 4611 one in the same sequence. If there is only a single char in a sequence, 4612 then `delay` will be ignored. 4613 - `duration` is the time spent on holding every char before releasing it 4614 again. 4615 4616 If `_pause` is True (default), then an automatic sleep will be performed 4617 after the function finshes executing. The duration is set by the global 4618 variable `PAUSE`. 4619 Be aware, that the global pause defined by the PAUSE `constant` only 4620 applies after every call to this function, not inbetween (no extra pause 4621 between pressing and releasing key, use the `duration` argument instead)! 4622 4623 ---------------------------------------------------------------------------- 4624 4625 NOTE: `logScreenshot` is currently unsupported. 4626 """ 4627 if isinstance(chars, str): 4628 chars = [chars] 4629 4630 # We need to press x keys y times, which comes out to x*y presses in total 4631 expectedPresses: int = presses * len(chars) 4632 completedPresses: int = 0 4633 4634 apply_interval: bool = False 4635 for _ in range(presses): 4636 if apply_interval: # Don't delay first press 4637 _sleep(interval) 4638 apply_interval = True 4639 4640 apply_delay: bool = False 4641 for c in chars: 4642 if apply_delay: # Don't delay first press 4643 _sleep(delay) 4644 apply_delay = True 4645 4646 completedPresses += _helper_unicode_press_char( 4647 c, 4648 duration, 4649 _pause=False, 4650 ) 4651 4652 return completedPresses == expectedPresses 4653 # -------------------------------------------------------------------------- 4654 4655 4656# ----- unicode_hold ----------------------------------------------------------- 4657@contextmanager 4658@_genericPyDirectInputChecks 4659def unicode_hold( 4660 chars: str | Sequence[str], 4661 logScreenshot: None = None, 4662 _pause: bool = True, 4663 *, 4664 raise_on_failure: bool = False, 4665) -> Generator[None, None, None]: 4666 """ 4667 Hold the sequence of "keys" corresponding to unicode characters in `chars` 4668 as long as the context manager is in scope (press upon entry, 4669 release upon exit). 4670 4671 `chars` will be interpreted as a sequence of Unicode characters 4672 (independet from keyboard layout). Supports complete Unicode character set 4673 but may not be compatible with every application. 4674 4675 Keys will be released in reverse order (LIFO), but still practically 4676 instantenous. 4677 4678 If `_pause` is True (default), then an automatic sleep will be performed 4679 after the function finshes executing. The duration is set by the global 4680 variable `PAUSE`. 4681 Be aware, that the global pause defined by the PAUSE `constant` only 4682 applies after every call to this function, not inbetween (no pause between 4683 press and releasing key)! 4684 4685 If `raise_on_failure` is True, then `PriorInputFailedException` will be 4686 raised if not all keyboard inputs could be executed successfully. 4687 4688 ---------------------------------------------------------------------------- 4689 4690 NOTE: `logScreenshot` is currently unsupported. 4691 """ 4692 if isinstance(chars, str): 4693 chars = [chars] # make single element into iterable 4694 4695 expectedPresses: int = len(chars) 4696 downed: int = 0 4697 upped: int = 0 4698 4699 try: 4700 for c in chars: 4701 downed += unicode_charDown(c, _pause=False) 4702 yield 4703 finally: 4704 for c in reversed(chars): 4705 upped += unicode_charUp(c, _pause=False) 4706 if raise_on_failure and not (expectedPresses == downed == upped): 4707 raise PriorInputFailedException 4708 # -------------------------------------------------------------------------- 4709 4710 4711# ----- unicode_typewrite ------------------------------------------------------ 4712@_genericPyDirectInputChecks 4713def unicode_typewrite( 4714 message: str, 4715 interval: float = 0.0, 4716 logScreenshot: None = None, 4717 _pause: bool = True, 4718 *, 4719 delay: float = 0.0, 4720 duration: float = 0.0, 4721) -> None: 4722 """ 4723 Break down `message` into characters and press them one by one. 4724 4725 `message` will be interpreted as a sequence of Unicode characters 4726 (independet from keyboard layout). Supports complete Unicode character set 4727 but may not be compatible with every application. 4728 4729 Explanation of time parameters (seconds as floating point numbers): 4730 4731 - `interval` is the time spent waiting between sequences. If `message` is a 4732 single character string, then `interval` will be ignored. 4733 - `delay` is the time from one complete key (press+release) to the next one 4734 in the same sequence. If there is only a single key in a sequence, then 4735 `delay` will be ignored. 4736 - `duration` is the time spent on holding every key before releasing it 4737 again. 4738 4739 If `_pause` is True (default), then an automatic sleep will be performed 4740 after the function finshes executing. The duration is set by the global 4741 variable `PAUSE`. 4742 Be aware, that the global pause defined by the PAUSE `constant` only 4743 applies after every call to this function, not inbetween (no pause between 4744 press and releasing key)! 4745 4746 ---------------------------------------------------------------------------- 4747 4748 NOTE: `logScreenshot` is currently unsupported. 4749 """ 4750 apply_interval: bool = False 4751 for char in message: 4752 if apply_interval: 4753 _sleep(interval) # sleep between iterations 4754 apply_interval = True 4755 4756 unicode_press(char, _pause=False, delay=delay, duration=duration) 4757 # -------------------------------------------------------------------------- 4758 4759 4760# ----- unicode_typewrite alias ------------------------------------------------ 4761unicode_write = unicode_typewrite 4762# ------------------------------------------------------------------------------ 4763 4764 4765# ----- unicode_hotkey --------------------------------------------------------- 4766@_genericPyDirectInputChecks 4767def unicode_hotkey( 4768 *args: str, 4769 interval: float = 0.0, 4770 wait: float = 0.0, 4771 logScreenshot: None = None, 4772 _pause: bool = True, 4773) -> None: 4774 """ 4775 Press down buttons in order they are specified as arguments, 4776 releasing them in reverse order. 4777 4778 This function makes little sense for Unicode characters and mainly exists 4779 for parity with the other, lower-level hotkey functions! 4780 4781 See `unicode_press()` for an alternative function that presses keys in 4782 series instead. 4783 4784 Use keyword-only argument `interval` to specify a delay between single 4785 keys when pressing and releasing and `wait` for delay between last press 4786 and first release. 4787 4788 If `_pause` is True (default), then an automatic sleep will be performed 4789 after the function finshes executing. The duration is set by the global 4790 variable `PAUSE`. 4791 Be aware, that the global pause defined by the PAUSE `constant` only 4792 applies after every call to this function, not inbetween (no pause between 4793 press and releasing key)! 4794 4795 ---------------------------------------------------------------------------- 4796 4797 NOTE: `logScreenshot` is currently unsupported. 4798 """ 4799 apply_interval: bool = False 4800 for char in args: 4801 if apply_interval: 4802 _sleep(interval) # sleep between iterations 4803 apply_interval = True 4804 4805 unicode_charDown(char, _pause=False) 4806 4807 _sleep(wait) 4808 4809 apply_interval = False 4810 for char in reversed(args): 4811 if apply_interval: 4812 _sleep(interval) # sleep between iterations 4813 apply_interval = True 4814 4815 unicode_charUp(char, _pause=False) 4816 # -------------------------------------------------------------------------- 4817 4818 4819# ------------------------------------------------------------------------------ 4820# Save current Enhanced Pointer Precsion setting during import 4821# unless disabled by environment variable. 4822# Since this is a safety feature, this import side-effect is enabled by default. 4823if not os.environ.get("PYDIRECTINPUT_SKIP_STORING_MOUSE_SETTINGS"): 4824 store_mouse_acceleration_settings() 4825# ------------------------------------------------------------------------------
Stop execution if mouse is moved into one of FAILSAFE_POINTS.
Change to disable failsafe behaviour.
List of coordinates that trigger failafe exception. (default: top left corner)
Default pause interval in seconds if _pause argument isn't set to False. 1/100 second pause by default.
Set to None to disable automatic pauses entirely.
Extremely small timer interval greater than 0 that still causes the system to
sleep. This is the ideal value, the system may not be able to sleep for this
short of a time. See MINIMUM_SLEEP_ACTUAL and calibrate_real_sleep_minimum.
Actual time spent on sleeping with MINIMUM_SLEEP_IDEAL, rounded up for safety.
Determined ahead of time by calibrate_real_sleep_minimum. The MINIMUM_SLEEP_
values may differ between systems. If you're unsure, run the calibration
and correct this value after importing the module.
Name of left mouse button
Name of middle mouse button
Name of right mouse button
Name of primary mouse button (left mouse button unless swapped)
Name of secondary mouse button (right mouse button unless swapped)
Name of first additional mouse button (usually a side button)
Name of first additional mouse button (usually a side button)
Name of second additional mouse button (usually a side button)
Name of second additional mouse button (usually a side button)
209def calibrate_real_sleep_minimum( 210 runs: int = 10, *, verbose: bool = False 211) -> None: 212 """ 213 Measure your system's minimum sleep duration and calibrate 214 `MINIMUM_SLEEP_ACTUAL` accordingly. 215 216 Will try to sleep for `MINIMUM_SLEEP_IDEAL` seconds and measure actual time 217 difference. Repeat for `runs` amount of times, take the highest measurement 218 and round it up to the next higher value in the same order of magnitude. 219 220 Example: [0.001874, 0.001721, 0.001806] would round up to 0.002 221 """ 222 223 def round_up_same_magnitude(x: float) -> float: 224 mag: float = 10 ** floor(log10(x)) 225 return ceil(x / mag) * mag 226 227 def stopwatch(duration: float) -> float: 228 t1: int = _time_ns() 229 _sleep(duration) 230 t2: int = _time_ns() 231 return (t2 - t1) * 1e-9 232 233 if verbose: 234 print("Calibrating real sleep minimum...") 235 236 measurements = [stopwatch(MINIMUM_SLEEP_IDEAL) for _ in range(runs)] 237 if verbose: 238 print(f"Real measurements: {measurements}") 239 240 new_sleep_minimum = round_up_same_magnitude(max(measurements)) 241 if verbose: 242 print( 243 "Rounding max measurement to next higher value in same order of " 244 f"magnitude: {new_sleep_minimum}" 245 ) 246 247 global MINIMUM_SLEEP_ACTUAL 248 if verbose: 249 print( 250 f"Changing MINIMUM_SLEEP_ACTUAL from {MINIMUM_SLEEP_ACTUAL} to " 251 f"{new_sleep_minimum}" 252 ) 253 MINIMUM_SLEEP_ACTUAL = ( # pyright: ignore[reportConstantRedefinition] 254 new_sleep_minimum 255 ) 256 # --------------------------------------------------------------------------
Measure your system's minimum sleep duration and calibrate
MINIMUM_SLEEP_ACTUAL accordingly.
Will try to sleep for MINIMUM_SLEEP_IDEAL seconds and measure actual time
difference. Repeat for runs amount of times, take the highest measurement
and round it up to the next higher value in the same order of magnitude.
Example: [0.001874, 0.001721, 0.001806] would round up to 0.002
614def update_MOUSEEVENT_mappings() -> None: 615 """ 616 Update the MOUSEEVENT mappings if you change the name of the button name 617 constants. 618 619 This function MUST be called every time one of the `MOUSE_*` constants 620 has been changed! 621 """ 622 _MOUSE_MAPPING_EVENTF.update( 623 { 624 MOUSE_LEFT: _MOUSEEVENTF_LEFT, 625 MOUSE_MIDDLE: _MOUSEEVENTF_MIDDLE, 626 MOUSE_RIGHT: _MOUSEEVENTF_RIGHT, 627 MOUSE_BUTTON4: _MOUSEEVENTF_X, 628 MOUSE_X1: _MOUSEEVENTF_X, 629 MOUSE_BUTTON5: _MOUSEEVENTF_X, 630 MOUSE_X2: _MOUSEEVENTF_X, 631 } 632 ) 633 _MOUSE_MAPPING_DATA.update( 634 { 635 MOUSE_LEFT: 0, 636 MOUSE_MIDDLE: 0, 637 MOUSE_RIGHT: 0, 638 MOUSE_BUTTON4: _XBUTTON1, 639 MOUSE_X1: _XBUTTON1, 640 MOUSE_BUTTON5: _XBUTTON2, 641 MOUSE_X2: _XBUTTON2, 642 } 643 )
Update the MOUSEEVENT mappings if you change the name of the button name constants.
This function MUST be called every time one of the MOUSE_* constants
has been changed!
1546class ScancodeSequence(List[int]): 1547 """ 1548 A special class with the sole purpose of representing extended scancode 1549 sequences that should be grouped together in a single INPUT array. 1550 1551 Inserting non-scancode elements is illegal, but no runtime checks exist 1552 to verify correct input! Violations could lead to unpredictable runtime 1553 behaviour. You've been warned. 1554 """ 1555 1556 pass 1557 # --------------------------------------------------------------------------
A special class with the sole purpose of representing extended scancode sequences that should be grouped together in a single INPUT array.
Inserting non-scancode elements is illegal, but no runtime checks exist to verify correct input! Violations could lead to unpredictable runtime behaviour. You've been warned.
Acceptable value types in KEYBOARD_MAPPING.
Accepts single standalone scancode integer or multiple scancode integers contained in a special class ScancodeSequence instance.
Maps a string representation of keyboard keys to their corresponding hardware scan code. Based on standard US QWERTY-Layout.
Not intended to be changed at runtime!
If you want to change the keyboard mapping to better reflect your own keyboard
layout, use KEYBOARD_MAPPING.update(your_dict) where your_dict is a dict
that maps keynames to scancodes.
Maps a string representation of keyboard keys to their corresponding hardware scan code. Based on standard US QWERTY-Layout by default.
If you want to change the keyboard mapping to better reflect your own keyboard
layout, use KEYBOARD_MAPPING.update(your_dict), where your_dict is a dict
that maps keynames to scancodes.
1853class FailSafeException(Exception): 1854 """Raised when _failSafeCheck detects failsafe mouse position.""" 1855 1856 pass
Raised when _failSafeCheck detects failsafe mouse position.
1859class PriorInputFailedException(Exception): 1860 """Raised in hold() context managers when raise_on_failure is set.""" 1861 1862 pass 1863 # --------------------------------------------------------------------------
Raised in hold() context managers when raise_on_failure is set.
2071def position( 2072 x: int | float | None = None, y: int | float | None = None 2073) -> tuple[int, int]: 2074 """ 2075 Return a postion tuple `(x, y)`. 2076 2077 If x and/or y argument(s) are not given, use current mouse cursor coordinate 2078 instead. 2079 """ 2080 cursor: _POINT = _get_cursor_pos() 2081 return ( 2082 cursor.x if x is None else int(x), 2083 cursor.y if y is None else int(y), 2084 ) 2085 # --------------------------------------------------------------------------
Return a postion tuple (x, y).
If x and/or y argument(s) are not given, use current mouse cursor coordinate instead.
2089def size() -> tuple[int, int]: 2090 """ 2091 Return the size of the primary display as tuple `(width, height)`. 2092 """ 2093 return ( 2094 _get_system_metrics(_SM_CXSCREEN), 2095 _get_system_metrics(_SM_CYSCREEN), 2096 ) 2097 # --------------------------------------------------------------------------
Return the size of the primary display as tuple (width, height).
2101def virtual_size() -> tuple[int, int, int, int]: 2102 """ 2103 Return the the display size of the complete virtual monitor bounding box 2104 rectangle as tuple `(width, height, left_offset, top_offset)`. 2105 2106 On a single monitor system, this function is equal to `(*size(), 0, 0)`. 2107 2108 `left_offset` and `top_offset` are measured from the top left pixel of the 2109 primary monitor. 2110 """ 2111 return ( 2112 _get_system_metrics(_SM_CXVIRTUALSCREEN), 2113 _get_system_metrics(_SM_CYVIRTUALSCREEN), 2114 _get_system_metrics(_SM_XVIRTUALSCREEN), 2115 _get_system_metrics(_SM_YVIRTUALSCREEN), 2116 ) 2117 # --------------------------------------------------------------------------
Return the the display size of the complete virtual monitor bounding box
rectangle as tuple (width, height, left_offset, top_offset).
On a single monitor system, this function is equal to (*size(), 0, 0).
left_offset and top_offset are measured from the top left pixel of the
primary monitor.
2135def on_primary_monitor( 2136 x: int | tuple[int, int] | None = None, 2137 y: int | None = None, 2138) -> bool: 2139 """ 2140 Returns whether the given xy coordinates are on the primary screen or not. 2141 2142 If x and/or y argument(s) are not given, current mouse cursor coordinates 2143 will be used instead. 2144 """ 2145 _x: int | None 2146 _y: int | None 2147 if isinstance(x, Sequence): 2148 assert not isinstance(x, int) # remove int annotation, mypy needs this 2149 if y is not None: 2150 raise ValueError( 2151 "onScreen() does not accept Sequence-types as first argument " 2152 "if a second argument is also provided!" 2153 ) 2154 try: 2155 _x, _y = x[0], x[1] 2156 except IndexError as e: 2157 raise ValueError( 2158 "onScreen() does not accept single element sequences " 2159 "as first argument!" 2160 ) from e 2161 else: 2162 _x, _y = x, y 2163 2164 x, y = position(_x, _y) 2165 display_width: int 2166 display_height: int 2167 display_width, display_height = size() 2168 2169 return 0 <= x < display_width and 0 <= y < display_height
Returns whether the given xy coordinates are on the primary screen or not.
If x and/or y argument(s) are not given, current mouse cursor coordinates will be used instead.
2135def on_primary_monitor( 2136 x: int | tuple[int, int] | None = None, 2137 y: int | None = None, 2138) -> bool: 2139 """ 2140 Returns whether the given xy coordinates are on the primary screen or not. 2141 2142 If x and/or y argument(s) are not given, current mouse cursor coordinates 2143 will be used instead. 2144 """ 2145 _x: int | None 2146 _y: int | None 2147 if isinstance(x, Sequence): 2148 assert not isinstance(x, int) # remove int annotation, mypy needs this 2149 if y is not None: 2150 raise ValueError( 2151 "onScreen() does not accept Sequence-types as first argument " 2152 "if a second argument is also provided!" 2153 ) 2154 try: 2155 _x, _y = x[0], x[1] 2156 except IndexError as e: 2157 raise ValueError( 2158 "onScreen() does not accept single element sequences " 2159 "as first argument!" 2160 ) from e 2161 else: 2162 _x, _y = x, y 2163 2164 x, y = position(_x, _y) 2165 display_width: int 2166 display_height: int 2167 display_width, display_height = size() 2168 2169 return 0 <= x < display_width and 0 <= y < display_height
Returns whether the given xy coordinates are on the primary screen or not.
If x and/or y argument(s) are not given, current mouse cursor coordinates will be used instead.
2188def valid_screen_coordinates( 2189 x: int | tuple[int, int] | None = None, y: int | None = None 2190) -> bool: 2191 """ 2192 Returns whether the given xy coordinates are on a real monitor or not. 2193 2194 If x and/or y argument(s) are not given, current mouse cursor coordinates 2195 will be used instead. 2196 """ 2197 _x: int | None 2198 _y: int | None 2199 if isinstance(x, Sequence): 2200 assert not isinstance(x, int) # remove int annotation, mypy needs this 2201 if y is not None: 2202 raise ValueError( 2203 "onScreen() does not accept Sequence-types as first argument " 2204 "if a second argument is also provided!" 2205 ) 2206 try: 2207 _x, _y = x[0], x[1] 2208 except IndexError as e: 2209 raise ValueError( 2210 "onScreen() does not accept single element sequences " 2211 "as first argument!" 2212 ) from e 2213 else: 2214 _x, _y = x, y 2215 2216 x, y = position(_x, _y) 2217 return _monitor_from_point(x, y) is not None 2218 # --------------------------------------------------------------------------
Returns whether the given xy coordinates are on a real monitor or not.
If x and/or y argument(s) are not given, current mouse cursor coordinates will be used instead.
2355def store_mouse_acceleration_settings() -> None: 2356 """ 2357 Manually save the current Windows Enhanced Pointer Precision setting so 2358 that it can be restored later with `restore_mouse_acceleration_settings()`. 2359 """ 2360 precision: int 2361 _, _, precision = _get_mouse_parameters() 2362 speed: int = _get_mouse_speed() 2363 __MouseSpeedSettings.set_manual_mouse_settings(precision, speed) 2364 # --------------------------------------------------------------------------
Manually save the current Windows Enhanced Pointer Precision setting so
that it can be restored later with restore_mouse_acceleration_settings().
2368def restore_mouse_acceleration_settings() -> None: 2369 """ 2370 Manually restore the current Windows Enhanced Pointer Precision setting to 2371 what it was beforehand when it was saved with 2372 `store_mouse_acceleration_settings()`. 2373 """ 2374 precision: int | None 2375 speed: int | None 2376 precision, speed = __MouseSpeedSettings.get_manual_mouse_settings() 2377 if precision is None or speed is None: 2378 raise ValueError( 2379 "Can't restore Enhanced Pointer Precision setting! " 2380 "Setting was not saved beforehand!" 2381 ) 2382 th1: int 2383 th2: int 2384 th1, th2, _ = _get_mouse_parameters() 2385 _set_mouse_parameters(th1, th2, precision) 2386 _set_mouse_speed(speed) 2387 # --------------------------------------------------------------------------
Manually restore the current Windows Enhanced Pointer Precision setting to
what it was beforehand when it was saved with
store_mouse_acceleration_settings().
2396@_genericPyDirectInputChecks 2397def mouseDown( 2398 x: int | None = None, 2399 y: int | None = None, 2400 button: str = MOUSE_PRIMARY, 2401 duration: float = 0.0, 2402 tween: Callable[[float], float] | None = None, 2403 logScreenshot: bool = False, 2404 _pause: bool = True, 2405 *, 2406 relative: bool = False, 2407 virtual: bool = False, 2408 path_function: PathFunction | None = None, 2409 attempt_pixel_perfect: bool = False, 2410 disable_mouse_acceleration: bool = False, 2411) -> None: 2412 """ 2413 Press down mouse button `button`. 2414 2415 If `x` or `y` are given and not None, then the mouse will move the 2416 indicated postion before pressing the button. 2417 2418 `button` is the name of the button to press. Use the public `MOUSE_*` 2419 constants to get valid argument values. (If you change the constants, then 2420 you will have to call `update_MOUSEEVENT_mappings()` to resync the lookup 2421 functions) 2422 2423 If `_pause` is True (default), then an automatic sleep will be performed 2424 after the function finshes executing. The duration is set by the global 2425 variable `PAUSE`. 2426 2427 `duration`, `tween`, `relative`, `virtual`, `path_function`, 2428 `attempt_pixel_perfect`, `disable_mouse_acceleration` are only relevant 2429 if x or y are given. 2430 See `moveTo()` for further information. 2431 2432 Raises `ValueError` if `button` is not a valid mouse button name. 2433 2434 ---------------------------------------------------------------------------- 2435 2436 NOTE: `logScreenshot` is currently unsupported. 2437 """ 2438 # TODO: bounding box check for valid position 2439 if x is not None or y is not None: 2440 moveTo( 2441 x, 2442 y, 2443 duration=duration, 2444 tween=tween, 2445 logScreenshot=logScreenshot, 2446 _pause=False, # don't add an additional pause 2447 relative=relative, 2448 virtual=virtual, 2449 path_function=path_function, 2450 attempt_pixel_perfect=attempt_pixel_perfect, 2451 disable_mouse_acceleration=disable_mouse_acceleration, 2452 ) 2453 2454 event_value: int | None = None 2455 mouseData: int 2456 event_value, mouseData = _get_mouse_struct_data(button, _MOUSE_PRESS) 2457 2458 if not event_value: 2459 raise ValueError( 2460 f"Invalid button argument! " 2461 f'Expected "{MOUSE_LEFT}", "{MOUSE_RIGHT}", "{MOUSE_MIDDLE}", ' 2462 f'"{MOUSE_BUTTON4}", "{MOUSE_BUTTON5}", "{MOUSE_PRIMARY}" or ' 2463 f'"{MOUSE_SECONDARY}"; got "{button}" instead!' 2464 ) 2465 2466 _send_input(_create_mouse_input(mouseData=mouseData, dwFlags=event_value)) 2467 # --------------------------------------------------------------------------
Press down mouse button button.
If x or y are given and not None, then the mouse will move the
indicated postion before pressing the button.
button is the name of the button to press. Use the public MOUSE_*
constants to get valid argument values. (If you change the constants, then
you will have to call update_MOUSEEVENT_mappings() to resync the lookup
functions)
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
duration, tween, relative, virtual, path_function,
attempt_pixel_perfect, disable_mouse_acceleration are only relevant
if x or y are given.
See moveTo() for further information.
Raises ValueError if button is not a valid mouse button name.
NOTE: logScreenshot is currently unsupported.
2471@_genericPyDirectInputChecks 2472def mouseUp( 2473 x: int | None = None, 2474 y: int | None = None, 2475 button: str = MOUSE_PRIMARY, 2476 duration: float = 0.0, 2477 tween: Callable[[float], float] | None = None, 2478 logScreenshot: bool = False, 2479 _pause: bool = True, 2480 *, 2481 relative: bool = False, 2482 virtual: bool = False, 2483 path_function: PathFunction | None = None, 2484 attempt_pixel_perfect: bool = False, 2485 disable_mouse_acceleration: bool = False, 2486) -> None: 2487 """ 2488 Lift up mouse button `button`. 2489 2490 If `x` or `y` are given and not None, then the mouse will move the 2491 indicated postion before lifting the button. 2492 2493 `button` is the name of the button to press. Use the public `MOUSE_*` 2494 constants to get valid argument values. (If you change the constants, then 2495 you will have to call `update_MOUSEEVENT_mappings()` to resync the lookup 2496 functions) 2497 2498 If `_pause` is True (default), then an automatic sleep will be performed 2499 after the function finshes executing. The duration is set by the global 2500 variable `PAUSE`. 2501 2502 `duration`, `tween`, `relative`, `virtual`, `path_function`, 2503 `attempt_pixel_perfect`, `disable_mouse_acceleration` are only relevant 2504 if x or y are given. 2505 See `moveTo()` for further information. 2506 2507 Raises `ValueError` if `button` is not a valid mouse button name. 2508 2509 ---------------------------------------------------------------------------- 2510 2511 NOTE: `logScreenshot` is currently unsupported. 2512 """ 2513 # TODO: bounding box check for valid position 2514 if x is not None or y is not None: 2515 moveTo( 2516 x, 2517 y, 2518 duration=duration, 2519 tween=tween, 2520 logScreenshot=logScreenshot, 2521 _pause=False, # don't add an additional pause 2522 relative=relative, 2523 virtual=virtual, 2524 path_function=path_function, 2525 attempt_pixel_perfect=attempt_pixel_perfect, 2526 disable_mouse_acceleration=disable_mouse_acceleration, 2527 ) 2528 2529 event_value: int | None = None 2530 mouseData: int 2531 event_value, mouseData = _get_mouse_struct_data(button, _MOUSE_RELEASE) 2532 2533 if not event_value: 2534 raise ValueError( 2535 "Invalid button argument! " 2536 f'Expected "{MOUSE_LEFT}", "{MOUSE_RIGHT}", "{MOUSE_MIDDLE}", ' 2537 f'"{MOUSE_BUTTON4}", "{MOUSE_BUTTON5}", "{MOUSE_PRIMARY}" or ' 2538 f'"{MOUSE_SECONDARY}"; got "{button}" instead!' 2539 ) 2540 2541 _send_input(_create_mouse_input(mouseData=mouseData, dwFlags=event_value)) 2542 # --------------------------------------------------------------------------
Lift up mouse button button.
If x or y are given and not None, then the mouse will move the
indicated postion before lifting the button.
button is the name of the button to press. Use the public MOUSE_*
constants to get valid argument values. (If you change the constants, then
you will have to call update_MOUSEEVENT_mappings() to resync the lookup
functions)
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
duration, tween, relative, virtual, path_function,
attempt_pixel_perfect, disable_mouse_acceleration are only relevant
if x or y are given.
See moveTo() for further information.
Raises ValueError if button is not a valid mouse button name.
NOTE: logScreenshot is currently unsupported.
2546@_genericPyDirectInputChecks 2547def click( 2548 x: int | None = None, 2549 y: int | None = None, 2550 clicks: int = 1, 2551 interval: float = 0.0, 2552 button: str = MOUSE_PRIMARY, 2553 duration: float = 0.0, 2554 tween: Callable[[float], float] | None = None, 2555 logScreenshot: bool = False, 2556 _pause: bool = True, 2557 *, 2558 relative: bool = False, 2559 virtual: bool = False, 2560 path_function: PathFunction | None = None, 2561 attempt_pixel_perfect: bool = False, 2562 disable_mouse_acceleration: bool = False, 2563) -> None: 2564 """ 2565 Click mouse button `button` (combining press down and lift up). 2566 2567 If `x` or `y` are given and not None, then the mouse will move the 2568 indicated postion before clicking the button. 2569 2570 `button` is the name of the button to press. Use the public `MOUSE_*` 2571 constants to get valid argument values. (If you change the constants, then 2572 you will have to call `update_MOUSEEVENT_mappings()` to resync the lookup 2573 functions) 2574 2575 `clicks` is an integer that determines the amount of times the button will 2576 be clicked. 2577 2578 `interval` is the wait time in seconds between clicks. 2579 2580 If `_pause` is True (default), then an automatic sleep will be performed 2581 after the function finshes executing. The duration is set by the global 2582 variable `PAUSE`. 2583 2584 `duration`, `tween`, `relative`, `virtual`, `path_function`, 2585 `attempt_pixel_perfect`, `disable_mouse_acceleration` are only relevant 2586 if x or y are given. 2587 See `moveTo()` for further information. 2588 2589 Raises `ValueError` if `button` is not a valid mouse button name. 2590 2591 ---------------------------------------------------------------------------- 2592 2593 NOTE: `logScreenshot` is currently unsupported. 2594 """ 2595 # TODO: bounding box check for valid position 2596 if x is not None or y is not None: 2597 moveTo( 2598 x, 2599 y, 2600 duration=duration, 2601 tween=tween, 2602 logScreenshot=logScreenshot, 2603 _pause=False, # don't add an additional pause 2604 relative=relative, 2605 virtual=virtual, 2606 path_function=path_function, 2607 attempt_pixel_perfect=attempt_pixel_perfect, 2608 disable_mouse_acceleration=disable_mouse_acceleration, 2609 ) 2610 2611 event_value: int | None = None 2612 mouseData: int 2613 event_value, mouseData = _get_mouse_struct_data(button, _MOUSE_CLICK) 2614 2615 if not event_value: 2616 raise ValueError( 2617 f"Invalid button argument! " 2618 f'Expected "{MOUSE_LEFT}", "{MOUSE_RIGHT}", "{MOUSE_MIDDLE}", ' 2619 f'"{MOUSE_BUTTON4}", "{MOUSE_BUTTON5}", "{MOUSE_PRIMARY}" or ' 2620 f'"{MOUSE_SECONDARY}"; got "{button}" instead!' 2621 ) 2622 2623 apply_interval: bool = False 2624 for _ in range(clicks): 2625 if apply_interval: # Don't delay first press 2626 _sleep(interval) 2627 apply_interval = True 2628 2629 _send_input( 2630 _create_mouse_input(mouseData=mouseData, dwFlags=event_value) 2631 ) 2632 # --------------------------------------------------------------------------
Click mouse button button (combining press down and lift up).
If x or y are given and not None, then the mouse will move the
indicated postion before clicking the button.
button is the name of the button to press. Use the public MOUSE_*
constants to get valid argument values. (If you change the constants, then
you will have to call update_MOUSEEVENT_mappings() to resync the lookup
functions)
clicks is an integer that determines the amount of times the button will
be clicked.
interval is the wait time in seconds between clicks.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
duration, tween, relative, virtual, path_function,
attempt_pixel_perfect, disable_mouse_acceleration are only relevant
if x or y are given.
See moveTo() for further information.
Raises ValueError if button is not a valid mouse button name.
NOTE: logScreenshot is currently unsupported.
2636def leftClick( 2637 x: int | None = None, 2638 y: int | None = None, 2639 interval: float = 0.0, 2640 duration: float = 0.0, 2641 tween: Callable[[float], float] | None = None, 2642 logScreenshot: bool = False, 2643 _pause: bool = True, 2644 *, 2645 relative: bool = False, 2646 virtual: bool = False, 2647 path_function: PathFunction | None = None, 2648 attempt_pixel_perfect: bool = False, 2649 disable_mouse_acceleration: bool = False, 2650) -> None: 2651 """ 2652 Click Left Mouse button. 2653 2654 See `click()` for more information 2655 """ 2656 click( 2657 x, 2658 y, 2659 clicks=1, 2660 interval=interval, 2661 button=MOUSE_LEFT, 2662 duration=duration, 2663 tween=tween, 2664 logScreenshot=logScreenshot, 2665 _pause=_pause, # Keep _pause since this function has no input checks 2666 relative=relative, 2667 virtual=virtual, 2668 path_function=path_function, 2669 attempt_pixel_perfect=attempt_pixel_perfect, 2670 disable_mouse_acceleration=disable_mouse_acceleration, 2671 ) 2672 # --------------------------------------------------------------------------
Click Left Mouse button.
See click() for more information
2676def rightClick( 2677 x: int | None = None, 2678 y: int | None = None, 2679 interval: float = 0.0, 2680 duration: float = 0.0, 2681 tween: Callable[[float], float] | None = None, 2682 logScreenshot: bool = False, 2683 _pause: bool = True, 2684 *, 2685 relative: bool = False, 2686 virtual: bool = False, 2687 path_function: PathFunction | None = None, 2688 attempt_pixel_perfect: bool = False, 2689 disable_mouse_acceleration: bool = False, 2690) -> None: 2691 """ 2692 Click Right Mouse button. 2693 2694 See `click()` for more information 2695 """ 2696 click( 2697 x, 2698 y, 2699 clicks=1, 2700 interval=interval, 2701 button=MOUSE_RIGHT, 2702 duration=duration, 2703 tween=tween, 2704 logScreenshot=logScreenshot, 2705 _pause=_pause, # Keep _pause since this function has no input checks 2706 relative=relative, 2707 virtual=virtual, 2708 path_function=path_function, 2709 attempt_pixel_perfect=attempt_pixel_perfect, 2710 disable_mouse_acceleration=disable_mouse_acceleration, 2711 ) 2712 # --------------------------------------------------------------------------
Click Right Mouse button.
See click() for more information
2716def middleClick( 2717 x: int | None = None, 2718 y: int | None = None, 2719 interval: float = 0.0, 2720 duration: float = 0.0, 2721 tween: Callable[[float], float] | None = None, 2722 logScreenshot: bool = False, 2723 _pause: bool = True, 2724 *, 2725 relative: bool = False, 2726 virtual: bool = False, 2727 path_function: PathFunction | None = None, 2728 attempt_pixel_perfect: bool = False, 2729 disable_mouse_acceleration: bool = False, 2730) -> None: 2731 """ 2732 Click Middle Mouse button. 2733 2734 See `click()` for more information 2735 """ 2736 click( 2737 x, 2738 y, 2739 clicks=1, 2740 interval=interval, 2741 button=MOUSE_MIDDLE, 2742 duration=duration, 2743 tween=tween, 2744 logScreenshot=logScreenshot, 2745 _pause=_pause, # Keep _pause since this function has no input checks 2746 relative=relative, 2747 virtual=virtual, 2748 path_function=path_function, 2749 attempt_pixel_perfect=attempt_pixel_perfect, 2750 disable_mouse_acceleration=disable_mouse_acceleration, 2751 ) 2752 # --------------------------------------------------------------------------
Click Middle Mouse button.
See click() for more information
2756def doubleClick( 2757 x: int | None = None, 2758 y: int | None = None, 2759 interval: float = 0.0, 2760 button: str = MOUSE_LEFT, 2761 duration: float = 0.0, 2762 tween: Callable[[float], float] | None = None, 2763 logScreenshot: bool = False, 2764 _pause: bool = True, 2765 *, 2766 relative: bool = False, 2767 virtual: bool = False, 2768 path_function: PathFunction | None = None, 2769 attempt_pixel_perfect: bool = False, 2770 disable_mouse_acceleration: bool = False, 2771) -> None: 2772 """ 2773 Double click `button`. 2774 2775 See `click()` for more information 2776 """ 2777 click( 2778 x, 2779 y, 2780 clicks=2, 2781 interval=interval, 2782 button=button, 2783 duration=duration, 2784 tween=tween, 2785 logScreenshot=logScreenshot, 2786 _pause=_pause, # Keep _pause since this function has no input checks 2787 relative=relative, 2788 virtual=virtual, 2789 path_function=path_function, 2790 attempt_pixel_perfect=attempt_pixel_perfect, 2791 disable_mouse_acceleration=disable_mouse_acceleration, 2792 ) 2793 # --------------------------------------------------------------------------
Double click button.
See click() for more information
2797def tripleClick( 2798 x: int | None = None, 2799 y: int | None = None, 2800 interval: float = 0.0, 2801 button: str = MOUSE_LEFT, 2802 duration: float = 0.0, 2803 tween: Callable[[float], float] | None = None, 2804 logScreenshot: bool = False, 2805 _pause: bool = True, 2806 *, 2807 relative: bool = False, 2808 virtual: bool = False, 2809 path_function: PathFunction | None = None, 2810 attempt_pixel_perfect: bool = False, 2811 disable_mouse_acceleration: bool = False, 2812) -> None: 2813 """ 2814 Triple click `button`. 2815 2816 See `click()` for more information 2817 """ 2818 click( 2819 x, 2820 y, 2821 clicks=3, 2822 interval=interval, 2823 button=button, 2824 duration=duration, 2825 tween=tween, 2826 logScreenshot=logScreenshot, 2827 _pause=_pause, # Keep _pause since this function has no input checks 2828 relative=relative, 2829 virtual=virtual, 2830 path_function=path_function, 2831 attempt_pixel_perfect=attempt_pixel_perfect, 2832 disable_mouse_acceleration=disable_mouse_acceleration, 2833 ) 2834 # --------------------------------------------------------------------------
Triple click button.
See click() for more information
2840@_genericPyDirectInputChecks 2841def scroll( 2842 clicks: int = 0, 2843 x: Any = None, # x and y do absolutely nothing, still keeping the arguments 2844 y: Any = None, # to stay consistent with PyAutoGUI. 2845 logScreenshot: bool = False, 2846 _pause: bool = True, 2847 *, 2848 interval: float = 0.0, 2849) -> None: 2850 """ 2851 Vertically scroll mouse `clicks` number of times, waiting `interval` 2852 seconds between every scroll. 2853 2854 Negative values of `clicks` will scroll down, postive values will scroll 2855 up. 2856 2857 `x` and `y` are intentionally ignored and only exists to keep the call 2858 signature backwards-compatible with PyAutoGui. 2859 If you need to change the mouse position before scrolling use one of the 2860 `move()` functions. 2861 2862 If `_pause` is True (default), then an automatic sleep will be performed 2863 after the function finshes executing. The duration is set by the global 2864 variable `PAUSE`. 2865 2866 ---------------------------------------------------------------------------- 2867 2868 NOTE: `logScreenshot` is currently unsupported. 2869 """ 2870 direction: Literal[-1, 1] 2871 if clicks >= 0: 2872 direction = 1 2873 else: 2874 direction = -1 2875 clicks = abs(clicks) 2876 2877 apply_interval: bool = False 2878 for _ in range(clicks): 2879 if apply_interval: 2880 _sleep(interval) 2881 apply_interval = True 2882 2883 _send_input( 2884 _create_mouse_input( 2885 mouseData=(direction * _WHEEL_DELTA), dwFlags=_MOUSEEVENTF_WHEEL 2886 ) 2887 ) 2888 # --------------------------------------------------------------------------
Vertically scroll mouse clicks number of times, waiting interval
seconds between every scroll.
Negative values of clicks will scroll down, postive values will scroll
up.
x and y are intentionally ignored and only exists to keep the call
signature backwards-compatible with PyAutoGui.
If you need to change the mouse position before scrolling use one of the
move() functions.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
NOTE: logScreenshot is currently unsupported.
2892@_genericPyDirectInputChecks 2893def hscroll( 2894 clicks: int = 0, 2895 x: Any = None, # x and y do absolutely nothing, still keeping the arguments 2896 y: Any = None, # to stay consistent with PyAutoGUI. 2897 logScreenshot: bool = False, 2898 _pause: bool = True, 2899 *, 2900 interval: float = 0.0, 2901) -> None: 2902 """ 2903 Horizontally scroll mouse `clicks` number of times, waiting `interval` 2904 seconds between every scroll. 2905 2906 Negative values of `clicks` will scroll left, postive values will scroll 2907 right. 2908 2909 `x` and `y` are intentionally ignored and only exists to keep the call 2910 signature backwards-compatible with PyAutoGui. 2911 If you need to change the mouse position before scrolling use one of the 2912 `move()` functions. 2913 2914 If `_pause` is True (default), then an automatic sleep will be performed 2915 after the function finshes executing. The duration is set by the global 2916 variable `PAUSE`. 2917 2918 ---------------------------------------------------------------------------- 2919 2920 NOTE: `logScreenshot` is currently unsupported. 2921 """ 2922 direction: Literal[-1, 1] 2923 if clicks >= 0: 2924 direction = 1 2925 else: 2926 direction = -1 2927 clicks = abs(clicks) 2928 2929 apply_interval: bool = False 2930 for _ in range(clicks): 2931 if apply_interval: 2932 _sleep(interval) 2933 apply_interval = True 2934 2935 _send_input( 2936 _create_mouse_input( 2937 mouseData=(direction * _WHEEL_DELTA), 2938 dwFlags=_MOUSEEVENTF_HWHEEL, 2939 ) 2940 ) 2941 # --------------------------------------------------------------------------
Horizontally scroll mouse clicks number of times, waiting interval
seconds between every scroll.
Negative values of clicks will scroll left, postive values will scroll
right.
x and y are intentionally ignored and only exists to keep the call
signature backwards-compatible with PyAutoGui.
If you need to change the mouse position before scrolling use one of the
move() functions.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
NOTE: logScreenshot is currently unsupported.
2840@_genericPyDirectInputChecks 2841def scroll( 2842 clicks: int = 0, 2843 x: Any = None, # x and y do absolutely nothing, still keeping the arguments 2844 y: Any = None, # to stay consistent with PyAutoGUI. 2845 logScreenshot: bool = False, 2846 _pause: bool = True, 2847 *, 2848 interval: float = 0.0, 2849) -> None: 2850 """ 2851 Vertically scroll mouse `clicks` number of times, waiting `interval` 2852 seconds between every scroll. 2853 2854 Negative values of `clicks` will scroll down, postive values will scroll 2855 up. 2856 2857 `x` and `y` are intentionally ignored and only exists to keep the call 2858 signature backwards-compatible with PyAutoGui. 2859 If you need to change the mouse position before scrolling use one of the 2860 `move()` functions. 2861 2862 If `_pause` is True (default), then an automatic sleep will be performed 2863 after the function finshes executing. The duration is set by the global 2864 variable `PAUSE`. 2865 2866 ---------------------------------------------------------------------------- 2867 2868 NOTE: `logScreenshot` is currently unsupported. 2869 """ 2870 direction: Literal[-1, 1] 2871 if clicks >= 0: 2872 direction = 1 2873 else: 2874 direction = -1 2875 clicks = abs(clicks) 2876 2877 apply_interval: bool = False 2878 for _ in range(clicks): 2879 if apply_interval: 2880 _sleep(interval) 2881 apply_interval = True 2882 2883 _send_input( 2884 _create_mouse_input( 2885 mouseData=(direction * _WHEEL_DELTA), dwFlags=_MOUSEEVENTF_WHEEL 2886 ) 2887 ) 2888 # --------------------------------------------------------------------------
Vertically scroll mouse clicks number of times, waiting interval
seconds between every scroll.
Negative values of clicks will scroll down, postive values will scroll
up.
x and y are intentionally ignored and only exists to keep the call
signature backwards-compatible with PyAutoGui.
If you need to change the mouse position before scrolling use one of the
move() functions.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
NOTE: logScreenshot is currently unsupported.
3354@_genericPyDirectInputChecks 3355def moveTo( 3356 x: int | None = None, 3357 y: int | None = None, 3358 duration: float = 0.0, 3359 tween: Callable[[float], float] | None = None, 3360 logScreenshot: bool = False, 3361 _pause: bool = True, 3362 relative: bool = False, 3363 *, 3364 virtual: bool = False, 3365 path_function: PathFunction | None = None, 3366 attempt_pixel_perfect: bool = False, 3367 disable_mouse_acceleration: bool = False, 3368) -> None: 3369 """ 3370 Move the mouse to an absolute(*) postion indicated by the arguments of 3371 `x` and `y`. The coordinates 0,0 represent the top left pixel of the 3372 primary monitor. 3373 3374 If `duration` is floating point number greater than 0, then this function 3375 will automatically split the movement into microsteps instead of moving 3376 straight to the target position. 3377 3378 `tween` is a function that takes a floating point number between 0.0 and 3379 1.0 and returns another floating point number between 0.0 and 1.0. The 3380 returned number will be used to calculate the next position of the 3381 mouse between the start and the end position based on the current duration. 3382 The default tweening function is linear, which will move the mouse at a 3383 constant speed. See the `pytweening` package for more tweening functions. 3384 Be aware that tweening only controls to the timing of movement, not the 3385 path itself. If you need to non-linear movement (e.g. overshoot), then 3386 use the `path_function` argument. 3387 3388 `path_function` is a function that takes the start and end coordinates of 3389 the mouse movement (4 integers) and returns a list of coordinates (list of 3390 tuples, each containting 2 integers (x,y)) that the mouse will move 3391 through. The default path function is Bresenham's line algorithm, which 3392 will move the mouse in a straight line. 3393 3394 (*) `relative` parameter decides how the movement is executed: 3395 3396 -> `False`: Target postion is given and absolute movement is used. 3397 3398 -> `True`: Calculates target offset and uses relative movement API 3399 (can be inconsistent) 3400 3401 If `_pause` is True (default), then an automatic sleep will be performed 3402 after the function finshes executing. The duration is set by the global 3403 variable `PAUSE`. 3404 3405 Setting `virtual` to True (default: False) changes the way internal APIs 3406 handle coordinates and is intended for multi monitor systems. It should be 3407 pretty much unncessary even for multi monitor systems, since all the 3408 necessary internal calculations beyond the border of the primay monitor 3409 work without it. 3410 3411 The way that Windows calculates the target pixel coordinates internally 3412 unfortunately leads to inaccuracies and unreachable pixels, especially 3413 if the `virtual` option is used. 3414 3415 If you need the target position to be pixel perfect, you can try setting 3416 `attempt_pixel_perfect` to True, which will use tiny relative movements 3417 to correct the unreachable position. 3418 3419 Relative movement is influenced by mouse speed and Windows Enhanced Pointer 3420 Precision, which can be temporarily disabled by setting 3421 `disable_mouse_acceleration`. 3422 3423 ---------------------------------------------------------------------------- 3424 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 3425 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 3426 3427 If you you start a relative movement while another is already in progress 3428 than the second movement could overwrite the first setting and disable 3429 Enhanced Pointer Precision and change mouse speed. 3430 There are some measures in place to try to mitigate that risk, such as an 3431 internal counter that only allows storing and restoring the acceleration 3432 settings as long as no other movement is currently in progress. 3433 Additionally, the acceleration settings can be manually saved and 3434 restored with `store_mouse_acceleration_settings()` and 3435 `restore_mouse_acceleration_settings()`. For your convenience, the 3436 store function is automatically called during import to save your current 3437 setting. You can then call the restore function at any time. 3438 3439 If all fails, the setting is not written permanently to your Windows 3440 settings, so it should restore itself upon reboot. 3441 3442 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3443 this library in multiple threads / processes / programs at the same time! 3444 3445 ---------------------------------------------------------------------------- 3446 3447 NOTE: `logScreenshot` is currently unsupported. 3448 """ 3449 if relative: 3450 _relative_mouse_move( 3451 x=x, 3452 y=y, 3453 duration=duration, 3454 tween=tween, 3455 logScreenshot=logScreenshot, 3456 target_coords_relative=False, 3457 virtual=virtual, 3458 path_function=path_function, 3459 disable_mouse_acceleration=disable_mouse_acceleration, 3460 ) 3461 else: 3462 _absolute_mouse_move( 3463 x=x, 3464 y=y, 3465 duration=duration, 3466 tween=tween, 3467 logScreenshot=logScreenshot, 3468 target_coords_relative=False, 3469 virtual=virtual, 3470 path_function=path_function, 3471 attempt_pixel_perfect=attempt_pixel_perfect, 3472 disable_mouse_acceleration=disable_mouse_acceleration, 3473 ) 3474 # --------------------------------------------------------------------------
Move the mouse to an absolute(*) postion indicated by the arguments of
x and y. The coordinates 0,0 represent the top left pixel of the
primary monitor.
If duration is floating point number greater than 0, then this function
will automatically split the movement into microsteps instead of moving
straight to the target position.
tween is a function that takes a floating point number between 0.0 and
1.0 and returns another floating point number between 0.0 and 1.0. The
returned number will be used to calculate the next position of the
mouse between the start and the end position based on the current duration.
The default tweening function is linear, which will move the mouse at a
constant speed. See the pytweening package for more tweening functions.
Be aware that tweening only controls to the timing of movement, not the
path itself. If you need to non-linear movement (e.g. overshoot), then
use the path_function argument.
path_function is a function that takes the start and end coordinates of
the mouse movement (4 integers) and returns a list of coordinates (list of
tuples, each containting 2 integers (x,y)) that the mouse will move
through. The default path function is Bresenham's line algorithm, which
will move the mouse in a straight line.
(*) relative parameter decides how the movement is executed:
-> False: Target postion is given and absolute movement is used.
-> True: Calculates target offset and uses relative movement API
(can be inconsistent)
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
Setting virtual to True (default: False) changes the way internal APIs
handle coordinates and is intended for multi monitor systems. It should be
pretty much unncessary even for multi monitor systems, since all the
necessary internal calculations beyond the border of the primay monitor
work without it.
The way that Windows calculates the target pixel coordinates internally
unfortunately leads to inaccuracies and unreachable pixels, especially
if the virtual option is used.
If you need the target position to be pixel perfect, you can try setting
attempt_pixel_perfect to True, which will use tiny relative movements
to correct the unreachable position.
Relative movement is influenced by mouse speed and Windows Enhanced Pointer
Precision, which can be temporarily disabled by setting
disable_mouse_acceleration.
Careful! Disabling mouse acceleration settings is MAYBE thread-safe, NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe!
If you you start a relative movement while another is already in progress
than the second movement could overwrite the first setting and disable
Enhanced Pointer Precision and change mouse speed.
There are some measures in place to try to mitigate that risk, such as an
internal counter that only allows storing and restoring the acceleration
settings as long as no other movement is currently in progress.
Additionally, the acceleration settings can be manually saved and
restored with store_mouse_acceleration_settings() and
restore_mouse_acceleration_settings(). For your convenience, the
store function is automatically called during import to save your current
setting. You can then call the restore function at any time.
If all fails, the setting is not written permanently to your Windows settings, so it should restore itself upon reboot.
Bottom line: Don't use the disable_mouse_acceleration argument if you use
this library in multiple threads / processes / programs at the same time!
NOTE: logScreenshot is currently unsupported.
3478@_genericPyDirectInputChecks 3479def moveRel( 3480 xOffset: int | None = None, 3481 yOffset: int | None = None, 3482 duration: float = 0.0, 3483 tween: Callable[[float], float] | None = None, 3484 logScreenshot: bool = False, 3485 _pause: bool = True, 3486 relative: bool = False, 3487 *, 3488 virtual: bool = False, 3489 path_function: PathFunction | None = None, 3490 attempt_pixel_perfect: bool = False, 3491 disable_mouse_acceleration: bool = False, 3492) -> None: 3493 """ 3494 Move the mouse a relative amount determined by `xOffset` and `yOffset`. 3495 3496 If `duration` is floating point number greater than 0, then this function 3497 will automatically split the movement into microsteps instead of moving the 3498 complete distance instantly. 3499 3500 `tween` is a function that takes a floating point number between 0.0 and 3501 1.0 and returns another floating point number between 0.0 and 1.0. The 3502 returned number will be used to calculate the next position of the 3503 mouse between the start and the end position based on the current duration. 3504 The default tweening function is linear, which will move the mouse at a 3505 constant speed. See the `pytweening` package for more tweening functions. 3506 Be aware that tweening only controls to the timing of movement, not the 3507 path itself. If you need to non-linear movement (e.g. overshoot), then 3508 use the `path_function` argument. 3509 3510 `path_function` is a function that takes the start and end coordinates of 3511 the mouse movement (4 integers) and returns a list of coordinates (list of 3512 tuples, each containting 2 integers (x,y)) that the mouse will move 3513 through. The default path function is Bresenham's line algorithm, which 3514 will move the mouse in a straight line. 3515 3516 `relative` parameter decides how the movement is executed: 3517 3518 -> `False`: Target postion is calculated and absolute movement is used. 3519 3520 -> `True`: Target offset is given and relative movement API is used 3521 (can be inconsistent) 3522 3523 The inconsistency issue can be solved by disabling Enhanced Pointer 3524 Precision and set Mouse speed to 10 in Windows mouse settings. Since users 3525 may not want to permanently change their input settings just for this 3526 library, the `disable_mouse_acceleration` argument can be used to 3527 temporarily disable Enhanced Pointer Precision and fix mouse speed at 10 3528 and restore it after the mouse movement. 3529 3530 If `_pause` is True (default), then an automatic sleep will be performed 3531 after the function finshes executing. The duration is set by the global 3532 variable `PAUSE`. 3533 3534 Setting `virtual` to True (default: False) changes the way internal APIs 3535 handle coordinates and is intended for multi monitor systems. It should be 3536 pretty much unncessary even for multi monitor systems, since all the 3537 necessary internal calculations beyond the border of the primay monitor 3538 work without it. 3539 3540 The way that Windows calculates the target pixel coordinates internally 3541 unfortunately leads to inaccuracies and unreachable pixels, especially 3542 if the `virtual` option is used. 3543 3544 If you need the target position to be pixel perfect, you can try setting 3545 `attempt_pixel_perfect` to True, which will use tiny relative movements 3546 to correct the unreachable position. 3547 3548 ---------------------------------------------------------------------------- 3549 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 3550 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 3551 3552 If you you start a relative movement while another is already in progress 3553 than the second movement could overwrite the first setting and disable 3554 Enhanced Pointer Precision and change mouse speed. 3555 There are some measures in place to try to mitigate that risk, such as an 3556 internal counter that only allows storing and restoring the acceleration 3557 settings as long as no other movement is currently in progress. 3558 Additionally, the acceleration settings can be manually saved and 3559 restored with `store_mouse_acceleration_settings()` and 3560 `restore_mouse_acceleration_settings()`. For your convinnience, the 3561 store function is automatically called during import to save your current 3562 setting. You can then call the restore function at any time. 3563 3564 If all fails, the setting is not written permanently to your Windows 3565 settings, so it should restore itself upon reboot. 3566 3567 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3568 this library in multiple threads / processes / programs at the same time! 3569 3570 ---------------------------------------------------------------------------- 3571 3572 NOTE: `logScreenshot` is are currently unsupported. 3573 """ 3574 if relative: 3575 _relative_mouse_move( 3576 x=xOffset, 3577 y=yOffset, 3578 duration=duration, 3579 tween=tween, 3580 logScreenshot=logScreenshot, 3581 target_coords_relative=True, 3582 virtual=virtual, 3583 path_function=path_function, 3584 disable_mouse_acceleration=disable_mouse_acceleration, 3585 ) 3586 else: 3587 _absolute_mouse_move( 3588 x=xOffset, 3589 y=yOffset, 3590 duration=duration, 3591 tween=tween, 3592 logScreenshot=logScreenshot, 3593 target_coords_relative=True, 3594 virtual=virtual, 3595 path_function=path_function, 3596 attempt_pixel_perfect=attempt_pixel_perfect, 3597 disable_mouse_acceleration=disable_mouse_acceleration, 3598 ) 3599 # --------------------------------------------------------------------------
Move the mouse a relative amount determined by xOffset and yOffset.
If duration is floating point number greater than 0, then this function
will automatically split the movement into microsteps instead of moving the
complete distance instantly.
tween is a function that takes a floating point number between 0.0 and
1.0 and returns another floating point number between 0.0 and 1.0. The
returned number will be used to calculate the next position of the
mouse between the start and the end position based on the current duration.
The default tweening function is linear, which will move the mouse at a
constant speed. See the pytweening package for more tweening functions.
Be aware that tweening only controls to the timing of movement, not the
path itself. If you need to non-linear movement (e.g. overshoot), then
use the path_function argument.
path_function is a function that takes the start and end coordinates of
the mouse movement (4 integers) and returns a list of coordinates (list of
tuples, each containting 2 integers (x,y)) that the mouse will move
through. The default path function is Bresenham's line algorithm, which
will move the mouse in a straight line.
relative parameter decides how the movement is executed:
-> False: Target postion is calculated and absolute movement is used.
-> True: Target offset is given and relative movement API is used
(can be inconsistent)
The inconsistency issue can be solved by disabling Enhanced Pointer
Precision and set Mouse speed to 10 in Windows mouse settings. Since users
may not want to permanently change their input settings just for this
library, the disable_mouse_acceleration argument can be used to
temporarily disable Enhanced Pointer Precision and fix mouse speed at 10
and restore it after the mouse movement.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
Setting virtual to True (default: False) changes the way internal APIs
handle coordinates and is intended for multi monitor systems. It should be
pretty much unncessary even for multi monitor systems, since all the
necessary internal calculations beyond the border of the primay monitor
work without it.
The way that Windows calculates the target pixel coordinates internally
unfortunately leads to inaccuracies and unreachable pixels, especially
if the virtual option is used.
If you need the target position to be pixel perfect, you can try setting
attempt_pixel_perfect to True, which will use tiny relative movements
to correct the unreachable position.
Careful! Disabling mouse acceleration settings is MAYBE thread-safe, NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe!
If you you start a relative movement while another is already in progress
than the second movement could overwrite the first setting and disable
Enhanced Pointer Precision and change mouse speed.
There are some measures in place to try to mitigate that risk, such as an
internal counter that only allows storing and restoring the acceleration
settings as long as no other movement is currently in progress.
Additionally, the acceleration settings can be manually saved and
restored with store_mouse_acceleration_settings() and
restore_mouse_acceleration_settings(). For your convinnience, the
store function is automatically called during import to save your current
setting. You can then call the restore function at any time.
If all fails, the setting is not written permanently to your Windows settings, so it should restore itself upon reboot.
Bottom line: Don't use the disable_mouse_acceleration argument if you use
this library in multiple threads / processes / programs at the same time!
NOTE: logScreenshot is are currently unsupported.
3478@_genericPyDirectInputChecks 3479def moveRel( 3480 xOffset: int | None = None, 3481 yOffset: int | None = None, 3482 duration: float = 0.0, 3483 tween: Callable[[float], float] | None = None, 3484 logScreenshot: bool = False, 3485 _pause: bool = True, 3486 relative: bool = False, 3487 *, 3488 virtual: bool = False, 3489 path_function: PathFunction | None = None, 3490 attempt_pixel_perfect: bool = False, 3491 disable_mouse_acceleration: bool = False, 3492) -> None: 3493 """ 3494 Move the mouse a relative amount determined by `xOffset` and `yOffset`. 3495 3496 If `duration` is floating point number greater than 0, then this function 3497 will automatically split the movement into microsteps instead of moving the 3498 complete distance instantly. 3499 3500 `tween` is a function that takes a floating point number between 0.0 and 3501 1.0 and returns another floating point number between 0.0 and 1.0. The 3502 returned number will be used to calculate the next position of the 3503 mouse between the start and the end position based on the current duration. 3504 The default tweening function is linear, which will move the mouse at a 3505 constant speed. See the `pytweening` package for more tweening functions. 3506 Be aware that tweening only controls to the timing of movement, not the 3507 path itself. If you need to non-linear movement (e.g. overshoot), then 3508 use the `path_function` argument. 3509 3510 `path_function` is a function that takes the start and end coordinates of 3511 the mouse movement (4 integers) and returns a list of coordinates (list of 3512 tuples, each containting 2 integers (x,y)) that the mouse will move 3513 through. The default path function is Bresenham's line algorithm, which 3514 will move the mouse in a straight line. 3515 3516 `relative` parameter decides how the movement is executed: 3517 3518 -> `False`: Target postion is calculated and absolute movement is used. 3519 3520 -> `True`: Target offset is given and relative movement API is used 3521 (can be inconsistent) 3522 3523 The inconsistency issue can be solved by disabling Enhanced Pointer 3524 Precision and set Mouse speed to 10 in Windows mouse settings. Since users 3525 may not want to permanently change their input settings just for this 3526 library, the `disable_mouse_acceleration` argument can be used to 3527 temporarily disable Enhanced Pointer Precision and fix mouse speed at 10 3528 and restore it after the mouse movement. 3529 3530 If `_pause` is True (default), then an automatic sleep will be performed 3531 after the function finshes executing. The duration is set by the global 3532 variable `PAUSE`. 3533 3534 Setting `virtual` to True (default: False) changes the way internal APIs 3535 handle coordinates and is intended for multi monitor systems. It should be 3536 pretty much unncessary even for multi monitor systems, since all the 3537 necessary internal calculations beyond the border of the primay monitor 3538 work without it. 3539 3540 The way that Windows calculates the target pixel coordinates internally 3541 unfortunately leads to inaccuracies and unreachable pixels, especially 3542 if the `virtual` option is used. 3543 3544 If you need the target position to be pixel perfect, you can try setting 3545 `attempt_pixel_perfect` to True, which will use tiny relative movements 3546 to correct the unreachable position. 3547 3548 ---------------------------------------------------------------------------- 3549 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 3550 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 3551 3552 If you you start a relative movement while another is already in progress 3553 than the second movement could overwrite the first setting and disable 3554 Enhanced Pointer Precision and change mouse speed. 3555 There are some measures in place to try to mitigate that risk, such as an 3556 internal counter that only allows storing and restoring the acceleration 3557 settings as long as no other movement is currently in progress. 3558 Additionally, the acceleration settings can be manually saved and 3559 restored with `store_mouse_acceleration_settings()` and 3560 `restore_mouse_acceleration_settings()`. For your convinnience, the 3561 store function is automatically called during import to save your current 3562 setting. You can then call the restore function at any time. 3563 3564 If all fails, the setting is not written permanently to your Windows 3565 settings, so it should restore itself upon reboot. 3566 3567 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3568 this library in multiple threads / processes / programs at the same time! 3569 3570 ---------------------------------------------------------------------------- 3571 3572 NOTE: `logScreenshot` is are currently unsupported. 3573 """ 3574 if relative: 3575 _relative_mouse_move( 3576 x=xOffset, 3577 y=yOffset, 3578 duration=duration, 3579 tween=tween, 3580 logScreenshot=logScreenshot, 3581 target_coords_relative=True, 3582 virtual=virtual, 3583 path_function=path_function, 3584 disable_mouse_acceleration=disable_mouse_acceleration, 3585 ) 3586 else: 3587 _absolute_mouse_move( 3588 x=xOffset, 3589 y=yOffset, 3590 duration=duration, 3591 tween=tween, 3592 logScreenshot=logScreenshot, 3593 target_coords_relative=True, 3594 virtual=virtual, 3595 path_function=path_function, 3596 attempt_pixel_perfect=attempt_pixel_perfect, 3597 disable_mouse_acceleration=disable_mouse_acceleration, 3598 ) 3599 # --------------------------------------------------------------------------
Move the mouse a relative amount determined by xOffset and yOffset.
If duration is floating point number greater than 0, then this function
will automatically split the movement into microsteps instead of moving the
complete distance instantly.
tween is a function that takes a floating point number between 0.0 and
1.0 and returns another floating point number between 0.0 and 1.0. The
returned number will be used to calculate the next position of the
mouse between the start and the end position based on the current duration.
The default tweening function is linear, which will move the mouse at a
constant speed. See the pytweening package for more tweening functions.
Be aware that tweening only controls to the timing of movement, not the
path itself. If you need to non-linear movement (e.g. overshoot), then
use the path_function argument.
path_function is a function that takes the start and end coordinates of
the mouse movement (4 integers) and returns a list of coordinates (list of
tuples, each containting 2 integers (x,y)) that the mouse will move
through. The default path function is Bresenham's line algorithm, which
will move the mouse in a straight line.
relative parameter decides how the movement is executed:
-> False: Target postion is calculated and absolute movement is used.
-> True: Target offset is given and relative movement API is used
(can be inconsistent)
The inconsistency issue can be solved by disabling Enhanced Pointer
Precision and set Mouse speed to 10 in Windows mouse settings. Since users
may not want to permanently change their input settings just for this
library, the disable_mouse_acceleration argument can be used to
temporarily disable Enhanced Pointer Precision and fix mouse speed at 10
and restore it after the mouse movement.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
Setting virtual to True (default: False) changes the way internal APIs
handle coordinates and is intended for multi monitor systems. It should be
pretty much unncessary even for multi monitor systems, since all the
necessary internal calculations beyond the border of the primay monitor
work without it.
The way that Windows calculates the target pixel coordinates internally
unfortunately leads to inaccuracies and unreachable pixels, especially
if the virtual option is used.
If you need the target position to be pixel perfect, you can try setting
attempt_pixel_perfect to True, which will use tiny relative movements
to correct the unreachable position.
Careful! Disabling mouse acceleration settings is MAYBE thread-safe, NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe!
If you you start a relative movement while another is already in progress
than the second movement could overwrite the first setting and disable
Enhanced Pointer Precision and change mouse speed.
There are some measures in place to try to mitigate that risk, such as an
internal counter that only allows storing and restoring the acceleration
settings as long as no other movement is currently in progress.
Additionally, the acceleration settings can be manually saved and
restored with store_mouse_acceleration_settings() and
restore_mouse_acceleration_settings(). For your convinnience, the
store function is automatically called during import to save your current
setting. You can then call the restore function at any time.
If all fails, the setting is not written permanently to your Windows settings, so it should restore itself upon reboot.
Bottom line: Don't use the disable_mouse_acceleration argument if you use
this library in multiple threads / processes / programs at the same time!
NOTE: logScreenshot is are currently unsupported.
3609@_genericPyDirectInputChecks 3610def dragTo( 3611 x: int | None = None, 3612 y: int | None = None, 3613 duration: float = 0.0, 3614 tween: Callable[[float], float] | None = None, 3615 button: str | None = None, 3616 logScreenshot: bool = False, 3617 _pause: bool = True, 3618 mouseDownUp: bool = True, 3619 *, 3620 relative: bool = False, 3621 virtual: bool = False, 3622 path_function: PathFunction | None = None, 3623 attempt_pixel_perfect: bool = False, 3624 disable_mouse_acceleration: bool = False, 3625) -> None: 3626 """ 3627 Press and hold a mouse button while moving to the target coordinates. 3628 3629 See `moveTo` for more information on most arguments. 3630 3631 `button` is a string that is one of the following constants: 3632 MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, MOUSE_BUTTON4, MOUSE_BUTTON5, 3633 MOUSE_PRIMARY (default), MOUSE_SECONDARY. 3634 3635 If `mouseDownUp` (default: True) is manually set to False, then this 3636 function is basically the same as `moveTo`. Only exists to match PyAutoGUI. 3637 3638 If `_pause` is True (default), then an automatic sleep will be performed 3639 after the function finshes executing. The duration is set by the global 3640 variable `PAUSE`. 3641 3642 ---------------------------------------------------------------------------- 3643 3644 NOTE: `logScreenshot` is currently unsupported. 3645 """ 3646 # TODO: bounding box check for valid position 3647 if button is None: 3648 button = MOUSE_PRIMARY 3649 if mouseDownUp: 3650 mouseDown(button=button, _pause=False, virtual=virtual) 3651 moveTo( 3652 x, 3653 y, 3654 duration=duration, 3655 tween=tween, 3656 logScreenshot=logScreenshot, 3657 _pause=False, # don't add an additional pause 3658 relative=relative, 3659 virtual=virtual, 3660 path_function=path_function, 3661 attempt_pixel_perfect=attempt_pixel_perfect, 3662 disable_mouse_acceleration=disable_mouse_acceleration, 3663 ) 3664 if mouseDownUp: 3665 mouseUp(button=button, _pause=False, virtual=virtual) 3666 # --------------------------------------------------------------------------
Press and hold a mouse button while moving to the target coordinates.
See moveTo for more information on most arguments.
button is a string that is one of the following constants:
MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, MOUSE_BUTTON4, MOUSE_BUTTON5,
MOUSE_PRIMARY (default), MOUSE_SECONDARY.
If mouseDownUp (default: True) is manually set to False, then this
function is basically the same as moveTo. Only exists to match PyAutoGUI.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
NOTE: logScreenshot is currently unsupported.
3670@_genericPyDirectInputChecks 3671def dragRel( 3672 xOffset: int | None = None, 3673 yOffset: int | None = None, 3674 duration: float = 0.0, 3675 tween: Callable[[float], float] | None = None, 3676 button: str | None = None, 3677 logScreenshot: bool = False, 3678 _pause: bool = True, 3679 mouseDownUp: bool = True, 3680 *, 3681 relative: bool = False, 3682 virtual: bool = False, 3683 path_function: PathFunction | None = None, 3684 disable_mouse_acceleration: bool = False, 3685) -> None: 3686 """ 3687 Press and hold a mouse button while moving a relative distance 3688 3689 See `moveRel` for more information on most arguments. 3690 3691 `button` is a string that is one of the following constants: 3692 MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, MOUSE_BUTTON4, MOUSE_BUTTON5, 3693 MOUSE_PRIMARY (default), MOUSE_SECONDARY. 3694 3695 If `mouseDownUp` (default: True) is manually set to False, then this 3696 function is basically the same as `moveTo`. Only exists to match PyAutoGUI. 3697 3698 If `_pause` is True (default), then an automatic sleep will be performed 3699 after the function finshes executing. The duration is set by the global 3700 variable `PAUSE`. 3701 3702 ---------------------------------------------------------------------------- 3703 3704 NOTE: `logScreenshot` is currently unsupported. 3705 """ 3706 # TODO: bounding box check for valid position 3707 if button is None: 3708 button = MOUSE_PRIMARY 3709 if mouseDownUp: 3710 mouseDown(button=button, _pause=False, virtual=virtual) 3711 moveRel( 3712 xOffset, 3713 yOffset, 3714 duration=duration, 3715 tween=tween, 3716 logScreenshot=logScreenshot, 3717 _pause=False, # don't add an additional pause 3718 relative=relative, 3719 virtual=virtual, 3720 path_function=path_function, 3721 disable_mouse_acceleration=disable_mouse_acceleration, 3722 ) 3723 if mouseDownUp: 3724 mouseUp(button=button, _pause=False, virtual=virtual) 3725 # --------------------------------------------------------------------------
Press and hold a mouse button while moving a relative distance
See moveRel for more information on most arguments.
button is a string that is one of the following constants:
MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, MOUSE_BUTTON4, MOUSE_BUTTON5,
MOUSE_PRIMARY (default), MOUSE_SECONDARY.
If mouseDownUp (default: True) is manually set to False, then this
function is basically the same as moveTo. Only exists to match PyAutoGUI.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
NOTE: logScreenshot is currently unsupported.
3670@_genericPyDirectInputChecks 3671def dragRel( 3672 xOffset: int | None = None, 3673 yOffset: int | None = None, 3674 duration: float = 0.0, 3675 tween: Callable[[float], float] | None = None, 3676 button: str | None = None, 3677 logScreenshot: bool = False, 3678 _pause: bool = True, 3679 mouseDownUp: bool = True, 3680 *, 3681 relative: bool = False, 3682 virtual: bool = False, 3683 path_function: PathFunction | None = None, 3684 disable_mouse_acceleration: bool = False, 3685) -> None: 3686 """ 3687 Press and hold a mouse button while moving a relative distance 3688 3689 See `moveRel` for more information on most arguments. 3690 3691 `button` is a string that is one of the following constants: 3692 MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, MOUSE_BUTTON4, MOUSE_BUTTON5, 3693 MOUSE_PRIMARY (default), MOUSE_SECONDARY. 3694 3695 If `mouseDownUp` (default: True) is manually set to False, then this 3696 function is basically the same as `moveTo`. Only exists to match PyAutoGUI. 3697 3698 If `_pause` is True (default), then an automatic sleep will be performed 3699 after the function finshes executing. The duration is set by the global 3700 variable `PAUSE`. 3701 3702 ---------------------------------------------------------------------------- 3703 3704 NOTE: `logScreenshot` is currently unsupported. 3705 """ 3706 # TODO: bounding box check for valid position 3707 if button is None: 3708 button = MOUSE_PRIMARY 3709 if mouseDownUp: 3710 mouseDown(button=button, _pause=False, virtual=virtual) 3711 moveRel( 3712 xOffset, 3713 yOffset, 3714 duration=duration, 3715 tween=tween, 3716 logScreenshot=logScreenshot, 3717 _pause=False, # don't add an additional pause 3718 relative=relative, 3719 virtual=virtual, 3720 path_function=path_function, 3721 disable_mouse_acceleration=disable_mouse_acceleration, 3722 ) 3723 if mouseDownUp: 3724 mouseUp(button=button, _pause=False, virtual=virtual) 3725 # --------------------------------------------------------------------------
Press and hold a mouse button while moving a relative distance
See moveRel for more information on most arguments.
button is a string that is one of the following constants:
MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, MOUSE_BUTTON4, MOUSE_BUTTON5,
MOUSE_PRIMARY (default), MOUSE_SECONDARY.
If mouseDownUp (default: True) is manually set to False, then this
function is basically the same as moveTo. Only exists to match PyAutoGUI.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
NOTE: logScreenshot is currently unsupported.
3739def is_valid_key(key: str) -> bool: 3740 """ 3741 Returns true if key name `key` can be translated into a valid scan code. 3742 """ 3743 return key in KEYBOARD_MAPPING
Returns true if key name key can be translated into a valid scan code.
3739def is_valid_key(key: str) -> bool: 3740 """ 3741 Returns true if key name `key` can be translated into a valid scan code. 3742 """ 3743 return key in KEYBOARD_MAPPING
Returns true if key name key can be translated into a valid scan code.
3754@_genericPyDirectInputChecks 3755def scancode_keyDown( 3756 scancodes: ScancodeTypes, 3757 logScreenshot: None = None, 3758 _pause: bool = True, 3759 *, 3760 auto_shift: bool = False, 3761) -> bool: 3762 """ 3763 Press down key corresponding to `scancodes`. 3764 3765 The actually pressed key will depend on your system keyboard layout. 3766 Limits the available character set but should provide the best 3767 compatibility. 3768 3769 If `_pause` is True (default), then an automatic sleep will be performed 3770 after the function finshes executing. The duration is set by the global 3771 variable `PAUSE`. 3772 3773 `auto_shift` is used internally by higher level functions to automatically 3774 press the shift key before supported scancodes (indicitated by a special 3775 bit outside the regular scancode range, while it technically can be used, 3776 it's not intended for public access). 3777 3778 ---------------------------------------------------------------------------- 3779 3780 NOTE: `logScreenshot` is currently unsupported. 3781 """ 3782 scancodes_sequence: ScancodeSequence 3783 if isinstance(scancodes, int): 3784 scancodes_sequence = ScancodeSequence([scancodes]) 3785 else: 3786 scancodes_sequence = scancodes 3787 3788 keybdFlags: int = _KEYEVENTF_SCANCODE 3789 input_structs: list[_INPUT] = [] 3790 extendedFlag: int 3791 3792 # Init event tracking 3793 insertedEvents: int = 0 3794 expectedEvents: int = 0 3795 3796 for scancode in scancodes_sequence: 3797 if auto_shift and scancode & _OFFSET_SHIFTKEY: 3798 input_structs += [ 3799 _create_keyboard_input( 3800 wScan=_SHIFT_SCANCODE, dwFlags=keybdFlags 3801 ) 3802 ] 3803 expectedEvents += 1 3804 3805 scancode = scancode & 0xFFFF 3806 3807 extendedFlag = _KEYEVENTF_EXTENDEDKEY if scancode >= 0xE000 else 0 3808 input_structs += [ 3809 _create_keyboard_input( 3810 wScan=scancode, dwFlags=keybdFlags | extendedFlag 3811 ) 3812 ] 3813 expectedEvents += 1 3814 3815 insertedEvents += _send_input(input_structs) 3816 3817 # SendInput returns the number of event successfully inserted into 3818 # input stream 3819 # https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput#return-value 3820 return insertedEvents == expectedEvents 3821 # --------------------------------------------------------------------------
Press down key corresponding to scancodes.
The actually pressed key will depend on your system keyboard layout. Limits the available character set but should provide the best compatibility.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
auto_shift is used internally by higher level functions to automatically
press the shift key before supported scancodes (indicitated by a special
bit outside the regular scancode range, while it technically can be used,
it's not intended for public access).
NOTE: logScreenshot is currently unsupported.
3825@_genericPyDirectInputChecks 3826def scancode_keyUp( 3827 scancodes: ScancodeTypes, 3828 logScreenshot: None = None, 3829 _pause: bool = True, 3830 *, 3831 auto_shift: bool = False, 3832) -> bool: 3833 """ 3834 Release key corresponding to `scancodes`. 3835 3836 The actually pressed key will depend on your system keyboard layout. 3837 Limits the available character set but should provide the best 3838 compatibility. 3839 3840 If `_pause` is True (default), then an automatic sleep will be performed 3841 after the function finshes executing. The duration is set by the global 3842 variable `PAUSE`. 3843 3844 `auto_shift` is used internally by higher level functions to automatically 3845 press the shift key before supported scancodes (indicitated by a special 3846 bit outside the regular scancode range, while it technically can be used, 3847 it's not intended for public access). 3848 3849 ---------------------------------------------------------------------------- 3850 3851 NOTE: `logScreenshot` is currently unsupported. 3852 """ 3853 scancodes_sequence: ScancodeSequence 3854 if isinstance(scancodes, int): 3855 scancodes_sequence = ScancodeSequence([scancodes]) 3856 else: 3857 scancodes_sequence = scancodes 3858 3859 keybdFlags: int = _KEYEVENTF_SCANCODE | _KEYEVENTF_KEYUP 3860 input_structs: list[_INPUT] = [] 3861 extendedFlag: int 3862 3863 # Init event tracking 3864 insertedEvents: int = 0 3865 expectedEvents: int = 0 3866 3867 for scancode in scancodes_sequence: 3868 if auto_shift and scancode & _OFFSET_SHIFTKEY: 3869 input_structs += [ 3870 _create_keyboard_input( 3871 wScan=_SHIFT_SCANCODE, dwFlags=keybdFlags 3872 ) 3873 ] 3874 expectedEvents += 1 3875 3876 scancode = scancode & 0xFFFF 3877 3878 extendedFlag = _KEYEVENTF_EXTENDEDKEY if scancode >= 0xE000 else 0 3879 input_structs += [ 3880 _create_keyboard_input( 3881 wScan=scancode & 0xFFFF, dwFlags=keybdFlags | extendedFlag 3882 ) 3883 ] 3884 expectedEvents += 1 3885 3886 insertedEvents += _send_input(input_structs) 3887 return insertedEvents == expectedEvents 3888 # --------------------------------------------------------------------------
Release key corresponding to scancodes.
The actually pressed key will depend on your system keyboard layout. Limits the available character set but should provide the best compatibility.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
auto_shift is used internally by higher level functions to automatically
press the shift key before supported scancodes (indicitated by a special
bit outside the regular scancode range, while it technically can be used,
it's not intended for public access).
NOTE: logScreenshot is currently unsupported.
3918@_genericPyDirectInputChecks 3919def scancode_press( 3920 scancodes: ScancodeTypes | Sequence[ScancodeTypes], 3921 presses: int = 1, 3922 interval: float = 0.0, 3923 logScreenshot: None = None, 3924 _pause: bool = True, 3925 *, 3926 auto_shift: bool = False, 3927 delay: float = 0.0, 3928 duration: float = 0.0, 3929) -> bool: 3930 """ 3931 Press the sequence of `keys` for `presses` amount of times. 3932 3933 The actually pressed key will depend on your system keyboard layout. 3934 Limits the available character set but should provide the best 3935 compatibility. 3936 3937 Explanation of time parameters (seconds as floating point numbers): 3938 3939 - `interval` is the time spent waiting between sequences. If `keys` is a 3940 str instance or single element list, then `interval` will be ignored. 3941 - `delay` is the time from one complete key (press+release) to the next one 3942 in the same sequence. If there is only a single key in a sequence, then 3943 `delay` will be ignored. 3944 - `duration` is the time spent on holding every key before releasing it 3945 again. 3946 3947 If `_pause` is True (default), then an automatic sleep will be performed 3948 after the function finshes executing. The duration is set by the global 3949 variable `PAUSE`. 3950 Be aware, that the global pause defined by the PAUSE `constant` only 3951 applies after every call to this function, not inbetween (no extra pause 3952 between pressing and releasing key, use the `duration` argument instead)! 3953 3954 `auto_shift` is used internally by higher level functions to automatically 3955 press the shift key before supported scancodes (indicitated by a special 3956 bit outside the regular scancode range, while it technically can be used, 3957 it's not intended for public access). 3958 3959 ---------------------------------------------------------------------------- 3960 3961 NOTE: `logScreenshot` is currently unsupported. 3962 """ 3963 scancodes_sequence: Sequence[ScancodeTypes] 3964 if isinstance(scancodes, int): 3965 scancodes_sequence = [ScancodeSequence([scancodes])] 3966 elif isinstance(scancodes, ScancodeSequence): 3967 scancodes_sequence = [scancodes] 3968 else: 3969 scancodes_sequence = scancodes 3970 3971 # We need to press x keys y times, which comes out to x*y presses in total 3972 expectedPresses: int = presses * len(scancodes_sequence) 3973 completedPresses: int = 0 3974 3975 apply_interval: bool = False 3976 for _ in range(presses): 3977 if apply_interval: # Don't delay first press 3978 _sleep(interval) 3979 apply_interval = True 3980 3981 apply_delay: bool = False 3982 for c in scancodes_sequence: 3983 if apply_delay: # Don't delay first press 3984 _sleep(delay) 3985 apply_delay = True 3986 3987 completedPresses += _helper_scancode_press( 3988 c, duration, _pause=False, auto_shift=auto_shift 3989 ) 3990 3991 return completedPresses == expectedPresses 3992 # --------------------------------------------------------------------------
Press the sequence of keys for presses amount of times.
The actually pressed key will depend on your system keyboard layout. Limits the available character set but should provide the best compatibility.
Explanation of time parameters (seconds as floating point numbers):
intervalis the time spent waiting between sequences. Ifkeysis a str instance or single element list, thenintervalwill be ignored.delayis the time from one complete key (press+release) to the next one in the same sequence. If there is only a single key in a sequence, thendelaywill be ignored.durationis the time spent on holding every key before releasing it again.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
Be aware, that the global pause defined by the PAUSE constant only
applies after every call to this function, not inbetween (no extra pause
between pressing and releasing key, use the duration argument instead)!
auto_shift is used internally by higher level functions to automatically
press the shift key before supported scancodes (indicitated by a special
bit outside the regular scancode range, while it technically can be used,
it's not intended for public access).
NOTE: logScreenshot is currently unsupported.
3996@contextmanager 3997@_genericPyDirectInputChecks 3998def scancode_hold( 3999 scancodes: ScancodeTypes | Sequence[ScancodeTypes], 4000 logScreenshot: None = None, 4001 _pause: bool = True, 4002 *, 4003 auto_shift: bool = False, 4004 raise_on_failure: bool = False, 4005) -> Generator[None, None, None]: 4006 """ 4007 Hold the sequence of keys corresponding to `scancodes` as long as the 4008 context manager is in scope (press upon entry, release upon exit). 4009 4010 Keys will be released in reverse order (LIFO), but still practically 4011 instantenous. 4012 4013 The actually pressed key will depend on your system keyboard layout. 4014 Limits the available character set but should provide the best 4015 compatibility. 4016 4017 If `_pause` is True (default), then an automatic sleep will be performed 4018 after the function finshes executing. The duration is set by the global 4019 variable `PAUSE`. 4020 Be aware, that the global pause defined by the PAUSE `constant` only 4021 applies after every call to this function, not inbetween (no pause between 4022 press and releasing key)! 4023 4024 `auto_shift` is used internally by higher level functions to automatically 4025 press the shift key before supported scancodes (indicitated by a special 4026 bit outside the regular scancode range, while it technically can be used, 4027 it's not intended for public access). 4028 4029 If `raise_on_failure` is True, then `PriorInputFailedException` will be 4030 raised if not all keyboard inputs could be executed successfully. 4031 4032 ---------------------------------------------------------------------------- 4033 4034 NOTE: `logScreenshot` is currently unsupported. 4035 """ 4036 scancodes_sequence: Sequence[ScancodeTypes] 4037 if isinstance(scancodes, int): 4038 scancodes_sequence = [ScancodeSequence([scancodes])] 4039 elif isinstance(scancodes, ScancodeSequence): 4040 scancodes_sequence = [scancodes] 4041 else: 4042 scancodes_sequence = scancodes 4043 4044 expectedPresses: int = len(scancodes_sequence) 4045 downed: int = 0 4046 upped: int = 0 4047 4048 try: 4049 for c in scancodes_sequence: 4050 downed += scancode_keyDown(c, _pause=False, auto_shift=auto_shift) 4051 yield 4052 finally: 4053 for c in reversed(scancodes_sequence): 4054 upped += scancode_keyUp(c, _pause=False, auto_shift=auto_shift) 4055 if raise_on_failure and not (expectedPresses == downed == upped): 4056 raise PriorInputFailedException 4057 # --------------------------------------------------------------------------
Hold the sequence of keys corresponding to scancodes as long as the
context manager is in scope (press upon entry, release upon exit).
Keys will be released in reverse order (LIFO), but still practically instantenous.
The actually pressed key will depend on your system keyboard layout. Limits the available character set but should provide the best compatibility.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
Be aware, that the global pause defined by the PAUSE constant only
applies after every call to this function, not inbetween (no pause between
press and releasing key)!
auto_shift is used internally by higher level functions to automatically
press the shift key before supported scancodes (indicitated by a special
bit outside the regular scancode range, while it technically can be used,
it's not intended for public access).
If raise_on_failure is True, then PriorInputFailedException will be
raised if not all keyboard inputs could be executed successfully.
NOTE: logScreenshot is currently unsupported.
4061@_genericPyDirectInputChecks 4062def scancode_hotkey( 4063 *args: ScancodeTypes, 4064 interval: float = 0.0, 4065 wait: float = 0.0, 4066 logScreenshot: None = None, 4067 _pause: bool = True, 4068 auto_shift: bool = True, 4069) -> bool: 4070 """ 4071 Press down buttons in order they are specified as arguments, 4072 releasing them in reverse order, e.g. 0x1D, 0x2E will first press 4073 Control, then C and release C before releasing Control. 4074 4075 Use keyword-only argument `interval` to specify a delay between single 4076 keys when pressing and releasing and `wait` for delay between last press 4077 and first release. 4078 4079 If `_pause` is True (default), then an automatic sleep will be performed 4080 after the function finshes executing. The duration is set by the global 4081 variable `PAUSE`. 4082 Be aware, that the global pause defined by the PAUSE `constant` only 4083 applies after every call to this function, not inbetween (no pause between 4084 press and releasing key)! 4085 4086 `auto_shift` is used internally by higher level functions to automatically 4087 press the shift key before supported scancodes (indicitated by a special 4088 bit outside the regular scancode range, while it technically can be used, 4089 it's not intended for public access). 4090 4091 ---------------------------------------------------------------------------- 4092 4093 NOTE: `logScreenshot` is currently unsupported. 4094 """ 4095 expectedPresses: int = len(args) 4096 downed: int = 0 4097 upped: int = 0 4098 4099 apply_interval: bool = False 4100 for code in args: 4101 if apply_interval: 4102 _sleep(interval) # sleep between iterations 4103 apply_interval = True 4104 4105 downed += scancode_keyDown(code, _pause=False, auto_shift=auto_shift) 4106 4107 _sleep(wait) 4108 4109 apply_interval = False 4110 for code in reversed(args): 4111 if apply_interval: 4112 _sleep(interval) # sleep between iterations 4113 apply_interval = True 4114 4115 upped += scancode_keyUp(code, _pause=False, auto_shift=auto_shift) 4116 4117 return expectedPresses == downed == upped 4118 # --------------------------------------------------------------------------
Press down buttons in order they are specified as arguments, releasing them in reverse order, e.g. 0x1D, 0x2E will first press Control, then C and release C before releasing Control.
Use keyword-only argument interval to specify a delay between single
keys when pressing and releasing and wait for delay between last press
and first release.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
Be aware, that the global pause defined by the PAUSE constant only
applies after every call to this function, not inbetween (no pause between
press and releasing key)!
auto_shift is used internally by higher level functions to automatically
press the shift key before supported scancodes (indicitated by a special
bit outside the regular scancode range, while it technically can be used,
it's not intended for public access).
NOTE: logScreenshot is currently unsupported.
4126def keyDown( 4127 key: str, 4128 logScreenshot: None = None, 4129 _pause: bool = True, 4130 *, 4131 auto_shift: bool = False, 4132) -> bool: 4133 """ 4134 Press down key corresponding to key name `key`. 4135 4136 `key` will be interpreted as a keyboard key (US QWERTY). 4137 The actually pressed key will depend on your system keyboard layout. 4138 Limits the available character set but should provide the best 4139 compatibility. 4140 4141 If `_pause` is True (default), then an automatic sleep will be performed 4142 after the function finshes executing. The duration is set by the global 4143 variable `PAUSE`. 4144 4145 If `auto_shift` is True, then "shifted" characters like upper case letters 4146 and the symbols on the number row automatically insert a Shift scancode 4147 into the input sequence. 4148 4149 ---------------------------------------------------------------------------- 4150 4151 NOTE: `logScreenshot` is currently unsupported. 4152 """ 4153 scancode: ScancodeTypes | None = KEYBOARD_MAPPING.get(key) 4154 if scancode is None: 4155 return False 4156 return scancode_keyDown( 4157 scancode, logScreenshot, _pause=_pause, auto_shift=auto_shift 4158 ) 4159 # --------------------------------------------------------------------------
Press down key corresponding to key name key.
key will be interpreted as a keyboard key (US QWERTY).
The actually pressed key will depend on your system keyboard layout.
Limits the available character set but should provide the best
compatibility.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
If auto_shift is True, then "shifted" characters like upper case letters
and the symbols on the number row automatically insert a Shift scancode
into the input sequence.
NOTE: logScreenshot is currently unsupported.
4164def keyUp( 4165 key: str, 4166 logScreenshot: None = None, 4167 _pause: bool = True, 4168 *, 4169 auto_shift: bool = False, 4170) -> bool: 4171 """ 4172 Lift up key corresponding to key name `key`. 4173 4174 `key` will be interpreted as a keyboard key (US QWERTY). 4175 The actually lifted key will depend on your system keyboard layout. 4176 Limits the available character set but should provide the best 4177 compatibility. 4178 4179 If `_pause` is True (default), then an automatic sleep will be performed 4180 after the function finshes executing. The duration is set by the global 4181 variable `PAUSE`. 4182 4183 If `auto_shift` is True, then "shifted" characters like upper case letters 4184 and the symbols on the number row automatically insert a Shift scancode 4185 into the input sequence. 4186 4187 ---------------------------------------------------------------------------- 4188 4189 NOTE: `logScreenshot` is currently unsupported. 4190 """ 4191 scancode: ScancodeTypes | None = KEYBOARD_MAPPING.get(key) 4192 if scancode is None: 4193 return False 4194 return scancode_keyUp( 4195 scancode, logScreenshot, _pause=_pause, auto_shift=auto_shift 4196 ) 4197 # --------------------------------------------------------------------------
Lift up key corresponding to key name key.
key will be interpreted as a keyboard key (US QWERTY).
The actually lifted key will depend on your system keyboard layout.
Limits the available character set but should provide the best
compatibility.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
If auto_shift is True, then "shifted" characters like upper case letters
and the symbols on the number row automatically insert a Shift scancode
into the input sequence.
NOTE: logScreenshot is currently unsupported.
4223@_genericPyDirectInputChecks 4224def press( 4225 keys: str | Sequence[str], 4226 presses: int = 1, 4227 interval: float = 0.0, 4228 logScreenshot: None = None, 4229 _pause: bool = True, 4230 *, 4231 auto_shift: bool = False, 4232 delay: float = 0.0, 4233 duration: float = 0.0, 4234) -> bool: 4235 """ 4236 Press the sequence of `keys` for `presses` amount of times. 4237 4238 `keys` will be interpreted as sequence of keyboard keys (US QWERTY). 4239 The actually pressed key will depend on your system keyboard layout. 4240 Limits the available character set but should provide the best 4241 compatibility. 4242 4243 Explanation of time parameters (seconds as floating point numbers): 4244 4245 - `interval` is the time spent waiting between sequences. If `keys` is a 4246 str instance, single element list or presses equals 1 (the default), 4247 then `interval` will be ignored. 4248 - `delay` is the time from one complete key (press+release) to the next one 4249 in the same sequence. If there is only a single key in a sequence, then 4250 `delay` will be ignored. 4251 - `duration` is the time spent on holding every key before releasing it 4252 again. 4253 4254 If `_pause` is True (default), then an automatic sleep will be performed 4255 after the function finshes executing. The duration is set by the global 4256 variable `PAUSE`. 4257 Be aware, that the global pause defined by the `PAUSE` var only applies 4258 after every call to this function, not inbetween (no extra pause between 4259 pressing and releasing key, use the `duration` argument instead)! 4260 4261 If `auto_shift` is True, then "shifted" characters like upper case letters 4262 and the symbols on the number row automatically insert a Shift scancode 4263 into the input sequence. 4264 4265 ---------------------------------------------------------------------------- 4266 4267 NOTE: `logScreenshot` is currently unsupported. 4268 """ 4269 if isinstance(keys, str): 4270 keys = [keys] # If keys is 'enter', convert it to ['enter']. 4271 keys = [_normalize_key(key, auto_shift=auto_shift) for key in keys] 4272 4273 # We need to press x keys y times, which comes out to x*y presses in total 4274 expectedPresses: int = presses * len(keys) 4275 completedPresses: int = 0 4276 4277 apply_interval: bool = False 4278 for _ in range(presses): 4279 if apply_interval: # Don't delay first press 4280 _sleep(interval) 4281 apply_interval = True 4282 4283 apply_delay: bool = False 4284 for k in keys: 4285 if apply_delay: # Don't delay first press 4286 _sleep(delay) 4287 apply_delay = True 4288 4289 completedPresses += _helper_press( 4290 k, duration, _pause=False, auto_shift=auto_shift 4291 ) 4292 4293 return completedPresses == expectedPresses 4294 # --------------------------------------------------------------------------
Press the sequence of keys for presses amount of times.
keys will be interpreted as sequence of keyboard keys (US QWERTY).
The actually pressed key will depend on your system keyboard layout.
Limits the available character set but should provide the best
compatibility.
Explanation of time parameters (seconds as floating point numbers):
intervalis the time spent waiting between sequences. Ifkeysis a str instance, single element list or presses equals 1 (the default), thenintervalwill be ignored.delayis the time from one complete key (press+release) to the next one in the same sequence. If there is only a single key in a sequence, thendelaywill be ignored.durationis the time spent on holding every key before releasing it again.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
Be aware, that the global pause defined by the PAUSE var only applies
after every call to this function, not inbetween (no extra pause between
pressing and releasing key, use the duration argument instead)!
If auto_shift is True, then "shifted" characters like upper case letters
and the symbols on the number row automatically insert a Shift scancode
into the input sequence.
NOTE: logScreenshot is currently unsupported.
4298@contextmanager 4299@_genericPyDirectInputChecks 4300def hold( 4301 keys: str | Sequence[str], 4302 logScreenshot: None = None, 4303 _pause: bool = True, 4304 *, 4305 auto_shift: bool = False, 4306 raise_on_failure: bool = False, 4307) -> Generator[None, None, None]: 4308 """ 4309 Hold the sequence of keys corresponding to key names in `keys` as long as 4310 the context manager is in scope (press upon entry, release upon exit). 4311 4312 Keys will be released in reverse order (LIFO), but still practically 4313 instantenous. 4314 4315 `key` will be interpreted as a keyboard key (US QWERTY). 4316 The actually pressed key will depend on your system keyboard layout. 4317 Limits the available character set but should provide the best 4318 compatibility. 4319 4320 If `_pause` is True (default), then an automatic sleep will be performed 4321 after the function finshes executing. The duration is set by the global 4322 variable `PAUSE`. 4323 Be aware, that the global pause defined by the PAUSE `constant` only 4324 applies after every call to this function, not inbetween (no pause between 4325 press and releasing key)! 4326 4327 `auto_shift` is used internally by higher level functions to automatically 4328 press the shift key before supported scancodes (indicitated by a special 4329 bit outside the regular scancode range, while it technically can be used, 4330 it's not intended for public access). 4331 4332 If `raise_on_failure` is True, then `PriorInputFailedException` will be 4333 raised if not all keyboard inputs could be executed successfully. 4334 4335 ---------------------------------------------------------------------------- 4336 4337 NOTE: `logScreenshot` is currently unsupported. 4338 """ 4339 if isinstance(keys, str): 4340 keys = [keys] # make single element into iterable 4341 keys = [_normalize_key(key, auto_shift=auto_shift) for key in keys] 4342 4343 expectedPresses: int = len(keys) 4344 downed: int = 0 4345 upped: int = 0 4346 4347 try: 4348 for k in keys: 4349 downed += keyDown(k, auto_shift=auto_shift) 4350 yield 4351 finally: 4352 for k in reversed(keys): 4353 upped += keyUp(k, auto_shift=auto_shift) 4354 if raise_on_failure and not (expectedPresses == downed == upped): 4355 raise PriorInputFailedException 4356 # --------------------------------------------------------------------------
Hold the sequence of keys corresponding to key names in keys as long as
the context manager is in scope (press upon entry, release upon exit).
Keys will be released in reverse order (LIFO), but still practically instantenous.
key will be interpreted as a keyboard key (US QWERTY).
The actually pressed key will depend on your system keyboard layout.
Limits the available character set but should provide the best
compatibility.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
Be aware, that the global pause defined by the PAUSE constant only
applies after every call to this function, not inbetween (no pause between
press and releasing key)!
auto_shift is used internally by higher level functions to automatically
press the shift key before supported scancodes (indicitated by a special
bit outside the regular scancode range, while it technically can be used,
it's not intended for public access).
If raise_on_failure is True, then PriorInputFailedException will be
raised if not all keyboard inputs could be executed successfully.
NOTE: logScreenshot is currently unsupported.
4360@_genericPyDirectInputChecks 4361def typewrite( 4362 message: str, 4363 interval: float = 0.0, 4364 logScreenshot: None = None, 4365 _pause: bool = True, 4366 *, 4367 auto_shift: bool = False, 4368 delay: float = 0.0, 4369 duration: float = 0.0, 4370) -> None: 4371 """ 4372 Break down `message` into a single character key sequence and press each 4373 key one by one. 4374 4375 `message` will be interpreted as sequence of keyboard keys (US QWERTY). 4376 The actually pressed keys will depend on your system keyboard layout. 4377 Limits the available character set but should provide the best 4378 compatibility. 4379 4380 Explanation of time parameters (seconds as floating point numbers): 4381 4382 - `interval` is the time spent waiting between sequences. If `message` is a 4383 single character string, then `interval` will be ignored. 4384 - `delay` is the time from one complete key (press+release) to the next one 4385 in the same sequence. If there is only a single key in a sequence, then 4386 `delay` will be ignored. 4387 - `duration` is the time spent on holding every key before releasing it 4388 again. 4389 4390 If `_pause` is True (default), then an automatic sleep will be performed 4391 after the function finshes executing. The duration is set by the global 4392 variable `PAUSE`. 4393 Be aware, that the global pause defined by the PAUSE `constant` only 4394 applies after every call to this function, not inbetween (no pause between 4395 press and releasing key)! 4396 4397 `auto_shift` is used internally by higher level functions to automatically 4398 press the shift key before supported scancodes (indicitated by a special 4399 bit outside the regular scancode range, while it technically can be used, 4400 it's not intended for public access). 4401 4402 ---------------------------------------------------------------------------- 4403 4404 NOTE: `logScreenshot` is currently unsupported. 4405 """ 4406 4407 apply_interval: bool = False 4408 for key in message: 4409 if apply_interval: # Don't delay first press 4410 _sleep(interval) 4411 apply_interval = True 4412 4413 press( 4414 key, 4415 _pause=False, 4416 auto_shift=auto_shift, 4417 delay=delay, 4418 duration=duration, 4419 ) 4420 # --------------------------------------------------------------------------
Break down message into a single character key sequence and press each
key one by one.
message will be interpreted as sequence of keyboard keys (US QWERTY).
The actually pressed keys will depend on your system keyboard layout.
Limits the available character set but should provide the best
compatibility.
Explanation of time parameters (seconds as floating point numbers):
intervalis the time spent waiting between sequences. Ifmessageis a single character string, thenintervalwill be ignored.delayis the time from one complete key (press+release) to the next one in the same sequence. If there is only a single key in a sequence, thendelaywill be ignored.durationis the time spent on holding every key before releasing it again.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
Be aware, that the global pause defined by the PAUSE constant only
applies after every call to this function, not inbetween (no pause between
press and releasing key)!
auto_shift is used internally by higher level functions to automatically
press the shift key before supported scancodes (indicitated by a special
bit outside the regular scancode range, while it technically can be used,
it's not intended for public access).
NOTE: logScreenshot is currently unsupported.
4360@_genericPyDirectInputChecks 4361def typewrite( 4362 message: str, 4363 interval: float = 0.0, 4364 logScreenshot: None = None, 4365 _pause: bool = True, 4366 *, 4367 auto_shift: bool = False, 4368 delay: float = 0.0, 4369 duration: float = 0.0, 4370) -> None: 4371 """ 4372 Break down `message` into a single character key sequence and press each 4373 key one by one. 4374 4375 `message` will be interpreted as sequence of keyboard keys (US QWERTY). 4376 The actually pressed keys will depend on your system keyboard layout. 4377 Limits the available character set but should provide the best 4378 compatibility. 4379 4380 Explanation of time parameters (seconds as floating point numbers): 4381 4382 - `interval` is the time spent waiting between sequences. If `message` is a 4383 single character string, then `interval` will be ignored. 4384 - `delay` is the time from one complete key (press+release) to the next one 4385 in the same sequence. If there is only a single key in a sequence, then 4386 `delay` will be ignored. 4387 - `duration` is the time spent on holding every key before releasing it 4388 again. 4389 4390 If `_pause` is True (default), then an automatic sleep will be performed 4391 after the function finshes executing. The duration is set by the global 4392 variable `PAUSE`. 4393 Be aware, that the global pause defined by the PAUSE `constant` only 4394 applies after every call to this function, not inbetween (no pause between 4395 press and releasing key)! 4396 4397 `auto_shift` is used internally by higher level functions to automatically 4398 press the shift key before supported scancodes (indicitated by a special 4399 bit outside the regular scancode range, while it technically can be used, 4400 it's not intended for public access). 4401 4402 ---------------------------------------------------------------------------- 4403 4404 NOTE: `logScreenshot` is currently unsupported. 4405 """ 4406 4407 apply_interval: bool = False 4408 for key in message: 4409 if apply_interval: # Don't delay first press 4410 _sleep(interval) 4411 apply_interval = True 4412 4413 press( 4414 key, 4415 _pause=False, 4416 auto_shift=auto_shift, 4417 delay=delay, 4418 duration=duration, 4419 ) 4420 # --------------------------------------------------------------------------
Break down message into a single character key sequence and press each
key one by one.
message will be interpreted as sequence of keyboard keys (US QWERTY).
The actually pressed keys will depend on your system keyboard layout.
Limits the available character set but should provide the best
compatibility.
Explanation of time parameters (seconds as floating point numbers):
intervalis the time spent waiting between sequences. Ifmessageis a single character string, thenintervalwill be ignored.delayis the time from one complete key (press+release) to the next one in the same sequence. If there is only a single key in a sequence, thendelaywill be ignored.durationis the time spent on holding every key before releasing it again.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
Be aware, that the global pause defined by the PAUSE constant only
applies after every call to this function, not inbetween (no pause between
press and releasing key)!
auto_shift is used internally by higher level functions to automatically
press the shift key before supported scancodes (indicitated by a special
bit outside the regular scancode range, while it technically can be used,
it's not intended for public access).
NOTE: logScreenshot is currently unsupported.
4431@_genericPyDirectInputChecks 4432def hotkey( 4433 *args: str, 4434 interval: float = 0.0, 4435 wait: float = 0.0, 4436 logScreenshot: None = None, 4437 _pause: bool = True, 4438 auto_shift: bool = True, 4439) -> None: 4440 """ 4441 Press down buttons in order they are specified as arguments, 4442 releasing them in reverse order, e.g. 'ctrl', 'c' will first press 4443 Control, then C and release C before releasing Control. 4444 4445 Use keyword-only argument `interval` to specify a delay between single 4446 keys when pressing and releasing and `wait` for delay between last press 4447 and first release. 4448 4449 If `_pause` is True (default), then an automatic sleep will be performed 4450 after the function finshes executing. The duration is set by the global 4451 variable `PAUSE`. 4452 Be aware, that the global pause defined by the PAUSE `constant` only 4453 applies after every call to this function, not inbetween (no pause between 4454 press and releasing key)! 4455 4456 `auto_shift` is used internally by higher level functions to automatically 4457 press the shift key before supported scancodes (indicitated by a special 4458 bit outside the regular scancode range, while it technically can be used, 4459 it's not intended for public access). 4460 4461 ---------------------------------------------------------------------------- 4462 4463 NOTE: `logScreenshot` is currently unsupported. 4464 """ 4465 apply_interval: bool = False 4466 for key in args: 4467 if apply_interval: 4468 _sleep(interval) # sleep between iterations 4469 apply_interval = True 4470 4471 keyDown(key, _pause=False, auto_shift=auto_shift) 4472 4473 _sleep(wait) 4474 4475 apply_interval = False 4476 for key in reversed(args): 4477 if apply_interval: 4478 _sleep(interval) # sleep between iterations 4479 apply_interval = True 4480 4481 keyUp(key, _pause=False, auto_shift=auto_shift) 4482 # --------------------------------------------------------------------------
Press down buttons in order they are specified as arguments, releasing them in reverse order, e.g. 'ctrl', 'c' will first press Control, then C and release C before releasing Control.
Use keyword-only argument interval to specify a delay between single
keys when pressing and releasing and wait for delay between last press
and first release.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
Be aware, that the global pause defined by the PAUSE constant only
applies after every call to this function, not inbetween (no pause between
press and releasing key)!
auto_shift is used internally by higher level functions to automatically
press the shift key before supported scancodes (indicitated by a special
bit outside the regular scancode range, while it technically can be used,
it's not intended for public access).
NOTE: logScreenshot is currently unsupported.
4489@_genericPyDirectInputChecks 4490def unicode_charDown( 4491 char: str, logScreenshot: None = None, _pause: bool = True 4492) -> bool: 4493 """ 4494 Send Unicode character(s) `char` to currently focused application as 4495 WM_KEYDOWN message. 4496 4497 `char` will be interpreted as a string of Unicode characters 4498 (independet from keyboard layout). Supports complete Unicode character set 4499 but may not be compatible with every application. 4500 4501 If `_pause` is True (default), then an automatic sleep will be performed 4502 after the function finshes executing. The duration is set by the global 4503 variable `PAUSE`. 4504 4505 ---------------------------------------------------------------------------- 4506 4507 NOTE: `logScreenshot` is currently unsupported. 4508 """ 4509 utf16surrogates: bytes = char.encode("utf-16be") 4510 codes: Sequence[int] = unpack( 4511 f">{len(utf16surrogates) // 2}H", utf16surrogates 4512 ) 4513 4514 keybdFlags: int = _KEYEVENTF_UNICODE 4515 4516 input_structs: list[_INPUT] = [ 4517 _create_keyboard_input(wVk=0, wScan=charcode, dwFlags=keybdFlags) 4518 for charcode in codes 4519 ] 4520 # Init event tracking 4521 expectedEvents: int = len(input_structs) 4522 insertedEvents: int = _send_input(input_structs) 4523 4524 return insertedEvents == expectedEvents 4525 # --------------------------------------------------------------------------
Send Unicode character(s) char to currently focused application as
WM_KEYDOWN message.
char will be interpreted as a string of Unicode characters
(independet from keyboard layout). Supports complete Unicode character set
but may not be compatible with every application.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
NOTE: logScreenshot is currently unsupported.
4529@_genericPyDirectInputChecks 4530def unicode_charUp( 4531 char: str, logScreenshot: None = None, _pause: bool = True 4532) -> bool: 4533 """ 4534 Send Unicode character(s) `char` to currently focused application as 4535 WM_KEYUP message. 4536 4537 `char` will be interpreted as a string of Unicode characters 4538 (independet from keyboard layout). Supports complete Unicode character set 4539 but may not be compatible with every application. 4540 4541 If `_pause` is True (default), then an automatic sleep will be performed 4542 after the function finshes executing. The duration is set by the global 4543 variable `PAUSE`. 4544 4545 ---------------------------------------------------------------------------- 4546 4547 NOTE: `logScreenshot` is currently unsupported. 4548 """ 4549 utf16surrogates: bytes = char.encode("utf-16be") 4550 codes: Sequence[int] = unpack( 4551 f">{len(utf16surrogates) // 2}H", utf16surrogates 4552 ) 4553 4554 keybdFlags: int = _KEYEVENTF_UNICODE | _KEYEVENTF_KEYUP 4555 4556 input_structs: list[_INPUT] = [ 4557 _create_keyboard_input(wVk=0, wScan=charcode, dwFlags=keybdFlags) 4558 for charcode in codes 4559 ] 4560 # Init event tracking 4561 expectedEvents: int = len(input_structs) 4562 insertedEvents: int = _send_input(input_structs) 4563 4564 return insertedEvents == expectedEvents 4565 # --------------------------------------------------------------------------
Send Unicode character(s) char to currently focused application as
WM_KEYUP message.
char will be interpreted as a string of Unicode characters
(independet from keyboard layout). Supports complete Unicode character set
but may not be compatible with every application.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
NOTE: logScreenshot is currently unsupported.
4589@_genericPyDirectInputChecks 4590def unicode_press( 4591 chars: str | Sequence[str], 4592 presses: int = 1, 4593 interval: float = 0.0, 4594 logScreenshot: None = None, 4595 _pause: bool = True, 4596 *, 4597 delay: float = 0.0, 4598 duration: float = 0.0, 4599) -> bool: 4600 """ 4601 Press the sequence of `chars` for `presses` amount of times. 4602 4603 `chars` will be interpreted as a sequence of Unicode characters 4604 (independent from keyboard layout). Supports complete Unicode character set 4605 but may not be compatible with every application. 4606 4607 Explanation of time parameters (seconds as floating point numbers): 4608 4609 - `interval` is the time spent waiting between sequences. If `chars` is a 4610 str instance or single element list, then `interval` will be ignored. 4611 - `delay` is the time from one complete char (press+release) to the next 4612 one in the same sequence. If there is only a single char in a sequence, 4613 then `delay` will be ignored. 4614 - `duration` is the time spent on holding every char before releasing it 4615 again. 4616 4617 If `_pause` is True (default), then an automatic sleep will be performed 4618 after the function finshes executing. The duration is set by the global 4619 variable `PAUSE`. 4620 Be aware, that the global pause defined by the PAUSE `constant` only 4621 applies after every call to this function, not inbetween (no extra pause 4622 between pressing and releasing key, use the `duration` argument instead)! 4623 4624 ---------------------------------------------------------------------------- 4625 4626 NOTE: `logScreenshot` is currently unsupported. 4627 """ 4628 if isinstance(chars, str): 4629 chars = [chars] 4630 4631 # We need to press x keys y times, which comes out to x*y presses in total 4632 expectedPresses: int = presses * len(chars) 4633 completedPresses: int = 0 4634 4635 apply_interval: bool = False 4636 for _ in range(presses): 4637 if apply_interval: # Don't delay first press 4638 _sleep(interval) 4639 apply_interval = True 4640 4641 apply_delay: bool = False 4642 for c in chars: 4643 if apply_delay: # Don't delay first press 4644 _sleep(delay) 4645 apply_delay = True 4646 4647 completedPresses += _helper_unicode_press_char( 4648 c, 4649 duration, 4650 _pause=False, 4651 ) 4652 4653 return completedPresses == expectedPresses 4654 # --------------------------------------------------------------------------
Press the sequence of chars for presses amount of times.
chars will be interpreted as a sequence of Unicode characters
(independent from keyboard layout). Supports complete Unicode character set
but may not be compatible with every application.
Explanation of time parameters (seconds as floating point numbers):
intervalis the time spent waiting between sequences. Ifcharsis a str instance or single element list, thenintervalwill be ignored.delayis the time from one complete char (press+release) to the next one in the same sequence. If there is only a single char in a sequence, thendelaywill be ignored.durationis the time spent on holding every char before releasing it again.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
Be aware, that the global pause defined by the PAUSE constant only
applies after every call to this function, not inbetween (no extra pause
between pressing and releasing key, use the duration argument instead)!
NOTE: logScreenshot is currently unsupported.
4658@contextmanager 4659@_genericPyDirectInputChecks 4660def unicode_hold( 4661 chars: str | Sequence[str], 4662 logScreenshot: None = None, 4663 _pause: bool = True, 4664 *, 4665 raise_on_failure: bool = False, 4666) -> Generator[None, None, None]: 4667 """ 4668 Hold the sequence of "keys" corresponding to unicode characters in `chars` 4669 as long as the context manager is in scope (press upon entry, 4670 release upon exit). 4671 4672 `chars` will be interpreted as a sequence of Unicode characters 4673 (independet from keyboard layout). Supports complete Unicode character set 4674 but may not be compatible with every application. 4675 4676 Keys will be released in reverse order (LIFO), but still practically 4677 instantenous. 4678 4679 If `_pause` is True (default), then an automatic sleep will be performed 4680 after the function finshes executing. The duration is set by the global 4681 variable `PAUSE`. 4682 Be aware, that the global pause defined by the PAUSE `constant` only 4683 applies after every call to this function, not inbetween (no pause between 4684 press and releasing key)! 4685 4686 If `raise_on_failure` is True, then `PriorInputFailedException` will be 4687 raised if not all keyboard inputs could be executed successfully. 4688 4689 ---------------------------------------------------------------------------- 4690 4691 NOTE: `logScreenshot` is currently unsupported. 4692 """ 4693 if isinstance(chars, str): 4694 chars = [chars] # make single element into iterable 4695 4696 expectedPresses: int = len(chars) 4697 downed: int = 0 4698 upped: int = 0 4699 4700 try: 4701 for c in chars: 4702 downed += unicode_charDown(c, _pause=False) 4703 yield 4704 finally: 4705 for c in reversed(chars): 4706 upped += unicode_charUp(c, _pause=False) 4707 if raise_on_failure and not (expectedPresses == downed == upped): 4708 raise PriorInputFailedException 4709 # --------------------------------------------------------------------------
Hold the sequence of "keys" corresponding to unicode characters in chars
as long as the context manager is in scope (press upon entry,
release upon exit).
chars will be interpreted as a sequence of Unicode characters
(independet from keyboard layout). Supports complete Unicode character set
but may not be compatible with every application.
Keys will be released in reverse order (LIFO), but still practically instantenous.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
Be aware, that the global pause defined by the PAUSE constant only
applies after every call to this function, not inbetween (no pause between
press and releasing key)!
If raise_on_failure is True, then PriorInputFailedException will be
raised if not all keyboard inputs could be executed successfully.
NOTE: logScreenshot is currently unsupported.
4713@_genericPyDirectInputChecks 4714def unicode_typewrite( 4715 message: str, 4716 interval: float = 0.0, 4717 logScreenshot: None = None, 4718 _pause: bool = True, 4719 *, 4720 delay: float = 0.0, 4721 duration: float = 0.0, 4722) -> None: 4723 """ 4724 Break down `message` into characters and press them one by one. 4725 4726 `message` will be interpreted as a sequence of Unicode characters 4727 (independet from keyboard layout). Supports complete Unicode character set 4728 but may not be compatible with every application. 4729 4730 Explanation of time parameters (seconds as floating point numbers): 4731 4732 - `interval` is the time spent waiting between sequences. If `message` is a 4733 single character string, then `interval` will be ignored. 4734 - `delay` is the time from one complete key (press+release) to the next one 4735 in the same sequence. If there is only a single key in a sequence, then 4736 `delay` will be ignored. 4737 - `duration` is the time spent on holding every key before releasing it 4738 again. 4739 4740 If `_pause` is True (default), then an automatic sleep will be performed 4741 after the function finshes executing. The duration is set by the global 4742 variable `PAUSE`. 4743 Be aware, that the global pause defined by the PAUSE `constant` only 4744 applies after every call to this function, not inbetween (no pause between 4745 press and releasing key)! 4746 4747 ---------------------------------------------------------------------------- 4748 4749 NOTE: `logScreenshot` is currently unsupported. 4750 """ 4751 apply_interval: bool = False 4752 for char in message: 4753 if apply_interval: 4754 _sleep(interval) # sleep between iterations 4755 apply_interval = True 4756 4757 unicode_press(char, _pause=False, delay=delay, duration=duration) 4758 # --------------------------------------------------------------------------
Break down message into characters and press them one by one.
message will be interpreted as a sequence of Unicode characters
(independet from keyboard layout). Supports complete Unicode character set
but may not be compatible with every application.
Explanation of time parameters (seconds as floating point numbers):
intervalis the time spent waiting between sequences. Ifmessageis a single character string, thenintervalwill be ignored.delayis the time from one complete key (press+release) to the next one in the same sequence. If there is only a single key in a sequence, thendelaywill be ignored.durationis the time spent on holding every key before releasing it again.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
Be aware, that the global pause defined by the PAUSE constant only
applies after every call to this function, not inbetween (no pause between
press and releasing key)!
NOTE: logScreenshot is currently unsupported.
4713@_genericPyDirectInputChecks 4714def unicode_typewrite( 4715 message: str, 4716 interval: float = 0.0, 4717 logScreenshot: None = None, 4718 _pause: bool = True, 4719 *, 4720 delay: float = 0.0, 4721 duration: float = 0.0, 4722) -> None: 4723 """ 4724 Break down `message` into characters and press them one by one. 4725 4726 `message` will be interpreted as a sequence of Unicode characters 4727 (independet from keyboard layout). Supports complete Unicode character set 4728 but may not be compatible with every application. 4729 4730 Explanation of time parameters (seconds as floating point numbers): 4731 4732 - `interval` is the time spent waiting between sequences. If `message` is a 4733 single character string, then `interval` will be ignored. 4734 - `delay` is the time from one complete key (press+release) to the next one 4735 in the same sequence. If there is only a single key in a sequence, then 4736 `delay` will be ignored. 4737 - `duration` is the time spent on holding every key before releasing it 4738 again. 4739 4740 If `_pause` is True (default), then an automatic sleep will be performed 4741 after the function finshes executing. The duration is set by the global 4742 variable `PAUSE`. 4743 Be aware, that the global pause defined by the PAUSE `constant` only 4744 applies after every call to this function, not inbetween (no pause between 4745 press and releasing key)! 4746 4747 ---------------------------------------------------------------------------- 4748 4749 NOTE: `logScreenshot` is currently unsupported. 4750 """ 4751 apply_interval: bool = False 4752 for char in message: 4753 if apply_interval: 4754 _sleep(interval) # sleep between iterations 4755 apply_interval = True 4756 4757 unicode_press(char, _pause=False, delay=delay, duration=duration) 4758 # --------------------------------------------------------------------------
Break down message into characters and press them one by one.
message will be interpreted as a sequence of Unicode characters
(independet from keyboard layout). Supports complete Unicode character set
but may not be compatible with every application.
Explanation of time parameters (seconds as floating point numbers):
intervalis the time spent waiting between sequences. Ifmessageis a single character string, thenintervalwill be ignored.delayis the time from one complete key (press+release) to the next one in the same sequence. If there is only a single key in a sequence, thendelaywill be ignored.durationis the time spent on holding every key before releasing it again.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
Be aware, that the global pause defined by the PAUSE constant only
applies after every call to this function, not inbetween (no pause between
press and releasing key)!
NOTE: logScreenshot is currently unsupported.
4767@_genericPyDirectInputChecks 4768def unicode_hotkey( 4769 *args: str, 4770 interval: float = 0.0, 4771 wait: float = 0.0, 4772 logScreenshot: None = None, 4773 _pause: bool = True, 4774) -> None: 4775 """ 4776 Press down buttons in order they are specified as arguments, 4777 releasing them in reverse order. 4778 4779 This function makes little sense for Unicode characters and mainly exists 4780 for parity with the other, lower-level hotkey functions! 4781 4782 See `unicode_press()` for an alternative function that presses keys in 4783 series instead. 4784 4785 Use keyword-only argument `interval` to specify a delay between single 4786 keys when pressing and releasing and `wait` for delay between last press 4787 and first release. 4788 4789 If `_pause` is True (default), then an automatic sleep will be performed 4790 after the function finshes executing. The duration is set by the global 4791 variable `PAUSE`. 4792 Be aware, that the global pause defined by the PAUSE `constant` only 4793 applies after every call to this function, not inbetween (no pause between 4794 press and releasing key)! 4795 4796 ---------------------------------------------------------------------------- 4797 4798 NOTE: `logScreenshot` is currently unsupported. 4799 """ 4800 apply_interval: bool = False 4801 for char in args: 4802 if apply_interval: 4803 _sleep(interval) # sleep between iterations 4804 apply_interval = True 4805 4806 unicode_charDown(char, _pause=False) 4807 4808 _sleep(wait) 4809 4810 apply_interval = False 4811 for char in reversed(args): 4812 if apply_interval: 4813 _sleep(interval) # sleep between iterations 4814 apply_interval = True 4815 4816 unicode_charUp(char, _pause=False) 4817 # --------------------------------------------------------------------------
Press down buttons in order they are specified as arguments, releasing them in reverse order.
This function makes little sense for Unicode characters and mainly exists for parity with the other, lower-level hotkey functions!
See unicode_press() for an alternative function that presses keys in
series instead.
Use keyword-only argument interval to specify a delay between single
keys when pressing and releasing and wait for delay between last press
and first release.
If _pause is True (default), then an automatic sleep will be performed
after the function finshes executing. The duration is set by the global
variable PAUSE.
Be aware, that the global pause defined by the PAUSE constant only
applies after every call to this function, not inbetween (no pause between
press and releasing key)!
NOTE: logScreenshot is currently unsupported.