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 3384 `path_function` is a function that takes the start and end coordinates of 3385 the mouse movement (4 integers) and returns a list of coordinates (list of 3386 tuples containting 2 integers each) that the mouse will move through. 3387 The default path function is Bresenham's line algorithm, which will move 3388 the mouse in a straight line. 3389 3390 (*) `relative` parameter decides how the movement is executed: 3391 3392 -> `False`: Target postion is given and absolute movement is used. 3393 3394 -> `True`: Calculates target offset and uses relative movement API 3395 (can be inconsistent) 3396 3397 If `_pause` is True (default), then an automatic sleep will be performed 3398 after the function finshes executing. The duration is set by the global 3399 variable `PAUSE`. 3400 3401 Setting `virtual` to True (default: False) changes the way internal APIs 3402 handle coordinates and is intended for multi monitor systems. It should be 3403 pretty much unncessary even for multi monitor systems, since all the 3404 necessary internal calculations beyond the border of the primay monitor 3405 work without it. 3406 3407 The way that Windows calculates the target pixel coordinates internally 3408 unfortunately leads to inaccuracies and unreachable pixels, especially 3409 if the `virtual` option is used. 3410 3411 If you need the target position to be pixel perfect, you can try setting 3412 `attempt_pixel_perfect` to True, which will use tiny relative movements 3413 to correct the unreachable position. 3414 3415 Relative movement is influenced by mouse speed and Windows Enhanced Pointer 3416 Precision, which can be temporarily disabled by setting 3417 `disable_mouse_acceleration`. 3418 3419 ---------------------------------------------------------------------------- 3420 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 3421 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 3422 3423 If you you start a relative movement while another is already in progress 3424 than the second movement could overwrite the first setting and disable 3425 Enhanced Pointer Precision and change mouse speed. 3426 There are some measures in place to try to mitigate that risk, such as an 3427 internal counter that only allows storing and restoring the acceleration 3428 settings as long as no other movement is currently in progress. 3429 Additionally, the acceleration settings can be manually saved and 3430 restored with `store_mouse_acceleration_settings()` and 3431 `restore_mouse_acceleration_settings()`. For your convenience, the 3432 store function is automatically called during import to save your current 3433 setting. You can then call the restore function at any time. 3434 3435 If all fails, the setting is not written permanently to your Windows 3436 settings, so it should restore itself upon reboot. 3437 3438 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3439 this library in multiple threads / processes / programs at the same time! 3440 3441 ---------------------------------------------------------------------------- 3442 3443 NOTE: `logScreenshot` is currently unsupported. 3444 """ 3445 if relative: 3446 _relative_mouse_move( 3447 x=x, 3448 y=y, 3449 duration=duration, 3450 tween=tween, 3451 logScreenshot=logScreenshot, 3452 target_coords_relative=False, 3453 virtual=virtual, 3454 path_function=path_function, 3455 disable_mouse_acceleration=disable_mouse_acceleration, 3456 ) 3457 else: 3458 _absolute_mouse_move( 3459 x=x, 3460 y=y, 3461 duration=duration, 3462 tween=tween, 3463 logScreenshot=logScreenshot, 3464 target_coords_relative=False, 3465 virtual=virtual, 3466 path_function=path_function, 3467 attempt_pixel_perfect=attempt_pixel_perfect, 3468 disable_mouse_acceleration=disable_mouse_acceleration, 3469 ) 3470 # -------------------------------------------------------------------------- 3471 3472 3473# ----- moveRel ---------------------------------------------------------------- 3474@_genericPyDirectInputChecks 3475def moveRel( 3476 xOffset: int | None = None, 3477 yOffset: int | None = None, 3478 duration: float = 0.0, 3479 tween: Callable[[float], float] | None = None, 3480 logScreenshot: bool = False, 3481 _pause: bool = True, 3482 relative: bool = False, 3483 *, 3484 virtual: bool = False, 3485 path_function: PathFunction | None = None, 3486 attempt_pixel_perfect: bool = False, 3487 disable_mouse_acceleration: bool = False, 3488) -> None: 3489 """ 3490 Move the mouse a relative amount determined by `xOffset` and `yOffset`. 3491 3492 If `duration` is floating point number greater than 0, then this function 3493 will automatically split the movement into microsteps instead of moving the 3494 complete distance instantly. 3495 3496 `tween` is a function that takes a floating point number between 0.0 and 3497 1.0 and returns another floating point number between 0.0 and 1.0. The 3498 returned number will be used to calculate the next position of the 3499 mouse between the start and the end position based on the current duration. 3500 The default tweening function is linear, which will move the mouse at a 3501 constant speed. See the `pytweening` package for more tweening functions. 3502 3503 `path_function` is a function that takes the start and end coordinates of 3504 the mouse movement (4 integers) and returns a list of coordinates (list of 3505 tuples containting 2 integers each) that the mouse will move through. 3506 The default path function is Bresenham's line algorithm, which will move 3507 the mouse in a straight line. 3508 3509 `relative` parameter decides how the movement is executed: 3510 3511 -> `False`: Target postion is calculated and absolute movement is used. 3512 3513 -> `True`: Target offset is given and relative movement API is used 3514 (can be inconsistent) 3515 3516 The inconsistency issue can be solved by disabling Enhanced Pointer 3517 Precision and set Mouse speed to 10 in Windows mouse settings. Since users 3518 may not want to permanently change their input settings just for this 3519 library, the `disable_mouse_acceleration` argument can be used to 3520 temporarily disable Enhanced Pointer Precision and fix mouse speed at 10 3521 and restore it after the mouse movement. 3522 3523 If `_pause` is True (default), then an automatic sleep will be performed 3524 after the function finshes executing. The duration is set by the global 3525 variable `PAUSE`. 3526 3527 Setting `virtual` to True (default: False) changes the way internal APIs 3528 handle coordinates and is intended for multi monitor systems. It should be 3529 pretty much unncessary even for multi monitor systems, since all the 3530 necessary internal calculations beyond the border of the primay monitor 3531 work without it. 3532 3533 The way that Windows calculates the target pixel coordinates internally 3534 unfortunately leads to inaccuracies and unreachable pixels, especially 3535 if the `virtual` option is used. 3536 3537 If you need the target position to be pixel perfect, you can try setting 3538 `attempt_pixel_perfect` to True, which will use tiny relative movements 3539 to correct the unreachable position. 3540 3541 ---------------------------------------------------------------------------- 3542 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 3543 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 3544 3545 If you you start a relative movement while another is already in progress 3546 than the second movement could overwrite the first setting and disable 3547 Enhanced Pointer Precision and change mouse speed. 3548 There are some measures in place to try to mitigate that risk, such as an 3549 internal counter that only allows storing and restoring the acceleration 3550 settings as long as no other movement is currently in progress. 3551 Additionally, the acceleration settings can be manually saved and 3552 restored with `store_mouse_acceleration_settings()` and 3553 `restore_mouse_acceleration_settings()`. For your convinnience, the 3554 store function is automatically called during import to save your current 3555 setting. You can then call the restore function at any time. 3556 3557 If all fails, the setting is not written permanently to your Windows 3558 settings, so it should restore itself upon reboot. 3559 3560 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3561 this library in multiple threads / processes / programs at the same time! 3562 3563 ---------------------------------------------------------------------------- 3564 3565 NOTE: `logScreenshot` is are currently unsupported. 3566 """ 3567 if relative: 3568 _relative_mouse_move( 3569 x=xOffset, 3570 y=yOffset, 3571 duration=duration, 3572 tween=tween, 3573 logScreenshot=logScreenshot, 3574 target_coords_relative=True, 3575 virtual=virtual, 3576 path_function=path_function, 3577 disable_mouse_acceleration=disable_mouse_acceleration, 3578 ) 3579 else: 3580 _absolute_mouse_move( 3581 x=xOffset, 3582 y=yOffset, 3583 duration=duration, 3584 tween=tween, 3585 logScreenshot=logScreenshot, 3586 target_coords_relative=True, 3587 virtual=virtual, 3588 path_function=path_function, 3589 attempt_pixel_perfect=attempt_pixel_perfect, 3590 disable_mouse_acceleration=disable_mouse_acceleration, 3591 ) 3592 # -------------------------------------------------------------------------- 3593 3594 3595# ----- move alias ------------------------------------------------------------- 3596# move() and moveRel() are equivalent. 3597move = moveRel 3598# ------------------------------------------------------------------------------ 3599 3600 3601# ----- dragTo ----------------------------------------------------------------- 3602@_genericPyDirectInputChecks 3603def dragTo( 3604 x: int | None = None, 3605 y: int | None = None, 3606 duration: float = 0.0, 3607 tween: Callable[[float], float] | None = None, 3608 button: str | None = None, 3609 logScreenshot: bool = False, 3610 _pause: bool = True, 3611 mouseDownUp: bool = True, 3612 *, 3613 relative: bool = False, 3614 virtual: bool = False, 3615 path_function: PathFunction | None = None, 3616 attempt_pixel_perfect: bool = False, 3617 disable_mouse_acceleration: bool = False, 3618) -> None: 3619 """ 3620 Press and hold a mouse button while moving to the target coordinates. 3621 3622 See `moveTo` for more information on most arguments. 3623 3624 `button` is a string that is one of the following constants: 3625 MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, MOUSE_BUTTON4, MOUSE_BUTTON5, 3626 MOUSE_PRIMARY (default), MOUSE_SECONDARY. 3627 3628 If `mouseDownUp` (default: True) is manually set to False, then this 3629 function is basically the same as `moveTo`. Only exists to match PyAutoGUI. 3630 3631 If `_pause` is True (default), then an automatic sleep will be performed 3632 after the function finshes executing. The duration is set by the global 3633 variable `PAUSE`. 3634 3635 ---------------------------------------------------------------------------- 3636 3637 NOTE: `logScreenshot` is currently unsupported. 3638 """ 3639 # TODO: bounding box check for valid position 3640 if button is None: 3641 button = MOUSE_PRIMARY 3642 if mouseDownUp: 3643 mouseDown(button=button, _pause=False, virtual=virtual) 3644 moveTo( 3645 x, 3646 y, 3647 duration=duration, 3648 tween=tween, 3649 logScreenshot=logScreenshot, 3650 _pause=False, # don't add an additional pause 3651 relative=relative, 3652 virtual=virtual, 3653 path_function=path_function, 3654 attempt_pixel_perfect=attempt_pixel_perfect, 3655 disable_mouse_acceleration=disable_mouse_acceleration, 3656 ) 3657 if mouseDownUp: 3658 mouseUp(button=button, _pause=False, virtual=virtual) 3659 # -------------------------------------------------------------------------- 3660 3661 3662# ----- dragRel ---------------------------------------------------------------- 3663@_genericPyDirectInputChecks 3664def dragRel( 3665 xOffset: int | None = None, 3666 yOffset: int | None = None, 3667 duration: float = 0.0, 3668 tween: Callable[[float], float] | None = None, 3669 button: str | None = None, 3670 logScreenshot: bool = False, 3671 _pause: bool = True, 3672 mouseDownUp: bool = True, 3673 *, 3674 relative: bool = False, 3675 virtual: bool = False, 3676 path_function: PathFunction | None = None, 3677 disable_mouse_acceleration: bool = False, 3678) -> None: 3679 """ 3680 Press and hold a mouse button while moving a relative distance 3681 3682 See `moveRel` for more information on most arguments. 3683 3684 `button` is a string that is one of the following constants: 3685 MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, MOUSE_BUTTON4, MOUSE_BUTTON5, 3686 MOUSE_PRIMARY (default), MOUSE_SECONDARY. 3687 3688 If `mouseDownUp` (default: True) is manually set to False, then this 3689 function is basically the same as `moveTo`. Only exists to match PyAutoGUI. 3690 3691 If `_pause` is True (default), then an automatic sleep will be performed 3692 after the function finshes executing. The duration is set by the global 3693 variable `PAUSE`. 3694 3695 ---------------------------------------------------------------------------- 3696 3697 NOTE: `logScreenshot` is currently unsupported. 3698 """ 3699 # TODO: bounding box check for valid position 3700 if button is None: 3701 button = MOUSE_PRIMARY 3702 if mouseDownUp: 3703 mouseDown(button=button, _pause=False, virtual=virtual) 3704 moveRel( 3705 xOffset, 3706 yOffset, 3707 duration=duration, 3708 tween=tween, 3709 logScreenshot=logScreenshot, 3710 _pause=False, # don't add an additional pause 3711 relative=relative, 3712 virtual=virtual, 3713 path_function=path_function, 3714 disable_mouse_acceleration=disable_mouse_acceleration, 3715 ) 3716 if mouseDownUp: 3717 mouseUp(button=button, _pause=False, virtual=virtual) 3718 # -------------------------------------------------------------------------- 3719 3720 3721# ----- drag alias ------------------------------------------------------------- 3722drag = dragRel 3723# ------------------------------------------------------------------------------ 3724 3725 3726# ============================================================================== 3727# ===== Keyboard Functions ===================================================== 3728# ============================================================================== 3729 3730 3731# ----- is_valid_key ------------------------------------------------------------- 3732def is_valid_key(key: str) -> bool: 3733 """ 3734 Returns true if key name `key` can be translated into a valid scan code. 3735 """ 3736 return key in KEYBOARD_MAPPING 3737 3738 3739isValidKey = is_valid_key 3740# ------------------------------------------------------------------------------ 3741 3742 3743# ===== scancode functions ===================================================== 3744 3745 3746# ----- scancode_keyDown ------------------------------------------------------- 3747@_genericPyDirectInputChecks 3748def scancode_keyDown( 3749 scancodes: ScancodeTypes, 3750 logScreenshot: None = None, 3751 _pause: bool = True, 3752 *, 3753 auto_shift: bool = False, 3754) -> bool: 3755 """ 3756 Press down key corresponding to `scancodes`. 3757 3758 The actually pressed key will depend on your system keyboard layout. 3759 Limits the available character set but should provide the best 3760 compatibility. 3761 3762 If `_pause` is True (default), then an automatic sleep will be performed 3763 after the function finshes executing. The duration is set by the global 3764 variable `PAUSE`. 3765 3766 `auto_shift` is used internally by higher level functions to automatically 3767 press the shift key before supported scancodes (indicitated by a special 3768 bit outside the regular scancode range, while it technically can be used, 3769 it's not intended for public access). 3770 3771 ---------------------------------------------------------------------------- 3772 3773 NOTE: `logScreenshot` is currently unsupported. 3774 """ 3775 scancodes_sequence: ScancodeSequence 3776 if isinstance(scancodes, int): 3777 scancodes_sequence = ScancodeSequence([scancodes]) 3778 else: 3779 scancodes_sequence = scancodes 3780 3781 keybdFlags: int = _KEYEVENTF_SCANCODE 3782 input_structs: list[_INPUT] = [] 3783 extendedFlag: int 3784 3785 # Init event tracking 3786 insertedEvents: int = 0 3787 expectedEvents: int = 0 3788 3789 for scancode in scancodes_sequence: 3790 if auto_shift and scancode & _OFFSET_SHIFTKEY: 3791 input_structs += [ 3792 _create_keyboard_input( 3793 wScan=_SHIFT_SCANCODE, dwFlags=keybdFlags 3794 ) 3795 ] 3796 expectedEvents += 1 3797 3798 scancode = scancode & 0xFFFF 3799 3800 extendedFlag = _KEYEVENTF_EXTENDEDKEY if scancode >= 0xE000 else 0 3801 input_structs += [ 3802 _create_keyboard_input( 3803 wScan=scancode, dwFlags=keybdFlags | extendedFlag 3804 ) 3805 ] 3806 expectedEvents += 1 3807 3808 insertedEvents += _send_input(input_structs) 3809 3810 # SendInput returns the number of event successfully inserted into 3811 # input stream 3812 # https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput#return-value 3813 return insertedEvents == expectedEvents 3814 # -------------------------------------------------------------------------- 3815 3816 3817# ----- scancode_keyUp --------------------------------------------------------- 3818@_genericPyDirectInputChecks 3819def scancode_keyUp( 3820 scancodes: ScancodeTypes, 3821 logScreenshot: None = None, 3822 _pause: bool = True, 3823 *, 3824 auto_shift: bool = False, 3825) -> bool: 3826 """ 3827 Release key corresponding to `scancodes`. 3828 3829 The actually pressed key will depend on your system keyboard layout. 3830 Limits the available character set but should provide the best 3831 compatibility. 3832 3833 If `_pause` is True (default), then an automatic sleep will be performed 3834 after the function finshes executing. The duration is set by the global 3835 variable `PAUSE`. 3836 3837 `auto_shift` is used internally by higher level functions to automatically 3838 press the shift key before supported scancodes (indicitated by a special 3839 bit outside the regular scancode range, while it technically can be used, 3840 it's not intended for public access). 3841 3842 ---------------------------------------------------------------------------- 3843 3844 NOTE: `logScreenshot` is currently unsupported. 3845 """ 3846 scancodes_sequence: ScancodeSequence 3847 if isinstance(scancodes, int): 3848 scancodes_sequence = ScancodeSequence([scancodes]) 3849 else: 3850 scancodes_sequence = scancodes 3851 3852 keybdFlags: int = _KEYEVENTF_SCANCODE | _KEYEVENTF_KEYUP 3853 input_structs: list[_INPUT] = [] 3854 extendedFlag: int 3855 3856 # Init event tracking 3857 insertedEvents: int = 0 3858 expectedEvents: int = 0 3859 3860 for scancode in scancodes_sequence: 3861 if auto_shift and scancode & _OFFSET_SHIFTKEY: 3862 input_structs += [ 3863 _create_keyboard_input( 3864 wScan=_SHIFT_SCANCODE, dwFlags=keybdFlags 3865 ) 3866 ] 3867 expectedEvents += 1 3868 3869 scancode = scancode & 0xFFFF 3870 3871 extendedFlag = _KEYEVENTF_EXTENDEDKEY if scancode >= 0xE000 else 0 3872 input_structs += [ 3873 _create_keyboard_input( 3874 wScan=scancode & 0xFFFF, dwFlags=keybdFlags | extendedFlag 3875 ) 3876 ] 3877 expectedEvents += 1 3878 3879 insertedEvents += _send_input(input_structs) 3880 return insertedEvents == expectedEvents 3881 # -------------------------------------------------------------------------- 3882 3883 3884# ----- _helper_scancode_press ------------------------------------------------- 3885def _helper_scancode_press( 3886 scancodes: ScancodeTypes, 3887 duration: float = 0.0, 3888 _pause: bool = True, 3889 auto_shift: bool = False, 3890) -> bool: 3891 """ 3892 Press `scancode`, wait for `duration` seconds, release `scancode`. 3893 3894 Return `True` if complete press was successful. 3895 """ 3896 downed: bool = scancode_keyDown( 3897 scancodes, _pause=_pause, auto_shift=auto_shift 3898 ) 3899 _sleep(duration) 3900 upped: bool = scancode_keyUp( 3901 scancodes, _pause=_pause, auto_shift=auto_shift 3902 ) 3903 # Count key press as complete if key was "downed" and "upped" 3904 # successfully 3905 return bool(downed and upped) 3906 # -------------------------------------------------------------------------- 3907 3908 3909# ----- scancode_press --------------------------------------------------------- 3910# Ignored parameters: logScreenshot 3911@_genericPyDirectInputChecks 3912def scancode_press( 3913 scancodes: ScancodeTypes | Sequence[ScancodeTypes], 3914 presses: int = 1, 3915 interval: float = 0.0, 3916 logScreenshot: None = None, 3917 _pause: bool = True, 3918 *, 3919 auto_shift: bool = False, 3920 delay: float = 0.0, 3921 duration: float = 0.0, 3922) -> bool: 3923 """ 3924 Press the sequence of `keys` for `presses` amount of times. 3925 3926 The actually pressed key will depend on your system keyboard layout. 3927 Limits the available character set but should provide the best 3928 compatibility. 3929 3930 Explanation of time parameters (seconds as floating point numbers): 3931 3932 - `interval` is the time spent waiting between sequences. If `keys` is a 3933 str instance or single element list, then `interval` will be ignored. 3934 - `delay` is the time from one complete key (press+release) to the next one 3935 in the same sequence. If there is only a single key in a sequence, then 3936 `delay` will be ignored. 3937 - `duration` is the time spent on holding every key before releasing it 3938 again. 3939 3940 If `_pause` is True (default), then an automatic sleep will be performed 3941 after the function finshes executing. The duration is set by the global 3942 variable `PAUSE`. 3943 Be aware, that the global pause defined by the PAUSE `constant` only 3944 applies after every call to this function, not inbetween (no extra pause 3945 between pressing and releasing key, use the `duration` argument instead)! 3946 3947 `auto_shift` is used internally by higher level functions to automatically 3948 press the shift key before supported scancodes (indicitated by a special 3949 bit outside the regular scancode range, while it technically can be used, 3950 it's not intended for public access). 3951 3952 ---------------------------------------------------------------------------- 3953 3954 NOTE: `logScreenshot` is currently unsupported. 3955 """ 3956 scancodes_sequence: Sequence[ScancodeTypes] 3957 if isinstance(scancodes, int): 3958 scancodes_sequence = [ScancodeSequence([scancodes])] 3959 elif isinstance(scancodes, ScancodeSequence): 3960 scancodes_sequence = [scancodes] 3961 else: 3962 scancodes_sequence = scancodes 3963 3964 # We need to press x keys y times, which comes out to x*y presses in total 3965 expectedPresses: int = presses * len(scancodes_sequence) 3966 completedPresses: int = 0 3967 3968 apply_interval: bool = False 3969 for _ in range(presses): 3970 if apply_interval: # Don't delay first press 3971 _sleep(interval) 3972 apply_interval = True 3973 3974 apply_delay: bool = False 3975 for c in scancodes_sequence: 3976 if apply_delay: # Don't delay first press 3977 _sleep(delay) 3978 apply_delay = True 3979 3980 completedPresses += _helper_scancode_press( 3981 c, duration, _pause=False, auto_shift=auto_shift 3982 ) 3983 3984 return completedPresses == expectedPresses 3985 # -------------------------------------------------------------------------- 3986 3987 3988# ----- scancode_hold ---------------------------------------------------------- 3989@contextmanager 3990@_genericPyDirectInputChecks 3991def scancode_hold( 3992 scancodes: ScancodeTypes | Sequence[ScancodeTypes], 3993 logScreenshot: None = None, 3994 _pause: bool = True, 3995 *, 3996 auto_shift: bool = False, 3997 raise_on_failure: bool = False, 3998) -> Generator[None, None, None]: 3999 """ 4000 Hold the sequence of keys corresponding to `scancodes` as long as the 4001 context manager is in scope (press upon entry, release upon exit). 4002 4003 Keys will be released in reverse order (LIFO), but still practically 4004 instantenous. 4005 4006 The actually pressed key will depend on your system keyboard layout. 4007 Limits the available character set but should provide the best 4008 compatibility. 4009 4010 If `_pause` is True (default), then an automatic sleep will be performed 4011 after the function finshes executing. The duration is set by the global 4012 variable `PAUSE`. 4013 Be aware, that the global pause defined by the PAUSE `constant` only 4014 applies after every call to this function, not inbetween (no pause between 4015 press and releasing key)! 4016 4017 `auto_shift` is used internally by higher level functions to automatically 4018 press the shift key before supported scancodes (indicitated by a special 4019 bit outside the regular scancode range, while it technically can be used, 4020 it's not intended for public access). 4021 4022 If `raise_on_failure` is True, then `PriorInputFailedException` will be 4023 raised if not all keyboard inputs could be executed successfully. 4024 4025 ---------------------------------------------------------------------------- 4026 4027 NOTE: `logScreenshot` is currently unsupported. 4028 """ 4029 scancodes_sequence: Sequence[ScancodeTypes] 4030 if isinstance(scancodes, int): 4031 scancodes_sequence = [ScancodeSequence([scancodes])] 4032 elif isinstance(scancodes, ScancodeSequence): 4033 scancodes_sequence = [scancodes] 4034 else: 4035 scancodes_sequence = scancodes 4036 4037 expectedPresses: int = len(scancodes_sequence) 4038 downed: int = 0 4039 upped: int = 0 4040 4041 try: 4042 for c in scancodes_sequence: 4043 downed += scancode_keyDown(c, _pause=False, auto_shift=auto_shift) 4044 yield 4045 finally: 4046 for c in reversed(scancodes_sequence): 4047 upped += scancode_keyUp(c, _pause=False, auto_shift=auto_shift) 4048 if raise_on_failure and not (expectedPresses == downed == upped): 4049 raise PriorInputFailedException 4050 # -------------------------------------------------------------------------- 4051 4052 4053# ----- scancode_hotkey -------------------------------------------------------- 4054@_genericPyDirectInputChecks 4055def scancode_hotkey( 4056 *args: ScancodeTypes, 4057 interval: float = 0.0, 4058 wait: float = 0.0, 4059 logScreenshot: None = None, 4060 _pause: bool = True, 4061 auto_shift: bool = True, 4062) -> bool: 4063 """ 4064 Press down buttons in order they are specified as arguments, 4065 releasing them in reverse order, e.g. 0x1D, 0x2E will first press 4066 Control, then C and release C before releasing Control. 4067 4068 Use keyword-only argument `interval` to specify a delay between single 4069 keys when pressing and releasing and `wait` for delay between last press 4070 and first release. 4071 4072 If `_pause` is True (default), then an automatic sleep will be performed 4073 after the function finshes executing. The duration is set by the global 4074 variable `PAUSE`. 4075 Be aware, that the global pause defined by the PAUSE `constant` only 4076 applies after every call to this function, not inbetween (no pause between 4077 press and releasing key)! 4078 4079 `auto_shift` is used internally by higher level functions to automatically 4080 press the shift key before supported scancodes (indicitated by a special 4081 bit outside the regular scancode range, while it technically can be used, 4082 it's not intended for public access). 4083 4084 ---------------------------------------------------------------------------- 4085 4086 NOTE: `logScreenshot` is currently unsupported. 4087 """ 4088 expectedPresses: int = len(args) 4089 downed: int = 0 4090 upped: int = 0 4091 4092 apply_interval: bool = False 4093 for code in args: 4094 if apply_interval: 4095 _sleep(interval) # sleep between iterations 4096 apply_interval = True 4097 4098 downed += scancode_keyDown(code, _pause=False, auto_shift=auto_shift) 4099 4100 _sleep(wait) 4101 4102 apply_interval = False 4103 for code in reversed(args): 4104 if apply_interval: 4105 _sleep(interval) # sleep between iterations 4106 apply_interval = True 4107 4108 upped += scancode_keyUp(code, _pause=False, auto_shift=auto_shift) 4109 4110 return expectedPresses == downed == upped 4111 # -------------------------------------------------------------------------- 4112 4113 4114# ===== keyname functions ====================================================== 4115 4116 4117# ----- keyDown ---------------------------------------------------------------- 4118# Ignored parameters: logScreenshot 4119def keyDown( 4120 key: str, 4121 logScreenshot: None = None, 4122 _pause: bool = True, 4123 *, 4124 auto_shift: bool = False, 4125) -> bool: 4126 """ 4127 Press down key corresponding to key name `key`. 4128 4129 `key` will be interpreted as a keyboard key (US QWERTY). 4130 The actually pressed key will depend on your system keyboard layout. 4131 Limits the available character set but should provide the best 4132 compatibility. 4133 4134 If `_pause` is True (default), then an automatic sleep will be performed 4135 after the function finshes executing. The duration is set by the global 4136 variable `PAUSE`. 4137 4138 If `auto_shift` is True, then "shifted" characters like upper case letters 4139 and the symbols on the number row automatically insert a Shift scancode 4140 into the input sequence. 4141 4142 ---------------------------------------------------------------------------- 4143 4144 NOTE: `logScreenshot` is currently unsupported. 4145 """ 4146 scancode: ScancodeTypes | None = KEYBOARD_MAPPING.get(key) 4147 if scancode is None: 4148 return False 4149 return scancode_keyDown( 4150 scancode, logScreenshot, _pause=_pause, auto_shift=auto_shift 4151 ) 4152 # -------------------------------------------------------------------------- 4153 4154 4155# ----- keyUp ------------------------------------------------------------------ 4156# Ignored parameters: logScreenshot 4157def keyUp( 4158 key: str, 4159 logScreenshot: None = None, 4160 _pause: bool = True, 4161 *, 4162 auto_shift: bool = False, 4163) -> bool: 4164 """ 4165 Lift up key corresponding to key name `key`. 4166 4167 `key` will be interpreted as a keyboard key (US QWERTY). 4168 The actually lifted key will depend on your system keyboard layout. 4169 Limits the available character set but should provide the best 4170 compatibility. 4171 4172 If `_pause` is True (default), then an automatic sleep will be performed 4173 after the function finshes executing. The duration is set by the global 4174 variable `PAUSE`. 4175 4176 If `auto_shift` is True, then "shifted" characters like upper case letters 4177 and the symbols on the number row automatically insert a Shift scancode 4178 into the input sequence. 4179 4180 ---------------------------------------------------------------------------- 4181 4182 NOTE: `logScreenshot` is currently unsupported. 4183 """ 4184 scancode: ScancodeTypes | None = KEYBOARD_MAPPING.get(key) 4185 if scancode is None: 4186 return False 4187 return scancode_keyUp( 4188 scancode, logScreenshot, _pause=_pause, auto_shift=auto_shift 4189 ) 4190 # -------------------------------------------------------------------------- 4191 4192 4193# ----- _helper_press ---------------------------------------------------------- 4194def _helper_press( 4195 key: str, 4196 duration: float = 0.0, 4197 _pause: bool = True, 4198 auto_shift: bool = False, 4199) -> bool: 4200 """ 4201 Press `key`, wait for `duration` seconds, release `key`. 4202 4203 Return `True` if complete press was successful. 4204 """ 4205 downed: bool = keyDown(key, _pause=_pause, auto_shift=auto_shift) 4206 _sleep(duration) 4207 upped: bool = keyUp(key, _pause=_pause, auto_shift=auto_shift) 4208 # Count key press as complete if key was "downed" and "upped" 4209 # successfully 4210 return bool(downed and upped) 4211 # -------------------------------------------------------------------------- 4212 4213 4214# ----- press ------------------------------------------------------------------ 4215# Ignored parameters: logScreenshot 4216@_genericPyDirectInputChecks 4217def press( 4218 keys: str | Sequence[str], 4219 presses: int = 1, 4220 interval: float = 0.0, 4221 logScreenshot: None = None, 4222 _pause: bool = True, 4223 *, 4224 auto_shift: bool = False, 4225 delay: float = 0.0, 4226 duration: float = 0.0, 4227) -> bool: 4228 """ 4229 Press the sequence of `keys` for `presses` amount of times. 4230 4231 `keys` will be interpreted as sequence of keyboard keys (US QWERTY). 4232 The actually pressed key will depend on your system keyboard layout. 4233 Limits the available character set but should provide the best 4234 compatibility. 4235 4236 Explanation of time parameters (seconds as floating point numbers): 4237 4238 - `interval` is the time spent waiting between sequences. If `keys` is a 4239 str instance, single element list or presses equals 1 (the default), 4240 then `interval` will be ignored. 4241 - `delay` is the time from one complete key (press+release) to the next one 4242 in the same sequence. If there is only a single key in a sequence, then 4243 `delay` will be ignored. 4244 - `duration` is the time spent on holding every key before releasing it 4245 again. 4246 4247 If `_pause` is True (default), then an automatic sleep will be performed 4248 after the function finshes executing. The duration is set by the global 4249 variable `PAUSE`. 4250 Be aware, that the global pause defined by the `PAUSE` var only applies 4251 after every call to this function, not inbetween (no extra pause between 4252 pressing and releasing key, use the `duration` argument instead)! 4253 4254 If `auto_shift` is True, then "shifted" characters like upper case letters 4255 and the symbols on the number row automatically insert a Shift scancode 4256 into the input sequence. 4257 4258 ---------------------------------------------------------------------------- 4259 4260 NOTE: `logScreenshot` is currently unsupported. 4261 """ 4262 if isinstance(keys, str): 4263 keys = [keys] # If keys is 'enter', convert it to ['enter']. 4264 keys = [_normalize_key(key, auto_shift=auto_shift) for key in keys] 4265 4266 # We need to press x keys y times, which comes out to x*y presses in total 4267 expectedPresses: int = presses * len(keys) 4268 completedPresses: int = 0 4269 4270 apply_interval: bool = False 4271 for _ in range(presses): 4272 if apply_interval: # Don't delay first press 4273 _sleep(interval) 4274 apply_interval = True 4275 4276 apply_delay: bool = False 4277 for k in keys: 4278 if apply_delay: # Don't delay first press 4279 _sleep(delay) 4280 apply_delay = True 4281 4282 completedPresses += _helper_press( 4283 k, duration, _pause=False, auto_shift=auto_shift 4284 ) 4285 4286 return completedPresses == expectedPresses 4287 # -------------------------------------------------------------------------- 4288 4289 4290# ----- hold ------------------------------------------------------------------- 4291@contextmanager 4292@_genericPyDirectInputChecks 4293def hold( 4294 keys: str | Sequence[str], 4295 logScreenshot: None = None, 4296 _pause: bool = True, 4297 *, 4298 auto_shift: bool = False, 4299 raise_on_failure: bool = False, 4300) -> Generator[None, None, None]: 4301 """ 4302 Hold the sequence of keys corresponding to key names in `keys` as long as 4303 the context manager is in scope (press upon entry, release upon exit). 4304 4305 Keys will be released in reverse order (LIFO), but still practically 4306 instantenous. 4307 4308 `key` will be interpreted as a keyboard key (US QWERTY). 4309 The actually pressed key will depend on your system keyboard layout. 4310 Limits the available character set but should provide the best 4311 compatibility. 4312 4313 If `_pause` is True (default), then an automatic sleep will be performed 4314 after the function finshes executing. The duration is set by the global 4315 variable `PAUSE`. 4316 Be aware, that the global pause defined by the PAUSE `constant` only 4317 applies after every call to this function, not inbetween (no pause between 4318 press and releasing key)! 4319 4320 `auto_shift` is used internally by higher level functions to automatically 4321 press the shift key before supported scancodes (indicitated by a special 4322 bit outside the regular scancode range, while it technically can be used, 4323 it's not intended for public access). 4324 4325 If `raise_on_failure` is True, then `PriorInputFailedException` will be 4326 raised if not all keyboard inputs could be executed successfully. 4327 4328 ---------------------------------------------------------------------------- 4329 4330 NOTE: `logScreenshot` is currently unsupported. 4331 """ 4332 if isinstance(keys, str): 4333 keys = [keys] # make single element into iterable 4334 keys = [_normalize_key(key, auto_shift=auto_shift) for key in keys] 4335 4336 expectedPresses: int = len(keys) 4337 downed: int = 0 4338 upped: int = 0 4339 4340 try: 4341 for k in keys: 4342 downed += keyDown(k, auto_shift=auto_shift) 4343 yield 4344 finally: 4345 for k in reversed(keys): 4346 upped += keyUp(k, auto_shift=auto_shift) 4347 if raise_on_failure and not (expectedPresses == downed == upped): 4348 raise PriorInputFailedException 4349 # -------------------------------------------------------------------------- 4350 4351 4352# ----- typewrite -------------------------------------------------------------- 4353@_genericPyDirectInputChecks 4354def typewrite( 4355 message: str, 4356 interval: float = 0.0, 4357 logScreenshot: None = None, 4358 _pause: bool = True, 4359 *, 4360 auto_shift: bool = False, 4361 delay: float = 0.0, 4362 duration: float = 0.0, 4363) -> None: 4364 """ 4365 Break down `message` into a single character key sequence and press each 4366 key one by one. 4367 4368 `message` will be interpreted as sequence of keyboard keys (US QWERTY). 4369 The actually pressed keys will depend on your system keyboard layout. 4370 Limits the available character set but should provide the best 4371 compatibility. 4372 4373 Explanation of time parameters (seconds as floating point numbers): 4374 4375 - `interval` is the time spent waiting between sequences. If `message` is a 4376 single character string, then `interval` will be ignored. 4377 - `delay` is the time from one complete key (press+release) to the next one 4378 in the same sequence. If there is only a single key in a sequence, then 4379 `delay` will be ignored. 4380 - `duration` is the time spent on holding every key before releasing it 4381 again. 4382 4383 If `_pause` is True (default), then an automatic sleep will be performed 4384 after the function finshes executing. The duration is set by the global 4385 variable `PAUSE`. 4386 Be aware, that the global pause defined by the PAUSE `constant` only 4387 applies after every call to this function, not inbetween (no pause between 4388 press and releasing key)! 4389 4390 `auto_shift` is used internally by higher level functions to automatically 4391 press the shift key before supported scancodes (indicitated by a special 4392 bit outside the regular scancode range, while it technically can be used, 4393 it's not intended for public access). 4394 4395 ---------------------------------------------------------------------------- 4396 4397 NOTE: `logScreenshot` is currently unsupported. 4398 """ 4399 4400 apply_interval: bool = False 4401 for key in message: 4402 if apply_interval: # Don't delay first press 4403 _sleep(interval) 4404 apply_interval = True 4405 4406 press( 4407 key, 4408 _pause=False, 4409 auto_shift=auto_shift, 4410 delay=delay, 4411 duration=duration, 4412 ) 4413 # -------------------------------------------------------------------------- 4414 4415 4416# ----- typewrite alias -------------------------------------------------------- 4417write = typewrite 4418# ------------------------------------------------------------------------------ 4419 4420 4421# ----- hotkey ----------------------------------------------------------------- 4422# Originally implemented by 4423# https://github.com/learncodebygaming/pydirectinput/pull/30 4424@_genericPyDirectInputChecks 4425def hotkey( 4426 *args: str, 4427 interval: float = 0.0, 4428 wait: float = 0.0, 4429 logScreenshot: None = None, 4430 _pause: bool = True, 4431 auto_shift: bool = True, 4432) -> None: 4433 """ 4434 Press down buttons in order they are specified as arguments, 4435 releasing them in reverse order, e.g. 'ctrl', 'c' will first press 4436 Control, then C and release C before releasing Control. 4437 4438 Use keyword-only argument `interval` to specify a delay between single 4439 keys when pressing and releasing and `wait` for delay between last press 4440 and first release. 4441 4442 If `_pause` is True (default), then an automatic sleep will be performed 4443 after the function finshes executing. The duration is set by the global 4444 variable `PAUSE`. 4445 Be aware, that the global pause defined by the PAUSE `constant` only 4446 applies after every call to this function, not inbetween (no pause between 4447 press and releasing key)! 4448 4449 `auto_shift` is used internally by higher level functions to automatically 4450 press the shift key before supported scancodes (indicitated by a special 4451 bit outside the regular scancode range, while it technically can be used, 4452 it's not intended for public access). 4453 4454 ---------------------------------------------------------------------------- 4455 4456 NOTE: `logScreenshot` is currently unsupported. 4457 """ 4458 apply_interval: bool = False 4459 for key in args: 4460 if apply_interval: 4461 _sleep(interval) # sleep between iterations 4462 apply_interval = True 4463 4464 keyDown(key, _pause=False, auto_shift=auto_shift) 4465 4466 _sleep(wait) 4467 4468 apply_interval = False 4469 for key in reversed(args): 4470 if apply_interval: 4471 _sleep(interval) # sleep between iterations 4472 apply_interval = True 4473 4474 keyUp(key, _pause=False, auto_shift=auto_shift) 4475 # -------------------------------------------------------------------------- 4476 4477 4478# ===== unicode functions ====================================================== 4479 4480 4481# ----- unicode_charDown ------------------------------------------------------- 4482@_genericPyDirectInputChecks 4483def unicode_charDown( 4484 char: str, logScreenshot: None = None, _pause: bool = True 4485) -> bool: 4486 """ 4487 Send Unicode character(s) `char` to currently focused application as 4488 WM_KEYDOWN message. 4489 4490 `char` will be interpreted as a string of Unicode characters 4491 (independet from keyboard layout). Supports complete Unicode character set 4492 but may not be compatible with every application. 4493 4494 If `_pause` is True (default), then an automatic sleep will be performed 4495 after the function finshes executing. The duration is set by the global 4496 variable `PAUSE`. 4497 4498 ---------------------------------------------------------------------------- 4499 4500 NOTE: `logScreenshot` is currently unsupported. 4501 """ 4502 utf16surrogates: bytes = char.encode("utf-16be") 4503 codes: Sequence[int] = unpack( 4504 f">{len(utf16surrogates) // 2}H", utf16surrogates 4505 ) 4506 4507 keybdFlags: int = _KEYEVENTF_UNICODE 4508 4509 input_structs: list[_INPUT] = [ 4510 _create_keyboard_input(wVk=0, wScan=charcode, dwFlags=keybdFlags) 4511 for charcode in codes 4512 ] 4513 # Init event tracking 4514 expectedEvents: int = len(input_structs) 4515 insertedEvents: int = _send_input(input_structs) 4516 4517 return insertedEvents == expectedEvents 4518 # -------------------------------------------------------------------------- 4519 4520 4521# ----- unicode_charUp --------------------------------------------------------- 4522@_genericPyDirectInputChecks 4523def unicode_charUp( 4524 char: str, logScreenshot: None = None, _pause: bool = True 4525) -> bool: 4526 """ 4527 Send Unicode character(s) `char` to currently focused application as 4528 WM_KEYUP message. 4529 4530 `char` will be interpreted as a string of Unicode characters 4531 (independet from keyboard layout). Supports complete Unicode character set 4532 but may not be compatible with every application. 4533 4534 If `_pause` is True (default), then an automatic sleep will be performed 4535 after the function finshes executing. The duration is set by the global 4536 variable `PAUSE`. 4537 4538 ---------------------------------------------------------------------------- 4539 4540 NOTE: `logScreenshot` is currently unsupported. 4541 """ 4542 utf16surrogates: bytes = char.encode("utf-16be") 4543 codes: Sequence[int] = unpack( 4544 f">{len(utf16surrogates) // 2}H", utf16surrogates 4545 ) 4546 4547 keybdFlags: int = _KEYEVENTF_UNICODE | _KEYEVENTF_KEYUP 4548 4549 input_structs: list[_INPUT] = [ 4550 _create_keyboard_input(wVk=0, wScan=charcode, dwFlags=keybdFlags) 4551 for charcode in codes 4552 ] 4553 # Init event tracking 4554 expectedEvents: int = len(input_structs) 4555 insertedEvents: int = _send_input(input_structs) 4556 4557 return insertedEvents == expectedEvents 4558 # -------------------------------------------------------------------------- 4559 4560 4561# ----- _helper_unicode_press_char --------------------------------------------- 4562def _helper_unicode_press_char( 4563 char: str, 4564 duration: float = 0.0, 4565 _pause: bool = True, 4566) -> bool: 4567 """ 4568 Press `key`, wait for `duration` seconds, release `key`. 4569 4570 Return `True` if complete press was successful. 4571 """ 4572 downed: bool = unicode_charDown(char, _pause=_pause) 4573 _sleep(duration) 4574 upped: bool = unicode_charUp(char, _pause=_pause) 4575 # Count key press as complete if key was "downed" and "upped" 4576 # successfully 4577 return bool(downed and upped) 4578 # -------------------------------------------------------------------------- 4579 4580 4581# ----- unicode_press ---------------------------------------------------------- 4582@_genericPyDirectInputChecks 4583def unicode_press( 4584 chars: str | Sequence[str], 4585 presses: int = 1, 4586 interval: float = 0.0, 4587 logScreenshot: None = None, 4588 _pause: bool = True, 4589 *, 4590 delay: float = 0.0, 4591 duration: float = 0.0, 4592) -> bool: 4593 """ 4594 Press the sequence of `chars` for `presses` amount of times. 4595 4596 `chars` will be interpreted as a sequence of Unicode characters 4597 (independent from keyboard layout). Supports complete Unicode character set 4598 but may not be compatible with every application. 4599 4600 Explanation of time parameters (seconds as floating point numbers): 4601 4602 - `interval` is the time spent waiting between sequences. If `chars` is a 4603 str instance or single element list, then `interval` will be ignored. 4604 - `delay` is the time from one complete char (press+release) to the next 4605 one in the same sequence. If there is only a single char in a sequence, 4606 then `delay` will be ignored. 4607 - `duration` is the time spent on holding every char before releasing it 4608 again. 4609 4610 If `_pause` is True (default), then an automatic sleep will be performed 4611 after the function finshes executing. The duration is set by the global 4612 variable `PAUSE`. 4613 Be aware, that the global pause defined by the PAUSE `constant` only 4614 applies after every call to this function, not inbetween (no extra pause 4615 between pressing and releasing key, use the `duration` argument instead)! 4616 4617 ---------------------------------------------------------------------------- 4618 4619 NOTE: `logScreenshot` is currently unsupported. 4620 """ 4621 if isinstance(chars, str): 4622 chars = [chars] 4623 4624 # We need to press x keys y times, which comes out to x*y presses in total 4625 expectedPresses: int = presses * len(chars) 4626 completedPresses: int = 0 4627 4628 apply_interval: bool = False 4629 for _ in range(presses): 4630 if apply_interval: # Don't delay first press 4631 _sleep(interval) 4632 apply_interval = True 4633 4634 apply_delay: bool = False 4635 for c in chars: 4636 if apply_delay: # Don't delay first press 4637 _sleep(delay) 4638 apply_delay = True 4639 4640 completedPresses += _helper_unicode_press_char( 4641 c, 4642 duration, 4643 _pause=False, 4644 ) 4645 4646 return completedPresses == expectedPresses 4647 # -------------------------------------------------------------------------- 4648 4649 4650# ----- unicode_hold ----------------------------------------------------------- 4651@contextmanager 4652@_genericPyDirectInputChecks 4653def unicode_hold( 4654 chars: str | Sequence[str], 4655 logScreenshot: None = None, 4656 _pause: bool = True, 4657 *, 4658 raise_on_failure: bool = False, 4659) -> Generator[None, None, None]: 4660 """ 4661 Hold the sequence of "keys" corresponding to unicode characters in `chars` 4662 as long as the context manager is in scope (press upon entry, 4663 release upon exit). 4664 4665 `chars` will be interpreted as a sequence of Unicode characters 4666 (independet from keyboard layout). Supports complete Unicode character set 4667 but may not be compatible with every application. 4668 4669 Keys will be released in reverse order (LIFO), but still practically 4670 instantenous. 4671 4672 If `_pause` is True (default), then an automatic sleep will be performed 4673 after the function finshes executing. The duration is set by the global 4674 variable `PAUSE`. 4675 Be aware, that the global pause defined by the PAUSE `constant` only 4676 applies after every call to this function, not inbetween (no pause between 4677 press and releasing key)! 4678 4679 If `raise_on_failure` is True, then `PriorInputFailedException` will be 4680 raised if not all keyboard inputs could be executed successfully. 4681 4682 ---------------------------------------------------------------------------- 4683 4684 NOTE: `logScreenshot` is currently unsupported. 4685 """ 4686 if isinstance(chars, str): 4687 chars = [chars] # make single element into iterable 4688 4689 expectedPresses: int = len(chars) 4690 downed: int = 0 4691 upped: int = 0 4692 4693 try: 4694 for c in chars: 4695 downed += unicode_charDown(c, _pause=False) 4696 yield 4697 finally: 4698 for c in reversed(chars): 4699 upped += unicode_charUp(c, _pause=False) 4700 if raise_on_failure and not (expectedPresses == downed == upped): 4701 raise PriorInputFailedException 4702 # -------------------------------------------------------------------------- 4703 4704 4705# ----- unicode_typewrite ------------------------------------------------------ 4706@_genericPyDirectInputChecks 4707def unicode_typewrite( 4708 message: str, 4709 interval: float = 0.0, 4710 logScreenshot: None = None, 4711 _pause: bool = True, 4712 *, 4713 delay: float = 0.0, 4714 duration: float = 0.0, 4715) -> None: 4716 """ 4717 Break down `message` into characters and press them one by one. 4718 4719 `message` will be interpreted as a sequence of Unicode characters 4720 (independet from keyboard layout). Supports complete Unicode character set 4721 but may not be compatible with every application. 4722 4723 Explanation of time parameters (seconds as floating point numbers): 4724 4725 - `interval` is the time spent waiting between sequences. If `message` is a 4726 single character string, then `interval` will be ignored. 4727 - `delay` is the time from one complete key (press+release) to the next one 4728 in the same sequence. If there is only a single key in a sequence, then 4729 `delay` will be ignored. 4730 - `duration` is the time spent on holding every key before releasing it 4731 again. 4732 4733 If `_pause` is True (default), then an automatic sleep will be performed 4734 after the function finshes executing. The duration is set by the global 4735 variable `PAUSE`. 4736 Be aware, that the global pause defined by the PAUSE `constant` only 4737 applies after every call to this function, not inbetween (no pause between 4738 press and releasing key)! 4739 4740 ---------------------------------------------------------------------------- 4741 4742 NOTE: `logScreenshot` is currently unsupported. 4743 """ 4744 apply_interval: bool = False 4745 for char in message: 4746 if apply_interval: 4747 _sleep(interval) # sleep between iterations 4748 apply_interval = True 4749 4750 unicode_press(char, _pause=False, delay=delay, duration=duration) 4751 # -------------------------------------------------------------------------- 4752 4753 4754# ----- unicode_typewrite alias ------------------------------------------------ 4755unicode_write = unicode_typewrite 4756# ------------------------------------------------------------------------------ 4757 4758 4759# ----- unicode_hotkey --------------------------------------------------------- 4760@_genericPyDirectInputChecks 4761def unicode_hotkey( 4762 *args: str, 4763 interval: float = 0.0, 4764 wait: float = 0.0, 4765 logScreenshot: None = None, 4766 _pause: bool = True, 4767) -> None: 4768 """ 4769 Press down buttons in order they are specified as arguments, 4770 releasing them in reverse order. 4771 4772 This function makes little sense for Unicode characters and mainly exists 4773 for parity with the other, lower-level hotkey functions! 4774 4775 See `unicode_press()` for an alternative function that presses keys in 4776 series instead. 4777 4778 Use keyword-only argument `interval` to specify a delay between single 4779 keys when pressing and releasing and `wait` for delay between last press 4780 and first release. 4781 4782 If `_pause` is True (default), then an automatic sleep will be performed 4783 after the function finshes executing. The duration is set by the global 4784 variable `PAUSE`. 4785 Be aware, that the global pause defined by the PAUSE `constant` only 4786 applies after every call to this function, not inbetween (no pause between 4787 press and releasing key)! 4788 4789 ---------------------------------------------------------------------------- 4790 4791 NOTE: `logScreenshot` is currently unsupported. 4792 """ 4793 apply_interval: bool = False 4794 for char in args: 4795 if apply_interval: 4796 _sleep(interval) # sleep between iterations 4797 apply_interval = True 4798 4799 unicode_charDown(char, _pause=False) 4800 4801 _sleep(wait) 4802 4803 apply_interval = False 4804 for char in reversed(args): 4805 if apply_interval: 4806 _sleep(interval) # sleep between iterations 4807 apply_interval = True 4808 4809 unicode_charUp(char, _pause=False) 4810 # -------------------------------------------------------------------------- 4811 4812 4813# ------------------------------------------------------------------------------ 4814# Save current Enhanced Pointer Precsion setting during import 4815# unless disabled by environment variable. 4816# Since this is a safety feature, this import side-effect is enabled by default. 4817if not os.environ.get("PYDIRECTINPUT_SKIP_STORING_MOUSE_SETTINGS"): 4818 store_mouse_acceleration_settings() 4819# ------------------------------------------------------------------------------
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 3385 `path_function` is a function that takes the start and end coordinates of 3386 the mouse movement (4 integers) and returns a list of coordinates (list of 3387 tuples containting 2 integers each) that the mouse will move through. 3388 The default path function is Bresenham's line algorithm, which will move 3389 the mouse in a straight line. 3390 3391 (*) `relative` parameter decides how the movement is executed: 3392 3393 -> `False`: Target postion is given and absolute movement is used. 3394 3395 -> `True`: Calculates target offset and uses relative movement API 3396 (can be inconsistent) 3397 3398 If `_pause` is True (default), then an automatic sleep will be performed 3399 after the function finshes executing. The duration is set by the global 3400 variable `PAUSE`. 3401 3402 Setting `virtual` to True (default: False) changes the way internal APIs 3403 handle coordinates and is intended for multi monitor systems. It should be 3404 pretty much unncessary even for multi monitor systems, since all the 3405 necessary internal calculations beyond the border of the primay monitor 3406 work without it. 3407 3408 The way that Windows calculates the target pixel coordinates internally 3409 unfortunately leads to inaccuracies and unreachable pixels, especially 3410 if the `virtual` option is used. 3411 3412 If you need the target position to be pixel perfect, you can try setting 3413 `attempt_pixel_perfect` to True, which will use tiny relative movements 3414 to correct the unreachable position. 3415 3416 Relative movement is influenced by mouse speed and Windows Enhanced Pointer 3417 Precision, which can be temporarily disabled by setting 3418 `disable_mouse_acceleration`. 3419 3420 ---------------------------------------------------------------------------- 3421 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 3422 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 3423 3424 If you you start a relative movement while another is already in progress 3425 than the second movement could overwrite the first setting and disable 3426 Enhanced Pointer Precision and change mouse speed. 3427 There are some measures in place to try to mitigate that risk, such as an 3428 internal counter that only allows storing and restoring the acceleration 3429 settings as long as no other movement is currently in progress. 3430 Additionally, the acceleration settings can be manually saved and 3431 restored with `store_mouse_acceleration_settings()` and 3432 `restore_mouse_acceleration_settings()`. For your convenience, the 3433 store function is automatically called during import to save your current 3434 setting. You can then call the restore function at any time. 3435 3436 If all fails, the setting is not written permanently to your Windows 3437 settings, so it should restore itself upon reboot. 3438 3439 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3440 this library in multiple threads / processes / programs at the same time! 3441 3442 ---------------------------------------------------------------------------- 3443 3444 NOTE: `logScreenshot` is currently unsupported. 3445 """ 3446 if relative: 3447 _relative_mouse_move( 3448 x=x, 3449 y=y, 3450 duration=duration, 3451 tween=tween, 3452 logScreenshot=logScreenshot, 3453 target_coords_relative=False, 3454 virtual=virtual, 3455 path_function=path_function, 3456 disable_mouse_acceleration=disable_mouse_acceleration, 3457 ) 3458 else: 3459 _absolute_mouse_move( 3460 x=x, 3461 y=y, 3462 duration=duration, 3463 tween=tween, 3464 logScreenshot=logScreenshot, 3465 target_coords_relative=False, 3466 virtual=virtual, 3467 path_function=path_function, 3468 attempt_pixel_perfect=attempt_pixel_perfect, 3469 disable_mouse_acceleration=disable_mouse_acceleration, 3470 ) 3471 # --------------------------------------------------------------------------
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.
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 containting 2 integers each) 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.
3475@_genericPyDirectInputChecks 3476def moveRel( 3477 xOffset: int | None = None, 3478 yOffset: int | None = None, 3479 duration: float = 0.0, 3480 tween: Callable[[float], float] | None = None, 3481 logScreenshot: bool = False, 3482 _pause: bool = True, 3483 relative: bool = False, 3484 *, 3485 virtual: bool = False, 3486 path_function: PathFunction | None = None, 3487 attempt_pixel_perfect: bool = False, 3488 disable_mouse_acceleration: bool = False, 3489) -> None: 3490 """ 3491 Move the mouse a relative amount determined by `xOffset` and `yOffset`. 3492 3493 If `duration` is floating point number greater than 0, then this function 3494 will automatically split the movement into microsteps instead of moving the 3495 complete distance instantly. 3496 3497 `tween` is a function that takes a floating point number between 0.0 and 3498 1.0 and returns another floating point number between 0.0 and 1.0. The 3499 returned number will be used to calculate the next position of the 3500 mouse between the start and the end position based on the current duration. 3501 The default tweening function is linear, which will move the mouse at a 3502 constant speed. See the `pytweening` package for more tweening functions. 3503 3504 `path_function` is a function that takes the start and end coordinates of 3505 the mouse movement (4 integers) and returns a list of coordinates (list of 3506 tuples containting 2 integers each) that the mouse will move through. 3507 The default path function is Bresenham's line algorithm, which will move 3508 the mouse in a straight line. 3509 3510 `relative` parameter decides how the movement is executed: 3511 3512 -> `False`: Target postion is calculated and absolute movement is used. 3513 3514 -> `True`: Target offset is given and relative movement API is used 3515 (can be inconsistent) 3516 3517 The inconsistency issue can be solved by disabling Enhanced Pointer 3518 Precision and set Mouse speed to 10 in Windows mouse settings. Since users 3519 may not want to permanently change their input settings just for this 3520 library, the `disable_mouse_acceleration` argument can be used to 3521 temporarily disable Enhanced Pointer Precision and fix mouse speed at 10 3522 and restore it after the mouse movement. 3523 3524 If `_pause` is True (default), then an automatic sleep will be performed 3525 after the function finshes executing. The duration is set by the global 3526 variable `PAUSE`. 3527 3528 Setting `virtual` to True (default: False) changes the way internal APIs 3529 handle coordinates and is intended for multi monitor systems. It should be 3530 pretty much unncessary even for multi monitor systems, since all the 3531 necessary internal calculations beyond the border of the primay monitor 3532 work without it. 3533 3534 The way that Windows calculates the target pixel coordinates internally 3535 unfortunately leads to inaccuracies and unreachable pixels, especially 3536 if the `virtual` option is used. 3537 3538 If you need the target position to be pixel perfect, you can try setting 3539 `attempt_pixel_perfect` to True, which will use tiny relative movements 3540 to correct the unreachable position. 3541 3542 ---------------------------------------------------------------------------- 3543 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 3544 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 3545 3546 If you you start a relative movement while another is already in progress 3547 than the second movement could overwrite the first setting and disable 3548 Enhanced Pointer Precision and change mouse speed. 3549 There are some measures in place to try to mitigate that risk, such as an 3550 internal counter that only allows storing and restoring the acceleration 3551 settings as long as no other movement is currently in progress. 3552 Additionally, the acceleration settings can be manually saved and 3553 restored with `store_mouse_acceleration_settings()` and 3554 `restore_mouse_acceleration_settings()`. For your convinnience, the 3555 store function is automatically called during import to save your current 3556 setting. You can then call the restore function at any time. 3557 3558 If all fails, the setting is not written permanently to your Windows 3559 settings, so it should restore itself upon reboot. 3560 3561 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3562 this library in multiple threads / processes / programs at the same time! 3563 3564 ---------------------------------------------------------------------------- 3565 3566 NOTE: `logScreenshot` is are currently unsupported. 3567 """ 3568 if relative: 3569 _relative_mouse_move( 3570 x=xOffset, 3571 y=yOffset, 3572 duration=duration, 3573 tween=tween, 3574 logScreenshot=logScreenshot, 3575 target_coords_relative=True, 3576 virtual=virtual, 3577 path_function=path_function, 3578 disable_mouse_acceleration=disable_mouse_acceleration, 3579 ) 3580 else: 3581 _absolute_mouse_move( 3582 x=xOffset, 3583 y=yOffset, 3584 duration=duration, 3585 tween=tween, 3586 logScreenshot=logScreenshot, 3587 target_coords_relative=True, 3588 virtual=virtual, 3589 path_function=path_function, 3590 attempt_pixel_perfect=attempt_pixel_perfect, 3591 disable_mouse_acceleration=disable_mouse_acceleration, 3592 ) 3593 # --------------------------------------------------------------------------
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.
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 containting 2 integers each) 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.
3475@_genericPyDirectInputChecks 3476def moveRel( 3477 xOffset: int | None = None, 3478 yOffset: int | None = None, 3479 duration: float = 0.0, 3480 tween: Callable[[float], float] | None = None, 3481 logScreenshot: bool = False, 3482 _pause: bool = True, 3483 relative: bool = False, 3484 *, 3485 virtual: bool = False, 3486 path_function: PathFunction | None = None, 3487 attempt_pixel_perfect: bool = False, 3488 disable_mouse_acceleration: bool = False, 3489) -> None: 3490 """ 3491 Move the mouse a relative amount determined by `xOffset` and `yOffset`. 3492 3493 If `duration` is floating point number greater than 0, then this function 3494 will automatically split the movement into microsteps instead of moving the 3495 complete distance instantly. 3496 3497 `tween` is a function that takes a floating point number between 0.0 and 3498 1.0 and returns another floating point number between 0.0 and 1.0. The 3499 returned number will be used to calculate the next position of the 3500 mouse between the start and the end position based on the current duration. 3501 The default tweening function is linear, which will move the mouse at a 3502 constant speed. See the `pytweening` package for more tweening functions. 3503 3504 `path_function` is a function that takes the start and end coordinates of 3505 the mouse movement (4 integers) and returns a list of coordinates (list of 3506 tuples containting 2 integers each) that the mouse will move through. 3507 The default path function is Bresenham's line algorithm, which will move 3508 the mouse in a straight line. 3509 3510 `relative` parameter decides how the movement is executed: 3511 3512 -> `False`: Target postion is calculated and absolute movement is used. 3513 3514 -> `True`: Target offset is given and relative movement API is used 3515 (can be inconsistent) 3516 3517 The inconsistency issue can be solved by disabling Enhanced Pointer 3518 Precision and set Mouse speed to 10 in Windows mouse settings. Since users 3519 may not want to permanently change their input settings just for this 3520 library, the `disable_mouse_acceleration` argument can be used to 3521 temporarily disable Enhanced Pointer Precision and fix mouse speed at 10 3522 and restore it after the mouse movement. 3523 3524 If `_pause` is True (default), then an automatic sleep will be performed 3525 after the function finshes executing. The duration is set by the global 3526 variable `PAUSE`. 3527 3528 Setting `virtual` to True (default: False) changes the way internal APIs 3529 handle coordinates and is intended for multi monitor systems. It should be 3530 pretty much unncessary even for multi monitor systems, since all the 3531 necessary internal calculations beyond the border of the primay monitor 3532 work without it. 3533 3534 The way that Windows calculates the target pixel coordinates internally 3535 unfortunately leads to inaccuracies and unreachable pixels, especially 3536 if the `virtual` option is used. 3537 3538 If you need the target position to be pixel perfect, you can try setting 3539 `attempt_pixel_perfect` to True, which will use tiny relative movements 3540 to correct the unreachable position. 3541 3542 ---------------------------------------------------------------------------- 3543 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 3544 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 3545 3546 If you you start a relative movement while another is already in progress 3547 than the second movement could overwrite the first setting and disable 3548 Enhanced Pointer Precision and change mouse speed. 3549 There are some measures in place to try to mitigate that risk, such as an 3550 internal counter that only allows storing and restoring the acceleration 3551 settings as long as no other movement is currently in progress. 3552 Additionally, the acceleration settings can be manually saved and 3553 restored with `store_mouse_acceleration_settings()` and 3554 `restore_mouse_acceleration_settings()`. For your convinnience, the 3555 store function is automatically called during import to save your current 3556 setting. You can then call the restore function at any time. 3557 3558 If all fails, the setting is not written permanently to your Windows 3559 settings, so it should restore itself upon reboot. 3560 3561 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3562 this library in multiple threads / processes / programs at the same time! 3563 3564 ---------------------------------------------------------------------------- 3565 3566 NOTE: `logScreenshot` is are currently unsupported. 3567 """ 3568 if relative: 3569 _relative_mouse_move( 3570 x=xOffset, 3571 y=yOffset, 3572 duration=duration, 3573 tween=tween, 3574 logScreenshot=logScreenshot, 3575 target_coords_relative=True, 3576 virtual=virtual, 3577 path_function=path_function, 3578 disable_mouse_acceleration=disable_mouse_acceleration, 3579 ) 3580 else: 3581 _absolute_mouse_move( 3582 x=xOffset, 3583 y=yOffset, 3584 duration=duration, 3585 tween=tween, 3586 logScreenshot=logScreenshot, 3587 target_coords_relative=True, 3588 virtual=virtual, 3589 path_function=path_function, 3590 attempt_pixel_perfect=attempt_pixel_perfect, 3591 disable_mouse_acceleration=disable_mouse_acceleration, 3592 ) 3593 # --------------------------------------------------------------------------
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.
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 containting 2 integers each) 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.
3603@_genericPyDirectInputChecks 3604def dragTo( 3605 x: int | None = None, 3606 y: int | None = None, 3607 duration: float = 0.0, 3608 tween: Callable[[float], float] | None = None, 3609 button: str | None = None, 3610 logScreenshot: bool = False, 3611 _pause: bool = True, 3612 mouseDownUp: bool = True, 3613 *, 3614 relative: bool = False, 3615 virtual: bool = False, 3616 path_function: PathFunction | None = None, 3617 attempt_pixel_perfect: bool = False, 3618 disable_mouse_acceleration: bool = False, 3619) -> None: 3620 """ 3621 Press and hold a mouse button while moving to the target coordinates. 3622 3623 See `moveTo` for more information on most arguments. 3624 3625 `button` is a string that is one of the following constants: 3626 MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, MOUSE_BUTTON4, MOUSE_BUTTON5, 3627 MOUSE_PRIMARY (default), MOUSE_SECONDARY. 3628 3629 If `mouseDownUp` (default: True) is manually set to False, then this 3630 function is basically the same as `moveTo`. Only exists to match PyAutoGUI. 3631 3632 If `_pause` is True (default), then an automatic sleep will be performed 3633 after the function finshes executing. The duration is set by the global 3634 variable `PAUSE`. 3635 3636 ---------------------------------------------------------------------------- 3637 3638 NOTE: `logScreenshot` is currently unsupported. 3639 """ 3640 # TODO: bounding box check for valid position 3641 if button is None: 3642 button = MOUSE_PRIMARY 3643 if mouseDownUp: 3644 mouseDown(button=button, _pause=False, virtual=virtual) 3645 moveTo( 3646 x, 3647 y, 3648 duration=duration, 3649 tween=tween, 3650 logScreenshot=logScreenshot, 3651 _pause=False, # don't add an additional pause 3652 relative=relative, 3653 virtual=virtual, 3654 path_function=path_function, 3655 attempt_pixel_perfect=attempt_pixel_perfect, 3656 disable_mouse_acceleration=disable_mouse_acceleration, 3657 ) 3658 if mouseDownUp: 3659 mouseUp(button=button, _pause=False, virtual=virtual) 3660 # --------------------------------------------------------------------------
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.
3664@_genericPyDirectInputChecks 3665def dragRel( 3666 xOffset: int | None = None, 3667 yOffset: int | None = None, 3668 duration: float = 0.0, 3669 tween: Callable[[float], float] | None = None, 3670 button: str | None = None, 3671 logScreenshot: bool = False, 3672 _pause: bool = True, 3673 mouseDownUp: bool = True, 3674 *, 3675 relative: bool = False, 3676 virtual: bool = False, 3677 path_function: PathFunction | None = None, 3678 disable_mouse_acceleration: bool = False, 3679) -> None: 3680 """ 3681 Press and hold a mouse button while moving a relative distance 3682 3683 See `moveRel` for more information on most arguments. 3684 3685 `button` is a string that is one of the following constants: 3686 MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, MOUSE_BUTTON4, MOUSE_BUTTON5, 3687 MOUSE_PRIMARY (default), MOUSE_SECONDARY. 3688 3689 If `mouseDownUp` (default: True) is manually set to False, then this 3690 function is basically the same as `moveTo`. Only exists to match PyAutoGUI. 3691 3692 If `_pause` is True (default), then an automatic sleep will be performed 3693 after the function finshes executing. The duration is set by the global 3694 variable `PAUSE`. 3695 3696 ---------------------------------------------------------------------------- 3697 3698 NOTE: `logScreenshot` is currently unsupported. 3699 """ 3700 # TODO: bounding box check for valid position 3701 if button is None: 3702 button = MOUSE_PRIMARY 3703 if mouseDownUp: 3704 mouseDown(button=button, _pause=False, virtual=virtual) 3705 moveRel( 3706 xOffset, 3707 yOffset, 3708 duration=duration, 3709 tween=tween, 3710 logScreenshot=logScreenshot, 3711 _pause=False, # don't add an additional pause 3712 relative=relative, 3713 virtual=virtual, 3714 path_function=path_function, 3715 disable_mouse_acceleration=disable_mouse_acceleration, 3716 ) 3717 if mouseDownUp: 3718 mouseUp(button=button, _pause=False, virtual=virtual) 3719 # --------------------------------------------------------------------------
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.
3664@_genericPyDirectInputChecks 3665def dragRel( 3666 xOffset: int | None = None, 3667 yOffset: int | None = None, 3668 duration: float = 0.0, 3669 tween: Callable[[float], float] | None = None, 3670 button: str | None = None, 3671 logScreenshot: bool = False, 3672 _pause: bool = True, 3673 mouseDownUp: bool = True, 3674 *, 3675 relative: bool = False, 3676 virtual: bool = False, 3677 path_function: PathFunction | None = None, 3678 disable_mouse_acceleration: bool = False, 3679) -> None: 3680 """ 3681 Press and hold a mouse button while moving a relative distance 3682 3683 See `moveRel` for more information on most arguments. 3684 3685 `button` is a string that is one of the following constants: 3686 MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, MOUSE_BUTTON4, MOUSE_BUTTON5, 3687 MOUSE_PRIMARY (default), MOUSE_SECONDARY. 3688 3689 If `mouseDownUp` (default: True) is manually set to False, then this 3690 function is basically the same as `moveTo`. Only exists to match PyAutoGUI. 3691 3692 If `_pause` is True (default), then an automatic sleep will be performed 3693 after the function finshes executing. The duration is set by the global 3694 variable `PAUSE`. 3695 3696 ---------------------------------------------------------------------------- 3697 3698 NOTE: `logScreenshot` is currently unsupported. 3699 """ 3700 # TODO: bounding box check for valid position 3701 if button is None: 3702 button = MOUSE_PRIMARY 3703 if mouseDownUp: 3704 mouseDown(button=button, _pause=False, virtual=virtual) 3705 moveRel( 3706 xOffset, 3707 yOffset, 3708 duration=duration, 3709 tween=tween, 3710 logScreenshot=logScreenshot, 3711 _pause=False, # don't add an additional pause 3712 relative=relative, 3713 virtual=virtual, 3714 path_function=path_function, 3715 disable_mouse_acceleration=disable_mouse_acceleration, 3716 ) 3717 if mouseDownUp: 3718 mouseUp(button=button, _pause=False, virtual=virtual) 3719 # --------------------------------------------------------------------------
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.
3733def is_valid_key(key: str) -> bool: 3734 """ 3735 Returns true if key name `key` can be translated into a valid scan code. 3736 """ 3737 return key in KEYBOARD_MAPPING
Returns true if key name key can be translated into a valid scan code.
3733def is_valid_key(key: str) -> bool: 3734 """ 3735 Returns true if key name `key` can be translated into a valid scan code. 3736 """ 3737 return key in KEYBOARD_MAPPING
Returns true if key name key can be translated into a valid scan code.
3748@_genericPyDirectInputChecks 3749def scancode_keyDown( 3750 scancodes: ScancodeTypes, 3751 logScreenshot: None = None, 3752 _pause: bool = True, 3753 *, 3754 auto_shift: bool = False, 3755) -> bool: 3756 """ 3757 Press down key corresponding to `scancodes`. 3758 3759 The actually pressed key will depend on your system keyboard layout. 3760 Limits the available character set but should provide the best 3761 compatibility. 3762 3763 If `_pause` is True (default), then an automatic sleep will be performed 3764 after the function finshes executing. The duration is set by the global 3765 variable `PAUSE`. 3766 3767 `auto_shift` is used internally by higher level functions to automatically 3768 press the shift key before supported scancodes (indicitated by a special 3769 bit outside the regular scancode range, while it technically can be used, 3770 it's not intended for public access). 3771 3772 ---------------------------------------------------------------------------- 3773 3774 NOTE: `logScreenshot` is currently unsupported. 3775 """ 3776 scancodes_sequence: ScancodeSequence 3777 if isinstance(scancodes, int): 3778 scancodes_sequence = ScancodeSequence([scancodes]) 3779 else: 3780 scancodes_sequence = scancodes 3781 3782 keybdFlags: int = _KEYEVENTF_SCANCODE 3783 input_structs: list[_INPUT] = [] 3784 extendedFlag: int 3785 3786 # Init event tracking 3787 insertedEvents: int = 0 3788 expectedEvents: int = 0 3789 3790 for scancode in scancodes_sequence: 3791 if auto_shift and scancode & _OFFSET_SHIFTKEY: 3792 input_structs += [ 3793 _create_keyboard_input( 3794 wScan=_SHIFT_SCANCODE, dwFlags=keybdFlags 3795 ) 3796 ] 3797 expectedEvents += 1 3798 3799 scancode = scancode & 0xFFFF 3800 3801 extendedFlag = _KEYEVENTF_EXTENDEDKEY if scancode >= 0xE000 else 0 3802 input_structs += [ 3803 _create_keyboard_input( 3804 wScan=scancode, dwFlags=keybdFlags | extendedFlag 3805 ) 3806 ] 3807 expectedEvents += 1 3808 3809 insertedEvents += _send_input(input_structs) 3810 3811 # SendInput returns the number of event successfully inserted into 3812 # input stream 3813 # https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput#return-value 3814 return insertedEvents == expectedEvents 3815 # --------------------------------------------------------------------------
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.
3819@_genericPyDirectInputChecks 3820def scancode_keyUp( 3821 scancodes: ScancodeTypes, 3822 logScreenshot: None = None, 3823 _pause: bool = True, 3824 *, 3825 auto_shift: bool = False, 3826) -> bool: 3827 """ 3828 Release key corresponding to `scancodes`. 3829 3830 The actually pressed key will depend on your system keyboard layout. 3831 Limits the available character set but should provide the best 3832 compatibility. 3833 3834 If `_pause` is True (default), then an automatic sleep will be performed 3835 after the function finshes executing. The duration is set by the global 3836 variable `PAUSE`. 3837 3838 `auto_shift` is used internally by higher level functions to automatically 3839 press the shift key before supported scancodes (indicitated by a special 3840 bit outside the regular scancode range, while it technically can be used, 3841 it's not intended for public access). 3842 3843 ---------------------------------------------------------------------------- 3844 3845 NOTE: `logScreenshot` is currently unsupported. 3846 """ 3847 scancodes_sequence: ScancodeSequence 3848 if isinstance(scancodes, int): 3849 scancodes_sequence = ScancodeSequence([scancodes]) 3850 else: 3851 scancodes_sequence = scancodes 3852 3853 keybdFlags: int = _KEYEVENTF_SCANCODE | _KEYEVENTF_KEYUP 3854 input_structs: list[_INPUT] = [] 3855 extendedFlag: int 3856 3857 # Init event tracking 3858 insertedEvents: int = 0 3859 expectedEvents: int = 0 3860 3861 for scancode in scancodes_sequence: 3862 if auto_shift and scancode & _OFFSET_SHIFTKEY: 3863 input_structs += [ 3864 _create_keyboard_input( 3865 wScan=_SHIFT_SCANCODE, dwFlags=keybdFlags 3866 ) 3867 ] 3868 expectedEvents += 1 3869 3870 scancode = scancode & 0xFFFF 3871 3872 extendedFlag = _KEYEVENTF_EXTENDEDKEY if scancode >= 0xE000 else 0 3873 input_structs += [ 3874 _create_keyboard_input( 3875 wScan=scancode & 0xFFFF, dwFlags=keybdFlags | extendedFlag 3876 ) 3877 ] 3878 expectedEvents += 1 3879 3880 insertedEvents += _send_input(input_structs) 3881 return insertedEvents == expectedEvents 3882 # --------------------------------------------------------------------------
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.
3912@_genericPyDirectInputChecks 3913def scancode_press( 3914 scancodes: ScancodeTypes | Sequence[ScancodeTypes], 3915 presses: int = 1, 3916 interval: float = 0.0, 3917 logScreenshot: None = None, 3918 _pause: bool = True, 3919 *, 3920 auto_shift: bool = False, 3921 delay: float = 0.0, 3922 duration: float = 0.0, 3923) -> bool: 3924 """ 3925 Press the sequence of `keys` for `presses` amount of times. 3926 3927 The actually pressed key will depend on your system keyboard layout. 3928 Limits the available character set but should provide the best 3929 compatibility. 3930 3931 Explanation of time parameters (seconds as floating point numbers): 3932 3933 - `interval` is the time spent waiting between sequences. If `keys` is a 3934 str instance or single element list, then `interval` will be ignored. 3935 - `delay` is the time from one complete key (press+release) to the next one 3936 in the same sequence. If there is only a single key in a sequence, then 3937 `delay` will be ignored. 3938 - `duration` is the time spent on holding every key before releasing it 3939 again. 3940 3941 If `_pause` is True (default), then an automatic sleep will be performed 3942 after the function finshes executing. The duration is set by the global 3943 variable `PAUSE`. 3944 Be aware, that the global pause defined by the PAUSE `constant` only 3945 applies after every call to this function, not inbetween (no extra pause 3946 between pressing and releasing key, use the `duration` argument instead)! 3947 3948 `auto_shift` is used internally by higher level functions to automatically 3949 press the shift key before supported scancodes (indicitated by a special 3950 bit outside the regular scancode range, while it technically can be used, 3951 it's not intended for public access). 3952 3953 ---------------------------------------------------------------------------- 3954 3955 NOTE: `logScreenshot` is currently unsupported. 3956 """ 3957 scancodes_sequence: Sequence[ScancodeTypes] 3958 if isinstance(scancodes, int): 3959 scancodes_sequence = [ScancodeSequence([scancodes])] 3960 elif isinstance(scancodes, ScancodeSequence): 3961 scancodes_sequence = [scancodes] 3962 else: 3963 scancodes_sequence = scancodes 3964 3965 # We need to press x keys y times, which comes out to x*y presses in total 3966 expectedPresses: int = presses * len(scancodes_sequence) 3967 completedPresses: int = 0 3968 3969 apply_interval: bool = False 3970 for _ in range(presses): 3971 if apply_interval: # Don't delay first press 3972 _sleep(interval) 3973 apply_interval = True 3974 3975 apply_delay: bool = False 3976 for c in scancodes_sequence: 3977 if apply_delay: # Don't delay first press 3978 _sleep(delay) 3979 apply_delay = True 3980 3981 completedPresses += _helper_scancode_press( 3982 c, duration, _pause=False, auto_shift=auto_shift 3983 ) 3984 3985 return completedPresses == expectedPresses 3986 # --------------------------------------------------------------------------
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.
3990@contextmanager 3991@_genericPyDirectInputChecks 3992def scancode_hold( 3993 scancodes: ScancodeTypes | Sequence[ScancodeTypes], 3994 logScreenshot: None = None, 3995 _pause: bool = True, 3996 *, 3997 auto_shift: bool = False, 3998 raise_on_failure: bool = False, 3999) -> Generator[None, None, None]: 4000 """ 4001 Hold the sequence of keys corresponding to `scancodes` as long as the 4002 context manager is in scope (press upon entry, release upon exit). 4003 4004 Keys will be released in reverse order (LIFO), but still practically 4005 instantenous. 4006 4007 The actually pressed key will depend on your system keyboard layout. 4008 Limits the available character set but should provide the best 4009 compatibility. 4010 4011 If `_pause` is True (default), then an automatic sleep will be performed 4012 after the function finshes executing. The duration is set by the global 4013 variable `PAUSE`. 4014 Be aware, that the global pause defined by the PAUSE `constant` only 4015 applies after every call to this function, not inbetween (no pause between 4016 press and releasing key)! 4017 4018 `auto_shift` is used internally by higher level functions to automatically 4019 press the shift key before supported scancodes (indicitated by a special 4020 bit outside the regular scancode range, while it technically can be used, 4021 it's not intended for public access). 4022 4023 If `raise_on_failure` is True, then `PriorInputFailedException` will be 4024 raised if not all keyboard inputs could be executed successfully. 4025 4026 ---------------------------------------------------------------------------- 4027 4028 NOTE: `logScreenshot` is currently unsupported. 4029 """ 4030 scancodes_sequence: Sequence[ScancodeTypes] 4031 if isinstance(scancodes, int): 4032 scancodes_sequence = [ScancodeSequence([scancodes])] 4033 elif isinstance(scancodes, ScancodeSequence): 4034 scancodes_sequence = [scancodes] 4035 else: 4036 scancodes_sequence = scancodes 4037 4038 expectedPresses: int = len(scancodes_sequence) 4039 downed: int = 0 4040 upped: int = 0 4041 4042 try: 4043 for c in scancodes_sequence: 4044 downed += scancode_keyDown(c, _pause=False, auto_shift=auto_shift) 4045 yield 4046 finally: 4047 for c in reversed(scancodes_sequence): 4048 upped += scancode_keyUp(c, _pause=False, auto_shift=auto_shift) 4049 if raise_on_failure and not (expectedPresses == downed == upped): 4050 raise PriorInputFailedException 4051 # --------------------------------------------------------------------------
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.
4055@_genericPyDirectInputChecks 4056def scancode_hotkey( 4057 *args: ScancodeTypes, 4058 interval: float = 0.0, 4059 wait: float = 0.0, 4060 logScreenshot: None = None, 4061 _pause: bool = True, 4062 auto_shift: bool = True, 4063) -> bool: 4064 """ 4065 Press down buttons in order they are specified as arguments, 4066 releasing them in reverse order, e.g. 0x1D, 0x2E will first press 4067 Control, then C and release C before releasing Control. 4068 4069 Use keyword-only argument `interval` to specify a delay between single 4070 keys when pressing and releasing and `wait` for delay between last press 4071 and first release. 4072 4073 If `_pause` is True (default), then an automatic sleep will be performed 4074 after the function finshes executing. The duration is set by the global 4075 variable `PAUSE`. 4076 Be aware, that the global pause defined by the PAUSE `constant` only 4077 applies after every call to this function, not inbetween (no pause between 4078 press and releasing key)! 4079 4080 `auto_shift` is used internally by higher level functions to automatically 4081 press the shift key before supported scancodes (indicitated by a special 4082 bit outside the regular scancode range, while it technically can be used, 4083 it's not intended for public access). 4084 4085 ---------------------------------------------------------------------------- 4086 4087 NOTE: `logScreenshot` is currently unsupported. 4088 """ 4089 expectedPresses: int = len(args) 4090 downed: int = 0 4091 upped: int = 0 4092 4093 apply_interval: bool = False 4094 for code in args: 4095 if apply_interval: 4096 _sleep(interval) # sleep between iterations 4097 apply_interval = True 4098 4099 downed += scancode_keyDown(code, _pause=False, auto_shift=auto_shift) 4100 4101 _sleep(wait) 4102 4103 apply_interval = False 4104 for code in reversed(args): 4105 if apply_interval: 4106 _sleep(interval) # sleep between iterations 4107 apply_interval = True 4108 4109 upped += scancode_keyUp(code, _pause=False, auto_shift=auto_shift) 4110 4111 return expectedPresses == downed == upped 4112 # --------------------------------------------------------------------------
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.
4120def keyDown( 4121 key: str, 4122 logScreenshot: None = None, 4123 _pause: bool = True, 4124 *, 4125 auto_shift: bool = False, 4126) -> bool: 4127 """ 4128 Press down key corresponding to key name `key`. 4129 4130 `key` will be interpreted as a keyboard key (US QWERTY). 4131 The actually pressed key will depend on your system keyboard layout. 4132 Limits the available character set but should provide the best 4133 compatibility. 4134 4135 If `_pause` is True (default), then an automatic sleep will be performed 4136 after the function finshes executing. The duration is set by the global 4137 variable `PAUSE`. 4138 4139 If `auto_shift` is True, then "shifted" characters like upper case letters 4140 and the symbols on the number row automatically insert a Shift scancode 4141 into the input sequence. 4142 4143 ---------------------------------------------------------------------------- 4144 4145 NOTE: `logScreenshot` is currently unsupported. 4146 """ 4147 scancode: ScancodeTypes | None = KEYBOARD_MAPPING.get(key) 4148 if scancode is None: 4149 return False 4150 return scancode_keyDown( 4151 scancode, logScreenshot, _pause=_pause, auto_shift=auto_shift 4152 ) 4153 # --------------------------------------------------------------------------
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.
4158def keyUp( 4159 key: str, 4160 logScreenshot: None = None, 4161 _pause: bool = True, 4162 *, 4163 auto_shift: bool = False, 4164) -> bool: 4165 """ 4166 Lift up key corresponding to key name `key`. 4167 4168 `key` will be interpreted as a keyboard key (US QWERTY). 4169 The actually lifted key will depend on your system keyboard layout. 4170 Limits the available character set but should provide the best 4171 compatibility. 4172 4173 If `_pause` is True (default), then an automatic sleep will be performed 4174 after the function finshes executing. The duration is set by the global 4175 variable `PAUSE`. 4176 4177 If `auto_shift` is True, then "shifted" characters like upper case letters 4178 and the symbols on the number row automatically insert a Shift scancode 4179 into the input sequence. 4180 4181 ---------------------------------------------------------------------------- 4182 4183 NOTE: `logScreenshot` is currently unsupported. 4184 """ 4185 scancode: ScancodeTypes | None = KEYBOARD_MAPPING.get(key) 4186 if scancode is None: 4187 return False 4188 return scancode_keyUp( 4189 scancode, logScreenshot, _pause=_pause, auto_shift=auto_shift 4190 ) 4191 # --------------------------------------------------------------------------
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.
4217@_genericPyDirectInputChecks 4218def press( 4219 keys: str | Sequence[str], 4220 presses: int = 1, 4221 interval: float = 0.0, 4222 logScreenshot: None = None, 4223 _pause: bool = True, 4224 *, 4225 auto_shift: bool = False, 4226 delay: float = 0.0, 4227 duration: float = 0.0, 4228) -> bool: 4229 """ 4230 Press the sequence of `keys` for `presses` amount of times. 4231 4232 `keys` will be interpreted as sequence of keyboard keys (US QWERTY). 4233 The actually pressed key will depend on your system keyboard layout. 4234 Limits the available character set but should provide the best 4235 compatibility. 4236 4237 Explanation of time parameters (seconds as floating point numbers): 4238 4239 - `interval` is the time spent waiting between sequences. If `keys` is a 4240 str instance, single element list or presses equals 1 (the default), 4241 then `interval` will be ignored. 4242 - `delay` is the time from one complete key (press+release) to the next one 4243 in the same sequence. If there is only a single key in a sequence, then 4244 `delay` will be ignored. 4245 - `duration` is the time spent on holding every key before releasing it 4246 again. 4247 4248 If `_pause` is True (default), then an automatic sleep will be performed 4249 after the function finshes executing. The duration is set by the global 4250 variable `PAUSE`. 4251 Be aware, that the global pause defined by the `PAUSE` var only applies 4252 after every call to this function, not inbetween (no extra pause between 4253 pressing and releasing key, use the `duration` argument instead)! 4254 4255 If `auto_shift` is True, then "shifted" characters like upper case letters 4256 and the symbols on the number row automatically insert a Shift scancode 4257 into the input sequence. 4258 4259 ---------------------------------------------------------------------------- 4260 4261 NOTE: `logScreenshot` is currently unsupported. 4262 """ 4263 if isinstance(keys, str): 4264 keys = [keys] # If keys is 'enter', convert it to ['enter']. 4265 keys = [_normalize_key(key, auto_shift=auto_shift) for key in keys] 4266 4267 # We need to press x keys y times, which comes out to x*y presses in total 4268 expectedPresses: int = presses * len(keys) 4269 completedPresses: int = 0 4270 4271 apply_interval: bool = False 4272 for _ in range(presses): 4273 if apply_interval: # Don't delay first press 4274 _sleep(interval) 4275 apply_interval = True 4276 4277 apply_delay: bool = False 4278 for k in keys: 4279 if apply_delay: # Don't delay first press 4280 _sleep(delay) 4281 apply_delay = True 4282 4283 completedPresses += _helper_press( 4284 k, duration, _pause=False, auto_shift=auto_shift 4285 ) 4286 4287 return completedPresses == expectedPresses 4288 # --------------------------------------------------------------------------
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.
4292@contextmanager 4293@_genericPyDirectInputChecks 4294def hold( 4295 keys: str | Sequence[str], 4296 logScreenshot: None = None, 4297 _pause: bool = True, 4298 *, 4299 auto_shift: bool = False, 4300 raise_on_failure: bool = False, 4301) -> Generator[None, None, None]: 4302 """ 4303 Hold the sequence of keys corresponding to key names in `keys` as long as 4304 the context manager is in scope (press upon entry, release upon exit). 4305 4306 Keys will be released in reverse order (LIFO), but still practically 4307 instantenous. 4308 4309 `key` will be interpreted as a keyboard key (US QWERTY). 4310 The actually pressed key will depend on your system keyboard layout. 4311 Limits the available character set but should provide the best 4312 compatibility. 4313 4314 If `_pause` is True (default), then an automatic sleep will be performed 4315 after the function finshes executing. The duration is set by the global 4316 variable `PAUSE`. 4317 Be aware, that the global pause defined by the PAUSE `constant` only 4318 applies after every call to this function, not inbetween (no pause between 4319 press and releasing key)! 4320 4321 `auto_shift` is used internally by higher level functions to automatically 4322 press the shift key before supported scancodes (indicitated by a special 4323 bit outside the regular scancode range, while it technically can be used, 4324 it's not intended for public access). 4325 4326 If `raise_on_failure` is True, then `PriorInputFailedException` will be 4327 raised if not all keyboard inputs could be executed successfully. 4328 4329 ---------------------------------------------------------------------------- 4330 4331 NOTE: `logScreenshot` is currently unsupported. 4332 """ 4333 if isinstance(keys, str): 4334 keys = [keys] # make single element into iterable 4335 keys = [_normalize_key(key, auto_shift=auto_shift) for key in keys] 4336 4337 expectedPresses: int = len(keys) 4338 downed: int = 0 4339 upped: int = 0 4340 4341 try: 4342 for k in keys: 4343 downed += keyDown(k, auto_shift=auto_shift) 4344 yield 4345 finally: 4346 for k in reversed(keys): 4347 upped += keyUp(k, auto_shift=auto_shift) 4348 if raise_on_failure and not (expectedPresses == downed == upped): 4349 raise PriorInputFailedException 4350 # --------------------------------------------------------------------------
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.
4354@_genericPyDirectInputChecks 4355def typewrite( 4356 message: str, 4357 interval: float = 0.0, 4358 logScreenshot: None = None, 4359 _pause: bool = True, 4360 *, 4361 auto_shift: bool = False, 4362 delay: float = 0.0, 4363 duration: float = 0.0, 4364) -> None: 4365 """ 4366 Break down `message` into a single character key sequence and press each 4367 key one by one. 4368 4369 `message` will be interpreted as sequence of keyboard keys (US QWERTY). 4370 The actually pressed keys will depend on your system keyboard layout. 4371 Limits the available character set but should provide the best 4372 compatibility. 4373 4374 Explanation of time parameters (seconds as floating point numbers): 4375 4376 - `interval` is the time spent waiting between sequences. If `message` is a 4377 single character string, then `interval` will be ignored. 4378 - `delay` is the time from one complete key (press+release) to the next one 4379 in the same sequence. If there is only a single key in a sequence, then 4380 `delay` will be ignored. 4381 - `duration` is the time spent on holding every key before releasing it 4382 again. 4383 4384 If `_pause` is True (default), then an automatic sleep will be performed 4385 after the function finshes executing. The duration is set by the global 4386 variable `PAUSE`. 4387 Be aware, that the global pause defined by the PAUSE `constant` only 4388 applies after every call to this function, not inbetween (no pause between 4389 press and releasing key)! 4390 4391 `auto_shift` is used internally by higher level functions to automatically 4392 press the shift key before supported scancodes (indicitated by a special 4393 bit outside the regular scancode range, while it technically can be used, 4394 it's not intended for public access). 4395 4396 ---------------------------------------------------------------------------- 4397 4398 NOTE: `logScreenshot` is currently unsupported. 4399 """ 4400 4401 apply_interval: bool = False 4402 for key in message: 4403 if apply_interval: # Don't delay first press 4404 _sleep(interval) 4405 apply_interval = True 4406 4407 press( 4408 key, 4409 _pause=False, 4410 auto_shift=auto_shift, 4411 delay=delay, 4412 duration=duration, 4413 ) 4414 # --------------------------------------------------------------------------
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.
4354@_genericPyDirectInputChecks 4355def typewrite( 4356 message: str, 4357 interval: float = 0.0, 4358 logScreenshot: None = None, 4359 _pause: bool = True, 4360 *, 4361 auto_shift: bool = False, 4362 delay: float = 0.0, 4363 duration: float = 0.0, 4364) -> None: 4365 """ 4366 Break down `message` into a single character key sequence and press each 4367 key one by one. 4368 4369 `message` will be interpreted as sequence of keyboard keys (US QWERTY). 4370 The actually pressed keys will depend on your system keyboard layout. 4371 Limits the available character set but should provide the best 4372 compatibility. 4373 4374 Explanation of time parameters (seconds as floating point numbers): 4375 4376 - `interval` is the time spent waiting between sequences. If `message` is a 4377 single character string, then `interval` will be ignored. 4378 - `delay` is the time from one complete key (press+release) to the next one 4379 in the same sequence. If there is only a single key in a sequence, then 4380 `delay` will be ignored. 4381 - `duration` is the time spent on holding every key before releasing it 4382 again. 4383 4384 If `_pause` is True (default), then an automatic sleep will be performed 4385 after the function finshes executing. The duration is set by the global 4386 variable `PAUSE`. 4387 Be aware, that the global pause defined by the PAUSE `constant` only 4388 applies after every call to this function, not inbetween (no pause between 4389 press and releasing key)! 4390 4391 `auto_shift` is used internally by higher level functions to automatically 4392 press the shift key before supported scancodes (indicitated by a special 4393 bit outside the regular scancode range, while it technically can be used, 4394 it's not intended for public access). 4395 4396 ---------------------------------------------------------------------------- 4397 4398 NOTE: `logScreenshot` is currently unsupported. 4399 """ 4400 4401 apply_interval: bool = False 4402 for key in message: 4403 if apply_interval: # Don't delay first press 4404 _sleep(interval) 4405 apply_interval = True 4406 4407 press( 4408 key, 4409 _pause=False, 4410 auto_shift=auto_shift, 4411 delay=delay, 4412 duration=duration, 4413 ) 4414 # --------------------------------------------------------------------------
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.
4425@_genericPyDirectInputChecks 4426def hotkey( 4427 *args: str, 4428 interval: float = 0.0, 4429 wait: float = 0.0, 4430 logScreenshot: None = None, 4431 _pause: bool = True, 4432 auto_shift: bool = True, 4433) -> None: 4434 """ 4435 Press down buttons in order they are specified as arguments, 4436 releasing them in reverse order, e.g. 'ctrl', 'c' will first press 4437 Control, then C and release C before releasing Control. 4438 4439 Use keyword-only argument `interval` to specify a delay between single 4440 keys when pressing and releasing and `wait` for delay between last press 4441 and first release. 4442 4443 If `_pause` is True (default), then an automatic sleep will be performed 4444 after the function finshes executing. The duration is set by the global 4445 variable `PAUSE`. 4446 Be aware, that the global pause defined by the PAUSE `constant` only 4447 applies after every call to this function, not inbetween (no pause between 4448 press and releasing key)! 4449 4450 `auto_shift` is used internally by higher level functions to automatically 4451 press the shift key before supported scancodes (indicitated by a special 4452 bit outside the regular scancode range, while it technically can be used, 4453 it's not intended for public access). 4454 4455 ---------------------------------------------------------------------------- 4456 4457 NOTE: `logScreenshot` is currently unsupported. 4458 """ 4459 apply_interval: bool = False 4460 for key in args: 4461 if apply_interval: 4462 _sleep(interval) # sleep between iterations 4463 apply_interval = True 4464 4465 keyDown(key, _pause=False, auto_shift=auto_shift) 4466 4467 _sleep(wait) 4468 4469 apply_interval = False 4470 for key in reversed(args): 4471 if apply_interval: 4472 _sleep(interval) # sleep between iterations 4473 apply_interval = True 4474 4475 keyUp(key, _pause=False, auto_shift=auto_shift) 4476 # --------------------------------------------------------------------------
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.
4483@_genericPyDirectInputChecks 4484def unicode_charDown( 4485 char: str, logScreenshot: None = None, _pause: bool = True 4486) -> bool: 4487 """ 4488 Send Unicode character(s) `char` to currently focused application as 4489 WM_KEYDOWN message. 4490 4491 `char` will be interpreted as a string of Unicode characters 4492 (independet from keyboard layout). Supports complete Unicode character set 4493 but may not be compatible with every application. 4494 4495 If `_pause` is True (default), then an automatic sleep will be performed 4496 after the function finshes executing. The duration is set by the global 4497 variable `PAUSE`. 4498 4499 ---------------------------------------------------------------------------- 4500 4501 NOTE: `logScreenshot` is currently unsupported. 4502 """ 4503 utf16surrogates: bytes = char.encode("utf-16be") 4504 codes: Sequence[int] = unpack( 4505 f">{len(utf16surrogates) // 2}H", utf16surrogates 4506 ) 4507 4508 keybdFlags: int = _KEYEVENTF_UNICODE 4509 4510 input_structs: list[_INPUT] = [ 4511 _create_keyboard_input(wVk=0, wScan=charcode, dwFlags=keybdFlags) 4512 for charcode in codes 4513 ] 4514 # Init event tracking 4515 expectedEvents: int = len(input_structs) 4516 insertedEvents: int = _send_input(input_structs) 4517 4518 return insertedEvents == expectedEvents 4519 # --------------------------------------------------------------------------
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.
4523@_genericPyDirectInputChecks 4524def unicode_charUp( 4525 char: str, logScreenshot: None = None, _pause: bool = True 4526) -> bool: 4527 """ 4528 Send Unicode character(s) `char` to currently focused application as 4529 WM_KEYUP message. 4530 4531 `char` will be interpreted as a string of Unicode characters 4532 (independet from keyboard layout). Supports complete Unicode character set 4533 but may not be compatible with every application. 4534 4535 If `_pause` is True (default), then an automatic sleep will be performed 4536 after the function finshes executing. The duration is set by the global 4537 variable `PAUSE`. 4538 4539 ---------------------------------------------------------------------------- 4540 4541 NOTE: `logScreenshot` is currently unsupported. 4542 """ 4543 utf16surrogates: bytes = char.encode("utf-16be") 4544 codes: Sequence[int] = unpack( 4545 f">{len(utf16surrogates) // 2}H", utf16surrogates 4546 ) 4547 4548 keybdFlags: int = _KEYEVENTF_UNICODE | _KEYEVENTF_KEYUP 4549 4550 input_structs: list[_INPUT] = [ 4551 _create_keyboard_input(wVk=0, wScan=charcode, dwFlags=keybdFlags) 4552 for charcode in codes 4553 ] 4554 # Init event tracking 4555 expectedEvents: int = len(input_structs) 4556 insertedEvents: int = _send_input(input_structs) 4557 4558 return insertedEvents == expectedEvents 4559 # --------------------------------------------------------------------------
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.
4583@_genericPyDirectInputChecks 4584def unicode_press( 4585 chars: str | Sequence[str], 4586 presses: int = 1, 4587 interval: float = 0.0, 4588 logScreenshot: None = None, 4589 _pause: bool = True, 4590 *, 4591 delay: float = 0.0, 4592 duration: float = 0.0, 4593) -> bool: 4594 """ 4595 Press the sequence of `chars` for `presses` amount of times. 4596 4597 `chars` will be interpreted as a sequence of Unicode characters 4598 (independent from keyboard layout). Supports complete Unicode character set 4599 but may not be compatible with every application. 4600 4601 Explanation of time parameters (seconds as floating point numbers): 4602 4603 - `interval` is the time spent waiting between sequences. If `chars` is a 4604 str instance or single element list, then `interval` will be ignored. 4605 - `delay` is the time from one complete char (press+release) to the next 4606 one in the same sequence. If there is only a single char in a sequence, 4607 then `delay` will be ignored. 4608 - `duration` is the time spent on holding every char before releasing it 4609 again. 4610 4611 If `_pause` is True (default), then an automatic sleep will be performed 4612 after the function finshes executing. The duration is set by the global 4613 variable `PAUSE`. 4614 Be aware, that the global pause defined by the PAUSE `constant` only 4615 applies after every call to this function, not inbetween (no extra pause 4616 between pressing and releasing key, use the `duration` argument instead)! 4617 4618 ---------------------------------------------------------------------------- 4619 4620 NOTE: `logScreenshot` is currently unsupported. 4621 """ 4622 if isinstance(chars, str): 4623 chars = [chars] 4624 4625 # We need to press x keys y times, which comes out to x*y presses in total 4626 expectedPresses: int = presses * len(chars) 4627 completedPresses: int = 0 4628 4629 apply_interval: bool = False 4630 for _ in range(presses): 4631 if apply_interval: # Don't delay first press 4632 _sleep(interval) 4633 apply_interval = True 4634 4635 apply_delay: bool = False 4636 for c in chars: 4637 if apply_delay: # Don't delay first press 4638 _sleep(delay) 4639 apply_delay = True 4640 4641 completedPresses += _helper_unicode_press_char( 4642 c, 4643 duration, 4644 _pause=False, 4645 ) 4646 4647 return completedPresses == expectedPresses 4648 # --------------------------------------------------------------------------
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.
4652@contextmanager 4653@_genericPyDirectInputChecks 4654def unicode_hold( 4655 chars: str | Sequence[str], 4656 logScreenshot: None = None, 4657 _pause: bool = True, 4658 *, 4659 raise_on_failure: bool = False, 4660) -> Generator[None, None, None]: 4661 """ 4662 Hold the sequence of "keys" corresponding to unicode characters in `chars` 4663 as long as the context manager is in scope (press upon entry, 4664 release upon exit). 4665 4666 `chars` will be interpreted as a sequence of Unicode characters 4667 (independet from keyboard layout). Supports complete Unicode character set 4668 but may not be compatible with every application. 4669 4670 Keys will be released in reverse order (LIFO), but still practically 4671 instantenous. 4672 4673 If `_pause` is True (default), then an automatic sleep will be performed 4674 after the function finshes executing. The duration is set by the global 4675 variable `PAUSE`. 4676 Be aware, that the global pause defined by the PAUSE `constant` only 4677 applies after every call to this function, not inbetween (no pause between 4678 press and releasing key)! 4679 4680 If `raise_on_failure` is True, then `PriorInputFailedException` will be 4681 raised if not all keyboard inputs could be executed successfully. 4682 4683 ---------------------------------------------------------------------------- 4684 4685 NOTE: `logScreenshot` is currently unsupported. 4686 """ 4687 if isinstance(chars, str): 4688 chars = [chars] # make single element into iterable 4689 4690 expectedPresses: int = len(chars) 4691 downed: int = 0 4692 upped: int = 0 4693 4694 try: 4695 for c in chars: 4696 downed += unicode_charDown(c, _pause=False) 4697 yield 4698 finally: 4699 for c in reversed(chars): 4700 upped += unicode_charUp(c, _pause=False) 4701 if raise_on_failure and not (expectedPresses == downed == upped): 4702 raise PriorInputFailedException 4703 # --------------------------------------------------------------------------
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.
4707@_genericPyDirectInputChecks 4708def unicode_typewrite( 4709 message: str, 4710 interval: float = 0.0, 4711 logScreenshot: None = None, 4712 _pause: bool = True, 4713 *, 4714 delay: float = 0.0, 4715 duration: float = 0.0, 4716) -> None: 4717 """ 4718 Break down `message` into characters and press them one by one. 4719 4720 `message` will be interpreted as a sequence of Unicode characters 4721 (independet from keyboard layout). Supports complete Unicode character set 4722 but may not be compatible with every application. 4723 4724 Explanation of time parameters (seconds as floating point numbers): 4725 4726 - `interval` is the time spent waiting between sequences. If `message` is a 4727 single character string, then `interval` will be ignored. 4728 - `delay` is the time from one complete key (press+release) to the next one 4729 in the same sequence. If there is only a single key in a sequence, then 4730 `delay` will be ignored. 4731 - `duration` is the time spent on holding every key before releasing it 4732 again. 4733 4734 If `_pause` is True (default), then an automatic sleep will be performed 4735 after the function finshes executing. The duration is set by the global 4736 variable `PAUSE`. 4737 Be aware, that the global pause defined by the PAUSE `constant` only 4738 applies after every call to this function, not inbetween (no pause between 4739 press and releasing key)! 4740 4741 ---------------------------------------------------------------------------- 4742 4743 NOTE: `logScreenshot` is currently unsupported. 4744 """ 4745 apply_interval: bool = False 4746 for char in message: 4747 if apply_interval: 4748 _sleep(interval) # sleep between iterations 4749 apply_interval = True 4750 4751 unicode_press(char, _pause=False, delay=delay, duration=duration) 4752 # --------------------------------------------------------------------------
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.
4707@_genericPyDirectInputChecks 4708def unicode_typewrite( 4709 message: str, 4710 interval: float = 0.0, 4711 logScreenshot: None = None, 4712 _pause: bool = True, 4713 *, 4714 delay: float = 0.0, 4715 duration: float = 0.0, 4716) -> None: 4717 """ 4718 Break down `message` into characters and press them one by one. 4719 4720 `message` will be interpreted as a sequence of Unicode characters 4721 (independet from keyboard layout). Supports complete Unicode character set 4722 but may not be compatible with every application. 4723 4724 Explanation of time parameters (seconds as floating point numbers): 4725 4726 - `interval` is the time spent waiting between sequences. If `message` is a 4727 single character string, then `interval` will be ignored. 4728 - `delay` is the time from one complete key (press+release) to the next one 4729 in the same sequence. If there is only a single key in a sequence, then 4730 `delay` will be ignored. 4731 - `duration` is the time spent on holding every key before releasing it 4732 again. 4733 4734 If `_pause` is True (default), then an automatic sleep will be performed 4735 after the function finshes executing. The duration is set by the global 4736 variable `PAUSE`. 4737 Be aware, that the global pause defined by the PAUSE `constant` only 4738 applies after every call to this function, not inbetween (no pause between 4739 press and releasing key)! 4740 4741 ---------------------------------------------------------------------------- 4742 4743 NOTE: `logScreenshot` is currently unsupported. 4744 """ 4745 apply_interval: bool = False 4746 for char in message: 4747 if apply_interval: 4748 _sleep(interval) # sleep between iterations 4749 apply_interval = True 4750 4751 unicode_press(char, _pause=False, delay=delay, duration=duration) 4752 # --------------------------------------------------------------------------
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.
4761@_genericPyDirectInputChecks 4762def unicode_hotkey( 4763 *args: str, 4764 interval: float = 0.0, 4765 wait: float = 0.0, 4766 logScreenshot: None = None, 4767 _pause: bool = True, 4768) -> None: 4769 """ 4770 Press down buttons in order they are specified as arguments, 4771 releasing them in reverse order. 4772 4773 This function makes little sense for Unicode characters and mainly exists 4774 for parity with the other, lower-level hotkey functions! 4775 4776 See `unicode_press()` for an alternative function that presses keys in 4777 series instead. 4778 4779 Use keyword-only argument `interval` to specify a delay between single 4780 keys when pressing and releasing and `wait` for delay between last press 4781 and first release. 4782 4783 If `_pause` is True (default), then an automatic sleep will be performed 4784 after the function finshes executing. The duration is set by the global 4785 variable `PAUSE`. 4786 Be aware, that the global pause defined by the PAUSE `constant` only 4787 applies after every call to this function, not inbetween (no pause between 4788 press and releasing key)! 4789 4790 ---------------------------------------------------------------------------- 4791 4792 NOTE: `logScreenshot` is currently unsupported. 4793 """ 4794 apply_interval: bool = False 4795 for char in args: 4796 if apply_interval: 4797 _sleep(interval) # sleep between iterations 4798 apply_interval = True 4799 4800 unicode_charDown(char, _pause=False) 4801 4802 _sleep(wait) 4803 4804 apply_interval = False 4805 for char in reversed(args): 4806 if apply_interval: 4807 _sleep(interval) # sleep between iterations 4808 apply_interval = True 4809 4810 unicode_charUp(char, _pause=False) 4811 # --------------------------------------------------------------------------
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.