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, uCode: UINT | int, uMapType: UINT | int 1078 ) -> int: # UINT 1079 ... 1080 1081 1082_MapVirtualKeyW: _MapVirtualKeyWType = hint_cast( 1083 _MapVirtualKeyWType, _user32.MapVirtualKeyW 1084) 1085""" 1086----- MapVirtualKeyW function (winuser.h) ----- 1087 1088Translates (maps) a virtual-key code into a scan code or character value, or 1089translates a scan code into a virtual-key code. 1090 1091To specify a handle to the keyboard layout to use for translating the specified 1092code, use the MapVirtualKeyEx function. 1093 1094https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mapvirtualkeyw 1095 1096----- Parameters ----- 1097 1098[in] uCode 1099 1100Type: UINT 1101 1102The virtual key code[1] or scan code for a key. How this value is interpreted 1103depends on the value of the uMapType parameter. 1104 1105Starting with Windows Vista, the high byte of the uCode value can contain 1106either 0xe0 or 0xe1 to specify the extended scan code. 1107 1108[in] uMapType 1109 1110Type: UINT 1111 1112The translation to be performed. The value of this parameter depends on the 1113value of the uCode parameter. (See _MAPVK_VK_TO_* constants) 1114 1115----- Return value ----- 1116 1117Type: UINT 1118 1119The return value is either a scan code, a virtual-key code, or a character 1120value, depending on the value of uCode and uMapType. If there is no 1121translation, the return value is zero. 1122 1123----- Remarks ----- 1124 1125An application can use MapVirtualKey to translate scan codes to the 1126virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU, and vice versa. 1127These translations do not distinguish between the left and right instances 1128of the SHIFT, CTRL, or ALT keys. 1129 1130An application can get the scan code corresponding to the left or right 1131instance of one of these keys by calling MapVirtualKey with uCode set to 1132one of the following virtual-key code constants: 1133 1134 VK_LSHIFT 1135 VK_RSHIFT 1136 VK_LCONTROL 1137 VK_RCONTROL 1138 VK_LMENU 1139 VK_RMENU 1140 1141These left- and right-distinguishing constants are available to an application 1142only through the GetKeyboardState[2], SetKeyboardState[3], GetAsyncKeyState[4], 1143GetKeyState, MapVirtualKey, and MapVirtualKeyEx functions. For list complete 1144table of virtual key codes, see Virtual Key Codes[1]. 1145 1146[1] https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes 1147 1148[2] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeyboardstate 1149 1150[3] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setkeyboardstate 1151 1152[4] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate 1153 1154[5] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeystate 1155""" 1156_MapVirtualKeyW.argtypes = UINT, UINT 1157_MapVirtualKeyW.restype = UINT 1158 1159 1160def _map_virtual_key( 1161 uCode: int, uMapType: Literal[0, 1, 2, 3, 4] # See _MAPVK_* constants 1162) -> int: 1163 """ 1164 Abstraction layer over MapVirtualKeyW (winuser.h) 1165 1166 Accepted values for uMapType are: 1167 - _MAPVK_VK_TO_VSC = 0 1168 - _MAPVK_VSC_TO_VK = 1 1169 - _MAPVK_VK_TO_CHAR = 2 1170 - _MAPVK_VSC_TO_VK_EX = 3 1171 - _MAPVK_VK_TO_VSC_EX = 4 1172 1173 See https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mapvirtualkeyw 1174 """ 1175 return _MapVirtualKeyW(UINT(uCode), UINT(uMapType)) 1176 # -------------------------------------------------------------------------- 1177 1178 1179# ----- GetSystemMetrics Declaration ------------------------------------------- 1180class _GetSystemMetricsType(Protocol): 1181 argtypes: tuple[type[INT]] 1182 restype: type[INT] 1183 1184 def __call__( 1185 self, 1186 nIndex: INT | int, 1187 ) -> int: # c_int 1188 ... 1189 1190 1191_GetSystemMetrics: _GetSystemMetricsType = hint_cast( 1192 _GetSystemMetricsType, _user32.GetSystemMetrics 1193) 1194""" 1195----- GetSystemMetrics function (winuser.h) ----- 1196 1197Retrieves the specified system metric or system configuration setting. 1198 1199Note that all dimensions retrieved by GetSystemMetrics are in pixels. 1200 1201https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemmetrics 1202 1203----- Parameters ----- 1204 1205[in] nIndex 1206 1207Type: int 1208 1209The system metric or configuration setting to be retrieved. This parameter can 1210be one of the following values. Note that all SM_CX* values are widths and all 1211SM_CY* values are heights. Also note that all settings designed to return 1212Boolean data represent TRUE as any nonzero value, and FALSE as a zero value. 1213(See _SM_* constants) 1214 1215----- Return value ----- 1216 1217Type: int 1218 1219If the function succeeds, the return value is the requested system metric or 1220configuration setting. 1221 1222If the function fails, the return value is 0. GetLastError does not provide 1223extended error information. 1224 1225----- Remarks ----- 1226 1227System metrics can vary from display to display. 1228 1229GetSystemMetrics(SM_CMONITORS) counts only visible display monitors. This is 1230different from EnumDisplayMonitors[1], which enumerates both visible display 1231monitors and invisible pseudo-monitors that are associated with mirroring 1232drivers. An invisible pseudo-monitor is associated with a pseudo-device used 1233to mirror application drawing for remoting or other purposes. 1234 1235This API is not DPI aware, and should not be used if the calling thread is 1236per-monitor DPI aware. For the DPI-aware version of this API, see 1237GetSystemMetricsForDPI[2]. For more information on DPI awareness, see the 1238Windows High DPI documentation[3]. 1239 1240[1] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumdisplaymonitors 1241 1242[2] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemmetricsfordpi 1243 1244[3] https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows 1245""" # noqa (URL too long) 1246_GetSystemMetrics.argtypes = (INT,) 1247_GetSystemMetrics.restype = INT 1248 1249 1250def _get_system_metrics(nIndex: int) -> int: 1251 """ 1252 Abstraction layer over GetSystemMetrics (winuser.h) 1253 1254 See the _SM_* constants for accepted values for the nIndex argument. 1255 1256 See https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemmetrics 1257 """ 1258 return _GetSystemMetrics(nIndex) 1259 # -------------------------------------------------------------------------- 1260 1261 1262# ----- MonitorFromPoint Declaration ----------------------------------------------- 1263class _MonitorFromPointType(Protocol): 1264 argtypes: tuple[type[_POINT], type[DWORD]] 1265 restype: type[HMONITOR] 1266 1267 def __call__( 1268 self, 1269 pt: _POINT, 1270 dwFlags: DWORD | int, 1271 ) -> int | None: # HMONITOR 1272 ... 1273 1274 1275_MonitorFromPoint: _MonitorFromPointType = hint_cast( 1276 _MonitorFromPointType, _user32.MonitorFromPoint 1277) 1278""" 1279----- MonitorFromPoint function (winuser.h) ----- 1280 1281Retrieves the position of the mouse cursor, in screen coordinates. 1282 1283https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-monitorfrompoint 1284 1285----- Parameters ----- 1286 1287[in] pt 1288 1289Type: POINT 1290 1291A POINT structure that specifies the point of interest in 1292virtual-screen coordinates. 1293 1294[in] dwFlags 1295 1296Type: DWORD 1297 1298Determines the function's return value if the point is not contained within 1299any display monitor. 1300 1301This parameter can be one of the following values. 1302 1303MONITOR_DEFAULTTONULL 0x00000000 Returns NULL. 1304MONITOR_DEFAULTTOPRIMARY 0x00000001 Returns a handle to the primary 1305 display monitor. 1306MONITOR_DEFAULTTONEAREST 0x00000002 Returns a handle to the display monitor 1307 that is nearest to the point. 1308 1309----- Return value ----- 1310 1311If the point is contained by a display monitor, the return value is an 1312HMONITOR handle to that display monitor. 1313 1314If the point is not contained by a display monitor, the return value depends 1315on the value of dwFlags. 1316""" 1317_MonitorFromPoint.argtypes = (_POINT, DWORD) 1318_MonitorFromPoint.restype = HMONITOR 1319 1320 1321def _monitor_from_point(x: int, y: int) -> int | None: 1322 """ 1323 Abstraction layer over MonitorFromPoint (winuser.h) 1324 1325 See https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-monitorfrompoint 1326 """ 1327 pt = _POINT() 1328 pt.x, pt.y = x, y 1329 return _MonitorFromPoint(pt, _MONITOR_DEFAULTTONULL) 1330 # -------------------------------------------------------------------------- 1331 1332 1333# ----- GetCursorPos Declaration ----------------------------------------------- 1334class _GetCursorPosType(Protocol): 1335 argtypes: tuple[type[_POINTER_TYPE[_POINT]]] 1336 restype: type[BOOL] 1337 1338 def __call__( 1339 self, 1340 lpPoint: _POINTER_TYPE[_POINT] | _POINT, 1341 ) -> bool: # BOOL 1342 ... 1343 1344 1345_GetCursorPos: _GetCursorPosType = hint_cast( 1346 _GetCursorPosType, 1347 _user32.GetCursorPos 1348) 1349""" 1350----- GetCursorPos function (winuser.h) ----- 1351 1352Retrieves the position of the mouse cursor, in screen coordinates. 1353 1354https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcursorpos 1355 1356----- Parameters ----- 1357 1358[out] lpPoint 1359 1360Type: LPPOINT 1361 1362A pointer to a POINT structure that receives the screen coordinates of the 1363cursor. 1364 1365----- Return value ----- 1366 1367Type: BOOL 1368 1369Returns nonzero if successful or zero otherwise. To get extended error 1370information, call GetLastError. 1371 1372----- Remarks ----- 1373 1374The cursor position is always specified in screen coordinates and is not 1375affected by the mapping mode of the window that contains the cursor. 1376 1377The calling process must have WINSTA_READATTRIBUTES access to the window 1378station. 1379 1380The input desktop must be the current desktop when you call GetCursorPos. Call 1381OpenInputDesktop[1] to determine whether the current desktop is the input 1382desktop. If it is not, call SetThreadDesktop[2] with the HDESK returned by 1383OpenInputDesktop to switch to that desktop. 1384 1385[1] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-openinputdesktop 1386 1387[2] https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setthreaddesktop 1388""" 1389_GetCursorPos.argtypes = (POINTER(_POINT),) 1390_GetCursorPos.restype = BOOL 1391 1392 1393def _get_cursor_pos() -> _POINT: 1394 """ 1395 Abstraction layer over GetCursorPos (winuser.h) 1396 1397 See https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcursorpos 1398 """ 1399 cursor = _POINT() 1400 # cursor will be automatically be referenced by pointer 1401 _GetCursorPos(cursor) 1402 return cursor 1403 # -------------------------------------------------------------------------- 1404 1405 1406# ----- SystemParametersInfoW Declaration -------------------------------------- 1407class _SystemParametersInfoW_Type(Protocol): 1408 argtypes: tuple[type[UINT], type[UINT], type[LPCVOID], type[UINT]] 1409 restype: type[BOOL] 1410 1411 def __call__( 1412 self, 1413 uiAction: UINT | int, 1414 uiParam: UINT | int, 1415 pvParam: LPCVOID | Any, 1416 fWinIni: UINT | int, 1417 ) -> bool: # BOOL 1418 ... 1419 1420 1421_SystemParametersInfoW: _SystemParametersInfoW_Type = hint_cast( 1422 _SystemParametersInfoW_Type, _user32.SystemParametersInfoW 1423) 1424""" 1425----- SystemParametersInfoW function (winuser.h) ----- 1426 1427Retrieves or sets the value of one of the system-wide parameters. This 1428function can also update the user profile while setting a parameter. 1429 1430https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfow 1431 1432""" 1433_SystemParametersInfoW.argtypes = UINT, UINT, LPCVOID, UINT 1434_SystemParametersInfoW.restype = BOOL 1435 1436 1437# ----- Get system settings for mouse movement --------------------------------- 1438def _get_mouse_parameters() -> tuple[int, int, int]: 1439 """ 1440 Query system parameters for user's mouse settings. 1441 1442 Abstraction layer over SystemParametersInfoW (winuser.h) 1443 1444 https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfow 1445 1446 Information on _SPI_GETMOUSE 1447 1448 Retrieves the two mouse threshold values and the mouse acceleration. The 1449 pvParam parameter must point to an array of three integers that receives 1450 these values. See mouse_event[1] for further information. 1451 1452 https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mouse_event 1453 """ 1454 pvParam: Array[UINT] = (UINT * 3)() 1455 _SystemParametersInfoW(_SPI_GETMOUSE, 0, pointer(pvParam), 0) 1456 return (pvParam[0], pvParam[1], pvParam[2]) 1457 # -------------------------------------------------------------------------- 1458 1459 1460# ----- Set system settings for mouse movement --------------------------------- 1461def _set_mouse_parameters( 1462 threshold1: int, threshold2: int, enhanced_pointer_precision: int 1463) -> bool: 1464 """ 1465 Set system parameters for user's mouse settings. 1466 1467 Abstraction layer over SystemParametersInfoW (winuser.h) 1468 1469 https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfow 1470 1471 Information on _SPI_SETMOUSE 1472 1473 Sets the two mouse threshold values and the mouse acceleration. 1474 The pvParam parameter must point to an array of three integers that 1475 specifies these values. 1476 See mouse_event[1] for further information. 1477 1478 https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mouse_event 1479 """ 1480 pvParam: Final[Array[UINT]] = (UINT * 3)( 1481 threshold1, threshold2, enhanced_pointer_precision 1482 ) 1483 # leave last parameter as 0 to make changes non-permanent and restore 1484 # themselves upon reboot if something goes wrong and the wrong setting 1485 # was overwritten. 1486 return _SystemParametersInfoW(_SPI_SETMOUSE, 0, pointer(pvParam), 0) 1487 # -------------------------------------------------------------------------- 1488 1489 1490# ----- Get system settings for mouse speed ------------------------------------ 1491def _get_mouse_speed() -> int: 1492 """ 1493 Query system parameters for user's mouse settings. 1494 1495 Abstraction layer over SystemParametersInfoW (winuser.h) 1496 1497 https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfow 1498 1499 Information on SPI_GETMOUSESPEED 1500 1501 Retrieves the current mouse speed. The mouse speed determines how far the 1502 pointer will move based on the distance the mouse moves. The pvParam 1503 parameter must point to an integer that receives a value which ranges 1504 between 1 (slowest) and 20 (fastest). A value of 10 is the default. The 1505 value can be set by an end-user using the mouse control panel application 1506 or by an application using SPI_SETMOUSESPEED. 1507 """ 1508 pvParam: Array[UINT] = (UINT * 1)() 1509 _SystemParametersInfoW(_SPI_GETMOUSESPEED, 0, pointer(pvParam), 0) 1510 return pvParam[0] 1511 # -------------------------------------------------------------------------- 1512 1513 1514# ----- Set system settings for mouse movement --------------------------------- 1515def _set_mouse_speed(mouse_speed: int) -> bool: 1516 """ 1517 Set system parameters for user's mouse settings. 1518 1519 Abstraction layer over SystemParametersInfoW (winuser.h) 1520 1521 https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfow 1522 1523 Information on SPI_SETMOUSESPEED 1524 1525 Sets the current mouse speed. The pvParam parameter is an integer between 1526 1 (slowest) and 20 (fastest). A value of 10 is the default. This value is 1527 typically set using the mouse control panel application. 1528 """ 1529 pvParam: Final[Array[UINT]] = (UINT * 1)(mouse_speed) 1530 # leave last parameter as 0 to make changes non-permanent and restore 1531 # themselves upon reboot if something goes wrong and the wrong setting 1532 # was overwritten. 1533 return _SystemParametersInfoW(_SPI_SETMOUSESPEED, 0, pointer(pvParam), 0) 1534 # -------------------------------------------------------------------------- 1535 1536 1537# ============================================================================== 1538# ===== Keyboard Scan Code Mappings ============================================ 1539# ============================================================================== 1540 1541 1542# ----- Special class for key extended scancode sequences ---------------------- 1543class ScancodeSequence(List[int]): 1544 """ 1545 A special class with the sole purpose of representing extended scancode 1546 sequences that should be grouped together in a single INPUT array. 1547 1548 Inserting non-scancode elements is illegal, but no runtime checks exist 1549 to verify correct input! Violations could lead to unpredictable runtime 1550 behaviour. You've been warned. 1551 """ 1552 1553 pass 1554 # -------------------------------------------------------------------------- 1555 1556 1557# ----- TypeAlias for KEYBOARD_MAPPING values ---------------------------------- 1558ScancodeTypes: TypeAlias = "int | ScancodeSequence" # TODO 3.10: remove quotes 1559""" 1560Acceptable value types in KEYBOARD_MAPPING. 1561 1562Accepts single standalone scancode integer or multiple scancode integers 1563contained in a special class ScancodeSequence instance. 1564""" 1565# ------------------------------------------------------------------------------ 1566 1567 1568# ----- Offsets for values in KEYBOARD_MAPPING --------------------------------- 1569_OFFSET_EXTENDEDKEY: Final = 0xE000 1570_OFFSET_SHIFTKEY: Final = 0x10000 1571# ------------------------------------------------------------------------------ 1572 1573 1574# ----- KEYBOARD_MAPPING ------------------------------------------------------- 1575_SHIFT_SCANCODE: Final = 0x2A # Used in auto-shifting 1576# should be keyboard MAKE scancodes ( <0x80 ) 1577# some keys require the use of EXTENDEDKEY flags, they 1578US_QWERTY_MAPPING: Final[dict[str, ScancodeTypes]] = { 1579 "escape": 0x01, 1580 "esc": 0x01, 1581 "f1": 0x3B, 1582 "f2": 0x3C, 1583 "f3": 0x3D, 1584 "f4": 0x3E, 1585 "f5": 0x3F, 1586 "f6": 0x40, 1587 "f7": 0x41, 1588 "f8": 0x42, 1589 "f9": 0x43, 1590 "f10": 0x44, 1591 "f11": 0x57, 1592 "f12": 0x58, 1593 "printscreen": 0x54, # same result as ScancodeSequence([0xE02A, 0xE037]) 1594 "prntscrn": 0x54, # same result as ScancodeSequence([0xE02A, 0xE037]) 1595 "prtsc": 0x54, # same result as ScancodeSequence([0xE02A, 0xE037]) 1596 "prtscr": 0x54, # same result as ScancodeSequence([0xE02A, 0xE037]) 1597 "scrolllock": 0x46, 1598 "ctrlbreak": 0x46 + _OFFSET_EXTENDEDKEY, 1599 "pause": ScancodeSequence([0xE11D, 0x45, 0xE19D, 0xC5]), 1600 "`": 0x29, 1601 "1": 0x02, 1602 "2": 0x03, 1603 "3": 0x04, 1604 "4": 0x05, 1605 "5": 0x06, 1606 "6": 0x07, 1607 "7": 0x08, 1608 "8": 0x09, 1609 "9": 0x0A, 1610 "0": 0x0B, 1611 "-": 0x0C, 1612 "=": 0x0D, 1613 "~": 0x29 + _OFFSET_SHIFTKEY, 1614 "!": 0x02 + _OFFSET_SHIFTKEY, 1615 "@": 0x03 + _OFFSET_SHIFTKEY, 1616 "#": 0x04 + _OFFSET_SHIFTKEY, 1617 "$": 0x05 + _OFFSET_SHIFTKEY, 1618 "%": 0x06 + _OFFSET_SHIFTKEY, 1619 "^": 0x07 + _OFFSET_SHIFTKEY, 1620 "&": 0x08 + _OFFSET_SHIFTKEY, 1621 "*": 0x09 + _OFFSET_SHIFTKEY, 1622 "(": 0x0A + _OFFSET_SHIFTKEY, 1623 ")": 0x0B + _OFFSET_SHIFTKEY, 1624 "_": 0x0C + _OFFSET_SHIFTKEY, 1625 "+": 0x0D + _OFFSET_SHIFTKEY, 1626 "backspace": 0x0E, 1627 "\b": 0x0E, 1628 "insert": 0x52 + _OFFSET_EXTENDEDKEY, 1629 "home": 0x47 + _OFFSET_EXTENDEDKEY, 1630 "pageup": 0x49 + _OFFSET_EXTENDEDKEY, 1631 "pgup": 0x49 + _OFFSET_EXTENDEDKEY, 1632 "pagedown": 0x51 + _OFFSET_EXTENDEDKEY, 1633 "pgdn": 0x51 + _OFFSET_EXTENDEDKEY, 1634 # numpad 1635 "numlock": 0x45, 1636 "divide": 0x35 + _OFFSET_EXTENDEDKEY, 1637 "multiply": 0x37, 1638 "subtract": 0x4A, 1639 "add": 0x4E, 1640 "decimal": 0x53, 1641 "numperiod": 0x53, 1642 "numpadenter": 0x1C + _OFFSET_EXTENDEDKEY, 1643 "numpad1": 0x4F, 1644 "numpad2": 0x50, 1645 "numpad3": 0x51, 1646 "numpad4": 0x4B, 1647 "numpad5": 0x4C, 1648 "numpad6": 0x4D, 1649 "numpad7": 0x47, 1650 "numpad8": 0x48, 1651 "numpad9": 0x49, 1652 "num0": 0x52, 1653 "num1": 0x4F, 1654 "num2": 0x50, 1655 "num3": 0x51, 1656 "num4": 0x4B, 1657 "num5": 0x4C, 1658 "num6": 0x4D, 1659 "num7": 0x47, 1660 "num8": 0x48, 1661 "num9": 0x49, 1662 "num0": 0x52, 1663 "clear": 0x4C, # name from pyautogui 1664 # end numpad 1665 "tab": 0x0F, 1666 "\t": 0x0F, 1667 "q": 0x10, 1668 "w": 0x11, 1669 "e": 0x12, 1670 "r": 0x13, 1671 "t": 0x14, 1672 "y": 0x15, 1673 "u": 0x16, 1674 "i": 0x17, 1675 "o": 0x18, 1676 "p": 0x19, 1677 "[": 0x1A, 1678 "]": 0x1B, 1679 "\\": 0x2B, 1680 "Q": 0x10 + _OFFSET_SHIFTKEY, 1681 "W": 0x11 + _OFFSET_SHIFTKEY, 1682 "E": 0x12 + _OFFSET_SHIFTKEY, 1683 "R": 0x13 + _OFFSET_SHIFTKEY, 1684 "T": 0x14 + _OFFSET_SHIFTKEY, 1685 "Y": 0x15 + _OFFSET_SHIFTKEY, 1686 "U": 0x16 + _OFFSET_SHIFTKEY, 1687 "I": 0x17 + _OFFSET_SHIFTKEY, 1688 "O": 0x18 + _OFFSET_SHIFTKEY, 1689 "P": 0x19 + _OFFSET_SHIFTKEY, 1690 "{": 0x1A + _OFFSET_SHIFTKEY, 1691 "}": 0x1B + _OFFSET_SHIFTKEY, 1692 "|": 0x2B + _OFFSET_SHIFTKEY, 1693 "del": 0x53 + _OFFSET_EXTENDEDKEY, 1694 "delete": 0x53 + _OFFSET_EXTENDEDKEY, 1695 "end": 0x4F + _OFFSET_EXTENDEDKEY, 1696 "capslock": 0x3A, 1697 "a": 0x1E, 1698 "s": 0x1F, 1699 "d": 0x20, 1700 "f": 0x21, 1701 "g": 0x22, 1702 "h": 0x23, 1703 "j": 0x24, 1704 "k": 0x25, 1705 "l": 0x26, 1706 ";": 0x27, 1707 "'": 0x28, 1708 "A": 0x1E + _OFFSET_SHIFTKEY, 1709 "S": 0x1F + _OFFSET_SHIFTKEY, 1710 "D": 0x20 + _OFFSET_SHIFTKEY, 1711 "F": 0x21 + _OFFSET_SHIFTKEY, 1712 "G": 0x22 + _OFFSET_SHIFTKEY, 1713 "H": 0x23 + _OFFSET_SHIFTKEY, 1714 "J": 0x24 + _OFFSET_SHIFTKEY, 1715 "K": 0x25 + _OFFSET_SHIFTKEY, 1716 "L": 0x26 + _OFFSET_SHIFTKEY, 1717 ":": 0x27 + _OFFSET_SHIFTKEY, 1718 '"': 0x28 + _OFFSET_SHIFTKEY, 1719 "enter": 0x1C, 1720 "return": 0x1C, 1721 "\n": 0x1C, 1722 "shift": _SHIFT_SCANCODE, 1723 "shiftleft": _SHIFT_SCANCODE, 1724 "z": 0x2C, 1725 "x": 0x2D, 1726 "c": 0x2E, 1727 "v": 0x2F, 1728 "b": 0x30, 1729 "n": 0x31, 1730 "m": 0x32, 1731 ",": 0x33, 1732 ".": 0x34, 1733 "/": 0x35, 1734 "Z": 0x2C + _OFFSET_SHIFTKEY, 1735 "X": 0x2D + _OFFSET_SHIFTKEY, 1736 "C": 0x2E + _OFFSET_SHIFTKEY, 1737 "V": 0x2F + _OFFSET_SHIFTKEY, 1738 "B": 0x30 + _OFFSET_SHIFTKEY, 1739 "N": 0x31 + _OFFSET_SHIFTKEY, 1740 "M": 0x32 + _OFFSET_SHIFTKEY, 1741 "<": 0x33 + _OFFSET_SHIFTKEY, 1742 ">": 0x34 + _OFFSET_SHIFTKEY, 1743 "?": 0x35 + _OFFSET_SHIFTKEY, 1744 "shiftright": 0x36, 1745 "ctrl": 0x1D, 1746 "ctrlleft": 0x1D, 1747 "win": 0x5B + _OFFSET_EXTENDEDKEY, 1748 "super": 0x5B + _OFFSET_EXTENDEDKEY, # name from pyautogui 1749 "winleft": 0x5B + _OFFSET_EXTENDEDKEY, 1750 "alt": 0x38, 1751 "altleft": 0x38, 1752 " ": 0x39, 1753 "space": 0x39, 1754 "altright": 0x38 + _OFFSET_EXTENDEDKEY, 1755 "winright": 0x5C + _OFFSET_EXTENDEDKEY, 1756 "apps": 0x5D + _OFFSET_EXTENDEDKEY, 1757 "context": 0x5D + _OFFSET_EXTENDEDKEY, 1758 "contextmenu": 0x5D + _OFFSET_EXTENDEDKEY, 1759 "ctrlright": 0x1D + _OFFSET_EXTENDEDKEY, 1760 # Originally from learncodebygaming/pydirectinput: 1761 # arrow key scancodes can be different depending on the hardware, 1762 # so I think the best solution is to look it up based on the virtual key 1763 # https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mapvirtualkeya 1764 "up": _map_virtual_key(0x26, _MAPVK_VK_TO_VSC) + _OFFSET_EXTENDEDKEY, 1765 "left": _map_virtual_key(0x25, _MAPVK_VK_TO_VSC) + _OFFSET_EXTENDEDKEY, 1766 "down": _map_virtual_key(0x28, _MAPVK_VK_TO_VSC) + _OFFSET_EXTENDEDKEY, 1767 "right": _map_virtual_key(0x27, _MAPVK_VK_TO_VSC) + _OFFSET_EXTENDEDKEY, 1768 # While forking the original repository and working on the code, 1769 # I'm starting to doubt this still holds true. 1770 # As far as I can see, arrow keys are just the Numpad scancodes for Num 1771 # 2, 4, 6, and 8 with EXTENDEDKEY flag. 1772 # In fact, looking up the virtual key codes will just return the very same 1773 # scancodes the Numpad keys occupy. 1774 "help": 0x63, 1775 "sleep": 0x5F + _OFFSET_EXTENDEDKEY, 1776 "medianext": 0x19 + _OFFSET_EXTENDEDKEY, 1777 "nexttrack": 0x19 + _OFFSET_EXTENDEDKEY, 1778 "mediaprevious": 0x10 + _OFFSET_EXTENDEDKEY, 1779 "prevtrack": 0x10 + _OFFSET_EXTENDEDKEY, 1780 "mediastop": 0x24 + _OFFSET_EXTENDEDKEY, 1781 "stop": 0x24 + _OFFSET_EXTENDEDKEY, 1782 "mediaplay": 0x22 + _OFFSET_EXTENDEDKEY, 1783 "mediapause": 0x22 + _OFFSET_EXTENDEDKEY, 1784 "playpause": 0x22 + _OFFSET_EXTENDEDKEY, 1785 "mute": 0x20 + _OFFSET_EXTENDEDKEY, 1786 "volumemute": 0x20 + _OFFSET_EXTENDEDKEY, 1787 "volumeup": 0x30 + _OFFSET_EXTENDEDKEY, 1788 "volup": 0x30 + _OFFSET_EXTENDEDKEY, 1789 "volumedown": 0x2E + _OFFSET_EXTENDEDKEY, 1790 "voldown": 0x2E + _OFFSET_EXTENDEDKEY, 1791 "media": 0x6D + _OFFSET_EXTENDEDKEY, 1792 "launchmediaselect": 0x6D + _OFFSET_EXTENDEDKEY, 1793 "email": 0x6C + _OFFSET_EXTENDEDKEY, 1794 "launchmail": 0x6C + _OFFSET_EXTENDEDKEY, 1795 "calculator": 0x21 + _OFFSET_EXTENDEDKEY, 1796 "calc": 0x21 + _OFFSET_EXTENDEDKEY, 1797 "launch1": 0x6B + _OFFSET_EXTENDEDKEY, 1798 "launchapp1": 0x6B + _OFFSET_EXTENDEDKEY, 1799 "launch2": 0x21 + _OFFSET_EXTENDEDKEY, 1800 "launchapp2": 0x21 + _OFFSET_EXTENDEDKEY, 1801 "browsersearch": 0x65 + _OFFSET_EXTENDEDKEY, 1802 "browserhome": 0x32 + _OFFSET_EXTENDEDKEY, 1803 "browserforward": 0x69 + _OFFSET_EXTENDEDKEY, 1804 "browserback": 0x6A + _OFFSET_EXTENDEDKEY, 1805 "browserstop": 0x68 + _OFFSET_EXTENDEDKEY, 1806 "browserrefresh": 0x67 + _OFFSET_EXTENDEDKEY, 1807 "browserfavorites": 0x66 + _OFFSET_EXTENDEDKEY, 1808 "f13": 0x64, 1809 "f14": 0x65, 1810 "f15": 0x66, 1811 "f16": 0x67, 1812 "f17": 0x68, 1813 "f18": 0x69, 1814 "f19": 0x6A, 1815 "f20": 0x6B, 1816 "f21": 0x6C, 1817 "f22": 0x6D, 1818 "f23": 0x6E, 1819 "f24": 0x76, 1820} 1821""" 1822Maps a string representation of keyboard keys to their corresponding hardware 1823scan code. Based on standard US QWERTY-Layout. 1824 1825Not intended to be changed at runtime! 1826 1827If you want to change the keyboard mapping to better reflect your own keyboard 1828layout, use `KEYBOARD_MAPPING.update(your_dict)` where `your_dict` is a dict 1829that maps keynames to scancodes. 1830""" 1831 1832KEYBOARD_MAPPING: dict[str, ScancodeTypes] = {} 1833""" 1834Maps a string representation of keyboard keys to their corresponding hardware 1835scan code. Based on standard US QWERTY-Layout by default. 1836 1837If you want to change the keyboard mapping to better reflect your own keyboard 1838layout, use `KEYBOARD_MAPPING.update(your_dict)`, where `your_dict` is a dict 1839that maps keynames to scancodes. 1840""" 1841KEYBOARD_MAPPING.update(US_QWERTY_MAPPING) # use US QWERTY by default 1842# ------------------------------------------------------------------------------ 1843 1844 1845# ============================================================================== 1846# ===== Fail Safe and Pause implementation ===================================== 1847# ============================================================================== 1848 1849 1850# ----- Exceptions ------------------------------------------------------------- 1851class FailSafeException(Exception): 1852 """Raised when _failSafeCheck detects failsafe mouse position.""" 1853 1854 pass 1855 1856 1857class PriorInputFailedException(Exception): 1858 """Raised in hold() context managers when raise_on_failure is set.""" 1859 1860 pass 1861 # -------------------------------------------------------------------------- 1862 1863 1864# ----- Failsafe Check --------------------------------------------------------- 1865def _failSafeCheck() -> None: 1866 """ 1867 Check if mouse has been moved into one of the defined failsafe points, 1868 indicated by global var `FAILSAFE_POINTS`, and raise `FailSafeException` 1869 if that's the case. 1870 1871 Set global var `FAILSAFE` to False to stop raising exceptions. 1872 """ 1873 if FAILSAFE and tuple(position()) in FAILSAFE_POINTS: 1874 raise FailSafeException( 1875 "PyDirectInput fail-safe triggered from mouse moving to a corner " 1876 "of the screen. " 1877 "To disable this fail-safe, set pydirectinput.FAILSAFE to False. " 1878 "DISABLING FAIL-SAFE IS NOT RECOMMENDED." 1879 ) 1880 # -------------------------------------------------------------------------- 1881 1882 1883# ----- handle pause for generic input checks ---------------------------------- 1884def _handlePause(_pause: Any) -> None: 1885 """ 1886 Pause the default amount of time if `_pause=True` in function arguments. 1887 """ 1888 if _pause and PAUSE: 1889 _sleep(PAUSE) 1890 # -------------------------------------------------------------------------- 1891 1892 1893# ----- generic input check decorator ------------------------------------------ 1894_PS = ParamSpec("_PS") # param spec 1895_RT = TypeVar("_RT") # return type 1896 1897 1898# direct copy of _genericPyAutoGUIChecks() 1899def _genericPyDirectInputChecks( 1900 wrappedFunction: Callable[_PS, _RT] 1901) -> Callable[_PS, _RT]: 1902 """ 1903 Decorator for wrapping input functions. 1904 1905 Performs failsafe checking and inserts artifical delay after input 1906 functions have been executed unless disabled. 1907 1908 The delay amount is set by global var `PAUSE`. 1909 """ 1910 1911 @functools.wraps(wrappedFunction) 1912 def wrapper(*args: _PS.args, **kwargs: _PS.kwargs) -> _RT: 1913 returnVal: _RT 1914 if PAUSE: # Skip _pause checks if PAUSE has been globally disabled. 1915 _pause: Any 1916 if "_pause" in kwargs: # Fast track, low cost lookup. 1917 _pause = kwargs["_pause"] 1918 else: # Slow track, inspect.getcallargs() is expensive. 1919 funcArgs: dict[str, Any] = inspect.getcallargs( 1920 wrappedFunction, *args, **kwargs 1921 ) 1922 _pause = funcArgs.get("_pause") 1923 _failSafeCheck() 1924 returnVal = wrappedFunction(*args, **kwargs) 1925 _handlePause(_pause) 1926 else: 1927 _failSafeCheck() 1928 returnVal = wrappedFunction(*args, **kwargs) 1929 return returnVal 1930 1931 return wrapper 1932 # -------------------------------------------------------------------------- 1933 1934 1935# ============================================================================== 1936# ===== Helper Functions ======================================================= 1937# ============================================================================== 1938# -------------------------------------------------------------------------- 1939def _calc_normalized_screen_coord(pixel_coord: int, display_total: int) -> int: 1940 """ 1941 Convert a pixel coordinate to normalized Windows screen coordinate value 1942 (range 0 - 65535) by taking the average of two neighboring pixels. 1943 """ 1944 # formula from this strange (probably machine translated) article 1945 # 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/ 1946 # win_coord = (x * 65536 + width - 1) // width 1947 # This alone is not enough, but we can do better by taking the average of 1948 # this pixel plus the next pixel. 1949 # In my testing this perfectly reflected the real pixel that SendInput 1950 # moves to, down to the pixels that Windows itself can't resolve. 1951 this_pixel: Final[int] = ( 1952 pixel_coord * 65536 + display_total - 1 1953 ) // display_total 1954 next_pixel: Final[int] = ( 1955 (pixel_coord + 1) * 65536 + display_total - 1 1956 ) // display_total 1957 return (this_pixel + next_pixel) // 2 1958 # -------------------------------------------------------------------------- 1959 1960 1961# ----- translate pixels to normalized Windows coordinates --------------------- 1962def _to_windows_coordinates( 1963 x: int = 0, y: int = 0, *, virtual: bool = False 1964) -> tuple[int, int]: 1965 """ 1966 Convert x,y coordinates to normalized windows coordinates and return as 1967 tuple (x, y). 1968 """ 1969 display_width: int 1970 display_height: int 1971 offset_left: int 1972 offset_top: int 1973 1974 if virtual: 1975 display_width, display_height, offset_left, offset_top = virtual_size() 1976 else: 1977 display_width, display_height = size() 1978 offset_left, offset_top = 0, 0 1979 1980 windows_x: int = _calc_normalized_screen_coord( 1981 x - offset_left, display_width 1982 ) 1983 windows_y: int = _calc_normalized_screen_coord( 1984 y - offset_top, display_height 1985 ) 1986 1987 return windows_x, windows_y 1988 # -------------------------------------------------------------------------- 1989 1990 1991# ----- line coordinates based on Bresenham's line algorithm ------------------- 1992def _bresenham(x0: int, y0: int, x1: int, y1: int) -> list[tuple[int, int]]: 1993 """ 1994 Return a list of coordinates on the line from (x0, y0) to (x1, y1). 1995 Start and end point are included in the result. 1996 1997 Based on Bresenham's line algorithm. 1998 Using Petr Viktorin's implementation (MIT license) 1999 https://github.com/encukou/bresenham 2000 """ 2001 2002 def gen() -> Generator[tuple[int, int], None, None]: 2003 """ 2004 Yield integer coordinates on the line from (x0, y0) to (x1, y1). 2005 2006 Input coordinates should be integers. 2007 2008 The result will contain both the start and the end point. 2009 """ 2010 dx: int = x1 - x0 2011 dy: int = y1 - y0 2012 2013 xsign: Literal[1, -1] = 1 if dx > 0 else -1 2014 ysign: Literal[1, -1] = 1 if dy > 0 else -1 2015 2016 dx = abs(dx) 2017 dy = abs(dy) 2018 2019 xx: Literal[1, 0, -1] 2020 xy: Literal[1, 0, -1] 2021 yx: Literal[1, 0, -1] 2022 yy: Literal[1, 0, -1] 2023 2024 if dx > dy: 2025 xx, xy, yx, yy = xsign, 0, 0, ysign 2026 else: 2027 dx, dy = dy, dx 2028 xx, xy, yx, yy = 0, ysign, xsign, 0 2029 2030 d: int = 2 * dy - dx 2031 y = 0 2032 for x in range(dx + 1): 2033 yield x0 + x * xx + y * yx, y0 + x * xy + y * yy 2034 if d >= 0: 2035 y += 1 2036 d -= 2 * dx 2037 d += 2 * dy 2038 2039 return list(gen()) 2040 # -------------------------------------------------------------------------- 2041 2042 2043# ----- path function type alias ----------------------------------------------- 2044PathFunction: TypeAlias = ( 2045 "Callable[[int, int, int, int], list[tuple[int, int]]]" 2046) 2047# ------------------------------------------------------------------------------ 2048 2049 2050# ----- linear tweening function ----------------------------------------------- 2051def _linear(n: float) -> float: 2052 """ 2053 Linear tweening function that clamps n between 0.0 and 1.0. 2054 Otherwise returns n unchanged. 2055 """ 2056 if n >= 1.0: 2057 return 1.0 2058 if n <= 0.0: 2059 return 0.0 2060 return n 2061 # -------------------------------------------------------------------------- 2062 2063 2064# ----- get mouse position ----------------------------------------------------- 2065def position( 2066 x: int | float | None = None, y: int | float | None = None 2067) -> tuple[int, int]: 2068 """ 2069 Return a postion tuple `(x, y)`. 2070 2071 If x and/or y argument(s) are not given, use current mouse cursor coordinate 2072 instead. 2073 """ 2074 cursor: _POINT = _get_cursor_pos() 2075 return ( 2076 cursor.x if x is None else int(x), 2077 cursor.y if y is None else int(y), 2078 ) 2079 # -------------------------------------------------------------------------- 2080 2081 2082# ----- get primary screen resolution ------------------------------------------ 2083def size() -> tuple[int, int]: 2084 """ 2085 Return the size of the primary display as tuple `(width, height)`. 2086 """ 2087 return ( 2088 _get_system_metrics(_SM_CXSCREEN), 2089 _get_system_metrics(_SM_CYSCREEN), 2090 ) 2091 # -------------------------------------------------------------------------- 2092 2093 2094# ----- get resolution of multi monitor bounding box --------------------------- 2095def virtual_size() -> tuple[int, int, int, int]: 2096 """ 2097 Return the the display size of the complete virtual monitor bounding box 2098 rectangle as tuple `(width, height, left_offset, top_offset)`. 2099 2100 On a single monitor system, this function is equal to `(*size(), 0, 0)`. 2101 2102 `left_offset` and `top_offset` are measured from the top left pixel of the 2103 primary monitor. 2104 """ 2105 return ( 2106 _get_system_metrics(_SM_CXVIRTUALSCREEN), 2107 _get_system_metrics(_SM_CYVIRTUALSCREEN), 2108 _get_system_metrics(_SM_XVIRTUALSCREEN), 2109 _get_system_metrics(_SM_YVIRTUALSCREEN), 2110 ) 2111 # -------------------------------------------------------------------------- 2112 2113 2114# ----- are coordinates on primary monitor ------------------------------------- 2115@overload 2116def on_primary_monitor(x: int | None = None, y: int | None = None) -> bool: 2117 ... 2118 2119 2120@overload 2121def on_primary_monitor(x: tuple[int, int], y: None = None) -> bool: 2122 ... 2123 2124 2125def on_primary_monitor( 2126 x: int | tuple[int, int] | None = None, y: int | None = None 2127) -> bool: 2128 """ 2129 Returns whether the given xy coordinates are on the primary screen or not. 2130 2131 If x and/or y argument(s) are not given, current mouse cursor coordinates 2132 will be used instead. 2133 """ 2134 if isinstance(x, Sequence): 2135 assert not isinstance(x, int) # remove int annotation, mypy needs this 2136 if y is not None: 2137 raise ValueError( 2138 "onScreen() does not accept Sequence-types as first argument " 2139 "if a second argument is also provided!" 2140 ) 2141 try: 2142 x, y = x[0], x[1] 2143 except IndexError as e: 2144 raise ValueError( 2145 "onScreen() does not accept single element sequences " 2146 "as first argument!" 2147 ) from e 2148 2149 x, y = position(x, y) 2150 display_width: int 2151 display_height: int 2152 display_width, display_height = size() 2153 2154 return 0 <= x < display_width and 0 <= y < display_height 2155 2156 2157onScreen = on_primary_monitor 2158# ------------------------------------------------------------------------------ 2159 2160 2161# ----- are coordinates on any monitor ----------------------------------------- 2162@overload 2163def valid_screen_coordinates( 2164 x: int | None = None, 2165 y: int | None = None, 2166) -> bool: 2167 ... 2168 2169 2170@overload 2171def valid_screen_coordinates(x: tuple[int, int], y: None = None) -> bool: 2172 ... 2173 2174 2175def valid_screen_coordinates( 2176 x: int | tuple[int, int] | None = None, y: int | None = None 2177) -> bool: 2178 """ 2179 Returns whether the given xy coordinates are on a real monitor or not. 2180 2181 If x and/or y argument(s) are not given, current mouse cursor coordinates 2182 will be used instead. 2183 """ 2184 if isinstance(x, Sequence): 2185 assert not isinstance(x, int) # remove int annotation, mypy needs this 2186 if y is not None: 2187 raise ValueError( 2188 "onScreen() does not accept Sequence-types as first argument " 2189 "if a second argument is also provided!" 2190 ) 2191 try: 2192 x, y = x[0], x[1] 2193 except IndexError as e: 2194 raise ValueError( 2195 "onScreen() does not accept single element sequences " 2196 "as first argument!" 2197 ) from e 2198 2199 x, y = position(x, y) 2200 return _monitor_from_point(x, y) is not None 2201 # -------------------------------------------------------------------------- 2202 2203 2204# ----- lookup function for MOUSEINPUT data ------------------------------------ 2205def _get_mouse_struct_data( 2206 button: str, method: Literal[0, 1, 2] 2207) -> tuple[int | None, int]: 2208 """ 2209 Translate a button string to INPUT struct data. 2210 2211 Automatically detect the correct button if `MOUSE_PRIMARY` or 2212 `MOUSE_SECONDARY` are given as the button argument. 2213 """ 2214 if not (0 <= method <= 2): 2215 raise ValueError(f"method index {method} is not a valid argument!") 2216 2217 buttons_swapped: bool 2218 if button == MOUSE_PRIMARY: 2219 buttons_swapped = _get_system_metrics(_SM_SWAPBUTTON) != 0 2220 button = MOUSE_RIGHT if buttons_swapped else MOUSE_LEFT 2221 elif button == MOUSE_SECONDARY: 2222 buttons_swapped = _get_system_metrics(_SM_SWAPBUTTON) != 0 2223 button = MOUSE_LEFT if buttons_swapped else MOUSE_RIGHT 2224 2225 event_value: int | None 2226 event_value = _MOUSE_MAPPING_EVENTF.get(button, (None, None, None))[method] 2227 mouseData: int = _MOUSE_MAPPING_DATA.get(button, 0) 2228 2229 return event_value, mouseData 2230 # -------------------------------------------------------------------------- 2231 2232 2233# ----- normalize key name to lower case if not shifiting ---------------------- 2234def _normalize_key(key: str, *, auto_shift: bool = False) -> str: 2235 """ 2236 return a lowercase representation of `key` if key is longer than one 2237 character or automatic shifting is disabled (default). 2238 """ 2239 return key.lower() if (len(key) > 1 or not auto_shift) else key 2240 # -------------------------------------------------------------------------- 2241 2242 2243# ------------------------------------------------------------------------------ 2244# ----- Mouse acceleration and Ehanced Pointer Precision storage singleton ----- 2245class __MouseSpeedSettings: 2246 """ 2247 Allows controlled storage of Windows Enhanced Pointer Precision and mouse 2248 speed settings. 2249 """ 2250 2251 __context_manager_epp: ClassVar[int | None] = None 2252 __context_manager_speed: ClassVar[int | None] = None 2253 __context_manager_count: ClassVar[int] = 0 2254 __context_manager_lock: ClassVar[Lock] = Lock() 2255 __manual_store_epp: ClassVar[int | None] = None 2256 __manual_store_speed: ClassVar[int | None] = None 2257 __manual_lock: ClassVar[Lock] = Lock() 2258 # -------------------------------------------------------------------------- 2259 2260 @classmethod 2261 def get_manual_mouse_settings(cls) -> tuple[int | None, int | None]: 2262 with cls.__manual_lock: 2263 return (cls.__manual_store_epp, cls.__manual_store_speed) 2264 # ---------------------------------------------------------------------- 2265 2266 @classmethod 2267 def set_manual_mouse_settings( 2268 cls, enhanced_pointer_precision_enabled: int, mouse_speed: int 2269 ) -> None: 2270 with cls.__manual_lock: 2271 cls.__manual_store_epp = enhanced_pointer_precision_enabled 2272 cls.__manual_store_speed = mouse_speed 2273 # ---------------------------------------------------------------------- 2274 2275 @classmethod 2276 def get_ctxtmgr_mouse_settings(cls) -> tuple[int | None, int | None]: 2277 with cls.__context_manager_lock: 2278 cls.__context_manager_count -= 1 2279 if cls.__context_manager_count > 0: 2280 # Don't retrieve stored value until last 2281 return (None, None) 2282 epp_enabled: int | None = cls.__context_manager_epp 2283 mouse_speed: int | None = cls.__context_manager_speed 2284 cls.__context_manager_epp = None 2285 cls.__context_manager_speed = None 2286 return (epp_enabled, mouse_speed) 2287 # ---------------------------------------------------------------------- 2288 2289 @classmethod 2290 def set_ctxtmgr_mouse_settings( 2291 cls, enhanced_pointer_precision_enabled: int, mouse_speed: int 2292 ) -> None: 2293 with cls.__context_manager_lock: 2294 cls.__context_manager_count += 1 2295 if cls.__context_manager_count > 1: 2296 # Don't allow changing the stored value if another value is 2297 # already stored 2298 return 2299 cls.__context_manager_epp = enhanced_pointer_precision_enabled 2300 cls.__context_manager_speed = mouse_speed 2301 # ---------------------------------------------------------------------- 2302 2303 2304# ----- Temporarily disable Enhanced Pointer Precision ------------------------- 2305@contextmanager 2306def _no_mouse_acceleration() -> Generator[None, None, None]: 2307 """ 2308 Context manager that allows temporarily disabling Windows Enhanced Pointer 2309 Precision on enter and restoring the previous setting on exit. 2310 """ 2311 th1: int 2312 th2: int 2313 precision: int | None 2314 # store mouse parameters (thresholds, enhanced pointer precision) 2315 th1, th2, precision = _get_mouse_parameters() 2316 speed: int | None = _get_mouse_speed() 2317 assert isinstance(precision, int) 2318 assert isinstance(speed, int) 2319 __MouseSpeedSettings.set_ctxtmgr_mouse_settings(precision, speed) 2320 try: 2321 # modify mouse parameters 2322 if precision != 0: 2323 _set_mouse_parameters(th1, th2, 0) 2324 if speed != 10: 2325 _set_mouse_speed(10) 2326 yield 2327 finally: 2328 # restore mouse parameters 2329 precision, speed = __MouseSpeedSettings.get_ctxtmgr_mouse_settings() 2330 if precision is not None: 2331 _set_mouse_parameters(th1, th2, precision) 2332 if speed is not None: 2333 _set_mouse_speed(speed) 2334 # -------------------------------------------------------------------------- 2335 2336 2337# ----- manually store current enhanced pointer precision setting -------------- 2338def store_mouse_acceleration_settings() -> None: 2339 """ 2340 Manually save the current Windows Enhanced Pointer Precision setting so 2341 that it can be restored later with `restore_mouse_acceleration_settings()`. 2342 """ 2343 precision: int 2344 _, _, precision = _get_mouse_parameters() 2345 speed: int = _get_mouse_speed() 2346 __MouseSpeedSettings.set_manual_mouse_settings(precision, speed) 2347 # -------------------------------------------------------------------------- 2348 2349 2350# ----- manually restore current enhanced pointer precision setting ------------ 2351def restore_mouse_acceleration_settings() -> None: 2352 """ 2353 Manually restore the current Windows Enhanced Pointer Precision setting to 2354 what it was beforehand when it was saved with 2355 `store_mouse_acceleration_settings()`. 2356 """ 2357 precision: int | None 2358 speed: int | None 2359 precision, speed = __MouseSpeedSettings.get_manual_mouse_settings() 2360 if precision is None or speed is None: 2361 raise ValueError( 2362 "Can't restore Enhanced Pointer Precision setting! " 2363 "Setting was not saved beforehand!" 2364 ) 2365 th1: int 2366 th2: int 2367 th1, th2, _ = _get_mouse_parameters() 2368 _set_mouse_parameters(th1, th2, precision) 2369 _set_mouse_speed(speed) 2370 # -------------------------------------------------------------------------- 2371 2372 2373# ============================================================================== 2374# ===== Main Mouse Functions =================================================== 2375# ============================================================================== 2376 2377 2378# ----- mouseDown -------------------------------------------------------------- 2379@_genericPyDirectInputChecks 2380def mouseDown( 2381 x: int | None = None, 2382 y: int | None = None, 2383 button: str = MOUSE_PRIMARY, 2384 duration: float = 0.0, 2385 tween: Callable[[float], float] | None = None, 2386 logScreenshot: bool = False, 2387 _pause: bool = True, 2388 *, 2389 relative: bool = False, 2390 virtual: bool = False, 2391 path_function: PathFunction | None = None, 2392 attempt_pixel_perfect: bool = False, 2393 disable_mouse_acceleration: bool = False, 2394) -> None: 2395 """ 2396 Press down mouse button `button`. 2397 2398 If `x` or `y` are given and not None, then the mouse will move the 2399 indicated postion before pressing the button. 2400 2401 `button` is the name of the button to press. Use the public `MOUSE_*` 2402 constants to get valid argument values. (If you change the constants, then 2403 you will have to call `update_MOUSEEVENT_mappings()` to resync the lookup 2404 functions) 2405 2406 If `_pause` is True (default), then an automatic sleep will be performed 2407 after the function finshes executing. The duration is set by the global 2408 variable `PAUSE`. 2409 2410 `duration`, `tween`, `relative`, `virtual`, `path_function`, 2411 `attempt_pixel_perfect`, `disable_mouse_acceleration` are only relevant 2412 if x or y are given. 2413 See `moveTo()` for further information. 2414 2415 Raises `ValueError` if `button` is not a valid mouse button name. 2416 2417 ---------------------------------------------------------------------------- 2418 2419 NOTE: `logScreenshot` is currently unsupported. 2420 """ 2421 # TODO: bounding box check for valid position 2422 if x is not None or y is not None: 2423 moveTo( 2424 x, 2425 y, 2426 duration=duration, 2427 tween=tween, 2428 logScreenshot=logScreenshot, 2429 _pause=False, # don't add an additional pause 2430 relative=relative, 2431 virtual=virtual, 2432 path_function=path_function, 2433 attempt_pixel_perfect=attempt_pixel_perfect, 2434 disable_mouse_acceleration=disable_mouse_acceleration, 2435 ) 2436 2437 event_value: int | None = None 2438 mouseData: int 2439 event_value, mouseData = _get_mouse_struct_data(button, _MOUSE_PRESS) 2440 2441 if not event_value: 2442 raise ValueError( 2443 f"Invalid button argument! " 2444 f'Expected "{MOUSE_LEFT}", "{MOUSE_RIGHT}", "{MOUSE_MIDDLE}", ' 2445 f'"{MOUSE_BUTTON4}", "{MOUSE_BUTTON5}", "{MOUSE_PRIMARY}" or ' 2446 f'"{MOUSE_SECONDARY}"; got "{button}" instead!' 2447 ) 2448 2449 _send_input(_create_mouse_input(mouseData=mouseData, dwFlags=event_value)) 2450 # -------------------------------------------------------------------------- 2451 2452 2453# ----- mouseUp ---------------------------------------------------------------- 2454@_genericPyDirectInputChecks 2455def mouseUp( 2456 x: int | None = None, 2457 y: int | None = None, 2458 button: str = MOUSE_PRIMARY, 2459 duration: float = 0.0, 2460 tween: Callable[[float], float] | None = None, 2461 logScreenshot: bool = False, 2462 _pause: bool = True, 2463 *, 2464 relative: bool = False, 2465 virtual: bool = False, 2466 path_function: PathFunction | None = None, 2467 attempt_pixel_perfect: bool = False, 2468 disable_mouse_acceleration: bool = False, 2469) -> None: 2470 """ 2471 Lift up mouse button `button`. 2472 2473 If `x` or `y` are given and not None, then the mouse will move the 2474 indicated postion before lifting the button. 2475 2476 `button` is the name of the button to press. Use the public `MOUSE_*` 2477 constants to get valid argument values. (If you change the constants, then 2478 you will have to call `update_MOUSEEVENT_mappings()` to resync the lookup 2479 functions) 2480 2481 If `_pause` is True (default), then an automatic sleep will be performed 2482 after the function finshes executing. The duration is set by the global 2483 variable `PAUSE`. 2484 2485 `duration`, `tween`, `relative`, `virtual`, `path_function`, 2486 `attempt_pixel_perfect`, `disable_mouse_acceleration` are only relevant 2487 if x or y are given. 2488 See `moveTo()` for further information. 2489 2490 Raises `ValueError` if `button` is not a valid mouse button name. 2491 2492 ---------------------------------------------------------------------------- 2493 2494 NOTE: `logScreenshot` is currently unsupported. 2495 """ 2496 # TODO: bounding box check for valid position 2497 if x is not None or y is not None: 2498 moveTo( 2499 x, 2500 y, 2501 duration=duration, 2502 tween=tween, 2503 logScreenshot=logScreenshot, 2504 _pause=False, # don't add an additional pause 2505 relative=relative, 2506 virtual=virtual, 2507 path_function=path_function, 2508 attempt_pixel_perfect=attempt_pixel_perfect, 2509 disable_mouse_acceleration=disable_mouse_acceleration, 2510 ) 2511 2512 event_value: int | None = None 2513 mouseData: int 2514 event_value, mouseData = _get_mouse_struct_data(button, _MOUSE_RELEASE) 2515 2516 if not event_value: 2517 raise ValueError( 2518 "Invalid button argument! " 2519 f'Expected "{MOUSE_LEFT}", "{MOUSE_RIGHT}", "{MOUSE_MIDDLE}", ' 2520 f'"{MOUSE_BUTTON4}", "{MOUSE_BUTTON5}", "{MOUSE_PRIMARY}" or ' 2521 f'"{MOUSE_SECONDARY}"; got "{button}" instead!' 2522 ) 2523 2524 _send_input(_create_mouse_input(mouseData=mouseData, dwFlags=event_value)) 2525 # -------------------------------------------------------------------------- 2526 2527 2528# ----- click ------------------------------------------------------------------ 2529@_genericPyDirectInputChecks 2530def click( 2531 x: int | None = None, 2532 y: int | None = None, 2533 clicks: int = 1, 2534 interval: float = 0.0, 2535 button: str = MOUSE_PRIMARY, 2536 duration: float = 0.0, 2537 tween: Callable[[float], float] | None = None, 2538 logScreenshot: bool = False, 2539 _pause: bool = True, 2540 *, 2541 relative: bool = False, 2542 virtual: bool = False, 2543 path_function: PathFunction | None = None, 2544 attempt_pixel_perfect: bool = False, 2545 disable_mouse_acceleration: bool = False, 2546) -> None: 2547 """ 2548 Click mouse button `button` (combining press down and lift up). 2549 2550 If `x` or `y` are given and not None, then the mouse will move the 2551 indicated postion before clicking the button. 2552 2553 `button` is the name of the button to press. Use the public `MOUSE_*` 2554 constants to get valid argument values. (If you change the constants, then 2555 you will have to call `update_MOUSEEVENT_mappings()` to resync the lookup 2556 functions) 2557 2558 `clicks` is an integer that determines the amount of times the button will 2559 be clicked. 2560 2561 `interval` is the wait time in seconds between clicks. 2562 2563 If `_pause` is True (default), then an automatic sleep will be performed 2564 after the function finshes executing. The duration is set by the global 2565 variable `PAUSE`. 2566 2567 `duration`, `tween`, `relative`, `virtual`, `path_function`, 2568 `attempt_pixel_perfect`, `disable_mouse_acceleration` are only relevant 2569 if x or y are given. 2570 See `moveTo()` for further information. 2571 2572 Raises `ValueError` if `button` is not a valid mouse button name. 2573 2574 ---------------------------------------------------------------------------- 2575 2576 NOTE: `logScreenshot` is currently unsupported. 2577 """ 2578 # TODO: bounding box check for valid position 2579 if x is not None or y is not None: 2580 moveTo( 2581 x, 2582 y, 2583 duration=duration, 2584 tween=tween, 2585 logScreenshot=logScreenshot, 2586 _pause=False, # don't add an additional pause 2587 relative=relative, 2588 virtual=virtual, 2589 path_function=path_function, 2590 attempt_pixel_perfect=attempt_pixel_perfect, 2591 disable_mouse_acceleration=disable_mouse_acceleration, 2592 ) 2593 2594 event_value: int | None = None 2595 mouseData: int 2596 event_value, mouseData = _get_mouse_struct_data(button, _MOUSE_CLICK) 2597 2598 if not event_value: 2599 raise ValueError( 2600 f"Invalid button argument! " 2601 f'Expected "{MOUSE_LEFT}", "{MOUSE_RIGHT}", "{MOUSE_MIDDLE}", ' 2602 f'"{MOUSE_BUTTON4}", "{MOUSE_BUTTON5}", "{MOUSE_PRIMARY}" or ' 2603 f'"{MOUSE_SECONDARY}"; got "{button}" instead!' 2604 ) 2605 2606 apply_interval: bool = False 2607 for _ in range(clicks): 2608 if apply_interval: # Don't delay first press 2609 _sleep(interval) 2610 apply_interval = True 2611 2612 _send_input( 2613 _create_mouse_input(mouseData=mouseData, dwFlags=event_value) 2614 ) 2615 # -------------------------------------------------------------------------- 2616 2617 2618# ----- leftClick -------------------------------------------------------------- 2619def leftClick( 2620 x: int | None = None, 2621 y: int | None = None, 2622 interval: float = 0.0, 2623 duration: float = 0.0, 2624 tween: Callable[[float], float] | None = None, 2625 logScreenshot: bool = False, 2626 _pause: bool = True, 2627 *, 2628 relative: bool = False, 2629 virtual: bool = False, 2630 path_function: PathFunction | None = None, 2631 attempt_pixel_perfect: bool = False, 2632 disable_mouse_acceleration: bool = False, 2633) -> None: 2634 """ 2635 Click Left Mouse button. 2636 2637 See `click()` for more information 2638 """ 2639 click( 2640 x, 2641 y, 2642 clicks=1, 2643 interval=interval, 2644 button=MOUSE_LEFT, 2645 duration=duration, 2646 tween=tween, 2647 logScreenshot=logScreenshot, 2648 _pause=_pause, # Keep _pause since this function has no input checks 2649 relative=relative, 2650 virtual=virtual, 2651 path_function=path_function, 2652 attempt_pixel_perfect=attempt_pixel_perfect, 2653 disable_mouse_acceleration=disable_mouse_acceleration, 2654 ) 2655 # -------------------------------------------------------------------------- 2656 2657 2658# ----- rightClick ------------------------------------------------------------- 2659def rightClick( 2660 x: int | None = None, 2661 y: int | None = None, 2662 interval: float = 0.0, 2663 duration: float = 0.0, 2664 tween: Callable[[float], float] | None = None, 2665 logScreenshot: bool = False, 2666 _pause: bool = True, 2667 *, 2668 relative: bool = False, 2669 virtual: bool = False, 2670 path_function: PathFunction | None = None, 2671 attempt_pixel_perfect: bool = False, 2672 disable_mouse_acceleration: bool = False, 2673) -> None: 2674 """ 2675 Click Right Mouse button. 2676 2677 See `click()` for more information 2678 """ 2679 click( 2680 x, 2681 y, 2682 clicks=1, 2683 interval=interval, 2684 button=MOUSE_RIGHT, 2685 duration=duration, 2686 tween=tween, 2687 logScreenshot=logScreenshot, 2688 _pause=_pause, # Keep _pause since this function has no input checks 2689 relative=relative, 2690 virtual=virtual, 2691 path_function=path_function, 2692 attempt_pixel_perfect=attempt_pixel_perfect, 2693 disable_mouse_acceleration=disable_mouse_acceleration, 2694 ) 2695 # -------------------------------------------------------------------------- 2696 2697 2698# ----- middleClick ------------------------------------------------------------ 2699def middleClick( 2700 x: int | None = None, 2701 y: int | None = None, 2702 interval: float = 0.0, 2703 duration: float = 0.0, 2704 tween: Callable[[float], float] | None = None, 2705 logScreenshot: bool = False, 2706 _pause: bool = True, 2707 *, 2708 relative: bool = False, 2709 virtual: bool = False, 2710 path_function: PathFunction | None = None, 2711 attempt_pixel_perfect: bool = False, 2712 disable_mouse_acceleration: bool = False, 2713) -> None: 2714 """ 2715 Click Middle Mouse button. 2716 2717 See `click()` for more information 2718 """ 2719 click( 2720 x, 2721 y, 2722 clicks=1, 2723 interval=interval, 2724 button=MOUSE_MIDDLE, 2725 duration=duration, 2726 tween=tween, 2727 logScreenshot=logScreenshot, 2728 _pause=_pause, # Keep _pause since this function has no input checks 2729 relative=relative, 2730 virtual=virtual, 2731 path_function=path_function, 2732 attempt_pixel_perfect=attempt_pixel_perfect, 2733 disable_mouse_acceleration=disable_mouse_acceleration, 2734 ) 2735 # -------------------------------------------------------------------------- 2736 2737 2738# ----- doubleClick ------------------------------------------------------------ 2739def doubleClick( 2740 x: int | None = None, 2741 y: int | None = None, 2742 interval: float = 0.0, 2743 button: str = MOUSE_LEFT, 2744 duration: float = 0.0, 2745 tween: Callable[[float], float] | None = None, 2746 logScreenshot: bool = False, 2747 _pause: bool = True, 2748 *, 2749 relative: bool = False, 2750 virtual: bool = False, 2751 path_function: PathFunction | None = None, 2752 attempt_pixel_perfect: bool = False, 2753 disable_mouse_acceleration: bool = False, 2754) -> None: 2755 """ 2756 Double click `button`. 2757 2758 See `click()` for more information 2759 """ 2760 click( 2761 x, 2762 y, 2763 clicks=2, 2764 interval=interval, 2765 button=button, 2766 duration=duration, 2767 tween=tween, 2768 logScreenshot=logScreenshot, 2769 _pause=_pause, # Keep _pause since this function has no input checks 2770 relative=relative, 2771 virtual=virtual, 2772 path_function=path_function, 2773 attempt_pixel_perfect=attempt_pixel_perfect, 2774 disable_mouse_acceleration=disable_mouse_acceleration, 2775 ) 2776 # -------------------------------------------------------------------------- 2777 2778 2779# ----- tripleClick ------------------------------------------------------------ 2780def tripleClick( 2781 x: int | None = None, 2782 y: int | None = None, 2783 interval: float = 0.0, 2784 button: str = MOUSE_LEFT, 2785 duration: float = 0.0, 2786 tween: Callable[[float], float] | None = None, 2787 logScreenshot: bool = False, 2788 _pause: bool = True, 2789 *, 2790 relative: bool = False, 2791 virtual: bool = False, 2792 path_function: PathFunction | None = None, 2793 attempt_pixel_perfect: bool = False, 2794 disable_mouse_acceleration: bool = False, 2795) -> None: 2796 """ 2797 Triple click `button`. 2798 2799 See `click()` for more information 2800 """ 2801 click( 2802 x, 2803 y, 2804 clicks=3, 2805 interval=interval, 2806 button=button, 2807 duration=duration, 2808 tween=tween, 2809 logScreenshot=logScreenshot, 2810 _pause=_pause, # Keep _pause since this function has no input checks 2811 relative=relative, 2812 virtual=virtual, 2813 path_function=path_function, 2814 attempt_pixel_perfect=attempt_pixel_perfect, 2815 disable_mouse_acceleration=disable_mouse_acceleration, 2816 ) 2817 # -------------------------------------------------------------------------- 2818 2819 2820# ----- scroll ----------------------------------------------------------------- 2821# Originally implemented by 2822# https://github.com/learncodebygaming/pydirectinput/pull/22 2823@_genericPyDirectInputChecks 2824def scroll( 2825 clicks: int = 0, 2826 x: Any = None, # x and y do absolutely nothing, still keeping the arguments 2827 y: Any = None, # to stay consistent with PyAutoGUI. 2828 logScreenshot: bool = False, 2829 _pause: bool = True, 2830 *, 2831 interval: float = 0.0, 2832) -> None: 2833 """ 2834 Vertically scroll mouse `clicks` number of times, waiting `interval` 2835 seconds between every scroll. 2836 2837 Negative values of `clicks` will scroll down, postive values will scroll 2838 up. 2839 2840 `x` and `y` are intentionally ignored and only exists to keep the call 2841 signature backwards-compatible with PyAutoGui. 2842 If you need to change the mouse position before scrolling use one of the 2843 `move()` functions. 2844 2845 If `_pause` is True (default), then an automatic sleep will be performed 2846 after the function finshes executing. The duration is set by the global 2847 variable `PAUSE`. 2848 2849 ---------------------------------------------------------------------------- 2850 2851 NOTE: `logScreenshot` is currently unsupported. 2852 """ 2853 direction: Literal[-1, 1] 2854 if clicks >= 0: 2855 direction = 1 2856 else: 2857 direction = -1 2858 clicks = abs(clicks) 2859 2860 apply_interval: bool = False 2861 for _ in range(clicks): 2862 if apply_interval: 2863 _sleep(interval) 2864 apply_interval = True 2865 2866 _send_input( 2867 _create_mouse_input( 2868 mouseData=(direction * _WHEEL_DELTA), dwFlags=_MOUSEEVENTF_WHEEL 2869 ) 2870 ) 2871 # -------------------------------------------------------------------------- 2872 2873 2874# ----- hscroll ---------------------------------------------------------------- 2875@_genericPyDirectInputChecks 2876def hscroll( 2877 clicks: int = 0, 2878 x: Any = None, # x and y do absolutely nothing, still keeping the arguments 2879 y: Any = None, # to stay consistent with PyAutoGUI. 2880 logScreenshot: bool = False, 2881 _pause: bool = True, 2882 *, 2883 interval: float = 0.0, 2884) -> None: 2885 """ 2886 Horizontally scroll mouse `clicks` number of times, waiting `interval` 2887 seconds between every scroll. 2888 2889 Negative values of `clicks` will scroll left, postive values will scroll 2890 right. 2891 2892 `x` and `y` are intentionally ignored and only exists to keep the call 2893 signature backwards-compatible with PyAutoGui. 2894 If you need to change the mouse position before scrolling use one of the 2895 `move()` functions. 2896 2897 If `_pause` is True (default), then an automatic sleep will be performed 2898 after the function finshes executing. The duration is set by the global 2899 variable `PAUSE`. 2900 2901 ---------------------------------------------------------------------------- 2902 2903 NOTE: `logScreenshot` is currently unsupported. 2904 """ 2905 direction: Literal[-1, 1] 2906 if clicks >= 0: 2907 direction = 1 2908 else: 2909 direction = -1 2910 clicks = abs(clicks) 2911 2912 apply_interval: bool = False 2913 for _ in range(clicks): 2914 if apply_interval: 2915 _sleep(interval) 2916 apply_interval = True 2917 2918 _send_input( 2919 _create_mouse_input( 2920 mouseData=(direction * _WHEEL_DELTA), 2921 dwFlags=_MOUSEEVENTF_HWHEEL, 2922 ) 2923 ) 2924 # -------------------------------------------------------------------------- 2925 2926 2927# ----- scroll alias ----------------------------------------------------------- 2928vscroll = scroll 2929# ------------------------------------------------------------------------------ 2930 2931 2932# ----- absolute_mouse_move ---------------------------------------------------- 2933def _absolute_mouse_move( 2934 x: int | None = None, 2935 y: int | None = None, 2936 duration: float = 0.0, 2937 tween: Callable[[float], float] | None = None, 2938 logScreenshot: bool = False, 2939 target_coords_relative: bool = False, 2940 *, 2941 virtual: bool = False, 2942 path_function: PathFunction | None = None, 2943 attempt_pixel_perfect: bool = False, 2944 disable_mouse_acceleration: bool = False, 2945) -> None: 2946 """ 2947 Move the mouse to an absolute(*) postion indicated by the arguments of 2948 `x` and `y`. The coordinates 0,0 represent the top left pixel of the 2949 primary monitor. 2950 2951 If `duration` is floating point number greater than 0, then this function 2952 will automatically split the movement into microsteps instead of moving 2953 straight to the target position. 2954 2955 `tween` is a function that takes a floating point number between 0.0 and 2956 1.0 and returns another floating point number between 0.0 and 1.0. The 2957 returned number will be used to calculate the next position of the 2958 mouse between the start and the end position based on the current duration. 2959 The default tweening function is linear, which will move the mouse at a 2960 constant speed. See the `pytweening` package for more tweening functions. 2961 2962 `path_function` is a function that takes the start and end coordinates of 2963 the mouse movement (4 integers) and returns a list of coordinates (list of 2964 tuples containting 2 integers each) that the mouse will move through. 2965 The default path function is Bresenham's line algorithm, which will move 2966 the mouse in a straight line. 2967 2968 (*) If `target_coords_relative` is set: Use absolute mouse movement to move 2969 the mouse cursor to the current mouse position offset by arguments 2970 `x` and `y`. 2971 2972 If `_pause` is True (default), then an automatic sleep will be performed 2973 after the function finshes executing. The duration is set by the global 2974 variable `PAUSE`. 2975 2976 Setting `virtual` to True (default: False) changes the way internal APIs 2977 handle coordinates and is intended for multi monitor systems. It should be 2978 pretty much unncessary even for multi monitor systems, since all the 2979 necessary internal calculations beyond the border of the primay monitor 2980 work without it. 2981 2982 The way that Windows calculates the target pixel coordinates internally 2983 unfortunately leads to inaccuracies and unreachable pixels, especially 2984 if the `virtual` option is used. 2985 2986 If you need the target position to be pixel perfect, you can try setting 2987 `attempt_pixel_perfect` to True, which will use tiny relative movements 2988 to correct the unreachable position. 2989 2990 Relative movement is influenced by mouse speed and Windows Enhanced Pointer 2991 Precision, which can be temporarily disabled by setting 2992 `disable_mouse_acceleration`. 2993 2994 ---------------------------------------------------------------------------- 2995 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 2996 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 2997 2998 If you you start a relative movement while another is already in progress 2999 than the second movement could overwrite the first setting and disable 3000 Enhanced Pointer Precision and change mouse speed. 3001 There are some measures in place to try to mitigate that risk, such as an 3002 internal counter that only allows storing and restoring the acceleration 3003 settings as long as no other movement is currently in progress. 3004 Additionally, the acceleration settings can be manually saved and 3005 restored with `store_mouse_acceleration_settings()` and 3006 `restore_mouse_acceleration_settings()`. For your convenience, the 3007 store function is automatically called during import to save your current 3008 setting. You can then call the restore function at any time. 3009 3010 If all fails, the setting is not written permanently to your Windows 3011 settings, so it should restore itself upon reboot. 3012 3013 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3014 this library in multiple threads / processes / programs at the same time! 3015 3016 ---------------------------------------------------------------------------- 3017 3018 NOTE: `logScreenshot` is currently unsupported. 3019 """ 3020 # TODO: bounding box check for valid position 3021 if tween is None: 3022 tween = _linear 3023 if path_function is None: 3024 path_function = _bresenham 3025 final_x: int 3026 final_y: int 3027 current_x: int = 0 3028 current_y: int = 0 3029 current_x, current_y = position() 3030 if target_coords_relative: 3031 final_x = current_x + (0 if x is None else x) 3032 final_y = current_y + (0 if y is None else y) 3033 else: 3034 # if only x or y is provided, will keep the current position for the 3035 # other axis 3036 final_x, final_y = position(x, y) 3037 3038 dwFlags: int = _MOUSEEVENTF_MOVE | _MOUSEEVENTF_ABSOLUTE 3039 if virtual: 3040 dwFlags |= _MOUSEEVENTF_VIRTUALDESK 3041 3042 if duration <= 0.0: 3043 # no duration -> move mouse instantly 3044 x, y = _to_windows_coordinates(final_x, final_y, virtual=virtual) 3045 _send_input(_create_mouse_input(dx=x, dy=y, dwFlags=dwFlags)) 3046 3047 else: 3048 start_time: Final[float] = _time() 3049 final_time: Final[float] = start_time + duration 3050 path: list[tuple[int, int]] = path_function( 3051 current_x, current_y, final_x, final_y 3052 ) 3053 path_length = len(path) 3054 keep_looping: bool = True 3055 sleep_duration: float = MINIMUM_SLEEP_IDEAL 3056 3057 apply_duration: bool = False 3058 while keep_looping: 3059 if apply_duration: 3060 _sleep(sleep_duration) # sleep between iterations 3061 else: 3062 apply_duration = True 3063 3064 _failSafeCheck() 3065 3066 current_time = _time() 3067 if current_time >= final_time: 3068 keep_looping = False 3069 segment_count = path_length - 1 3070 else: 3071 time_ratio = (current_time - start_time) / duration 3072 if time_ratio <= 0.0: 3073 time_ratio = 0.0 3074 if time_ratio >= 1.0: 3075 time_ratio = 1.0 3076 path_ratio = tween(time_ratio) 3077 segment_count = int(path_length * path_ratio) 3078 if segment_count >= path_length: 3079 segment_count = path_length - 1 3080 3081 current_x, current_y = position() 3082 x, y = path[segment_count] 3083 3084 if x == current_x and y == current_y: 3085 # no change in movement for current segment ->try again 3086 continue 3087 3088 x, y = _to_windows_coordinates(x, y, virtual=virtual) 3089 _send_input(_create_mouse_input(dx=x, dy=y, dwFlags=dwFlags)) 3090 3091 # After-care: Did Windows move the cursor correctly? 3092 # If not, attempt to fix off-by-one errors. 3093 if attempt_pixel_perfect: 3094 current_x, current_y = position() 3095 if current_x == final_x and current_y == final_y: 3096 return # We are already pixel perfect, great! 3097 _relative_mouse_move( 3098 x=final_x - current_x, 3099 y=final_y - current_y, 3100 duration=0.0, 3101 target_coords_relative=True, 3102 virtual=virtual, 3103 disable_mouse_acceleration=disable_mouse_acceleration, 3104 ) 3105 # -------------------------------------------------------------------------- 3106 3107 3108# ----- relative_mouse_move ---------------------------------------------------- 3109def _relative_mouse_move( 3110 x: int | None = None, 3111 y: int | None = None, 3112 duration: float = 0.0, 3113 tween: Callable[[float], float] | None = None, 3114 logScreenshot: bool = False, 3115 target_coords_relative: bool = True, 3116 *, 3117 virtual: bool = False, 3118 path_function: PathFunction | None = None, 3119 disable_mouse_acceleration: bool = False, 3120) -> None: 3121 """ 3122 Move the mouse a relative amount determined by `x` and `y`. 3123 3124 If `duration` is floating point number greater than 0, then this function 3125 will automatically split the movement into microsteps instead of moving the 3126 complete distance instantly. 3127 3128 `tween` is a function that takes a floating point number between 0.0 and 3129 1.0 and returns another floating point number between 0.0 and 1.0. The 3130 returned number will be used to calculate the next position of the 3131 mouse between the start and the end position based on the current duration. 3132 The default tweening function is linear, which will move the mouse at a 3133 constant speed. See the `pytweening` package for more tweening functions. 3134 3135 `path_function` is a function that takes the start and end coordinates of 3136 the mouse movement (4 integers) and returns a list of coordinates (list of 3137 tuples containting 2 integers each) that the mouse will move through. 3138 The default path function is Bresenham's line algorithm, which will move 3139 the mouse in a straight line. 3140 3141 `target_coords_relative` parameter decides how `x` and `y` are interpreted: 3142 3143 -> `False`: `x` and `y` are assumed to be absolute coordinates 3144 and the offset to move will be calculated based on the current mouse 3145 position. Movement is then performed using relative mouse movements 3146 (can be inconsistent). 3147 3148 -> `True`: `x` and `y` are assumed to be relative coordinates 3149 and the mouse will be moved by that amount. Movement is then performed 3150 using relative mouse movements (can be inconsistent). 3151 3152 The inconsistency issue can be solved by disabling Enhanced Pointer 3153 Precision and set Mouse speed to 10 in Windows mouse settings. Since users 3154 may not want to permanently change their input settings just for this 3155 library, the `disable_mouse_acceleration` argument can be used to 3156 temporarily disable Enhanced Pointer Precision and fix mouse speed at 10 3157 and restore it after the mouse movement. 3158 3159 If `_pause` is True (default), then an automatic sleep will be performed 3160 after the function finshes executing. The duration is set by the global 3161 variable `PAUSE`. 3162 3163 Setting `virtual` to True (default: False) changes the way internal APIs 3164 handle coordinates and is intended for multi monitor systems. It should be 3165 pretty much unncessary even for multi monitor systems, since all the 3166 necessary internal calculations beyond the border of the primay monitor 3167 work without it. 3168 3169 ---------------------------------------------------------------------------- 3170 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 3171 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 3172 3173 If you you start a relative movement while another is already in progress 3174 than the second movement could overwrite the first setting and disable 3175 Enhanced Pointer Precision and change mouse speed. 3176 There are some measures in place to try to mitigate that risk, such as an 3177 internal counter that only allows storing and restoring the acceleration 3178 settings as long as no other movement is currently in progress. 3179 Additionally, the acceleration settings can be manually saved and 3180 restored with `store_mouse_acceleration_settings()` and 3181 `restore_mouse_acceleration_settings()`. For your convinnience, the 3182 store function is automatically called during import to save your current 3183 setting. You can then call the restore function at any time. 3184 3185 If all fails, the setting is not written permanently to your Windows 3186 settings, so it should restore itself upon reboot. 3187 3188 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3189 this library in multiple threads / processes / programs at the same time! 3190 3191 ---------------------------------------------------------------------------- 3192 3193 NOTE: `logScreenshot` is are currently unsupported. 3194 """ 3195 # TODO: bounding box check for valid position 3196 if tween is None: 3197 tween = _linear 3198 if path_function is None: 3199 path_function = _bresenham 3200 x, y = _helper_relative_move_target_coords(x, y, target_coords_relative) 3201 3202 if duration <= 0.0: 3203 # no duration -> move mouse instantly 3204 _helper_relative_mouse_move(x, y, disable_mouse_acceleration) 3205 return 3206 3207 current_x: int = 0 3208 current_y: int = 0 3209 3210 next_x: int 3211 next_y: int 3212 3213 final_x: int = x 3214 final_y: int = y 3215 3216 start_time: Final[float] = _time() 3217 final_time: Final[float] = start_time + duration 3218 3219 path: list[tuple[int, int]] = path_function( 3220 current_x, current_y, final_x, final_y 3221 ) 3222 path_length: int = len(path) 3223 3224 keep_looping: bool = True 3225 sleep_duration: float = MINIMUM_SLEEP_IDEAL 3226 3227 apply_duration: bool = False 3228 while keep_looping: 3229 if apply_duration: 3230 _sleep(sleep_duration) # sleep between iterations 3231 else: 3232 apply_duration = True 3233 3234 _failSafeCheck() 3235 3236 current_time: float = _time() 3237 if current_time >= final_time: 3238 keep_looping = False 3239 segment_count: int = path_length - 1 3240 else: 3241 time_ratio: float = (current_time - start_time) / duration 3242 if time_ratio <= 0.0: 3243 time_ratio = 0.0 3244 if time_ratio >= 1.0: 3245 time_ratio = 1.0 3246 path_ratio: float = tween(time_ratio) 3247 segment_count = int(path_length * path_ratio) 3248 if segment_count >= path_length: 3249 segment_count = path_length - 1 3250 3251 next_x, next_y = path[segment_count] 3252 x = next_x - current_x 3253 y = next_y - current_y 3254 3255 if x == 0 and y == 0: 3256 # no change in movement for current segment ->try again 3257 continue 3258 3259 current_x = next_x 3260 current_y = next_y 3261 3262 _helper_relative_mouse_move(x, y, disable_mouse_acceleration) 3263 # -------------------------------------------------------------------------- 3264 3265 3266# ----- helper_relative_move_target_coords ------------------------------------- 3267def _helper_relative_move_target_coords( 3268 x: int | None, 3269 y: int | None, 3270 target_coords_relative: bool 3271) -> tuple[int, int]: 3272 """ 3273 Calculate target coordinates for relative mouse movement. 3274 """ 3275 if target_coords_relative: 3276 if x is None: 3277 x = 0 3278 if y is None: 3279 y = 0 3280 else: 3281 if x is None and y is None: 3282 # Prevent unnecessary API calls 3283 return 0, 0 3284 current_x: int 3285 current_y: int 3286 current_x, current_y = position() 3287 if x is None: 3288 x = 0 3289 else: 3290 x = x - current_x 3291 if y is None: 3292 y = 0 3293 else: 3294 y = y - current_y 3295 return x, y 3296 # -------------------------------------------------------------------------- 3297 3298 3299# ----- helper_relative_mouse_move --------------------------------------------- 3300def _helper_relative_mouse_move( 3301 x: int, 3302 y: int, 3303 disable_mouse_acceleration: bool 3304) -> None: 3305 """ 3306 When using MOUSEEVENTF_MOVE for relative movement the results may 3307 be inconsistent. "Relative mouse motion is subject to the effects 3308 of the mouse speed and the two-mouse threshold values. A user 3309 sets these three values with the Pointer Speed slider of the 3310 Control Panel's Mouse Properties sheet. You can obtain and set 3311 these values using the SystemParametersInfo function." 3312 3313 https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-mouseinput 3314 https://stackoverflow.com/questions/50601200/pyhon-directinput-mouse-relative-moving-act-not-as-expected 3315 3316 We can solve this issue by just disabling Enhanced Pointer 3317 Precision and forcing Mouse speed to neutral 10. 3318 Since that is a user setting that users may want to have 3319 enabled, use a optional keyword-only argument and a 3320 state-restoring context manager to give users the choice if they 3321 want this library messing around in their Windows settings. 3322 """ 3323 input_struct: _INPUT = _create_mouse_input( 3324 dx=x, dy=y, dwFlags=_MOUSEEVENTF_MOVE 3325 ) 3326 if disable_mouse_acceleration: 3327 # Use a context manager to temporarily disable enhanced pointer 3328 # precision 3329 with _no_mouse_acceleration(): 3330 _send_input(input_struct) 3331 else: 3332 _send_input(input_struct) 3333 # -------------------------------------------------------------------------- 3334 3335 3336# ----- moveTo ----------------------------------------------------------------- 3337@_genericPyDirectInputChecks 3338def moveTo( 3339 x: int | None = None, 3340 y: int | None = None, 3341 duration: float = 0.0, 3342 tween: Callable[[float], float] | None = None, 3343 logScreenshot: bool = False, 3344 _pause: bool = True, 3345 relative: bool = False, 3346 *, 3347 virtual: bool = False, 3348 path_function: PathFunction | None = None, 3349 attempt_pixel_perfect: bool = False, 3350 disable_mouse_acceleration: bool = False, 3351) -> None: 3352 """ 3353 Move the mouse to an absolute(*) postion indicated by the arguments of 3354 `x` and `y`. The coordinates 0,0 represent the top left pixel of the 3355 primary monitor. 3356 3357 If `duration` is floating point number greater than 0, then this function 3358 will automatically split the movement into microsteps instead of moving 3359 straight to the target position. 3360 3361 `tween` is a function that takes a floating point number between 0.0 and 3362 1.0 and returns another floating point number between 0.0 and 1.0. The 3363 returned number will be used to calculate the next position of the 3364 mouse between the start and the end position based on the current duration. 3365 The default tweening function is linear, which will move the mouse at a 3366 constant speed. See the `pytweening` package for more tweening functions. 3367 3368 `path_function` is a function that takes the start and end coordinates of 3369 the mouse movement (4 integers) and returns a list of coordinates (list of 3370 tuples containting 2 integers each) that the mouse will move through. 3371 The default path function is Bresenham's line algorithm, which will move 3372 the mouse in a straight line. 3373 3374 (*) `relative` parameter decides how the movement is executed: 3375 3376 -> `False`: Target postion is given and absolute movement is used. 3377 3378 -> `True`: Calculates target offset and uses relative movement API 3379 (can be inconsistent) 3380 3381 If `_pause` is True (default), then an automatic sleep will be performed 3382 after the function finshes executing. The duration is set by the global 3383 variable `PAUSE`. 3384 3385 Setting `virtual` to True (default: False) changes the way internal APIs 3386 handle coordinates and is intended for multi monitor systems. It should be 3387 pretty much unncessary even for multi monitor systems, since all the 3388 necessary internal calculations beyond the border of the primay monitor 3389 work without it. 3390 3391 The way that Windows calculates the target pixel coordinates internally 3392 unfortunately leads to inaccuracies and unreachable pixels, especially 3393 if the `virtual` option is used. 3394 3395 If you need the target position to be pixel perfect, you can try setting 3396 `attempt_pixel_perfect` to True, which will use tiny relative movements 3397 to correct the unreachable position. 3398 3399 Relative movement is influenced by mouse speed and Windows Enhanced Pointer 3400 Precision, which can be temporarily disabled by setting 3401 `disable_mouse_acceleration`. 3402 3403 ---------------------------------------------------------------------------- 3404 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 3405 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 3406 3407 If you you start a relative movement while another is already in progress 3408 than the second movement could overwrite the first setting and disable 3409 Enhanced Pointer Precision and change mouse speed. 3410 There are some measures in place to try to mitigate that risk, such as an 3411 internal counter that only allows storing and restoring the acceleration 3412 settings as long as no other movement is currently in progress. 3413 Additionally, the acceleration settings can be manually saved and 3414 restored with `store_mouse_acceleration_settings()` and 3415 `restore_mouse_acceleration_settings()`. For your convenience, the 3416 store function is automatically called during import to save your current 3417 setting. You can then call the restore function at any time. 3418 3419 If all fails, the setting is not written permanently to your Windows 3420 settings, so it should restore itself upon reboot. 3421 3422 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3423 this library in multiple threads / processes / programs at the same time! 3424 3425 ---------------------------------------------------------------------------- 3426 3427 NOTE: `logScreenshot` is currently unsupported. 3428 """ 3429 if relative: 3430 _relative_mouse_move( 3431 x=x, 3432 y=y, 3433 duration=duration, 3434 tween=tween, 3435 logScreenshot=logScreenshot, 3436 target_coords_relative=False, 3437 virtual=virtual, 3438 path_function=path_function, 3439 disable_mouse_acceleration=disable_mouse_acceleration, 3440 ) 3441 else: 3442 _absolute_mouse_move( 3443 x=x, 3444 y=y, 3445 duration=duration, 3446 tween=tween, 3447 logScreenshot=logScreenshot, 3448 target_coords_relative=False, 3449 virtual=virtual, 3450 path_function=path_function, 3451 attempt_pixel_perfect=attempt_pixel_perfect, 3452 disable_mouse_acceleration=disable_mouse_acceleration, 3453 ) 3454 # -------------------------------------------------------------------------- 3455 3456 3457# ----- moveRel ---------------------------------------------------------------- 3458@_genericPyDirectInputChecks 3459def moveRel( 3460 xOffset: int | None = None, 3461 yOffset: int | None = None, 3462 duration: float = 0.0, 3463 tween: Callable[[float], float] | None = None, 3464 logScreenshot: bool = False, 3465 _pause: bool = True, 3466 relative: bool = False, 3467 *, 3468 virtual: bool = False, 3469 path_function: PathFunction | None = None, 3470 attempt_pixel_perfect: bool = False, 3471 disable_mouse_acceleration: bool = False, 3472) -> None: 3473 """ 3474 Move the mouse a relative amount determined by `xOffset` and `yOffset`. 3475 3476 If `duration` is floating point number greater than 0, then this function 3477 will automatically split the movement into microsteps instead of moving the 3478 complete distance instantly. 3479 3480 `tween` is a function that takes a floating point number between 0.0 and 3481 1.0 and returns another floating point number between 0.0 and 1.0. The 3482 returned number will be used to calculate the next position of the 3483 mouse between the start and the end position based on the current duration. 3484 The default tweening function is linear, which will move the mouse at a 3485 constant speed. See the `pytweening` package for more tweening functions. 3486 3487 `path_function` is a function that takes the start and end coordinates of 3488 the mouse movement (4 integers) and returns a list of coordinates (list of 3489 tuples containting 2 integers each) that the mouse will move through. 3490 The default path function is Bresenham's line algorithm, which will move 3491 the mouse in a straight line. 3492 3493 `relative` parameter decides how the movement is executed: 3494 3495 -> `False`: Target postion is calculated and absolute movement is used. 3496 3497 -> `True`: Target offset is given and relative movement API is used 3498 (can be inconsistent) 3499 3500 The inconsistency issue can be solved by disabling Enhanced Pointer 3501 Precision and set Mouse speed to 10 in Windows mouse settings. Since users 3502 may not want to permanently change their input settings just for this 3503 library, the `disable_mouse_acceleration` argument can be used to 3504 temporarily disable Enhanced Pointer Precision and fix mouse speed at 10 3505 and restore it after the mouse movement. 3506 3507 If `_pause` is True (default), then an automatic sleep will be performed 3508 after the function finshes executing. The duration is set by the global 3509 variable `PAUSE`. 3510 3511 Setting `virtual` to True (default: False) changes the way internal APIs 3512 handle coordinates and is intended for multi monitor systems. It should be 3513 pretty much unncessary even for multi monitor systems, since all the 3514 necessary internal calculations beyond the border of the primay monitor 3515 work without it. 3516 3517 The way that Windows calculates the target pixel coordinates internally 3518 unfortunately leads to inaccuracies and unreachable pixels, especially 3519 if the `virtual` option is used. 3520 3521 If you need the target position to be pixel perfect, you can try setting 3522 `attempt_pixel_perfect` to True, which will use tiny relative movements 3523 to correct the unreachable position. 3524 3525 ---------------------------------------------------------------------------- 3526 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 3527 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 3528 3529 If you you start a relative movement while another is already in progress 3530 than the second movement could overwrite the first setting and disable 3531 Enhanced Pointer Precision and change mouse speed. 3532 There are some measures in place to try to mitigate that risk, such as an 3533 internal counter that only allows storing and restoring the acceleration 3534 settings as long as no other movement is currently in progress. 3535 Additionally, the acceleration settings can be manually saved and 3536 restored with `store_mouse_acceleration_settings()` and 3537 `restore_mouse_acceleration_settings()`. For your convinnience, the 3538 store function is automatically called during import to save your current 3539 setting. You can then call the restore function at any time. 3540 3541 If all fails, the setting is not written permanently to your Windows 3542 settings, so it should restore itself upon reboot. 3543 3544 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3545 this library in multiple threads / processes / programs at the same time! 3546 3547 ---------------------------------------------------------------------------- 3548 3549 NOTE: `logScreenshot` is are currently unsupported. 3550 """ 3551 if relative: 3552 _relative_mouse_move( 3553 x=xOffset, 3554 y=yOffset, 3555 duration=duration, 3556 tween=tween, 3557 logScreenshot=logScreenshot, 3558 target_coords_relative=True, 3559 virtual=virtual, 3560 path_function=path_function, 3561 disable_mouse_acceleration=disable_mouse_acceleration, 3562 ) 3563 else: 3564 _absolute_mouse_move( 3565 x=xOffset, 3566 y=yOffset, 3567 duration=duration, 3568 tween=tween, 3569 logScreenshot=logScreenshot, 3570 target_coords_relative=True, 3571 virtual=virtual, 3572 path_function=path_function, 3573 attempt_pixel_perfect=attempt_pixel_perfect, 3574 disable_mouse_acceleration=disable_mouse_acceleration, 3575 ) 3576 # -------------------------------------------------------------------------- 3577 3578 3579# ----- move alias ------------------------------------------------------------- 3580# move() and moveRel() are equivalent. 3581move = moveRel 3582# ------------------------------------------------------------------------------ 3583 3584 3585# ----- dragTo ----------------------------------------------------------------- 3586@_genericPyDirectInputChecks 3587def dragTo( 3588 x: int | None = None, 3589 y: int | None = None, 3590 duration: float = 0.0, 3591 tween: Callable[[float], float] | None = None, 3592 button: str | None = None, 3593 logScreenshot: bool = False, 3594 _pause: bool = True, 3595 mouseDownUp: bool = True, 3596 *, 3597 relative: bool = False, 3598 virtual: bool = False, 3599 path_function: PathFunction | None = None, 3600 attempt_pixel_perfect: bool = False, 3601 disable_mouse_acceleration: bool = False, 3602) -> None: 3603 """ 3604 Press and hold a mouse button while moving to the target coordinates. 3605 3606 See `moveTo` for more information on most arguments. 3607 3608 `button` is a string that is one of the following constants: 3609 MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, MOUSE_BUTTON4, MOUSE_BUTTON5, 3610 MOUSE_PRIMARY (default), MOUSE_SECONDARY. 3611 3612 If `mouseDownUp` (default: True) is manually set to False, then this 3613 function is basically the same as `moveTo`. Only exists to match PyAutoGUI. 3614 3615 If `_pause` is True (default), then an automatic sleep will be performed 3616 after the function finshes executing. The duration is set by the global 3617 variable `PAUSE`. 3618 3619 ---------------------------------------------------------------------------- 3620 3621 NOTE: `logScreenshot` is currently unsupported. 3622 """ 3623 # TODO: bounding box check for valid position 3624 if button is None: 3625 button = MOUSE_PRIMARY 3626 if mouseDownUp: 3627 mouseDown(button=button, _pause=False, virtual=virtual) 3628 moveTo( 3629 x, 3630 y, 3631 duration=duration, 3632 tween=tween, 3633 logScreenshot=logScreenshot, 3634 _pause=False, # don't add an additional pause 3635 relative=relative, 3636 virtual=virtual, 3637 path_function=path_function, 3638 attempt_pixel_perfect=attempt_pixel_perfect, 3639 disable_mouse_acceleration=disable_mouse_acceleration, 3640 ) 3641 if mouseDownUp: 3642 mouseUp(button=button, _pause=False, virtual=virtual) 3643 # -------------------------------------------------------------------------- 3644 3645 3646# ----- dragRel ---------------------------------------------------------------- 3647@_genericPyDirectInputChecks 3648def dragRel( 3649 xOffset: int | None = None, 3650 yOffset: int | None = None, 3651 duration: float = 0.0, 3652 tween: Callable[[float], float] | None = None, 3653 button: str | None = None, 3654 logScreenshot: bool = False, 3655 _pause: bool = True, 3656 mouseDownUp: bool = True, 3657 *, 3658 relative: bool = False, 3659 virtual: bool = False, 3660 path_function: PathFunction | None = None, 3661 disable_mouse_acceleration: bool = False, 3662) -> None: 3663 """ 3664 Press and hold a mouse button while moving a relative distance 3665 3666 See `moveRel` for more information on most arguments. 3667 3668 `button` is a string that is one of the following constants: 3669 MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, MOUSE_BUTTON4, MOUSE_BUTTON5, 3670 MOUSE_PRIMARY (default), MOUSE_SECONDARY. 3671 3672 If `mouseDownUp` (default: True) is manually set to False, then this 3673 function is basically the same as `moveTo`. Only exists to match PyAutoGUI. 3674 3675 If `_pause` is True (default), then an automatic sleep will be performed 3676 after the function finshes executing. The duration is set by the global 3677 variable `PAUSE`. 3678 3679 ---------------------------------------------------------------------------- 3680 3681 NOTE: `logScreenshot` is currently unsupported. 3682 """ 3683 # TODO: bounding box check for valid position 3684 if button is None: 3685 button = MOUSE_PRIMARY 3686 if mouseDownUp: 3687 mouseDown(button=button, _pause=False, virtual=virtual) 3688 moveRel( 3689 xOffset, 3690 yOffset, 3691 duration=duration, 3692 tween=tween, 3693 logScreenshot=logScreenshot, 3694 _pause=False, # don't add an additional pause 3695 relative=relative, 3696 virtual=virtual, 3697 path_function=path_function, 3698 disable_mouse_acceleration=disable_mouse_acceleration, 3699 ) 3700 if mouseDownUp: 3701 mouseUp(button=button, _pause=False, virtual=virtual) 3702 # -------------------------------------------------------------------------- 3703 3704 3705# ----- drag alias ------------------------------------------------------------- 3706drag = dragRel 3707# ------------------------------------------------------------------------------ 3708 3709 3710# ============================================================================== 3711# ===== Keyboard Functions ===================================================== 3712# ============================================================================== 3713 3714 3715# ----- is_valid_key ------------------------------------------------------------- 3716def is_valid_key(key: str) -> bool: 3717 """ 3718 Returns true if key name `key` can be translated into a valid scan code. 3719 """ 3720 return key in KEYBOARD_MAPPING 3721 3722 3723isValidKey = is_valid_key 3724# ------------------------------------------------------------------------------ 3725 3726 3727# ===== scancode functions ===================================================== 3728 3729 3730# ----- scancode_keyDown ------------------------------------------------------- 3731@_genericPyDirectInputChecks 3732def scancode_keyDown( 3733 scancodes: ScancodeTypes, 3734 logScreenshot: None = None, 3735 _pause: bool = True, 3736 *, 3737 auto_shift: bool = False, 3738) -> bool: 3739 """ 3740 Press down key corresponding to `scancodes`. 3741 3742 The actually pressed key will depend on your system keyboard layout. 3743 Limits the available character set but should provide the best 3744 compatibility. 3745 3746 If `_pause` is True (default), then an automatic sleep will be performed 3747 after the function finshes executing. The duration is set by the global 3748 variable `PAUSE`. 3749 3750 `auto_shift` is used internally by higher level functions to automatically 3751 press the shift key before supported scancodes (indicitated by a special 3752 bit outside the regular scancode range, while it technically can be used, 3753 it's not intended for public access). 3754 3755 ---------------------------------------------------------------------------- 3756 3757 NOTE: `logScreenshot` is currently unsupported. 3758 """ 3759 scancodes_sequence: ScancodeSequence 3760 if isinstance(scancodes, int): 3761 scancodes_sequence = ScancodeSequence([scancodes]) 3762 else: 3763 scancodes_sequence = scancodes 3764 3765 keybdFlags: int = _KEYEVENTF_SCANCODE 3766 input_structs: list[_INPUT] = [] 3767 extendedFlag: int 3768 3769 # Init event tracking 3770 insertedEvents: int = 0 3771 expectedEvents: int = 0 3772 3773 for scancode in scancodes_sequence: 3774 if auto_shift and scancode & _OFFSET_SHIFTKEY: 3775 input_structs += [ 3776 _create_keyboard_input( 3777 wScan=_SHIFT_SCANCODE, dwFlags=keybdFlags 3778 ) 3779 ] 3780 expectedEvents += 1 3781 3782 scancode = scancode & 0xFFFF 3783 3784 extendedFlag = _KEYEVENTF_EXTENDEDKEY if scancode >= 0xE000 else 0 3785 input_structs += [ 3786 _create_keyboard_input( 3787 wScan=scancode, dwFlags=keybdFlags | extendedFlag 3788 ) 3789 ] 3790 expectedEvents += 1 3791 3792 insertedEvents += _send_input(input_structs) 3793 3794 # SendInput returns the number of event successfully inserted into 3795 # input stream 3796 # https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput#return-value 3797 return insertedEvents == expectedEvents 3798 # -------------------------------------------------------------------------- 3799 3800 3801# ----- scancode_keyUp --------------------------------------------------------- 3802@_genericPyDirectInputChecks 3803def scancode_keyUp( 3804 scancodes: ScancodeTypes, 3805 logScreenshot: None = None, 3806 _pause: bool = True, 3807 *, 3808 auto_shift: bool = False, 3809) -> bool: 3810 """ 3811 Release key corresponding to `scancodes`. 3812 3813 The actually pressed key will depend on your system keyboard layout. 3814 Limits the available character set but should provide the best 3815 compatibility. 3816 3817 If `_pause` is True (default), then an automatic sleep will be performed 3818 after the function finshes executing. The duration is set by the global 3819 variable `PAUSE`. 3820 3821 `auto_shift` is used internally by higher level functions to automatically 3822 press the shift key before supported scancodes (indicitated by a special 3823 bit outside the regular scancode range, while it technically can be used, 3824 it's not intended for public access). 3825 3826 ---------------------------------------------------------------------------- 3827 3828 NOTE: `logScreenshot` is currently unsupported. 3829 """ 3830 scancodes_sequence: ScancodeSequence 3831 if isinstance(scancodes, int): 3832 scancodes_sequence = ScancodeSequence([scancodes]) 3833 else: 3834 scancodes_sequence = scancodes 3835 3836 keybdFlags: int = _KEYEVENTF_SCANCODE | _KEYEVENTF_KEYUP 3837 input_structs: list[_INPUT] = [] 3838 extendedFlag: int 3839 3840 # Init event tracking 3841 insertedEvents: int = 0 3842 expectedEvents: int = 0 3843 3844 for scancode in scancodes_sequence: 3845 if auto_shift and scancode & _OFFSET_SHIFTKEY: 3846 input_structs += [ 3847 _create_keyboard_input( 3848 wScan=_SHIFT_SCANCODE, dwFlags=keybdFlags 3849 ) 3850 ] 3851 expectedEvents += 1 3852 3853 scancode = scancode & 0xFFFF 3854 3855 extendedFlag = _KEYEVENTF_EXTENDEDKEY if scancode >= 0xE000 else 0 3856 input_structs += [ 3857 _create_keyboard_input( 3858 wScan=scancode & 0xFFFF, dwFlags=keybdFlags | extendedFlag 3859 ) 3860 ] 3861 expectedEvents += 1 3862 3863 insertedEvents += _send_input(input_structs) 3864 return insertedEvents == expectedEvents 3865 # -------------------------------------------------------------------------- 3866 3867 3868# ----- _helper_scancode_press ------------------------------------------------- 3869def _helper_scancode_press( 3870 scancodes: ScancodeTypes, 3871 duration: float = 0.0, 3872 _pause: bool = True, 3873 auto_shift: bool = False, 3874) -> bool: 3875 """ 3876 Press `scancode`, wait for `duration` seconds, release `scancode`. 3877 3878 Return `True` if complete press was successful. 3879 """ 3880 downed: bool = scancode_keyDown( 3881 scancodes, _pause=_pause, auto_shift=auto_shift 3882 ) 3883 _sleep(duration) 3884 upped: bool = scancode_keyUp( 3885 scancodes, _pause=_pause, auto_shift=auto_shift 3886 ) 3887 # Count key press as complete if key was "downed" and "upped" 3888 # successfully 3889 return bool(downed and upped) 3890 # -------------------------------------------------------------------------- 3891 3892 3893# ----- scancode_press --------------------------------------------------------- 3894# Ignored parameters: logScreenshot 3895@_genericPyDirectInputChecks 3896def scancode_press( 3897 scancodes: ScancodeTypes | Sequence[ScancodeTypes], 3898 presses: int = 1, 3899 interval: float = 0.0, 3900 logScreenshot: None = None, 3901 _pause: bool = True, 3902 *, 3903 auto_shift: bool = False, 3904 delay: float = 0.0, 3905 duration: float = 0.0, 3906) -> bool: 3907 """ 3908 Press the sequence of `keys` for `presses` amount of times. 3909 3910 The actually pressed key will depend on your system keyboard layout. 3911 Limits the available character set but should provide the best 3912 compatibility. 3913 3914 Explanation of time parameters (seconds as floating point numbers): 3915 3916 - `interval` is the time spent waiting between sequences. If `keys` is a 3917 str instance or single element list, then `interval` will be ignored. 3918 - `delay` is the time from one complete key (press+release) to the next one 3919 in the same sequence. If there is only a single key in a sequence, then 3920 `delay` will be ignored. 3921 - `duration` is the time spent on holding every key before releasing it 3922 again. 3923 3924 If `_pause` is True (default), then an automatic sleep will be performed 3925 after the function finshes executing. The duration is set by the global 3926 variable `PAUSE`. 3927 Be aware, that the global pause defined by the PAUSE `constant` only 3928 applies after every call to this function, not inbetween (no extra pause 3929 between pressing and releasing key, use the `duration` argument instead)! 3930 3931 `auto_shift` is used internally by higher level functions to automatically 3932 press the shift key before supported scancodes (indicitated by a special 3933 bit outside the regular scancode range, while it technically can be used, 3934 it's not intended for public access). 3935 3936 ---------------------------------------------------------------------------- 3937 3938 NOTE: `logScreenshot` is currently unsupported. 3939 """ 3940 scancodes_sequence: Sequence[ScancodeTypes] 3941 if isinstance(scancodes, int): 3942 scancodes_sequence = [ScancodeSequence([scancodes])] 3943 elif isinstance(scancodes, ScancodeSequence): 3944 scancodes_sequence = [scancodes] 3945 else: 3946 scancodes_sequence = scancodes 3947 3948 # We need to press x keys y times, which comes out to x*y presses in total 3949 expectedPresses: int = presses * len(scancodes_sequence) 3950 completedPresses: int = 0 3951 3952 apply_interval: bool = False 3953 for _ in range(presses): 3954 if apply_interval: # Don't delay first press 3955 _sleep(interval) 3956 apply_interval = True 3957 3958 apply_delay: bool = False 3959 for c in scancodes_sequence: 3960 if apply_delay: # Don't delay first press 3961 _sleep(delay) 3962 apply_delay = True 3963 3964 completedPresses += _helper_scancode_press( 3965 c, duration, _pause=False, auto_shift=auto_shift 3966 ) 3967 3968 return completedPresses == expectedPresses 3969 # -------------------------------------------------------------------------- 3970 3971 3972# ----- scancode_hold ---------------------------------------------------------- 3973@contextmanager 3974@_genericPyDirectInputChecks 3975def scancode_hold( 3976 scancodes: ScancodeTypes | Sequence[ScancodeTypes], 3977 logScreenshot: None = None, 3978 _pause: bool = True, 3979 *, 3980 auto_shift: bool = False, 3981 raise_on_failure: bool = False, 3982) -> Generator[None, None, None]: 3983 """ 3984 Hold the sequence of keys corresponding to `scancodes` as long as the 3985 context manager is in scope (press upon entry, release upon exit). 3986 3987 Keys will be released in reverse order (LIFO), but still practically 3988 instantenous. 3989 3990 The actually pressed key will depend on your system keyboard layout. 3991 Limits the available character set but should provide the best 3992 compatibility. 3993 3994 If `_pause` is True (default), then an automatic sleep will be performed 3995 after the function finshes executing. The duration is set by the global 3996 variable `PAUSE`. 3997 Be aware, that the global pause defined by the PAUSE `constant` only 3998 applies after every call to this function, not inbetween (no pause between 3999 press and releasing key)! 4000 4001 `auto_shift` is used internally by higher level functions to automatically 4002 press the shift key before supported scancodes (indicitated by a special 4003 bit outside the regular scancode range, while it technically can be used, 4004 it's not intended for public access). 4005 4006 If `raise_on_failure` is True, then `PriorInputFailedException` will be 4007 raised if not all keyboard inputs could be executed successfully. 4008 4009 ---------------------------------------------------------------------------- 4010 4011 NOTE: `logScreenshot` is currently unsupported. 4012 """ 4013 scancodes_sequence: Sequence[ScancodeTypes] 4014 if isinstance(scancodes, int): 4015 scancodes_sequence = [ScancodeSequence([scancodes])] 4016 elif isinstance(scancodes, ScancodeSequence): 4017 scancodes_sequence = [scancodes] 4018 else: 4019 scancodes_sequence = scancodes 4020 4021 expectedPresses: int = len(scancodes_sequence) 4022 downed: int = 0 4023 upped: int = 0 4024 4025 try: 4026 for c in scancodes_sequence: 4027 downed += scancode_keyDown(c, _pause=False, auto_shift=auto_shift) 4028 yield 4029 finally: 4030 for c in reversed(scancodes_sequence): 4031 upped += scancode_keyUp(c, _pause=False, auto_shift=auto_shift) 4032 if raise_on_failure and not (expectedPresses == downed == upped): 4033 raise PriorInputFailedException 4034 # -------------------------------------------------------------------------- 4035 4036 4037# ----- scancode_hotkey -------------------------------------------------------- 4038@_genericPyDirectInputChecks 4039def scancode_hotkey( 4040 *args: ScancodeTypes, 4041 interval: float = 0.0, 4042 wait: float = 0.0, 4043 logScreenshot: None = None, 4044 _pause: bool = True, 4045 auto_shift: bool = True, 4046) -> bool: 4047 """ 4048 Press down buttons in order they are specified as arguments, 4049 releasing them in reverse order, e.g. 0x1D, 0x2E will first press 4050 Control, then C and release C before releasing Control. 4051 4052 Use keyword-only argument `interval` to specify a delay between single 4053 keys when pressing and releasing and `wait` for delay between last press 4054 and first release. 4055 4056 If `_pause` is True (default), then an automatic sleep will be performed 4057 after the function finshes executing. The duration is set by the global 4058 variable `PAUSE`. 4059 Be aware, that the global pause defined by the PAUSE `constant` only 4060 applies after every call to this function, not inbetween (no pause between 4061 press and releasing key)! 4062 4063 `auto_shift` is used internally by higher level functions to automatically 4064 press the shift key before supported scancodes (indicitated by a special 4065 bit outside the regular scancode range, while it technically can be used, 4066 it's not intended for public access). 4067 4068 ---------------------------------------------------------------------------- 4069 4070 NOTE: `logScreenshot` is currently unsupported. 4071 """ 4072 expectedPresses: int = len(args) 4073 downed: int = 0 4074 upped: int = 0 4075 4076 apply_interval: bool = False 4077 for code in args: 4078 if apply_interval: 4079 _sleep(interval) # sleep between iterations 4080 apply_interval = True 4081 4082 downed += scancode_keyDown(code, _pause=False, auto_shift=auto_shift) 4083 4084 _sleep(wait) 4085 4086 apply_interval = False 4087 for code in reversed(args): 4088 if apply_interval: 4089 _sleep(interval) # sleep between iterations 4090 apply_interval = True 4091 4092 upped += scancode_keyUp(code, _pause=False, auto_shift=auto_shift) 4093 4094 return expectedPresses == downed == upped 4095 # -------------------------------------------------------------------------- 4096 4097 4098# ===== keyname functions ====================================================== 4099 4100 4101# ----- keyDown ---------------------------------------------------------------- 4102# Ignored parameters: logScreenshot 4103def keyDown( 4104 key: str, 4105 logScreenshot: None = None, 4106 _pause: bool = True, 4107 *, 4108 auto_shift: bool = False, 4109) -> bool: 4110 """ 4111 Press down key corresponding to key name `key`. 4112 4113 `key` will be interpreted as a keyboard key (US QWERTY). 4114 The actually pressed key will depend on your system keyboard layout. 4115 Limits the available character set but should provide the best 4116 compatibility. 4117 4118 If `_pause` is True (default), then an automatic sleep will be performed 4119 after the function finshes executing. The duration is set by the global 4120 variable `PAUSE`. 4121 4122 If `auto_shift` is True, then "shifted" characters like upper case letters 4123 and the symbols on the number row automatically insert a Shift scancode 4124 into the input sequence. 4125 4126 ---------------------------------------------------------------------------- 4127 4128 NOTE: `logScreenshot` is currently unsupported. 4129 """ 4130 scancode: ScancodeTypes | None = KEYBOARD_MAPPING.get(key) 4131 if scancode is None: 4132 return False 4133 return scancode_keyDown( 4134 scancode, logScreenshot, _pause=_pause, auto_shift=auto_shift 4135 ) 4136 # -------------------------------------------------------------------------- 4137 4138 4139# ----- keyUp ------------------------------------------------------------------ 4140# Ignored parameters: logScreenshot 4141def keyUp( 4142 key: str, 4143 logScreenshot: None = None, 4144 _pause: bool = True, 4145 *, 4146 auto_shift: bool = False, 4147) -> bool: 4148 """ 4149 Lift up key corresponding to key name `key`. 4150 4151 `key` will be interpreted as a keyboard key (US QWERTY). 4152 The actually lifted key will depend on your system keyboard layout. 4153 Limits the available character set but should provide the best 4154 compatibility. 4155 4156 If `_pause` is True (default), then an automatic sleep will be performed 4157 after the function finshes executing. The duration is set by the global 4158 variable `PAUSE`. 4159 4160 If `auto_shift` is True, then "shifted" characters like upper case letters 4161 and the symbols on the number row automatically insert a Shift scancode 4162 into the input sequence. 4163 4164 ---------------------------------------------------------------------------- 4165 4166 NOTE: `logScreenshot` is currently unsupported. 4167 """ 4168 scancode: ScancodeTypes | None = KEYBOARD_MAPPING.get(key) 4169 if scancode is None: 4170 return False 4171 return scancode_keyUp( 4172 scancode, logScreenshot, _pause=_pause, auto_shift=auto_shift 4173 ) 4174 # -------------------------------------------------------------------------- 4175 4176 4177# ----- _helper_press ---------------------------------------------------------- 4178def _helper_press( 4179 key: str, 4180 duration: float = 0.0, 4181 _pause: bool = True, 4182 auto_shift: bool = False, 4183) -> bool: 4184 """ 4185 Press `key`, wait for `duration` seconds, release `key`. 4186 4187 Return `True` if complete press was successful. 4188 """ 4189 downed: bool = keyDown(key, _pause=_pause, auto_shift=auto_shift) 4190 _sleep(duration) 4191 upped: bool = keyUp(key, _pause=_pause, auto_shift=auto_shift) 4192 # Count key press as complete if key was "downed" and "upped" 4193 # successfully 4194 return bool(downed and upped) 4195 # -------------------------------------------------------------------------- 4196 4197 4198# ----- press ------------------------------------------------------------------ 4199# Ignored parameters: logScreenshot 4200@_genericPyDirectInputChecks 4201def press( 4202 keys: str | Sequence[str], 4203 presses: int = 1, 4204 interval: float = 0.0, 4205 logScreenshot: None = None, 4206 _pause: bool = True, 4207 *, 4208 auto_shift: bool = False, 4209 delay: float = 0.0, 4210 duration: float = 0.0, 4211) -> bool: 4212 """ 4213 Press the sequence of `keys` for `presses` amount of times. 4214 4215 `keys` will be interpreted as sequence of keyboard keys (US QWERTY). 4216 The actually pressed key will depend on your system keyboard layout. 4217 Limits the available character set but should provide the best 4218 compatibility. 4219 4220 Explanation of time parameters (seconds as floating point numbers): 4221 4222 - `interval` is the time spent waiting between sequences. If `keys` is a 4223 str instance, single element list or presses equals 1 (the default), 4224 then `interval` will be ignored. 4225 - `delay` is the time from one complete key (press+release) to the next one 4226 in the same sequence. If there is only a single key in a sequence, then 4227 `delay` will be ignored. 4228 - `duration` is the time spent on holding every key before releasing it 4229 again. 4230 4231 If `_pause` is True (default), then an automatic sleep will be performed 4232 after the function finshes executing. The duration is set by the global 4233 variable `PAUSE`. 4234 Be aware, that the global pause defined by the `PAUSE` var only applies 4235 after every call to this function, not inbetween (no extra pause between 4236 pressing and releasing key, use the `duration` argument instead)! 4237 4238 If `auto_shift` is True, then "shifted" characters like upper case letters 4239 and the symbols on the number row automatically insert a Shift scancode 4240 into the input sequence. 4241 4242 ---------------------------------------------------------------------------- 4243 4244 NOTE: `logScreenshot` is currently unsupported. 4245 """ 4246 if isinstance(keys, str): 4247 keys = [keys] # If keys is 'enter', convert it to ['enter']. 4248 keys = [_normalize_key(key, auto_shift=auto_shift) for key in keys] 4249 4250 # We need to press x keys y times, which comes out to x*y presses in total 4251 expectedPresses: int = presses * len(keys) 4252 completedPresses: int = 0 4253 4254 apply_interval: bool = False 4255 for _ in range(presses): 4256 if apply_interval: # Don't delay first press 4257 _sleep(interval) 4258 apply_interval = True 4259 4260 apply_delay: bool = False 4261 for k in keys: 4262 if apply_delay: # Don't delay first press 4263 _sleep(delay) 4264 apply_delay = True 4265 4266 completedPresses += _helper_press( 4267 k, duration, _pause=False, auto_shift=auto_shift 4268 ) 4269 4270 return completedPresses == expectedPresses 4271 # -------------------------------------------------------------------------- 4272 4273 4274# ----- hold ------------------------------------------------------------------- 4275@contextmanager 4276@_genericPyDirectInputChecks 4277def hold( 4278 keys: str | Sequence[str], 4279 logScreenshot: None = None, 4280 _pause: bool = True, 4281 *, 4282 auto_shift: bool = False, 4283 raise_on_failure: bool = False, 4284) -> Generator[None, None, None]: 4285 """ 4286 Hold the sequence of keys corresponding to key names in `keys` as long as 4287 the context manager is in scope (press upon entry, release upon exit). 4288 4289 Keys will be released in reverse order (LIFO), but still practically 4290 instantenous. 4291 4292 `key` will be interpreted as a keyboard key (US QWERTY). 4293 The actually pressed key will depend on your system keyboard layout. 4294 Limits the available character set but should provide the best 4295 compatibility. 4296 4297 If `_pause` is True (default), then an automatic sleep will be performed 4298 after the function finshes executing. The duration is set by the global 4299 variable `PAUSE`. 4300 Be aware, that the global pause defined by the PAUSE `constant` only 4301 applies after every call to this function, not inbetween (no pause between 4302 press and releasing key)! 4303 4304 `auto_shift` is used internally by higher level functions to automatically 4305 press the shift key before supported scancodes (indicitated by a special 4306 bit outside the regular scancode range, while it technically can be used, 4307 it's not intended for public access). 4308 4309 If `raise_on_failure` is True, then `PriorInputFailedException` will be 4310 raised if not all keyboard inputs could be executed successfully. 4311 4312 ---------------------------------------------------------------------------- 4313 4314 NOTE: `logScreenshot` is currently unsupported. 4315 """ 4316 if isinstance(keys, str): 4317 keys = [keys] # make single element into iterable 4318 keys = [_normalize_key(key, auto_shift=auto_shift) for key in keys] 4319 4320 expectedPresses: int = len(keys) 4321 downed: int = 0 4322 upped: int = 0 4323 4324 try: 4325 for k in keys: 4326 downed += keyDown(k, auto_shift=auto_shift) 4327 yield 4328 finally: 4329 for k in reversed(keys): 4330 upped += keyUp(k, auto_shift=auto_shift) 4331 if raise_on_failure and not (expectedPresses == downed == upped): 4332 raise PriorInputFailedException 4333 # -------------------------------------------------------------------------- 4334 4335 4336# ----- typewrite -------------------------------------------------------------- 4337@_genericPyDirectInputChecks 4338def typewrite( 4339 message: str, 4340 interval: float = 0.0, 4341 logScreenshot: None = None, 4342 _pause: bool = True, 4343 *, 4344 auto_shift: bool = False, 4345 delay: float = 0.0, 4346 duration: float = 0.0, 4347) -> None: 4348 """ 4349 Break down `message` into a single character key sequence and press each 4350 key one by one. 4351 4352 `message` will be interpreted as sequence of keyboard keys (US QWERTY). 4353 The actually pressed keys will depend on your system keyboard layout. 4354 Limits the available character set but should provide the best 4355 compatibility. 4356 4357 Explanation of time parameters (seconds as floating point numbers): 4358 4359 - `interval` is the time spent waiting between sequences. If `message` is a 4360 single character string, then `interval` will be ignored. 4361 - `delay` is the time from one complete key (press+release) to the next one 4362 in the same sequence. If there is only a single key in a sequence, then 4363 `delay` will be ignored. 4364 - `duration` is the time spent on holding every key before releasing it 4365 again. 4366 4367 If `_pause` is True (default), then an automatic sleep will be performed 4368 after the function finshes executing. The duration is set by the global 4369 variable `PAUSE`. 4370 Be aware, that the global pause defined by the PAUSE `constant` only 4371 applies after every call to this function, not inbetween (no pause between 4372 press and releasing key)! 4373 4374 `auto_shift` is used internally by higher level functions to automatically 4375 press the shift key before supported scancodes (indicitated by a special 4376 bit outside the regular scancode range, while it technically can be used, 4377 it's not intended for public access). 4378 4379 ---------------------------------------------------------------------------- 4380 4381 NOTE: `logScreenshot` is currently unsupported. 4382 """ 4383 4384 apply_interval: bool = False 4385 for key in message: 4386 if apply_interval: # Don't delay first press 4387 _sleep(interval) 4388 apply_interval = True 4389 4390 press( 4391 key, 4392 _pause=False, 4393 auto_shift=auto_shift, 4394 delay=delay, 4395 duration=duration, 4396 ) 4397 # -------------------------------------------------------------------------- 4398 4399 4400# ----- typewrite alias -------------------------------------------------------- 4401write = typewrite 4402# ------------------------------------------------------------------------------ 4403 4404 4405# ----- hotkey ----------------------------------------------------------------- 4406# Originally implemented by 4407# https://github.com/learncodebygaming/pydirectinput/pull/30 4408@_genericPyDirectInputChecks 4409def hotkey( 4410 *args: str, 4411 interval: float = 0.0, 4412 wait: float = 0.0, 4413 logScreenshot: None = None, 4414 _pause: bool = True, 4415 auto_shift: bool = True, 4416) -> None: 4417 """ 4418 Press down buttons in order they are specified as arguments, 4419 releasing them in reverse order, e.g. 'ctrl', 'c' will first press 4420 Control, then C and release C before releasing Control. 4421 4422 Use keyword-only argument `interval` to specify a delay between single 4423 keys when pressing and releasing and `wait` for delay between last press 4424 and first release. 4425 4426 If `_pause` is True (default), then an automatic sleep will be performed 4427 after the function finshes executing. The duration is set by the global 4428 variable `PAUSE`. 4429 Be aware, that the global pause defined by the PAUSE `constant` only 4430 applies after every call to this function, not inbetween (no pause between 4431 press and releasing key)! 4432 4433 `auto_shift` is used internally by higher level functions to automatically 4434 press the shift key before supported scancodes (indicitated by a special 4435 bit outside the regular scancode range, while it technically can be used, 4436 it's not intended for public access). 4437 4438 ---------------------------------------------------------------------------- 4439 4440 NOTE: `logScreenshot` is currently unsupported. 4441 """ 4442 apply_interval: bool = False 4443 for key in args: 4444 if apply_interval: 4445 _sleep(interval) # sleep between iterations 4446 apply_interval = True 4447 4448 keyDown(key, _pause=False, auto_shift=auto_shift) 4449 4450 _sleep(wait) 4451 4452 apply_interval = False 4453 for key in reversed(args): 4454 if apply_interval: 4455 _sleep(interval) # sleep between iterations 4456 apply_interval = True 4457 4458 keyUp(key, _pause=False, auto_shift=auto_shift) 4459 # -------------------------------------------------------------------------- 4460 4461 4462# ===== unicode functions ====================================================== 4463 4464 4465# ----- unicode_charDown ------------------------------------------------------- 4466@_genericPyDirectInputChecks 4467def unicode_charDown( 4468 char: str, logScreenshot: None = None, _pause: bool = True 4469) -> bool: 4470 """ 4471 Send Unicode character(s) `char` to currently focused application as 4472 WM_KEYDOWN message. 4473 4474 `char` will be interpreted as a string of Unicode characters 4475 (independet from keyboard layout). Supports complete Unicode character set 4476 but may not be compatible with every application. 4477 4478 If `_pause` is True (default), then an automatic sleep will be performed 4479 after the function finshes executing. The duration is set by the global 4480 variable `PAUSE`. 4481 4482 ---------------------------------------------------------------------------- 4483 4484 NOTE: `logScreenshot` is currently unsupported. 4485 """ 4486 utf16surrogates: bytes = char.encode("utf-16be") 4487 codes: Sequence[int] = unpack( 4488 f">{len(utf16surrogates) // 2}H", utf16surrogates 4489 ) 4490 4491 keybdFlags: int = _KEYEVENTF_UNICODE 4492 4493 input_structs: list[_INPUT] = [ 4494 _create_keyboard_input(wVk=0, wScan=charcode, dwFlags=keybdFlags) 4495 for charcode in codes 4496 ] 4497 # Init event tracking 4498 expectedEvents: int = len(input_structs) 4499 insertedEvents: int = _send_input(input_structs) 4500 4501 return insertedEvents == expectedEvents 4502 # -------------------------------------------------------------------------- 4503 4504 4505# ----- unicode_charUp --------------------------------------------------------- 4506@_genericPyDirectInputChecks 4507def unicode_charUp( 4508 char: str, logScreenshot: None = None, _pause: bool = True 4509) -> bool: 4510 """ 4511 Send Unicode character(s) `char` to currently focused application as 4512 WM_KEYUP message. 4513 4514 `char` will be interpreted as a string of Unicode characters 4515 (independet from keyboard layout). Supports complete Unicode character set 4516 but may not be compatible with every application. 4517 4518 If `_pause` is True (default), then an automatic sleep will be performed 4519 after the function finshes executing. The duration is set by the global 4520 variable `PAUSE`. 4521 4522 ---------------------------------------------------------------------------- 4523 4524 NOTE: `logScreenshot` is currently unsupported. 4525 """ 4526 utf16surrogates: bytes = char.encode("utf-16be") 4527 codes: Sequence[int] = unpack( 4528 f">{len(utf16surrogates) // 2}H", utf16surrogates 4529 ) 4530 4531 keybdFlags: int = _KEYEVENTF_UNICODE | _KEYEVENTF_KEYUP 4532 4533 input_structs: list[_INPUT] = [ 4534 _create_keyboard_input(wVk=0, wScan=charcode, dwFlags=keybdFlags) 4535 for charcode in codes 4536 ] 4537 # Init event tracking 4538 expectedEvents: int = len(input_structs) 4539 insertedEvents: int = _send_input(input_structs) 4540 4541 return insertedEvents == expectedEvents 4542 # -------------------------------------------------------------------------- 4543 4544 4545# ----- _helper_unicode_press_char --------------------------------------------- 4546def _helper_unicode_press_char( 4547 char: str, 4548 duration: float = 0.0, 4549 _pause: bool = True, 4550) -> bool: 4551 """ 4552 Press `key`, wait for `duration` seconds, release `key`. 4553 4554 Return `True` if complete press was successful. 4555 """ 4556 downed: bool = unicode_charDown(char, _pause=_pause) 4557 _sleep(duration) 4558 upped: bool = unicode_charUp(char, _pause=_pause) 4559 # Count key press as complete if key was "downed" and "upped" 4560 # successfully 4561 return bool(downed and upped) 4562 # -------------------------------------------------------------------------- 4563 4564 4565# ----- unicode_press ---------------------------------------------------------- 4566@_genericPyDirectInputChecks 4567def unicode_press( 4568 chars: str | Sequence[str], 4569 presses: int = 1, 4570 interval: float = 0.0, 4571 logScreenshot: None = None, 4572 _pause: bool = True, 4573 *, 4574 delay: float = 0.0, 4575 duration: float = 0.0, 4576) -> bool: 4577 """ 4578 Press the sequence of `chars` for `presses` amount of times. 4579 4580 `chars` will be interpreted as a sequence of Unicode characters 4581 (independent from keyboard layout). Supports complete Unicode character set 4582 but may not be compatible with every application. 4583 4584 Explanation of time parameters (seconds as floating point numbers): 4585 4586 - `interval` is the time spent waiting between sequences. If `chars` is a 4587 str instance or single element list, then `interval` will be ignored. 4588 - `delay` is the time from one complete char (press+release) to the next 4589 one in the same sequence. If there is only a single char in a sequence, 4590 then `delay` will be ignored. 4591 - `duration` is the time spent on holding every char before releasing it 4592 again. 4593 4594 If `_pause` is True (default), then an automatic sleep will be performed 4595 after the function finshes executing. The duration is set by the global 4596 variable `PAUSE`. 4597 Be aware, that the global pause defined by the PAUSE `constant` only 4598 applies after every call to this function, not inbetween (no extra pause 4599 between pressing and releasing key, use the `duration` argument instead)! 4600 4601 ---------------------------------------------------------------------------- 4602 4603 NOTE: `logScreenshot` is currently unsupported. 4604 """ 4605 if isinstance(chars, str): 4606 chars = [chars] 4607 4608 # We need to press x keys y times, which comes out to x*y presses in total 4609 expectedPresses: int = presses * len(chars) 4610 completedPresses: int = 0 4611 4612 apply_interval: bool = False 4613 for _ in range(presses): 4614 if apply_interval: # Don't delay first press 4615 _sleep(interval) 4616 apply_interval = True 4617 4618 apply_delay: bool = False 4619 for c in chars: 4620 if apply_delay: # Don't delay first press 4621 _sleep(delay) 4622 apply_delay = True 4623 4624 completedPresses += _helper_unicode_press_char( 4625 c, 4626 duration, 4627 _pause=False, 4628 ) 4629 4630 return completedPresses == expectedPresses 4631 # -------------------------------------------------------------------------- 4632 4633 4634# ----- unicode_hold ----------------------------------------------------------- 4635@contextmanager 4636@_genericPyDirectInputChecks 4637def unicode_hold( 4638 chars: str | Sequence[str], 4639 logScreenshot: None = None, 4640 _pause: bool = True, 4641 *, 4642 raise_on_failure: bool = False, 4643) -> Generator[None, None, None]: 4644 """ 4645 Hold the sequence of "keys" corresponding to unicode characters in `chars` 4646 as long as the context manager is in scope (press upon entry, 4647 release upon exit). 4648 4649 `chars` will be interpreted as a sequence of Unicode characters 4650 (independet from keyboard layout). Supports complete Unicode character set 4651 but may not be compatible with every application. 4652 4653 Keys will be released in reverse order (LIFO), but still practically 4654 instantenous. 4655 4656 If `_pause` is True (default), then an automatic sleep will be performed 4657 after the function finshes executing. The duration is set by the global 4658 variable `PAUSE`. 4659 Be aware, that the global pause defined by the PAUSE `constant` only 4660 applies after every call to this function, not inbetween (no pause between 4661 press and releasing key)! 4662 4663 If `raise_on_failure` is True, then `PriorInputFailedException` will be 4664 raised if not all keyboard inputs could be executed successfully. 4665 4666 ---------------------------------------------------------------------------- 4667 4668 NOTE: `logScreenshot` is currently unsupported. 4669 """ 4670 if isinstance(chars, str): 4671 chars = [chars] # make single element into iterable 4672 4673 expectedPresses: int = len(chars) 4674 downed: int = 0 4675 upped: int = 0 4676 4677 try: 4678 for c in chars: 4679 downed += unicode_charDown(c, _pause=False) 4680 yield 4681 finally: 4682 for c in reversed(chars): 4683 upped += unicode_charUp(c, _pause=False) 4684 if raise_on_failure and not (expectedPresses == downed == upped): 4685 raise PriorInputFailedException 4686 # -------------------------------------------------------------------------- 4687 4688 4689# ----- unicode_typewrite ------------------------------------------------------ 4690@_genericPyDirectInputChecks 4691def unicode_typewrite( 4692 message: str, 4693 interval: float = 0.0, 4694 logScreenshot: None = None, 4695 _pause: bool = True, 4696 *, 4697 delay: float = 0.0, 4698 duration: float = 0.0, 4699) -> None: 4700 """ 4701 Break down `message` into characters and press them one by one. 4702 4703 `message` will be interpreted as a sequence of Unicode characters 4704 (independet from keyboard layout). Supports complete Unicode character set 4705 but may not be compatible with every application. 4706 4707 Explanation of time parameters (seconds as floating point numbers): 4708 4709 - `interval` is the time spent waiting between sequences. If `message` is a 4710 single character string, then `interval` will be ignored. 4711 - `delay` is the time from one complete key (press+release) to the next one 4712 in the same sequence. If there is only a single key in a sequence, then 4713 `delay` will be ignored. 4714 - `duration` is the time spent on holding every key before releasing it 4715 again. 4716 4717 If `_pause` is True (default), then an automatic sleep will be performed 4718 after the function finshes executing. The duration is set by the global 4719 variable `PAUSE`. 4720 Be aware, that the global pause defined by the PAUSE `constant` only 4721 applies after every call to this function, not inbetween (no pause between 4722 press and releasing key)! 4723 4724 ---------------------------------------------------------------------------- 4725 4726 NOTE: `logScreenshot` is currently unsupported. 4727 """ 4728 apply_interval: bool = False 4729 for char in message: 4730 if apply_interval: 4731 _sleep(interval) # sleep between iterations 4732 apply_interval = True 4733 4734 unicode_press(char, _pause=False, delay=delay, duration=duration) 4735 # -------------------------------------------------------------------------- 4736 4737 4738# ----- unicode_typewrite alias ------------------------------------------------ 4739unicode_write = unicode_typewrite 4740# ------------------------------------------------------------------------------ 4741 4742 4743# ----- unicode_hotkey --------------------------------------------------------- 4744@_genericPyDirectInputChecks 4745def unicode_hotkey( 4746 *args: str, 4747 interval: float = 0.0, 4748 wait: float = 0.0, 4749 logScreenshot: None = None, 4750 _pause: bool = True, 4751) -> None: 4752 """ 4753 Press down buttons in order they are specified as arguments, 4754 releasing them in reverse order. 4755 4756 This function makes little sense for Unicode characters and mainly exists 4757 for parity with the other, lower-level hotkey functions! 4758 4759 See `unicode_press()` for an alternative function that presses keys in 4760 series instead. 4761 4762 Use keyword-only argument `interval` to specify a delay between single 4763 keys when pressing and releasing and `wait` for delay between last press 4764 and first release. 4765 4766 If `_pause` is True (default), then an automatic sleep will be performed 4767 after the function finshes executing. The duration is set by the global 4768 variable `PAUSE`. 4769 Be aware, that the global pause defined by the PAUSE `constant` only 4770 applies after every call to this function, not inbetween (no pause between 4771 press and releasing key)! 4772 4773 ---------------------------------------------------------------------------- 4774 4775 NOTE: `logScreenshot` is currently unsupported. 4776 """ 4777 apply_interval: bool = False 4778 for char in args: 4779 if apply_interval: 4780 _sleep(interval) # sleep between iterations 4781 apply_interval = True 4782 4783 unicode_charDown(char, _pause=False) 4784 4785 _sleep(wait) 4786 4787 apply_interval = False 4788 for char in reversed(args): 4789 if apply_interval: 4790 _sleep(interval) # sleep between iterations 4791 apply_interval = True 4792 4793 unicode_charUp(char, _pause=False) 4794 # -------------------------------------------------------------------------- 4795 4796 4797# ------------------------------------------------------------------------------ 4798# Save current Enhanced Pointer Precsion setting during import 4799# unless disabled by environment variable. 4800# Since this is a safety feature, this import side-effect is enabled by default. 4801if not os.environ.get("PYDIRECTINPUT_SKIP_STORING_MOUSE_SETTINGS"): 4802 store_mouse_acceleration_settings() 4803# ------------------------------------------------------------------------------
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!
1544class ScancodeSequence(List[int]): 1545 """ 1546 A special class with the sole purpose of representing extended scancode 1547 sequences that should be grouped together in a single INPUT array. 1548 1549 Inserting non-scancode elements is illegal, but no runtime checks exist 1550 to verify correct input! Violations could lead to unpredictable runtime 1551 behaviour. You've been warned. 1552 """ 1553 1554 pass 1555 # --------------------------------------------------------------------------
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.
Inherited Members
- builtins.list
- list
- clear
- copy
- append
- insert
- extend
- pop
- remove
- index
- count
- reverse
- sort
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.
1852class FailSafeException(Exception): 1853 """Raised when _failSafeCheck detects failsafe mouse position.""" 1854 1855 pass
Raised when _failSafeCheck detects failsafe mouse position.
Inherited Members
- builtins.Exception
- Exception
- builtins.BaseException
- with_traceback
- add_note
- args
1858class PriorInputFailedException(Exception): 1859 """Raised in hold() context managers when raise_on_failure is set.""" 1860 1861 pass 1862 # --------------------------------------------------------------------------
Raised in hold() context managers when raise_on_failure is set.
Inherited Members
- builtins.Exception
- Exception
- builtins.BaseException
- with_traceback
- add_note
- args
2066def position( 2067 x: int | float | None = None, y: int | float | None = None 2068) -> tuple[int, int]: 2069 """ 2070 Return a postion tuple `(x, y)`. 2071 2072 If x and/or y argument(s) are not given, use current mouse cursor coordinate 2073 instead. 2074 """ 2075 cursor: _POINT = _get_cursor_pos() 2076 return ( 2077 cursor.x if x is None else int(x), 2078 cursor.y if y is None else int(y), 2079 ) 2080 # --------------------------------------------------------------------------
Return a postion tuple (x, y)
.
If x and/or y argument(s) are not given, use current mouse cursor coordinate instead.
2084def size() -> tuple[int, int]: 2085 """ 2086 Return the size of the primary display as tuple `(width, height)`. 2087 """ 2088 return ( 2089 _get_system_metrics(_SM_CXSCREEN), 2090 _get_system_metrics(_SM_CYSCREEN), 2091 ) 2092 # --------------------------------------------------------------------------
Return the size of the primary display as tuple (width, height)
.
2096def virtual_size() -> tuple[int, int, int, int]: 2097 """ 2098 Return the the display size of the complete virtual monitor bounding box 2099 rectangle as tuple `(width, height, left_offset, top_offset)`. 2100 2101 On a single monitor system, this function is equal to `(*size(), 0, 0)`. 2102 2103 `left_offset` and `top_offset` are measured from the top left pixel of the 2104 primary monitor. 2105 """ 2106 return ( 2107 _get_system_metrics(_SM_CXVIRTUALSCREEN), 2108 _get_system_metrics(_SM_CYVIRTUALSCREEN), 2109 _get_system_metrics(_SM_XVIRTUALSCREEN), 2110 _get_system_metrics(_SM_YVIRTUALSCREEN), 2111 ) 2112 # --------------------------------------------------------------------------
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.
2126def on_primary_monitor( 2127 x: int | tuple[int, int] | None = None, y: int | None = None 2128) -> bool: 2129 """ 2130 Returns whether the given xy coordinates are on the primary screen or not. 2131 2132 If x and/or y argument(s) are not given, current mouse cursor coordinates 2133 will be used instead. 2134 """ 2135 if isinstance(x, Sequence): 2136 assert not isinstance(x, int) # remove int annotation, mypy needs this 2137 if y is not None: 2138 raise ValueError( 2139 "onScreen() does not accept Sequence-types as first argument " 2140 "if a second argument is also provided!" 2141 ) 2142 try: 2143 x, y = x[0], x[1] 2144 except IndexError as e: 2145 raise ValueError( 2146 "onScreen() does not accept single element sequences " 2147 "as first argument!" 2148 ) from e 2149 2150 x, y = position(x, y) 2151 display_width: int 2152 display_height: int 2153 display_width, display_height = size() 2154 2155 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.
2126def on_primary_monitor( 2127 x: int | tuple[int, int] | None = None, y: int | None = None 2128) -> bool: 2129 """ 2130 Returns whether the given xy coordinates are on the primary screen or not. 2131 2132 If x and/or y argument(s) are not given, current mouse cursor coordinates 2133 will be used instead. 2134 """ 2135 if isinstance(x, Sequence): 2136 assert not isinstance(x, int) # remove int annotation, mypy needs this 2137 if y is not None: 2138 raise ValueError( 2139 "onScreen() does not accept Sequence-types as first argument " 2140 "if a second argument is also provided!" 2141 ) 2142 try: 2143 x, y = x[0], x[1] 2144 except IndexError as e: 2145 raise ValueError( 2146 "onScreen() does not accept single element sequences " 2147 "as first argument!" 2148 ) from e 2149 2150 x, y = position(x, y) 2151 display_width: int 2152 display_height: int 2153 display_width, display_height = size() 2154 2155 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.
2176def valid_screen_coordinates( 2177 x: int | tuple[int, int] | None = None, y: int | None = None 2178) -> bool: 2179 """ 2180 Returns whether the given xy coordinates are on a real monitor or not. 2181 2182 If x and/or y argument(s) are not given, current mouse cursor coordinates 2183 will be used instead. 2184 """ 2185 if isinstance(x, Sequence): 2186 assert not isinstance(x, int) # remove int annotation, mypy needs this 2187 if y is not None: 2188 raise ValueError( 2189 "onScreen() does not accept Sequence-types as first argument " 2190 "if a second argument is also provided!" 2191 ) 2192 try: 2193 x, y = x[0], x[1] 2194 except IndexError as e: 2195 raise ValueError( 2196 "onScreen() does not accept single element sequences " 2197 "as first argument!" 2198 ) from e 2199 2200 x, y = position(x, y) 2201 return _monitor_from_point(x, y) is not None 2202 # --------------------------------------------------------------------------
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.
2339def store_mouse_acceleration_settings() -> None: 2340 """ 2341 Manually save the current Windows Enhanced Pointer Precision setting so 2342 that it can be restored later with `restore_mouse_acceleration_settings()`. 2343 """ 2344 precision: int 2345 _, _, precision = _get_mouse_parameters() 2346 speed: int = _get_mouse_speed() 2347 __MouseSpeedSettings.set_manual_mouse_settings(precision, speed) 2348 # --------------------------------------------------------------------------
Manually save the current Windows Enhanced Pointer Precision setting so
that it can be restored later with restore_mouse_acceleration_settings()
.
2352def restore_mouse_acceleration_settings() -> None: 2353 """ 2354 Manually restore the current Windows Enhanced Pointer Precision setting to 2355 what it was beforehand when it was saved with 2356 `store_mouse_acceleration_settings()`. 2357 """ 2358 precision: int | None 2359 speed: int | None 2360 precision, speed = __MouseSpeedSettings.get_manual_mouse_settings() 2361 if precision is None or speed is None: 2362 raise ValueError( 2363 "Can't restore Enhanced Pointer Precision setting! " 2364 "Setting was not saved beforehand!" 2365 ) 2366 th1: int 2367 th2: int 2368 th1, th2, _ = _get_mouse_parameters() 2369 _set_mouse_parameters(th1, th2, precision) 2370 _set_mouse_speed(speed) 2371 # --------------------------------------------------------------------------
Manually restore the current Windows Enhanced Pointer Precision setting to
what it was beforehand when it was saved with
store_mouse_acceleration_settings()
.
2380@_genericPyDirectInputChecks 2381def mouseDown( 2382 x: int | None = None, 2383 y: int | None = None, 2384 button: str = MOUSE_PRIMARY, 2385 duration: float = 0.0, 2386 tween: Callable[[float], float] | None = None, 2387 logScreenshot: bool = False, 2388 _pause: bool = True, 2389 *, 2390 relative: bool = False, 2391 virtual: bool = False, 2392 path_function: PathFunction | None = None, 2393 attempt_pixel_perfect: bool = False, 2394 disable_mouse_acceleration: bool = False, 2395) -> None: 2396 """ 2397 Press down mouse button `button`. 2398 2399 If `x` or `y` are given and not None, then the mouse will move the 2400 indicated postion before pressing the button. 2401 2402 `button` is the name of the button to press. Use the public `MOUSE_*` 2403 constants to get valid argument values. (If you change the constants, then 2404 you will have to call `update_MOUSEEVENT_mappings()` to resync the lookup 2405 functions) 2406 2407 If `_pause` is True (default), then an automatic sleep will be performed 2408 after the function finshes executing. The duration is set by the global 2409 variable `PAUSE`. 2410 2411 `duration`, `tween`, `relative`, `virtual`, `path_function`, 2412 `attempt_pixel_perfect`, `disable_mouse_acceleration` are only relevant 2413 if x or y are given. 2414 See `moveTo()` for further information. 2415 2416 Raises `ValueError` if `button` is not a valid mouse button name. 2417 2418 ---------------------------------------------------------------------------- 2419 2420 NOTE: `logScreenshot` is currently unsupported. 2421 """ 2422 # TODO: bounding box check for valid position 2423 if x is not None or y is not None: 2424 moveTo( 2425 x, 2426 y, 2427 duration=duration, 2428 tween=tween, 2429 logScreenshot=logScreenshot, 2430 _pause=False, # don't add an additional pause 2431 relative=relative, 2432 virtual=virtual, 2433 path_function=path_function, 2434 attempt_pixel_perfect=attempt_pixel_perfect, 2435 disable_mouse_acceleration=disable_mouse_acceleration, 2436 ) 2437 2438 event_value: int | None = None 2439 mouseData: int 2440 event_value, mouseData = _get_mouse_struct_data(button, _MOUSE_PRESS) 2441 2442 if not event_value: 2443 raise ValueError( 2444 f"Invalid button argument! " 2445 f'Expected "{MOUSE_LEFT}", "{MOUSE_RIGHT}", "{MOUSE_MIDDLE}", ' 2446 f'"{MOUSE_BUTTON4}", "{MOUSE_BUTTON5}", "{MOUSE_PRIMARY}" or ' 2447 f'"{MOUSE_SECONDARY}"; got "{button}" instead!' 2448 ) 2449 2450 _send_input(_create_mouse_input(mouseData=mouseData, dwFlags=event_value)) 2451 # --------------------------------------------------------------------------
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.
2455@_genericPyDirectInputChecks 2456def mouseUp( 2457 x: int | None = None, 2458 y: int | None = None, 2459 button: str = MOUSE_PRIMARY, 2460 duration: float = 0.0, 2461 tween: Callable[[float], float] | None = None, 2462 logScreenshot: bool = False, 2463 _pause: bool = True, 2464 *, 2465 relative: bool = False, 2466 virtual: bool = False, 2467 path_function: PathFunction | None = None, 2468 attempt_pixel_perfect: bool = False, 2469 disable_mouse_acceleration: bool = False, 2470) -> None: 2471 """ 2472 Lift up mouse button `button`. 2473 2474 If `x` or `y` are given and not None, then the mouse will move the 2475 indicated postion before lifting the button. 2476 2477 `button` is the name of the button to press. Use the public `MOUSE_*` 2478 constants to get valid argument values. (If you change the constants, then 2479 you will have to call `update_MOUSEEVENT_mappings()` to resync the lookup 2480 functions) 2481 2482 If `_pause` is True (default), then an automatic sleep will be performed 2483 after the function finshes executing. The duration is set by the global 2484 variable `PAUSE`. 2485 2486 `duration`, `tween`, `relative`, `virtual`, `path_function`, 2487 `attempt_pixel_perfect`, `disable_mouse_acceleration` are only relevant 2488 if x or y are given. 2489 See `moveTo()` for further information. 2490 2491 Raises `ValueError` if `button` is not a valid mouse button name. 2492 2493 ---------------------------------------------------------------------------- 2494 2495 NOTE: `logScreenshot` is currently unsupported. 2496 """ 2497 # TODO: bounding box check for valid position 2498 if x is not None or y is not None: 2499 moveTo( 2500 x, 2501 y, 2502 duration=duration, 2503 tween=tween, 2504 logScreenshot=logScreenshot, 2505 _pause=False, # don't add an additional pause 2506 relative=relative, 2507 virtual=virtual, 2508 path_function=path_function, 2509 attempt_pixel_perfect=attempt_pixel_perfect, 2510 disable_mouse_acceleration=disable_mouse_acceleration, 2511 ) 2512 2513 event_value: int | None = None 2514 mouseData: int 2515 event_value, mouseData = _get_mouse_struct_data(button, _MOUSE_RELEASE) 2516 2517 if not event_value: 2518 raise ValueError( 2519 "Invalid button argument! " 2520 f'Expected "{MOUSE_LEFT}", "{MOUSE_RIGHT}", "{MOUSE_MIDDLE}", ' 2521 f'"{MOUSE_BUTTON4}", "{MOUSE_BUTTON5}", "{MOUSE_PRIMARY}" or ' 2522 f'"{MOUSE_SECONDARY}"; got "{button}" instead!' 2523 ) 2524 2525 _send_input(_create_mouse_input(mouseData=mouseData, dwFlags=event_value)) 2526 # --------------------------------------------------------------------------
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.
2530@_genericPyDirectInputChecks 2531def click( 2532 x: int | None = None, 2533 y: int | None = None, 2534 clicks: int = 1, 2535 interval: float = 0.0, 2536 button: str = MOUSE_PRIMARY, 2537 duration: float = 0.0, 2538 tween: Callable[[float], float] | None = None, 2539 logScreenshot: bool = False, 2540 _pause: bool = True, 2541 *, 2542 relative: bool = False, 2543 virtual: bool = False, 2544 path_function: PathFunction | None = None, 2545 attempt_pixel_perfect: bool = False, 2546 disable_mouse_acceleration: bool = False, 2547) -> None: 2548 """ 2549 Click mouse button `button` (combining press down and lift up). 2550 2551 If `x` or `y` are given and not None, then the mouse will move the 2552 indicated postion before clicking the button. 2553 2554 `button` is the name of the button to press. Use the public `MOUSE_*` 2555 constants to get valid argument values. (If you change the constants, then 2556 you will have to call `update_MOUSEEVENT_mappings()` to resync the lookup 2557 functions) 2558 2559 `clicks` is an integer that determines the amount of times the button will 2560 be clicked. 2561 2562 `interval` is the wait time in seconds between clicks. 2563 2564 If `_pause` is True (default), then an automatic sleep will be performed 2565 after the function finshes executing. The duration is set by the global 2566 variable `PAUSE`. 2567 2568 `duration`, `tween`, `relative`, `virtual`, `path_function`, 2569 `attempt_pixel_perfect`, `disable_mouse_acceleration` are only relevant 2570 if x or y are given. 2571 See `moveTo()` for further information. 2572 2573 Raises `ValueError` if `button` is not a valid mouse button name. 2574 2575 ---------------------------------------------------------------------------- 2576 2577 NOTE: `logScreenshot` is currently unsupported. 2578 """ 2579 # TODO: bounding box check for valid position 2580 if x is not None or y is not None: 2581 moveTo( 2582 x, 2583 y, 2584 duration=duration, 2585 tween=tween, 2586 logScreenshot=logScreenshot, 2587 _pause=False, # don't add an additional pause 2588 relative=relative, 2589 virtual=virtual, 2590 path_function=path_function, 2591 attempt_pixel_perfect=attempt_pixel_perfect, 2592 disable_mouse_acceleration=disable_mouse_acceleration, 2593 ) 2594 2595 event_value: int | None = None 2596 mouseData: int 2597 event_value, mouseData = _get_mouse_struct_data(button, _MOUSE_CLICK) 2598 2599 if not event_value: 2600 raise ValueError( 2601 f"Invalid button argument! " 2602 f'Expected "{MOUSE_LEFT}", "{MOUSE_RIGHT}", "{MOUSE_MIDDLE}", ' 2603 f'"{MOUSE_BUTTON4}", "{MOUSE_BUTTON5}", "{MOUSE_PRIMARY}" or ' 2604 f'"{MOUSE_SECONDARY}"; got "{button}" instead!' 2605 ) 2606 2607 apply_interval: bool = False 2608 for _ in range(clicks): 2609 if apply_interval: # Don't delay first press 2610 _sleep(interval) 2611 apply_interval = True 2612 2613 _send_input( 2614 _create_mouse_input(mouseData=mouseData, dwFlags=event_value) 2615 ) 2616 # --------------------------------------------------------------------------
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.
2620def leftClick( 2621 x: int | None = None, 2622 y: int | None = None, 2623 interval: float = 0.0, 2624 duration: float = 0.0, 2625 tween: Callable[[float], float] | None = None, 2626 logScreenshot: bool = False, 2627 _pause: bool = True, 2628 *, 2629 relative: bool = False, 2630 virtual: bool = False, 2631 path_function: PathFunction | None = None, 2632 attempt_pixel_perfect: bool = False, 2633 disable_mouse_acceleration: bool = False, 2634) -> None: 2635 """ 2636 Click Left Mouse button. 2637 2638 See `click()` for more information 2639 """ 2640 click( 2641 x, 2642 y, 2643 clicks=1, 2644 interval=interval, 2645 button=MOUSE_LEFT, 2646 duration=duration, 2647 tween=tween, 2648 logScreenshot=logScreenshot, 2649 _pause=_pause, # Keep _pause since this function has no input checks 2650 relative=relative, 2651 virtual=virtual, 2652 path_function=path_function, 2653 attempt_pixel_perfect=attempt_pixel_perfect, 2654 disable_mouse_acceleration=disable_mouse_acceleration, 2655 ) 2656 # --------------------------------------------------------------------------
Click Left Mouse button.
See click()
for more information
2660def rightClick( 2661 x: int | None = None, 2662 y: int | None = None, 2663 interval: float = 0.0, 2664 duration: float = 0.0, 2665 tween: Callable[[float], float] | None = None, 2666 logScreenshot: bool = False, 2667 _pause: bool = True, 2668 *, 2669 relative: bool = False, 2670 virtual: bool = False, 2671 path_function: PathFunction | None = None, 2672 attempt_pixel_perfect: bool = False, 2673 disable_mouse_acceleration: bool = False, 2674) -> None: 2675 """ 2676 Click Right Mouse button. 2677 2678 See `click()` for more information 2679 """ 2680 click( 2681 x, 2682 y, 2683 clicks=1, 2684 interval=interval, 2685 button=MOUSE_RIGHT, 2686 duration=duration, 2687 tween=tween, 2688 logScreenshot=logScreenshot, 2689 _pause=_pause, # Keep _pause since this function has no input checks 2690 relative=relative, 2691 virtual=virtual, 2692 path_function=path_function, 2693 attempt_pixel_perfect=attempt_pixel_perfect, 2694 disable_mouse_acceleration=disable_mouse_acceleration, 2695 ) 2696 # --------------------------------------------------------------------------
Click Right Mouse button.
See click()
for more information
2700def middleClick( 2701 x: int | None = None, 2702 y: int | None = None, 2703 interval: float = 0.0, 2704 duration: float = 0.0, 2705 tween: Callable[[float], float] | None = None, 2706 logScreenshot: bool = False, 2707 _pause: bool = True, 2708 *, 2709 relative: bool = False, 2710 virtual: bool = False, 2711 path_function: PathFunction | None = None, 2712 attempt_pixel_perfect: bool = False, 2713 disable_mouse_acceleration: bool = False, 2714) -> None: 2715 """ 2716 Click Middle Mouse button. 2717 2718 See `click()` for more information 2719 """ 2720 click( 2721 x, 2722 y, 2723 clicks=1, 2724 interval=interval, 2725 button=MOUSE_MIDDLE, 2726 duration=duration, 2727 tween=tween, 2728 logScreenshot=logScreenshot, 2729 _pause=_pause, # Keep _pause since this function has no input checks 2730 relative=relative, 2731 virtual=virtual, 2732 path_function=path_function, 2733 attempt_pixel_perfect=attempt_pixel_perfect, 2734 disable_mouse_acceleration=disable_mouse_acceleration, 2735 ) 2736 # --------------------------------------------------------------------------
Click Middle Mouse button.
See click()
for more information
2740def doubleClick( 2741 x: int | None = None, 2742 y: int | None = None, 2743 interval: float = 0.0, 2744 button: str = MOUSE_LEFT, 2745 duration: float = 0.0, 2746 tween: Callable[[float], float] | None = None, 2747 logScreenshot: bool = False, 2748 _pause: bool = True, 2749 *, 2750 relative: bool = False, 2751 virtual: bool = False, 2752 path_function: PathFunction | None = None, 2753 attempt_pixel_perfect: bool = False, 2754 disable_mouse_acceleration: bool = False, 2755) -> None: 2756 """ 2757 Double click `button`. 2758 2759 See `click()` for more information 2760 """ 2761 click( 2762 x, 2763 y, 2764 clicks=2, 2765 interval=interval, 2766 button=button, 2767 duration=duration, 2768 tween=tween, 2769 logScreenshot=logScreenshot, 2770 _pause=_pause, # Keep _pause since this function has no input checks 2771 relative=relative, 2772 virtual=virtual, 2773 path_function=path_function, 2774 attempt_pixel_perfect=attempt_pixel_perfect, 2775 disable_mouse_acceleration=disable_mouse_acceleration, 2776 ) 2777 # --------------------------------------------------------------------------
Double click button
.
See click()
for more information
2781def tripleClick( 2782 x: int | None = None, 2783 y: int | None = None, 2784 interval: float = 0.0, 2785 button: str = MOUSE_LEFT, 2786 duration: float = 0.0, 2787 tween: Callable[[float], float] | None = None, 2788 logScreenshot: bool = False, 2789 _pause: bool = True, 2790 *, 2791 relative: bool = False, 2792 virtual: bool = False, 2793 path_function: PathFunction | None = None, 2794 attempt_pixel_perfect: bool = False, 2795 disable_mouse_acceleration: bool = False, 2796) -> None: 2797 """ 2798 Triple click `button`. 2799 2800 See `click()` for more information 2801 """ 2802 click( 2803 x, 2804 y, 2805 clicks=3, 2806 interval=interval, 2807 button=button, 2808 duration=duration, 2809 tween=tween, 2810 logScreenshot=logScreenshot, 2811 _pause=_pause, # Keep _pause since this function has no input checks 2812 relative=relative, 2813 virtual=virtual, 2814 path_function=path_function, 2815 attempt_pixel_perfect=attempt_pixel_perfect, 2816 disable_mouse_acceleration=disable_mouse_acceleration, 2817 ) 2818 # --------------------------------------------------------------------------
Triple click button
.
See click()
for more information
2824@_genericPyDirectInputChecks 2825def scroll( 2826 clicks: int = 0, 2827 x: Any = None, # x and y do absolutely nothing, still keeping the arguments 2828 y: Any = None, # to stay consistent with PyAutoGUI. 2829 logScreenshot: bool = False, 2830 _pause: bool = True, 2831 *, 2832 interval: float = 0.0, 2833) -> None: 2834 """ 2835 Vertically scroll mouse `clicks` number of times, waiting `interval` 2836 seconds between every scroll. 2837 2838 Negative values of `clicks` will scroll down, postive values will scroll 2839 up. 2840 2841 `x` and `y` are intentionally ignored and only exists to keep the call 2842 signature backwards-compatible with PyAutoGui. 2843 If you need to change the mouse position before scrolling use one of the 2844 `move()` functions. 2845 2846 If `_pause` is True (default), then an automatic sleep will be performed 2847 after the function finshes executing. The duration is set by the global 2848 variable `PAUSE`. 2849 2850 ---------------------------------------------------------------------------- 2851 2852 NOTE: `logScreenshot` is currently unsupported. 2853 """ 2854 direction: Literal[-1, 1] 2855 if clicks >= 0: 2856 direction = 1 2857 else: 2858 direction = -1 2859 clicks = abs(clicks) 2860 2861 apply_interval: bool = False 2862 for _ in range(clicks): 2863 if apply_interval: 2864 _sleep(interval) 2865 apply_interval = True 2866 2867 _send_input( 2868 _create_mouse_input( 2869 mouseData=(direction * _WHEEL_DELTA), dwFlags=_MOUSEEVENTF_WHEEL 2870 ) 2871 ) 2872 # --------------------------------------------------------------------------
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.
2876@_genericPyDirectInputChecks 2877def hscroll( 2878 clicks: int = 0, 2879 x: Any = None, # x and y do absolutely nothing, still keeping the arguments 2880 y: Any = None, # to stay consistent with PyAutoGUI. 2881 logScreenshot: bool = False, 2882 _pause: bool = True, 2883 *, 2884 interval: float = 0.0, 2885) -> None: 2886 """ 2887 Horizontally scroll mouse `clicks` number of times, waiting `interval` 2888 seconds between every scroll. 2889 2890 Negative values of `clicks` will scroll left, postive values will scroll 2891 right. 2892 2893 `x` and `y` are intentionally ignored and only exists to keep the call 2894 signature backwards-compatible with PyAutoGui. 2895 If you need to change the mouse position before scrolling use one of the 2896 `move()` functions. 2897 2898 If `_pause` is True (default), then an automatic sleep will be performed 2899 after the function finshes executing. The duration is set by the global 2900 variable `PAUSE`. 2901 2902 ---------------------------------------------------------------------------- 2903 2904 NOTE: `logScreenshot` is currently unsupported. 2905 """ 2906 direction: Literal[-1, 1] 2907 if clicks >= 0: 2908 direction = 1 2909 else: 2910 direction = -1 2911 clicks = abs(clicks) 2912 2913 apply_interval: bool = False 2914 for _ in range(clicks): 2915 if apply_interval: 2916 _sleep(interval) 2917 apply_interval = True 2918 2919 _send_input( 2920 _create_mouse_input( 2921 mouseData=(direction * _WHEEL_DELTA), 2922 dwFlags=_MOUSEEVENTF_HWHEEL, 2923 ) 2924 ) 2925 # --------------------------------------------------------------------------
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.
2824@_genericPyDirectInputChecks 2825def scroll( 2826 clicks: int = 0, 2827 x: Any = None, # x and y do absolutely nothing, still keeping the arguments 2828 y: Any = None, # to stay consistent with PyAutoGUI. 2829 logScreenshot: bool = False, 2830 _pause: bool = True, 2831 *, 2832 interval: float = 0.0, 2833) -> None: 2834 """ 2835 Vertically scroll mouse `clicks` number of times, waiting `interval` 2836 seconds between every scroll. 2837 2838 Negative values of `clicks` will scroll down, postive values will scroll 2839 up. 2840 2841 `x` and `y` are intentionally ignored and only exists to keep the call 2842 signature backwards-compatible with PyAutoGui. 2843 If you need to change the mouse position before scrolling use one of the 2844 `move()` functions. 2845 2846 If `_pause` is True (default), then an automatic sleep will be performed 2847 after the function finshes executing. The duration is set by the global 2848 variable `PAUSE`. 2849 2850 ---------------------------------------------------------------------------- 2851 2852 NOTE: `logScreenshot` is currently unsupported. 2853 """ 2854 direction: Literal[-1, 1] 2855 if clicks >= 0: 2856 direction = 1 2857 else: 2858 direction = -1 2859 clicks = abs(clicks) 2860 2861 apply_interval: bool = False 2862 for _ in range(clicks): 2863 if apply_interval: 2864 _sleep(interval) 2865 apply_interval = True 2866 2867 _send_input( 2868 _create_mouse_input( 2869 mouseData=(direction * _WHEEL_DELTA), dwFlags=_MOUSEEVENTF_WHEEL 2870 ) 2871 ) 2872 # --------------------------------------------------------------------------
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.
3338@_genericPyDirectInputChecks 3339def moveTo( 3340 x: int | None = None, 3341 y: int | None = None, 3342 duration: float = 0.0, 3343 tween: Callable[[float], float] | None = None, 3344 logScreenshot: bool = False, 3345 _pause: bool = True, 3346 relative: bool = False, 3347 *, 3348 virtual: bool = False, 3349 path_function: PathFunction | None = None, 3350 attempt_pixel_perfect: bool = False, 3351 disable_mouse_acceleration: bool = False, 3352) -> None: 3353 """ 3354 Move the mouse to an absolute(*) postion indicated by the arguments of 3355 `x` and `y`. The coordinates 0,0 represent the top left pixel of the 3356 primary monitor. 3357 3358 If `duration` is floating point number greater than 0, then this function 3359 will automatically split the movement into microsteps instead of moving 3360 straight to the target position. 3361 3362 `tween` is a function that takes a floating point number between 0.0 and 3363 1.0 and returns another floating point number between 0.0 and 1.0. The 3364 returned number will be used to calculate the next position of the 3365 mouse between the start and the end position based on the current duration. 3366 The default tweening function is linear, which will move the mouse at a 3367 constant speed. See the `pytweening` package for more tweening functions. 3368 3369 `path_function` is a function that takes the start and end coordinates of 3370 the mouse movement (4 integers) and returns a list of coordinates (list of 3371 tuples containting 2 integers each) that the mouse will move through. 3372 The default path function is Bresenham's line algorithm, which will move 3373 the mouse in a straight line. 3374 3375 (*) `relative` parameter decides how the movement is executed: 3376 3377 -> `False`: Target postion is given and absolute movement is used. 3378 3379 -> `True`: Calculates target offset and uses relative movement API 3380 (can be inconsistent) 3381 3382 If `_pause` is True (default), then an automatic sleep will be performed 3383 after the function finshes executing. The duration is set by the global 3384 variable `PAUSE`. 3385 3386 Setting `virtual` to True (default: False) changes the way internal APIs 3387 handle coordinates and is intended for multi monitor systems. It should be 3388 pretty much unncessary even for multi monitor systems, since all the 3389 necessary internal calculations beyond the border of the primay monitor 3390 work without it. 3391 3392 The way that Windows calculates the target pixel coordinates internally 3393 unfortunately leads to inaccuracies and unreachable pixels, especially 3394 if the `virtual` option is used. 3395 3396 If you need the target position to be pixel perfect, you can try setting 3397 `attempt_pixel_perfect` to True, which will use tiny relative movements 3398 to correct the unreachable position. 3399 3400 Relative movement is influenced by mouse speed and Windows Enhanced Pointer 3401 Precision, which can be temporarily disabled by setting 3402 `disable_mouse_acceleration`. 3403 3404 ---------------------------------------------------------------------------- 3405 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 3406 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 3407 3408 If you you start a relative movement while another is already in progress 3409 than the second movement could overwrite the first setting and disable 3410 Enhanced Pointer Precision and change mouse speed. 3411 There are some measures in place to try to mitigate that risk, such as an 3412 internal counter that only allows storing and restoring the acceleration 3413 settings as long as no other movement is currently in progress. 3414 Additionally, the acceleration settings can be manually saved and 3415 restored with `store_mouse_acceleration_settings()` and 3416 `restore_mouse_acceleration_settings()`. For your convenience, the 3417 store function is automatically called during import to save your current 3418 setting. You can then call the restore function at any time. 3419 3420 If all fails, the setting is not written permanently to your Windows 3421 settings, so it should restore itself upon reboot. 3422 3423 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3424 this library in multiple threads / processes / programs at the same time! 3425 3426 ---------------------------------------------------------------------------- 3427 3428 NOTE: `logScreenshot` is currently unsupported. 3429 """ 3430 if relative: 3431 _relative_mouse_move( 3432 x=x, 3433 y=y, 3434 duration=duration, 3435 tween=tween, 3436 logScreenshot=logScreenshot, 3437 target_coords_relative=False, 3438 virtual=virtual, 3439 path_function=path_function, 3440 disable_mouse_acceleration=disable_mouse_acceleration, 3441 ) 3442 else: 3443 _absolute_mouse_move( 3444 x=x, 3445 y=y, 3446 duration=duration, 3447 tween=tween, 3448 logScreenshot=logScreenshot, 3449 target_coords_relative=False, 3450 virtual=virtual, 3451 path_function=path_function, 3452 attempt_pixel_perfect=attempt_pixel_perfect, 3453 disable_mouse_acceleration=disable_mouse_acceleration, 3454 ) 3455 # --------------------------------------------------------------------------
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.
3459@_genericPyDirectInputChecks 3460def moveRel( 3461 xOffset: int | None = None, 3462 yOffset: int | None = None, 3463 duration: float = 0.0, 3464 tween: Callable[[float], float] | None = None, 3465 logScreenshot: bool = False, 3466 _pause: bool = True, 3467 relative: bool = False, 3468 *, 3469 virtual: bool = False, 3470 path_function: PathFunction | None = None, 3471 attempt_pixel_perfect: bool = False, 3472 disable_mouse_acceleration: bool = False, 3473) -> None: 3474 """ 3475 Move the mouse a relative amount determined by `xOffset` and `yOffset`. 3476 3477 If `duration` is floating point number greater than 0, then this function 3478 will automatically split the movement into microsteps instead of moving the 3479 complete distance instantly. 3480 3481 `tween` is a function that takes a floating point number between 0.0 and 3482 1.0 and returns another floating point number between 0.0 and 1.0. The 3483 returned number will be used to calculate the next position of the 3484 mouse between the start and the end position based on the current duration. 3485 The default tweening function is linear, which will move the mouse at a 3486 constant speed. See the `pytweening` package for more tweening functions. 3487 3488 `path_function` is a function that takes the start and end coordinates of 3489 the mouse movement (4 integers) and returns a list of coordinates (list of 3490 tuples containting 2 integers each) that the mouse will move through. 3491 The default path function is Bresenham's line algorithm, which will move 3492 the mouse in a straight line. 3493 3494 `relative` parameter decides how the movement is executed: 3495 3496 -> `False`: Target postion is calculated and absolute movement is used. 3497 3498 -> `True`: Target offset is given and relative movement API is used 3499 (can be inconsistent) 3500 3501 The inconsistency issue can be solved by disabling Enhanced Pointer 3502 Precision and set Mouse speed to 10 in Windows mouse settings. Since users 3503 may not want to permanently change their input settings just for this 3504 library, the `disable_mouse_acceleration` argument can be used to 3505 temporarily disable Enhanced Pointer Precision and fix mouse speed at 10 3506 and restore it after the mouse movement. 3507 3508 If `_pause` is True (default), then an automatic sleep will be performed 3509 after the function finshes executing. The duration is set by the global 3510 variable `PAUSE`. 3511 3512 Setting `virtual` to True (default: False) changes the way internal APIs 3513 handle coordinates and is intended for multi monitor systems. It should be 3514 pretty much unncessary even for multi monitor systems, since all the 3515 necessary internal calculations beyond the border of the primay monitor 3516 work without it. 3517 3518 The way that Windows calculates the target pixel coordinates internally 3519 unfortunately leads to inaccuracies and unreachable pixels, especially 3520 if the `virtual` option is used. 3521 3522 If you need the target position to be pixel perfect, you can try setting 3523 `attempt_pixel_perfect` to True, which will use tiny relative movements 3524 to correct the unreachable position. 3525 3526 ---------------------------------------------------------------------------- 3527 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 3528 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 3529 3530 If you you start a relative movement while another is already in progress 3531 than the second movement could overwrite the first setting and disable 3532 Enhanced Pointer Precision and change mouse speed. 3533 There are some measures in place to try to mitigate that risk, such as an 3534 internal counter that only allows storing and restoring the acceleration 3535 settings as long as no other movement is currently in progress. 3536 Additionally, the acceleration settings can be manually saved and 3537 restored with `store_mouse_acceleration_settings()` and 3538 `restore_mouse_acceleration_settings()`. For your convinnience, the 3539 store function is automatically called during import to save your current 3540 setting. You can then call the restore function at any time. 3541 3542 If all fails, the setting is not written permanently to your Windows 3543 settings, so it should restore itself upon reboot. 3544 3545 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3546 this library in multiple threads / processes / programs at the same time! 3547 3548 ---------------------------------------------------------------------------- 3549 3550 NOTE: `logScreenshot` is are currently unsupported. 3551 """ 3552 if relative: 3553 _relative_mouse_move( 3554 x=xOffset, 3555 y=yOffset, 3556 duration=duration, 3557 tween=tween, 3558 logScreenshot=logScreenshot, 3559 target_coords_relative=True, 3560 virtual=virtual, 3561 path_function=path_function, 3562 disable_mouse_acceleration=disable_mouse_acceleration, 3563 ) 3564 else: 3565 _absolute_mouse_move( 3566 x=xOffset, 3567 y=yOffset, 3568 duration=duration, 3569 tween=tween, 3570 logScreenshot=logScreenshot, 3571 target_coords_relative=True, 3572 virtual=virtual, 3573 path_function=path_function, 3574 attempt_pixel_perfect=attempt_pixel_perfect, 3575 disable_mouse_acceleration=disable_mouse_acceleration, 3576 ) 3577 # --------------------------------------------------------------------------
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.
3459@_genericPyDirectInputChecks 3460def moveRel( 3461 xOffset: int | None = None, 3462 yOffset: int | None = None, 3463 duration: float = 0.0, 3464 tween: Callable[[float], float] | None = None, 3465 logScreenshot: bool = False, 3466 _pause: bool = True, 3467 relative: bool = False, 3468 *, 3469 virtual: bool = False, 3470 path_function: PathFunction | None = None, 3471 attempt_pixel_perfect: bool = False, 3472 disable_mouse_acceleration: bool = False, 3473) -> None: 3474 """ 3475 Move the mouse a relative amount determined by `xOffset` and `yOffset`. 3476 3477 If `duration` is floating point number greater than 0, then this function 3478 will automatically split the movement into microsteps instead of moving the 3479 complete distance instantly. 3480 3481 `tween` is a function that takes a floating point number between 0.0 and 3482 1.0 and returns another floating point number between 0.0 and 1.0. The 3483 returned number will be used to calculate the next position of the 3484 mouse between the start and the end position based on the current duration. 3485 The default tweening function is linear, which will move the mouse at a 3486 constant speed. See the `pytweening` package for more tweening functions. 3487 3488 `path_function` is a function that takes the start and end coordinates of 3489 the mouse movement (4 integers) and returns a list of coordinates (list of 3490 tuples containting 2 integers each) that the mouse will move through. 3491 The default path function is Bresenham's line algorithm, which will move 3492 the mouse in a straight line. 3493 3494 `relative` parameter decides how the movement is executed: 3495 3496 -> `False`: Target postion is calculated and absolute movement is used. 3497 3498 -> `True`: Target offset is given and relative movement API is used 3499 (can be inconsistent) 3500 3501 The inconsistency issue can be solved by disabling Enhanced Pointer 3502 Precision and set Mouse speed to 10 in Windows mouse settings. Since users 3503 may not want to permanently change their input settings just for this 3504 library, the `disable_mouse_acceleration` argument can be used to 3505 temporarily disable Enhanced Pointer Precision and fix mouse speed at 10 3506 and restore it after the mouse movement. 3507 3508 If `_pause` is True (default), then an automatic sleep will be performed 3509 after the function finshes executing. The duration is set by the global 3510 variable `PAUSE`. 3511 3512 Setting `virtual` to True (default: False) changes the way internal APIs 3513 handle coordinates and is intended for multi monitor systems. It should be 3514 pretty much unncessary even for multi monitor systems, since all the 3515 necessary internal calculations beyond the border of the primay monitor 3516 work without it. 3517 3518 The way that Windows calculates the target pixel coordinates internally 3519 unfortunately leads to inaccuracies and unreachable pixels, especially 3520 if the `virtual` option is used. 3521 3522 If you need the target position to be pixel perfect, you can try setting 3523 `attempt_pixel_perfect` to True, which will use tiny relative movements 3524 to correct the unreachable position. 3525 3526 ---------------------------------------------------------------------------- 3527 Careful! Disabling mouse acceleration settings is MAYBE thread-safe, 3528 NOT multiprocessing-safe, and DEFINITELY NOT independent processses safe! 3529 3530 If you you start a relative movement while another is already in progress 3531 than the second movement could overwrite the first setting and disable 3532 Enhanced Pointer Precision and change mouse speed. 3533 There are some measures in place to try to mitigate that risk, such as an 3534 internal counter that only allows storing and restoring the acceleration 3535 settings as long as no other movement is currently in progress. 3536 Additionally, the acceleration settings can be manually saved and 3537 restored with `store_mouse_acceleration_settings()` and 3538 `restore_mouse_acceleration_settings()`. For your convinnience, the 3539 store function is automatically called during import to save your current 3540 setting. You can then call the restore function at any time. 3541 3542 If all fails, the setting is not written permanently to your Windows 3543 settings, so it should restore itself upon reboot. 3544 3545 Bottom line: Don't use the `disable_mouse_acceleration` argument if you use 3546 this library in multiple threads / processes / programs at the same time! 3547 3548 ---------------------------------------------------------------------------- 3549 3550 NOTE: `logScreenshot` is are currently unsupported. 3551 """ 3552 if relative: 3553 _relative_mouse_move( 3554 x=xOffset, 3555 y=yOffset, 3556 duration=duration, 3557 tween=tween, 3558 logScreenshot=logScreenshot, 3559 target_coords_relative=True, 3560 virtual=virtual, 3561 path_function=path_function, 3562 disable_mouse_acceleration=disable_mouse_acceleration, 3563 ) 3564 else: 3565 _absolute_mouse_move( 3566 x=xOffset, 3567 y=yOffset, 3568 duration=duration, 3569 tween=tween, 3570 logScreenshot=logScreenshot, 3571 target_coords_relative=True, 3572 virtual=virtual, 3573 path_function=path_function, 3574 attempt_pixel_perfect=attempt_pixel_perfect, 3575 disable_mouse_acceleration=disable_mouse_acceleration, 3576 ) 3577 # --------------------------------------------------------------------------
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.
3587@_genericPyDirectInputChecks 3588def dragTo( 3589 x: int | None = None, 3590 y: int | None = None, 3591 duration: float = 0.0, 3592 tween: Callable[[float], float] | None = None, 3593 button: str | None = None, 3594 logScreenshot: bool = False, 3595 _pause: bool = True, 3596 mouseDownUp: bool = True, 3597 *, 3598 relative: bool = False, 3599 virtual: bool = False, 3600 path_function: PathFunction | None = None, 3601 attempt_pixel_perfect: bool = False, 3602 disable_mouse_acceleration: bool = False, 3603) -> None: 3604 """ 3605 Press and hold a mouse button while moving to the target coordinates. 3606 3607 See `moveTo` for more information on most arguments. 3608 3609 `button` is a string that is one of the following constants: 3610 MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, MOUSE_BUTTON4, MOUSE_BUTTON5, 3611 MOUSE_PRIMARY (default), MOUSE_SECONDARY. 3612 3613 If `mouseDownUp` (default: True) is manually set to False, then this 3614 function is basically the same as `moveTo`. Only exists to match PyAutoGUI. 3615 3616 If `_pause` is True (default), then an automatic sleep will be performed 3617 after the function finshes executing. The duration is set by the global 3618 variable `PAUSE`. 3619 3620 ---------------------------------------------------------------------------- 3621 3622 NOTE: `logScreenshot` is currently unsupported. 3623 """ 3624 # TODO: bounding box check for valid position 3625 if button is None: 3626 button = MOUSE_PRIMARY 3627 if mouseDownUp: 3628 mouseDown(button=button, _pause=False, virtual=virtual) 3629 moveTo( 3630 x, 3631 y, 3632 duration=duration, 3633 tween=tween, 3634 logScreenshot=logScreenshot, 3635 _pause=False, # don't add an additional pause 3636 relative=relative, 3637 virtual=virtual, 3638 path_function=path_function, 3639 attempt_pixel_perfect=attempt_pixel_perfect, 3640 disable_mouse_acceleration=disable_mouse_acceleration, 3641 ) 3642 if mouseDownUp: 3643 mouseUp(button=button, _pause=False, virtual=virtual) 3644 # --------------------------------------------------------------------------
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.
3648@_genericPyDirectInputChecks 3649def dragRel( 3650 xOffset: int | None = None, 3651 yOffset: int | None = None, 3652 duration: float = 0.0, 3653 tween: Callable[[float], float] | None = None, 3654 button: str | None = None, 3655 logScreenshot: bool = False, 3656 _pause: bool = True, 3657 mouseDownUp: bool = True, 3658 *, 3659 relative: bool = False, 3660 virtual: bool = False, 3661 path_function: PathFunction | None = None, 3662 disable_mouse_acceleration: bool = False, 3663) -> None: 3664 """ 3665 Press and hold a mouse button while moving a relative distance 3666 3667 See `moveRel` for more information on most arguments. 3668 3669 `button` is a string that is one of the following constants: 3670 MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, MOUSE_BUTTON4, MOUSE_BUTTON5, 3671 MOUSE_PRIMARY (default), MOUSE_SECONDARY. 3672 3673 If `mouseDownUp` (default: True) is manually set to False, then this 3674 function is basically the same as `moveTo`. Only exists to match PyAutoGUI. 3675 3676 If `_pause` is True (default), then an automatic sleep will be performed 3677 after the function finshes executing. The duration is set by the global 3678 variable `PAUSE`. 3679 3680 ---------------------------------------------------------------------------- 3681 3682 NOTE: `logScreenshot` is currently unsupported. 3683 """ 3684 # TODO: bounding box check for valid position 3685 if button is None: 3686 button = MOUSE_PRIMARY 3687 if mouseDownUp: 3688 mouseDown(button=button, _pause=False, virtual=virtual) 3689 moveRel( 3690 xOffset, 3691 yOffset, 3692 duration=duration, 3693 tween=tween, 3694 logScreenshot=logScreenshot, 3695 _pause=False, # don't add an additional pause 3696 relative=relative, 3697 virtual=virtual, 3698 path_function=path_function, 3699 disable_mouse_acceleration=disable_mouse_acceleration, 3700 ) 3701 if mouseDownUp: 3702 mouseUp(button=button, _pause=False, virtual=virtual) 3703 # --------------------------------------------------------------------------
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.
3648@_genericPyDirectInputChecks 3649def dragRel( 3650 xOffset: int | None = None, 3651 yOffset: int | None = None, 3652 duration: float = 0.0, 3653 tween: Callable[[float], float] | None = None, 3654 button: str | None = None, 3655 logScreenshot: bool = False, 3656 _pause: bool = True, 3657 mouseDownUp: bool = True, 3658 *, 3659 relative: bool = False, 3660 virtual: bool = False, 3661 path_function: PathFunction | None = None, 3662 disable_mouse_acceleration: bool = False, 3663) -> None: 3664 """ 3665 Press and hold a mouse button while moving a relative distance 3666 3667 See `moveRel` for more information on most arguments. 3668 3669 `button` is a string that is one of the following constants: 3670 MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE, MOUSE_BUTTON4, MOUSE_BUTTON5, 3671 MOUSE_PRIMARY (default), MOUSE_SECONDARY. 3672 3673 If `mouseDownUp` (default: True) is manually set to False, then this 3674 function is basically the same as `moveTo`. Only exists to match PyAutoGUI. 3675 3676 If `_pause` is True (default), then an automatic sleep will be performed 3677 after the function finshes executing. The duration is set by the global 3678 variable `PAUSE`. 3679 3680 ---------------------------------------------------------------------------- 3681 3682 NOTE: `logScreenshot` is currently unsupported. 3683 """ 3684 # TODO: bounding box check for valid position 3685 if button is None: 3686 button = MOUSE_PRIMARY 3687 if mouseDownUp: 3688 mouseDown(button=button, _pause=False, virtual=virtual) 3689 moveRel( 3690 xOffset, 3691 yOffset, 3692 duration=duration, 3693 tween=tween, 3694 logScreenshot=logScreenshot, 3695 _pause=False, # don't add an additional pause 3696 relative=relative, 3697 virtual=virtual, 3698 path_function=path_function, 3699 disable_mouse_acceleration=disable_mouse_acceleration, 3700 ) 3701 if mouseDownUp: 3702 mouseUp(button=button, _pause=False, virtual=virtual) 3703 # --------------------------------------------------------------------------
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.
3717def is_valid_key(key: str) -> bool: 3718 """ 3719 Returns true if key name `key` can be translated into a valid scan code. 3720 """ 3721 return key in KEYBOARD_MAPPING
Returns true if key name key
can be translated into a valid scan code.
3717def is_valid_key(key: str) -> bool: 3718 """ 3719 Returns true if key name `key` can be translated into a valid scan code. 3720 """ 3721 return key in KEYBOARD_MAPPING
Returns true if key name key
can be translated into a valid scan code.
3732@_genericPyDirectInputChecks 3733def scancode_keyDown( 3734 scancodes: ScancodeTypes, 3735 logScreenshot: None = None, 3736 _pause: bool = True, 3737 *, 3738 auto_shift: bool = False, 3739) -> bool: 3740 """ 3741 Press down key corresponding to `scancodes`. 3742 3743 The actually pressed key will depend on your system keyboard layout. 3744 Limits the available character set but should provide the best 3745 compatibility. 3746 3747 If `_pause` is True (default), then an automatic sleep will be performed 3748 after the function finshes executing. The duration is set by the global 3749 variable `PAUSE`. 3750 3751 `auto_shift` is used internally by higher level functions to automatically 3752 press the shift key before supported scancodes (indicitated by a special 3753 bit outside the regular scancode range, while it technically can be used, 3754 it's not intended for public access). 3755 3756 ---------------------------------------------------------------------------- 3757 3758 NOTE: `logScreenshot` is currently unsupported. 3759 """ 3760 scancodes_sequence: ScancodeSequence 3761 if isinstance(scancodes, int): 3762 scancodes_sequence = ScancodeSequence([scancodes]) 3763 else: 3764 scancodes_sequence = scancodes 3765 3766 keybdFlags: int = _KEYEVENTF_SCANCODE 3767 input_structs: list[_INPUT] = [] 3768 extendedFlag: int 3769 3770 # Init event tracking 3771 insertedEvents: int = 0 3772 expectedEvents: int = 0 3773 3774 for scancode in scancodes_sequence: 3775 if auto_shift and scancode & _OFFSET_SHIFTKEY: 3776 input_structs += [ 3777 _create_keyboard_input( 3778 wScan=_SHIFT_SCANCODE, dwFlags=keybdFlags 3779 ) 3780 ] 3781 expectedEvents += 1 3782 3783 scancode = scancode & 0xFFFF 3784 3785 extendedFlag = _KEYEVENTF_EXTENDEDKEY if scancode >= 0xE000 else 0 3786 input_structs += [ 3787 _create_keyboard_input( 3788 wScan=scancode, dwFlags=keybdFlags | extendedFlag 3789 ) 3790 ] 3791 expectedEvents += 1 3792 3793 insertedEvents += _send_input(input_structs) 3794 3795 # SendInput returns the number of event successfully inserted into 3796 # input stream 3797 # https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput#return-value 3798 return insertedEvents == expectedEvents 3799 # --------------------------------------------------------------------------
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.
3803@_genericPyDirectInputChecks 3804def scancode_keyUp( 3805 scancodes: ScancodeTypes, 3806 logScreenshot: None = None, 3807 _pause: bool = True, 3808 *, 3809 auto_shift: bool = False, 3810) -> bool: 3811 """ 3812 Release key corresponding to `scancodes`. 3813 3814 The actually pressed key will depend on your system keyboard layout. 3815 Limits the available character set but should provide the best 3816 compatibility. 3817 3818 If `_pause` is True (default), then an automatic sleep will be performed 3819 after the function finshes executing. The duration is set by the global 3820 variable `PAUSE`. 3821 3822 `auto_shift` is used internally by higher level functions to automatically 3823 press the shift key before supported scancodes (indicitated by a special 3824 bit outside the regular scancode range, while it technically can be used, 3825 it's not intended for public access). 3826 3827 ---------------------------------------------------------------------------- 3828 3829 NOTE: `logScreenshot` is currently unsupported. 3830 """ 3831 scancodes_sequence: ScancodeSequence 3832 if isinstance(scancodes, int): 3833 scancodes_sequence = ScancodeSequence([scancodes]) 3834 else: 3835 scancodes_sequence = scancodes 3836 3837 keybdFlags: int = _KEYEVENTF_SCANCODE | _KEYEVENTF_KEYUP 3838 input_structs: list[_INPUT] = [] 3839 extendedFlag: int 3840 3841 # Init event tracking 3842 insertedEvents: int = 0 3843 expectedEvents: int = 0 3844 3845 for scancode in scancodes_sequence: 3846 if auto_shift and scancode & _OFFSET_SHIFTKEY: 3847 input_structs += [ 3848 _create_keyboard_input( 3849 wScan=_SHIFT_SCANCODE, dwFlags=keybdFlags 3850 ) 3851 ] 3852 expectedEvents += 1 3853 3854 scancode = scancode & 0xFFFF 3855 3856 extendedFlag = _KEYEVENTF_EXTENDEDKEY if scancode >= 0xE000 else 0 3857 input_structs += [ 3858 _create_keyboard_input( 3859 wScan=scancode & 0xFFFF, dwFlags=keybdFlags | extendedFlag 3860 ) 3861 ] 3862 expectedEvents += 1 3863 3864 insertedEvents += _send_input(input_structs) 3865 return insertedEvents == expectedEvents 3866 # --------------------------------------------------------------------------
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.
3896@_genericPyDirectInputChecks 3897def scancode_press( 3898 scancodes: ScancodeTypes | Sequence[ScancodeTypes], 3899 presses: int = 1, 3900 interval: float = 0.0, 3901 logScreenshot: None = None, 3902 _pause: bool = True, 3903 *, 3904 auto_shift: bool = False, 3905 delay: float = 0.0, 3906 duration: float = 0.0, 3907) -> bool: 3908 """ 3909 Press the sequence of `keys` for `presses` amount of times. 3910 3911 The actually pressed key will depend on your system keyboard layout. 3912 Limits the available character set but should provide the best 3913 compatibility. 3914 3915 Explanation of time parameters (seconds as floating point numbers): 3916 3917 - `interval` is the time spent waiting between sequences. If `keys` is a 3918 str instance or single element list, then `interval` will be ignored. 3919 - `delay` is the time from one complete key (press+release) to the next one 3920 in the same sequence. If there is only a single key in a sequence, then 3921 `delay` will be ignored. 3922 - `duration` is the time spent on holding every key before releasing it 3923 again. 3924 3925 If `_pause` is True (default), then an automatic sleep will be performed 3926 after the function finshes executing. The duration is set by the global 3927 variable `PAUSE`. 3928 Be aware, that the global pause defined by the PAUSE `constant` only 3929 applies after every call to this function, not inbetween (no extra pause 3930 between pressing and releasing key, use the `duration` argument instead)! 3931 3932 `auto_shift` is used internally by higher level functions to automatically 3933 press the shift key before supported scancodes (indicitated by a special 3934 bit outside the regular scancode range, while it technically can be used, 3935 it's not intended for public access). 3936 3937 ---------------------------------------------------------------------------- 3938 3939 NOTE: `logScreenshot` is currently unsupported. 3940 """ 3941 scancodes_sequence: Sequence[ScancodeTypes] 3942 if isinstance(scancodes, int): 3943 scancodes_sequence = [ScancodeSequence([scancodes])] 3944 elif isinstance(scancodes, ScancodeSequence): 3945 scancodes_sequence = [scancodes] 3946 else: 3947 scancodes_sequence = scancodes 3948 3949 # We need to press x keys y times, which comes out to x*y presses in total 3950 expectedPresses: int = presses * len(scancodes_sequence) 3951 completedPresses: int = 0 3952 3953 apply_interval: bool = False 3954 for _ in range(presses): 3955 if apply_interval: # Don't delay first press 3956 _sleep(interval) 3957 apply_interval = True 3958 3959 apply_delay: bool = False 3960 for c in scancodes_sequence: 3961 if apply_delay: # Don't delay first press 3962 _sleep(delay) 3963 apply_delay = True 3964 3965 completedPresses += _helper_scancode_press( 3966 c, duration, _pause=False, auto_shift=auto_shift 3967 ) 3968 3969 return completedPresses == expectedPresses 3970 # --------------------------------------------------------------------------
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):
interval
is the time spent waiting between sequences. Ifkeys
is a str instance or single element list, theninterval
will be ignored.delay
is 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, thendelay
will be ignored.duration
is 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.
3974@contextmanager 3975@_genericPyDirectInputChecks 3976def scancode_hold( 3977 scancodes: ScancodeTypes | Sequence[ScancodeTypes], 3978 logScreenshot: None = None, 3979 _pause: bool = True, 3980 *, 3981 auto_shift: bool = False, 3982 raise_on_failure: bool = False, 3983) -> Generator[None, None, None]: 3984 """ 3985 Hold the sequence of keys corresponding to `scancodes` as long as the 3986 context manager is in scope (press upon entry, release upon exit). 3987 3988 Keys will be released in reverse order (LIFO), but still practically 3989 instantenous. 3990 3991 The actually pressed key will depend on your system keyboard layout. 3992 Limits the available character set but should provide the best 3993 compatibility. 3994 3995 If `_pause` is True (default), then an automatic sleep will be performed 3996 after the function finshes executing. The duration is set by the global 3997 variable `PAUSE`. 3998 Be aware, that the global pause defined by the PAUSE `constant` only 3999 applies after every call to this function, not inbetween (no pause between 4000 press and releasing key)! 4001 4002 `auto_shift` is used internally by higher level functions to automatically 4003 press the shift key before supported scancodes (indicitated by a special 4004 bit outside the regular scancode range, while it technically can be used, 4005 it's not intended for public access). 4006 4007 If `raise_on_failure` is True, then `PriorInputFailedException` will be 4008 raised if not all keyboard inputs could be executed successfully. 4009 4010 ---------------------------------------------------------------------------- 4011 4012 NOTE: `logScreenshot` is currently unsupported. 4013 """ 4014 scancodes_sequence: Sequence[ScancodeTypes] 4015 if isinstance(scancodes, int): 4016 scancodes_sequence = [ScancodeSequence([scancodes])] 4017 elif isinstance(scancodes, ScancodeSequence): 4018 scancodes_sequence = [scancodes] 4019 else: 4020 scancodes_sequence = scancodes 4021 4022 expectedPresses: int = len(scancodes_sequence) 4023 downed: int = 0 4024 upped: int = 0 4025 4026 try: 4027 for c in scancodes_sequence: 4028 downed += scancode_keyDown(c, _pause=False, auto_shift=auto_shift) 4029 yield 4030 finally: 4031 for c in reversed(scancodes_sequence): 4032 upped += scancode_keyUp(c, _pause=False, auto_shift=auto_shift) 4033 if raise_on_failure and not (expectedPresses == downed == upped): 4034 raise PriorInputFailedException 4035 # --------------------------------------------------------------------------
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.
4039@_genericPyDirectInputChecks 4040def scancode_hotkey( 4041 *args: ScancodeTypes, 4042 interval: float = 0.0, 4043 wait: float = 0.0, 4044 logScreenshot: None = None, 4045 _pause: bool = True, 4046 auto_shift: bool = True, 4047) -> bool: 4048 """ 4049 Press down buttons in order they are specified as arguments, 4050 releasing them in reverse order, e.g. 0x1D, 0x2E will first press 4051 Control, then C and release C before releasing Control. 4052 4053 Use keyword-only argument `interval` to specify a delay between single 4054 keys when pressing and releasing and `wait` for delay between last press 4055 and first release. 4056 4057 If `_pause` is True (default), then an automatic sleep will be performed 4058 after the function finshes executing. The duration is set by the global 4059 variable `PAUSE`. 4060 Be aware, that the global pause defined by the PAUSE `constant` only 4061 applies after every call to this function, not inbetween (no pause between 4062 press and releasing key)! 4063 4064 `auto_shift` is used internally by higher level functions to automatically 4065 press the shift key before supported scancodes (indicitated by a special 4066 bit outside the regular scancode range, while it technically can be used, 4067 it's not intended for public access). 4068 4069 ---------------------------------------------------------------------------- 4070 4071 NOTE: `logScreenshot` is currently unsupported. 4072 """ 4073 expectedPresses: int = len(args) 4074 downed: int = 0 4075 upped: int = 0 4076 4077 apply_interval: bool = False 4078 for code in args: 4079 if apply_interval: 4080 _sleep(interval) # sleep between iterations 4081 apply_interval = True 4082 4083 downed += scancode_keyDown(code, _pause=False, auto_shift=auto_shift) 4084 4085 _sleep(wait) 4086 4087 apply_interval = False 4088 for code in reversed(args): 4089 if apply_interval: 4090 _sleep(interval) # sleep between iterations 4091 apply_interval = True 4092 4093 upped += scancode_keyUp(code, _pause=False, auto_shift=auto_shift) 4094 4095 return expectedPresses == downed == upped 4096 # --------------------------------------------------------------------------
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.
4104def keyDown( 4105 key: str, 4106 logScreenshot: None = None, 4107 _pause: bool = True, 4108 *, 4109 auto_shift: bool = False, 4110) -> bool: 4111 """ 4112 Press down key corresponding to key name `key`. 4113 4114 `key` will be interpreted as a keyboard key (US QWERTY). 4115 The actually pressed key will depend on your system keyboard layout. 4116 Limits the available character set but should provide the best 4117 compatibility. 4118 4119 If `_pause` is True (default), then an automatic sleep will be performed 4120 after the function finshes executing. The duration is set by the global 4121 variable `PAUSE`. 4122 4123 If `auto_shift` is True, then "shifted" characters like upper case letters 4124 and the symbols on the number row automatically insert a Shift scancode 4125 into the input sequence. 4126 4127 ---------------------------------------------------------------------------- 4128 4129 NOTE: `logScreenshot` is currently unsupported. 4130 """ 4131 scancode: ScancodeTypes | None = KEYBOARD_MAPPING.get(key) 4132 if scancode is None: 4133 return False 4134 return scancode_keyDown( 4135 scancode, logScreenshot, _pause=_pause, auto_shift=auto_shift 4136 ) 4137 # --------------------------------------------------------------------------
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.
4142def keyUp( 4143 key: str, 4144 logScreenshot: None = None, 4145 _pause: bool = True, 4146 *, 4147 auto_shift: bool = False, 4148) -> bool: 4149 """ 4150 Lift up key corresponding to key name `key`. 4151 4152 `key` will be interpreted as a keyboard key (US QWERTY). 4153 The actually lifted key will depend on your system keyboard layout. 4154 Limits the available character set but should provide the best 4155 compatibility. 4156 4157 If `_pause` is True (default), then an automatic sleep will be performed 4158 after the function finshes executing. The duration is set by the global 4159 variable `PAUSE`. 4160 4161 If `auto_shift` is True, then "shifted" characters like upper case letters 4162 and the symbols on the number row automatically insert a Shift scancode 4163 into the input sequence. 4164 4165 ---------------------------------------------------------------------------- 4166 4167 NOTE: `logScreenshot` is currently unsupported. 4168 """ 4169 scancode: ScancodeTypes | None = KEYBOARD_MAPPING.get(key) 4170 if scancode is None: 4171 return False 4172 return scancode_keyUp( 4173 scancode, logScreenshot, _pause=_pause, auto_shift=auto_shift 4174 ) 4175 # --------------------------------------------------------------------------
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.
4201@_genericPyDirectInputChecks 4202def press( 4203 keys: str | Sequence[str], 4204 presses: int = 1, 4205 interval: float = 0.0, 4206 logScreenshot: None = None, 4207 _pause: bool = True, 4208 *, 4209 auto_shift: bool = False, 4210 delay: float = 0.0, 4211 duration: float = 0.0, 4212) -> bool: 4213 """ 4214 Press the sequence of `keys` for `presses` amount of times. 4215 4216 `keys` will be interpreted as sequence of keyboard keys (US QWERTY). 4217 The actually pressed key will depend on your system keyboard layout. 4218 Limits the available character set but should provide the best 4219 compatibility. 4220 4221 Explanation of time parameters (seconds as floating point numbers): 4222 4223 - `interval` is the time spent waiting between sequences. If `keys` is a 4224 str instance, single element list or presses equals 1 (the default), 4225 then `interval` will be ignored. 4226 - `delay` is the time from one complete key (press+release) to the next one 4227 in the same sequence. If there is only a single key in a sequence, then 4228 `delay` will be ignored. 4229 - `duration` is the time spent on holding every key before releasing it 4230 again. 4231 4232 If `_pause` is True (default), then an automatic sleep will be performed 4233 after the function finshes executing. The duration is set by the global 4234 variable `PAUSE`. 4235 Be aware, that the global pause defined by the `PAUSE` var only applies 4236 after every call to this function, not inbetween (no extra pause between 4237 pressing and releasing key, use the `duration` argument instead)! 4238 4239 If `auto_shift` is True, then "shifted" characters like upper case letters 4240 and the symbols on the number row automatically insert a Shift scancode 4241 into the input sequence. 4242 4243 ---------------------------------------------------------------------------- 4244 4245 NOTE: `logScreenshot` is currently unsupported. 4246 """ 4247 if isinstance(keys, str): 4248 keys = [keys] # If keys is 'enter', convert it to ['enter']. 4249 keys = [_normalize_key(key, auto_shift=auto_shift) for key in keys] 4250 4251 # We need to press x keys y times, which comes out to x*y presses in total 4252 expectedPresses: int = presses * len(keys) 4253 completedPresses: int = 0 4254 4255 apply_interval: bool = False 4256 for _ in range(presses): 4257 if apply_interval: # Don't delay first press 4258 _sleep(interval) 4259 apply_interval = True 4260 4261 apply_delay: bool = False 4262 for k in keys: 4263 if apply_delay: # Don't delay first press 4264 _sleep(delay) 4265 apply_delay = True 4266 4267 completedPresses += _helper_press( 4268 k, duration, _pause=False, auto_shift=auto_shift 4269 ) 4270 4271 return completedPresses == expectedPresses 4272 # --------------------------------------------------------------------------
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):
interval
is the time spent waiting between sequences. Ifkeys
is a str instance, single element list or presses equals 1 (the default), theninterval
will be ignored.delay
is 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, thendelay
will be ignored.duration
is 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.
4276@contextmanager 4277@_genericPyDirectInputChecks 4278def hold( 4279 keys: str | Sequence[str], 4280 logScreenshot: None = None, 4281 _pause: bool = True, 4282 *, 4283 auto_shift: bool = False, 4284 raise_on_failure: bool = False, 4285) -> Generator[None, None, None]: 4286 """ 4287 Hold the sequence of keys corresponding to key names in `keys` as long as 4288 the context manager is in scope (press upon entry, release upon exit). 4289 4290 Keys will be released in reverse order (LIFO), but still practically 4291 instantenous. 4292 4293 `key` will be interpreted as a keyboard key (US QWERTY). 4294 The actually pressed key will depend on your system keyboard layout. 4295 Limits the available character set but should provide the best 4296 compatibility. 4297 4298 If `_pause` is True (default), then an automatic sleep will be performed 4299 after the function finshes executing. The duration is set by the global 4300 variable `PAUSE`. 4301 Be aware, that the global pause defined by the PAUSE `constant` only 4302 applies after every call to this function, not inbetween (no pause between 4303 press and releasing key)! 4304 4305 `auto_shift` is used internally by higher level functions to automatically 4306 press the shift key before supported scancodes (indicitated by a special 4307 bit outside the regular scancode range, while it technically can be used, 4308 it's not intended for public access). 4309 4310 If `raise_on_failure` is True, then `PriorInputFailedException` will be 4311 raised if not all keyboard inputs could be executed successfully. 4312 4313 ---------------------------------------------------------------------------- 4314 4315 NOTE: `logScreenshot` is currently unsupported. 4316 """ 4317 if isinstance(keys, str): 4318 keys = [keys] # make single element into iterable 4319 keys = [_normalize_key(key, auto_shift=auto_shift) for key in keys] 4320 4321 expectedPresses: int = len(keys) 4322 downed: int = 0 4323 upped: int = 0 4324 4325 try: 4326 for k in keys: 4327 downed += keyDown(k, auto_shift=auto_shift) 4328 yield 4329 finally: 4330 for k in reversed(keys): 4331 upped += keyUp(k, auto_shift=auto_shift) 4332 if raise_on_failure and not (expectedPresses == downed == upped): 4333 raise PriorInputFailedException 4334 # --------------------------------------------------------------------------
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.
4338@_genericPyDirectInputChecks 4339def typewrite( 4340 message: str, 4341 interval: float = 0.0, 4342 logScreenshot: None = None, 4343 _pause: bool = True, 4344 *, 4345 auto_shift: bool = False, 4346 delay: float = 0.0, 4347 duration: float = 0.0, 4348) -> None: 4349 """ 4350 Break down `message` into a single character key sequence and press each 4351 key one by one. 4352 4353 `message` will be interpreted as sequence of keyboard keys (US QWERTY). 4354 The actually pressed keys will depend on your system keyboard layout. 4355 Limits the available character set but should provide the best 4356 compatibility. 4357 4358 Explanation of time parameters (seconds as floating point numbers): 4359 4360 - `interval` is the time spent waiting between sequences. If `message` is a 4361 single character string, then `interval` will be ignored. 4362 - `delay` is the time from one complete key (press+release) to the next one 4363 in the same sequence. If there is only a single key in a sequence, then 4364 `delay` will be ignored. 4365 - `duration` is the time spent on holding every key before releasing it 4366 again. 4367 4368 If `_pause` is True (default), then an automatic sleep will be performed 4369 after the function finshes executing. The duration is set by the global 4370 variable `PAUSE`. 4371 Be aware, that the global pause defined by the PAUSE `constant` only 4372 applies after every call to this function, not inbetween (no pause between 4373 press and releasing key)! 4374 4375 `auto_shift` is used internally by higher level functions to automatically 4376 press the shift key before supported scancodes (indicitated by a special 4377 bit outside the regular scancode range, while it technically can be used, 4378 it's not intended for public access). 4379 4380 ---------------------------------------------------------------------------- 4381 4382 NOTE: `logScreenshot` is currently unsupported. 4383 """ 4384 4385 apply_interval: bool = False 4386 for key in message: 4387 if apply_interval: # Don't delay first press 4388 _sleep(interval) 4389 apply_interval = True 4390 4391 press( 4392 key, 4393 _pause=False, 4394 auto_shift=auto_shift, 4395 delay=delay, 4396 duration=duration, 4397 ) 4398 # --------------------------------------------------------------------------
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):
interval
is the time spent waiting between sequences. Ifmessage
is a single character string, theninterval
will be ignored.delay
is 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, thendelay
will be ignored.duration
is 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.
4338@_genericPyDirectInputChecks 4339def typewrite( 4340 message: str, 4341 interval: float = 0.0, 4342 logScreenshot: None = None, 4343 _pause: bool = True, 4344 *, 4345 auto_shift: bool = False, 4346 delay: float = 0.0, 4347 duration: float = 0.0, 4348) -> None: 4349 """ 4350 Break down `message` into a single character key sequence and press each 4351 key one by one. 4352 4353 `message` will be interpreted as sequence of keyboard keys (US QWERTY). 4354 The actually pressed keys will depend on your system keyboard layout. 4355 Limits the available character set but should provide the best 4356 compatibility. 4357 4358 Explanation of time parameters (seconds as floating point numbers): 4359 4360 - `interval` is the time spent waiting between sequences. If `message` is a 4361 single character string, then `interval` will be ignored. 4362 - `delay` is the time from one complete key (press+release) to the next one 4363 in the same sequence. If there is only a single key in a sequence, then 4364 `delay` will be ignored. 4365 - `duration` is the time spent on holding every key before releasing it 4366 again. 4367 4368 If `_pause` is True (default), then an automatic sleep will be performed 4369 after the function finshes executing. The duration is set by the global 4370 variable `PAUSE`. 4371 Be aware, that the global pause defined by the PAUSE `constant` only 4372 applies after every call to this function, not inbetween (no pause between 4373 press and releasing key)! 4374 4375 `auto_shift` is used internally by higher level functions to automatically 4376 press the shift key before supported scancodes (indicitated by a special 4377 bit outside the regular scancode range, while it technically can be used, 4378 it's not intended for public access). 4379 4380 ---------------------------------------------------------------------------- 4381 4382 NOTE: `logScreenshot` is currently unsupported. 4383 """ 4384 4385 apply_interval: bool = False 4386 for key in message: 4387 if apply_interval: # Don't delay first press 4388 _sleep(interval) 4389 apply_interval = True 4390 4391 press( 4392 key, 4393 _pause=False, 4394 auto_shift=auto_shift, 4395 delay=delay, 4396 duration=duration, 4397 ) 4398 # --------------------------------------------------------------------------
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):
interval
is the time spent waiting between sequences. Ifmessage
is a single character string, theninterval
will be ignored.delay
is 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, thendelay
will be ignored.duration
is 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.
4409@_genericPyDirectInputChecks 4410def hotkey( 4411 *args: str, 4412 interval: float = 0.0, 4413 wait: float = 0.0, 4414 logScreenshot: None = None, 4415 _pause: bool = True, 4416 auto_shift: bool = True, 4417) -> None: 4418 """ 4419 Press down buttons in order they are specified as arguments, 4420 releasing them in reverse order, e.g. 'ctrl', 'c' will first press 4421 Control, then C and release C before releasing Control. 4422 4423 Use keyword-only argument `interval` to specify a delay between single 4424 keys when pressing and releasing and `wait` for delay between last press 4425 and first release. 4426 4427 If `_pause` is True (default), then an automatic sleep will be performed 4428 after the function finshes executing. The duration is set by the global 4429 variable `PAUSE`. 4430 Be aware, that the global pause defined by the PAUSE `constant` only 4431 applies after every call to this function, not inbetween (no pause between 4432 press and releasing key)! 4433 4434 `auto_shift` is used internally by higher level functions to automatically 4435 press the shift key before supported scancodes (indicitated by a special 4436 bit outside the regular scancode range, while it technically can be used, 4437 it's not intended for public access). 4438 4439 ---------------------------------------------------------------------------- 4440 4441 NOTE: `logScreenshot` is currently unsupported. 4442 """ 4443 apply_interval: bool = False 4444 for key in args: 4445 if apply_interval: 4446 _sleep(interval) # sleep between iterations 4447 apply_interval = True 4448 4449 keyDown(key, _pause=False, auto_shift=auto_shift) 4450 4451 _sleep(wait) 4452 4453 apply_interval = False 4454 for key in reversed(args): 4455 if apply_interval: 4456 _sleep(interval) # sleep between iterations 4457 apply_interval = True 4458 4459 keyUp(key, _pause=False, auto_shift=auto_shift) 4460 # --------------------------------------------------------------------------
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.
4467@_genericPyDirectInputChecks 4468def unicode_charDown( 4469 char: str, logScreenshot: None = None, _pause: bool = True 4470) -> bool: 4471 """ 4472 Send Unicode character(s) `char` to currently focused application as 4473 WM_KEYDOWN message. 4474 4475 `char` will be interpreted as a string of Unicode characters 4476 (independet from keyboard layout). Supports complete Unicode character set 4477 but may not be compatible with every application. 4478 4479 If `_pause` is True (default), then an automatic sleep will be performed 4480 after the function finshes executing. The duration is set by the global 4481 variable `PAUSE`. 4482 4483 ---------------------------------------------------------------------------- 4484 4485 NOTE: `logScreenshot` is currently unsupported. 4486 """ 4487 utf16surrogates: bytes = char.encode("utf-16be") 4488 codes: Sequence[int] = unpack( 4489 f">{len(utf16surrogates) // 2}H", utf16surrogates 4490 ) 4491 4492 keybdFlags: int = _KEYEVENTF_UNICODE 4493 4494 input_structs: list[_INPUT] = [ 4495 _create_keyboard_input(wVk=0, wScan=charcode, dwFlags=keybdFlags) 4496 for charcode in codes 4497 ] 4498 # Init event tracking 4499 expectedEvents: int = len(input_structs) 4500 insertedEvents: int = _send_input(input_structs) 4501 4502 return insertedEvents == expectedEvents 4503 # --------------------------------------------------------------------------
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.
4507@_genericPyDirectInputChecks 4508def unicode_charUp( 4509 char: str, logScreenshot: None = None, _pause: bool = True 4510) -> bool: 4511 """ 4512 Send Unicode character(s) `char` to currently focused application as 4513 WM_KEYUP message. 4514 4515 `char` will be interpreted as a string of Unicode characters 4516 (independet from keyboard layout). Supports complete Unicode character set 4517 but may not be compatible with every application. 4518 4519 If `_pause` is True (default), then an automatic sleep will be performed 4520 after the function finshes executing. The duration is set by the global 4521 variable `PAUSE`. 4522 4523 ---------------------------------------------------------------------------- 4524 4525 NOTE: `logScreenshot` is currently unsupported. 4526 """ 4527 utf16surrogates: bytes = char.encode("utf-16be") 4528 codes: Sequence[int] = unpack( 4529 f">{len(utf16surrogates) // 2}H", utf16surrogates 4530 ) 4531 4532 keybdFlags: int = _KEYEVENTF_UNICODE | _KEYEVENTF_KEYUP 4533 4534 input_structs: list[_INPUT] = [ 4535 _create_keyboard_input(wVk=0, wScan=charcode, dwFlags=keybdFlags) 4536 for charcode in codes 4537 ] 4538 # Init event tracking 4539 expectedEvents: int = len(input_structs) 4540 insertedEvents: int = _send_input(input_structs) 4541 4542 return insertedEvents == expectedEvents 4543 # --------------------------------------------------------------------------
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.
4567@_genericPyDirectInputChecks 4568def unicode_press( 4569 chars: str | Sequence[str], 4570 presses: int = 1, 4571 interval: float = 0.0, 4572 logScreenshot: None = None, 4573 _pause: bool = True, 4574 *, 4575 delay: float = 0.0, 4576 duration: float = 0.0, 4577) -> bool: 4578 """ 4579 Press the sequence of `chars` for `presses` amount of times. 4580 4581 `chars` will be interpreted as a sequence of Unicode characters 4582 (independent from keyboard layout). Supports complete Unicode character set 4583 but may not be compatible with every application. 4584 4585 Explanation of time parameters (seconds as floating point numbers): 4586 4587 - `interval` is the time spent waiting between sequences. If `chars` is a 4588 str instance or single element list, then `interval` will be ignored. 4589 - `delay` is the time from one complete char (press+release) to the next 4590 one in the same sequence. If there is only a single char in a sequence, 4591 then `delay` will be ignored. 4592 - `duration` is the time spent on holding every char before releasing it 4593 again. 4594 4595 If `_pause` is True (default), then an automatic sleep will be performed 4596 after the function finshes executing. The duration is set by the global 4597 variable `PAUSE`. 4598 Be aware, that the global pause defined by the PAUSE `constant` only 4599 applies after every call to this function, not inbetween (no extra pause 4600 between pressing and releasing key, use the `duration` argument instead)! 4601 4602 ---------------------------------------------------------------------------- 4603 4604 NOTE: `logScreenshot` is currently unsupported. 4605 """ 4606 if isinstance(chars, str): 4607 chars = [chars] 4608 4609 # We need to press x keys y times, which comes out to x*y presses in total 4610 expectedPresses: int = presses * len(chars) 4611 completedPresses: int = 0 4612 4613 apply_interval: bool = False 4614 for _ in range(presses): 4615 if apply_interval: # Don't delay first press 4616 _sleep(interval) 4617 apply_interval = True 4618 4619 apply_delay: bool = False 4620 for c in chars: 4621 if apply_delay: # Don't delay first press 4622 _sleep(delay) 4623 apply_delay = True 4624 4625 completedPresses += _helper_unicode_press_char( 4626 c, 4627 duration, 4628 _pause=False, 4629 ) 4630 4631 return completedPresses == expectedPresses 4632 # --------------------------------------------------------------------------
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):
interval
is the time spent waiting between sequences. Ifchars
is a str instance or single element list, theninterval
will be ignored.delay
is 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, thendelay
will be ignored.duration
is 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.
4636@contextmanager 4637@_genericPyDirectInputChecks 4638def unicode_hold( 4639 chars: str | Sequence[str], 4640 logScreenshot: None = None, 4641 _pause: bool = True, 4642 *, 4643 raise_on_failure: bool = False, 4644) -> Generator[None, None, None]: 4645 """ 4646 Hold the sequence of "keys" corresponding to unicode characters in `chars` 4647 as long as the context manager is in scope (press upon entry, 4648 release upon exit). 4649 4650 `chars` will be interpreted as a sequence of Unicode characters 4651 (independet from keyboard layout). Supports complete Unicode character set 4652 but may not be compatible with every application. 4653 4654 Keys will be released in reverse order (LIFO), but still practically 4655 instantenous. 4656 4657 If `_pause` is True (default), then an automatic sleep will be performed 4658 after the function finshes executing. The duration is set by the global 4659 variable `PAUSE`. 4660 Be aware, that the global pause defined by the PAUSE `constant` only 4661 applies after every call to this function, not inbetween (no pause between 4662 press and releasing key)! 4663 4664 If `raise_on_failure` is True, then `PriorInputFailedException` will be 4665 raised if not all keyboard inputs could be executed successfully. 4666 4667 ---------------------------------------------------------------------------- 4668 4669 NOTE: `logScreenshot` is currently unsupported. 4670 """ 4671 if isinstance(chars, str): 4672 chars = [chars] # make single element into iterable 4673 4674 expectedPresses: int = len(chars) 4675 downed: int = 0 4676 upped: int = 0 4677 4678 try: 4679 for c in chars: 4680 downed += unicode_charDown(c, _pause=False) 4681 yield 4682 finally: 4683 for c in reversed(chars): 4684 upped += unicode_charUp(c, _pause=False) 4685 if raise_on_failure and not (expectedPresses == downed == upped): 4686 raise PriorInputFailedException 4687 # --------------------------------------------------------------------------
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.
4691@_genericPyDirectInputChecks 4692def unicode_typewrite( 4693 message: str, 4694 interval: float = 0.0, 4695 logScreenshot: None = None, 4696 _pause: bool = True, 4697 *, 4698 delay: float = 0.0, 4699 duration: float = 0.0, 4700) -> None: 4701 """ 4702 Break down `message` into characters and press them one by one. 4703 4704 `message` will be interpreted as a sequence of Unicode characters 4705 (independet from keyboard layout). Supports complete Unicode character set 4706 but may not be compatible with every application. 4707 4708 Explanation of time parameters (seconds as floating point numbers): 4709 4710 - `interval` is the time spent waiting between sequences. If `message` is a 4711 single character string, then `interval` will be ignored. 4712 - `delay` is the time from one complete key (press+release) to the next one 4713 in the same sequence. If there is only a single key in a sequence, then 4714 `delay` will be ignored. 4715 - `duration` is the time spent on holding every key before releasing it 4716 again. 4717 4718 If `_pause` is True (default), then an automatic sleep will be performed 4719 after the function finshes executing. The duration is set by the global 4720 variable `PAUSE`. 4721 Be aware, that the global pause defined by the PAUSE `constant` only 4722 applies after every call to this function, not inbetween (no pause between 4723 press and releasing key)! 4724 4725 ---------------------------------------------------------------------------- 4726 4727 NOTE: `logScreenshot` is currently unsupported. 4728 """ 4729 apply_interval: bool = False 4730 for char in message: 4731 if apply_interval: 4732 _sleep(interval) # sleep between iterations 4733 apply_interval = True 4734 4735 unicode_press(char, _pause=False, delay=delay, duration=duration) 4736 # --------------------------------------------------------------------------
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):
interval
is the time spent waiting between sequences. Ifmessage
is a single character string, theninterval
will be ignored.delay
is 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, thendelay
will be ignored.duration
is 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.
4691@_genericPyDirectInputChecks 4692def unicode_typewrite( 4693 message: str, 4694 interval: float = 0.0, 4695 logScreenshot: None = None, 4696 _pause: bool = True, 4697 *, 4698 delay: float = 0.0, 4699 duration: float = 0.0, 4700) -> None: 4701 """ 4702 Break down `message` into characters and press them one by one. 4703 4704 `message` will be interpreted as a sequence of Unicode characters 4705 (independet from keyboard layout). Supports complete Unicode character set 4706 but may not be compatible with every application. 4707 4708 Explanation of time parameters (seconds as floating point numbers): 4709 4710 - `interval` is the time spent waiting between sequences. If `message` is a 4711 single character string, then `interval` will be ignored. 4712 - `delay` is the time from one complete key (press+release) to the next one 4713 in the same sequence. If there is only a single key in a sequence, then 4714 `delay` will be ignored. 4715 - `duration` is the time spent on holding every key before releasing it 4716 again. 4717 4718 If `_pause` is True (default), then an automatic sleep will be performed 4719 after the function finshes executing. The duration is set by the global 4720 variable `PAUSE`. 4721 Be aware, that the global pause defined by the PAUSE `constant` only 4722 applies after every call to this function, not inbetween (no pause between 4723 press and releasing key)! 4724 4725 ---------------------------------------------------------------------------- 4726 4727 NOTE: `logScreenshot` is currently unsupported. 4728 """ 4729 apply_interval: bool = False 4730 for char in message: 4731 if apply_interval: 4732 _sleep(interval) # sleep between iterations 4733 apply_interval = True 4734 4735 unicode_press(char, _pause=False, delay=delay, duration=duration) 4736 # --------------------------------------------------------------------------
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):
interval
is the time spent waiting between sequences. Ifmessage
is a single character string, theninterval
will be ignored.delay
is 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, thendelay
will be ignored.duration
is 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.
4745@_genericPyDirectInputChecks 4746def unicode_hotkey( 4747 *args: str, 4748 interval: float = 0.0, 4749 wait: float = 0.0, 4750 logScreenshot: None = None, 4751 _pause: bool = True, 4752) -> None: 4753 """ 4754 Press down buttons in order they are specified as arguments, 4755 releasing them in reverse order. 4756 4757 This function makes little sense for Unicode characters and mainly exists 4758 for parity with the other, lower-level hotkey functions! 4759 4760 See `unicode_press()` for an alternative function that presses keys in 4761 series instead. 4762 4763 Use keyword-only argument `interval` to specify a delay between single 4764 keys when pressing and releasing and `wait` for delay between last press 4765 and first release. 4766 4767 If `_pause` is True (default), then an automatic sleep will be performed 4768 after the function finshes executing. The duration is set by the global 4769 variable `PAUSE`. 4770 Be aware, that the global pause defined by the PAUSE `constant` only 4771 applies after every call to this function, not inbetween (no pause between 4772 press and releasing key)! 4773 4774 ---------------------------------------------------------------------------- 4775 4776 NOTE: `logScreenshot` is currently unsupported. 4777 """ 4778 apply_interval: bool = False 4779 for char in args: 4780 if apply_interval: 4781 _sleep(interval) # sleep between iterations 4782 apply_interval = True 4783 4784 unicode_charDown(char, _pause=False) 4785 4786 _sleep(wait) 4787 4788 apply_interval = False 4789 for char in reversed(args): 4790 if apply_interval: 4791 _sleep(interval) # sleep between iterations 4792 apply_interval = True 4793 4794 unicode_charUp(char, _pause=False) 4795 # --------------------------------------------------------------------------
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.