Initial commit

This commit is contained in:
Untriex Programming
2021-08-31 22:06:02 +02:00
commit 9b6723e11e
5142 changed files with 1455625 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
from . import displayMousePosition
displayMousePosition()

View File

@@ -0,0 +1,434 @@
import time
import sys
try:
import Quartz
except:
assert False, "You must first install pyobjc-core and pyobjc: https://pyautogui.readthedocs.io/en/latest/install.html"
import AppKit
import pyautogui
from pyautogui import LEFT, MIDDLE, RIGHT
if sys.platform != 'darwin':
raise Exception('The pyautogui_osx module should only be loaded on an OS X system.')
""" Taken from events.h
/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h
The *KB dictionaries in pyautogui map a string that can be passed to keyDown(),
keyUp(), or press() into the code used for the OS-specific keyboard function.
They should always be lowercase, and the same keys should be used across all OSes."""
keyboardMapping = dict([(key, None) for key in pyautogui.KEY_NAMES])
keyboardMapping.update({
'a': 0x00, # kVK_ANSI_A
's': 0x01, # kVK_ANSI_S
'd': 0x02, # kVK_ANSI_D
'f': 0x03, # kVK_ANSI_F
'h': 0x04, # kVK_ANSI_H
'g': 0x05, # kVK_ANSI_G
'z': 0x06, # kVK_ANSI_Z
'x': 0x07, # kVK_ANSI_X
'c': 0x08, # kVK_ANSI_C
'v': 0x09, # kVK_ANSI_V
'b': 0x0b, # kVK_ANSI_B
'q': 0x0c, # kVK_ANSI_Q
'w': 0x0d, # kVK_ANSI_W
'e': 0x0e, # kVK_ANSI_E
'r': 0x0f, # kVK_ANSI_R
'y': 0x10, # kVK_ANSI_Y
't': 0x11, # kVK_ANSI_T
'1': 0x12, # kVK_ANSI_1
'!': 0x12, # kVK_ANSI_1
'2': 0x13, # kVK_ANSI_2
'@': 0x13, # kVK_ANSI_2
'3': 0x14, # kVK_ANSI_3
'#': 0x14, # kVK_ANSI_3
'4': 0x15, # kVK_ANSI_4
'$': 0x15, # kVK_ANSI_4
'6': 0x16, # kVK_ANSI_6
'^': 0x16, # kVK_ANSI_6
'5': 0x17, # kVK_ANSI_5
'%': 0x17, # kVK_ANSI_5
'=': 0x18, # kVK_ANSI_Equal
'+': 0x18, # kVK_ANSI_Equal
'9': 0x19, # kVK_ANSI_9
'(': 0x19, # kVK_ANSI_9
'7': 0x1a, # kVK_ANSI_7
'&': 0x1a, # kVK_ANSI_7
'-': 0x1b, # kVK_ANSI_Minus
'_': 0x1b, # kVK_ANSI_Minus
'8': 0x1c, # kVK_ANSI_8
'*': 0x1c, # kVK_ANSI_8
'0': 0x1d, # kVK_ANSI_0
')': 0x1d, # kVK_ANSI_0
']': 0x1e, # kVK_ANSI_RightBracket
'}': 0x1e, # kVK_ANSI_RightBracket
'o': 0x1f, # kVK_ANSI_O
'u': 0x20, # kVK_ANSI_U
'[': 0x21, # kVK_ANSI_LeftBracket
'{': 0x21, # kVK_ANSI_LeftBracket
'i': 0x22, # kVK_ANSI_I
'p': 0x23, # kVK_ANSI_P
'l': 0x25, # kVK_ANSI_L
'j': 0x26, # kVK_ANSI_J
"'": 0x27, # kVK_ANSI_Quote
'"': 0x27, # kVK_ANSI_Quote
'k': 0x28, # kVK_ANSI_K
';': 0x29, # kVK_ANSI_Semicolon
':': 0x29, # kVK_ANSI_Semicolon
'\\': 0x2a, # kVK_ANSI_Backslash
'|': 0x2a, # kVK_ANSI_Backslash
',': 0x2b, # kVK_ANSI_Comma
'<': 0x2b, # kVK_ANSI_Comma
'/': 0x2c, # kVK_ANSI_Slash
'?': 0x2c, # kVK_ANSI_Slash
'n': 0x2d, # kVK_ANSI_N
'm': 0x2e, # kVK_ANSI_M
'.': 0x2f, # kVK_ANSI_Period
'>': 0x2f, # kVK_ANSI_Period
'`': 0x32, # kVK_ANSI_Grave
'~': 0x32, # kVK_ANSI_Grave
' ': 0x31, # kVK_Space
'space': 0x31,
'\r': 0x24, # kVK_Return
'\n': 0x24, # kVK_Return
'enter': 0x24, # kVK_Return
'return': 0x24, # kVK_Return
'\t': 0x30, # kVK_Tab
'tab': 0x30, # kVK_Tab
'backspace': 0x33, # kVK_Delete, which is "Backspace" on OS X.
'\b': 0x33, # kVK_Delete, which is "Backspace" on OS X.
'esc': 0x35, # kVK_Escape
'escape': 0x35, # kVK_Escape
'command': 0x37, # kVK_Command
'shift': 0x38, # kVK_Shift
'shiftleft': 0x38, # kVK_Shift
'capslock': 0x39, # kVK_CapsLock
'option': 0x3a, # kVK_Option
'optionleft': 0x3a, # kVK_Option
'alt': 0x3a, # kVK_Option
'altleft': 0x3a, # kVK_Option
'ctrl': 0x3b, # kVK_Control
'ctrlleft': 0x3b, # kVK_Control
'shiftright': 0x3c, # kVK_RightShift
'optionright': 0x3d, # kVK_RightOption
'ctrlright': 0x3e, # kVK_RightControl
'fn': 0x3f, # kVK_Function
'f17': 0x40, # kVK_F17
'volumeup': 0x48, # kVK_VolumeUp
'volumedown': 0x49, # kVK_VolumeDown
'volumemute': 0x4a, # kVK_Mute
'f18': 0x4f, # kVK_F18
'f19': 0x50, # kVK_F19
'f20': 0x5a, # kVK_F20
'f5': 0x60, # kVK_F5
'f6': 0x61, # kVK_F6
'f7': 0x62, # kVK_F7
'f3': 0x63, # kVK_F3
'f8': 0x64, # kVK_F8
'f9': 0x65, # kVK_F9
'f11': 0x67, # kVK_F11
'f13': 0x69, # kVK_F13
'f16': 0x6a, # kVK_F16
'f14': 0x6b, # kVK_F14
'f10': 0x6d, # kVK_F10
'f12': 0x6f, # kVK_F12
'f15': 0x71, # kVK_F15
'help': 0x72, # kVK_Help
'home': 0x73, # kVK_Home
'pageup': 0x74, # kVK_PageUp
'pgup': 0x74, # kVK_PageUp
'del': 0x75, # kVK_ForwardDelete
'delete': 0x75, # kVK_ForwardDelete
'f4': 0x76, # kVK_F4
'end': 0x77, # kVK_End
'f2': 0x78, # kVK_F2
'pagedown': 0x79, # kVK_PageDown
'pgdn': 0x79, # kVK_PageDown
'f1': 0x7a, # kVK_F1
'left': 0x7b, # kVK_LeftArrow
'right': 0x7c, # kVK_RightArrow
'down': 0x7d, # kVK_DownArrow
'up': 0x7e, # kVK_UpArrow
'yen': 0x5d, # kVK_JIS_Yen
#'underscore' : 0x5e, # kVK_JIS_Underscore (only applies to Japanese keyboards)
#'comma': 0x5f, # kVK_JIS_KeypadComma (only applies to Japanese keyboards)
'eisu': 0x66, # kVK_JIS_Eisu
'kana': 0x68, # kVK_JIS_Kana
})
"""
# TODO - additional key codes to add
kVK_ANSI_KeypadDecimal = 0x41,
kVK_ANSI_KeypadMultiply = 0x43,
kVK_ANSI_KeypadPlus = 0x45,
kVK_ANSI_KeypadClear = 0x47,
kVK_ANSI_KeypadDivide = 0x4B,
kVK_ANSI_KeypadEnter = 0x4C,
kVK_ANSI_KeypadMinus = 0x4E,
kVK_ANSI_KeypadEquals = 0x51,
kVK_ANSI_Keypad0 = 0x52,
kVK_ANSI_Keypad1 = 0x53,
kVK_ANSI_Keypad2 = 0x54,
kVK_ANSI_Keypad3 = 0x55,
kVK_ANSI_Keypad4 = 0x56,
kVK_ANSI_Keypad5 = 0x57,
kVK_ANSI_Keypad6 = 0x58,
kVK_ANSI_Keypad7 = 0x59,
kVK_ANSI_Keypad8 = 0x5B,
kVK_ANSI_Keypad9 = 0x5C,
"""
# add mappings for uppercase letters
for c in 'abcdefghijklmnopqrstuvwxyz':
keyboardMapping[c.upper()] = keyboardMapping[c]
# Taken from ev_keymap.h
# http://www.opensource.apple.com/source/IOHIDFamily/IOHIDFamily-86.1/IOHIDSystem/IOKit/hidsystem/ev_keymap.h
special_key_translate_table = {
'KEYTYPE_SOUND_UP': 0,
'KEYTYPE_SOUND_DOWN': 1,
'KEYTYPE_BRIGHTNESS_UP': 2,
'KEYTYPE_BRIGHTNESS_DOWN': 3,
'KEYTYPE_CAPS_LOCK': 4,
'KEYTYPE_HELP': 5,
'POWER_KEY': 6,
'KEYTYPE_MUTE': 7,
'UP_ARROW_KEY': 8,
'DOWN_ARROW_KEY': 9,
'KEYTYPE_NUM_LOCK': 10,
'KEYTYPE_CONTRAST_UP': 11,
'KEYTYPE_CONTRAST_DOWN': 12,
'KEYTYPE_LAUNCH_PANEL': 13,
'KEYTYPE_EJECT': 14,
'KEYTYPE_VIDMIRROR': 15,
'KEYTYPE_PLAY': 16,
'KEYTYPE_NEXT': 17,
'KEYTYPE_PREVIOUS': 18,
'KEYTYPE_FAST': 19,
'KEYTYPE_REWIND': 20,
'KEYTYPE_ILLUMINATION_UP': 21,
'KEYTYPE_ILLUMINATION_DOWN': 22,
'KEYTYPE_ILLUMINATION_TOGGLE': 23
}
def _keyDown(key):
if key not in keyboardMapping or keyboardMapping[key] is None:
return
if key in special_key_translate_table:
_specialKeyEvent(key, 'down')
else:
_normalKeyEvent(key, 'down')
def _keyUp(key):
if key not in keyboardMapping or keyboardMapping[key] is None:
return
if key in special_key_translate_table:
_specialKeyEvent(key, 'up')
else:
_normalKeyEvent(key, 'up')
def _normalKeyEvent(key, upDown):
assert upDown in ('up', 'down'), "upDown argument must be 'up' or 'down'"
try:
if pyautogui.isShiftCharacter(key):
key_code = keyboardMapping[key.lower()]
event = Quartz.CGEventCreateKeyboardEvent(None,
keyboardMapping['shift'], upDown == 'down')
Quartz.CGEventPost(Quartz.kCGHIDEventTap, event)
# Tiny sleep to let OS X catch up on us pressing shift
time.sleep(pyautogui.DARWIN_CATCH_UP_TIME)
else:
key_code = keyboardMapping[key]
event = Quartz.CGEventCreateKeyboardEvent(None, key_code, upDown == 'down')
Quartz.CGEventPost(Quartz.kCGHIDEventTap, event)
time.sleep(pyautogui.DARWIN_CATCH_UP_TIME)
# TODO - wait, is the shift key's keyup not done?
# TODO - get rid of this try-except.
except KeyError:
raise RuntimeError("Key %s not implemented." % (key))
def _specialKeyEvent(key, upDown):
""" Helper method for special keys.
Source: http://stackoverflow.com/questions/11045814/emulate-media-key-press-on-mac
"""
assert upDown in ('up', 'down'), "upDown argument must be 'up' or 'down'"
key_code = special_key_translate_table[key]
ev = AppKit.NSEvent.otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2_(
Quartz.NSSystemDefined, # type
(0,0), # location
0xa00 if upDown == 'down' else 0xb00, # flags
0, # timestamp
0, # window
0, # ctx
8, # subtype
(key_code << 16) | ((0xa if upDown == 'down' else 0xb) << 8), # data1
-1 # data2
)
Quartz.CGEventPost(0, ev.CGEvent())
def _position():
loc = AppKit.NSEvent.mouseLocation()
return int(loc.x), int(Quartz.CGDisplayPixelsHigh(0) - loc.y)
def _size():
return Quartz.CGDisplayPixelsWide(Quartz.CGMainDisplayID()), Quartz.CGDisplayPixelsHigh(Quartz.CGMainDisplayID())
def _scroll(clicks, x=None, y=None):
_vscroll(clicks, x, y)
"""
According to https://developer.apple.com/library/mac/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html#//apple_ref/c/func/Quartz.CGEventCreateScrollWheelEvent
"Scrolling movement is generally represented by small signed integer values, typically in a range from -10 to +10. Large values may have unexpected results, depending on the application that processes the event."
The scrolling functions will create multiple events that scroll 10 each, and then scroll the remainder.
"""
def _vscroll(clicks, x=None, y=None):
_moveTo(x, y)
clicks = int(clicks)
for _ in range(abs(clicks) // 10):
scrollWheelEvent = Quartz.CGEventCreateScrollWheelEvent(
None, # no source
Quartz.kCGScrollEventUnitLine, # units
1, # wheelCount (number of dimensions)
10 if clicks >= 0 else -10) # vertical movement
Quartz.CGEventPost(Quartz.kCGHIDEventTap, scrollWheelEvent)
scrollWheelEvent = Quartz.CGEventCreateScrollWheelEvent(
None, # no source
Quartz.kCGScrollEventUnitLine, # units
1, # wheelCount (number of dimensions)
clicks % 10 if clicks >= 0 else -1 * (-clicks % 10)) # vertical movement
Quartz.CGEventPost(Quartz.kCGHIDEventTap, scrollWheelEvent)
def _hscroll(clicks, x=None, y=None):
_moveTo(x, y)
clicks = int(clicks)
for _ in range(abs(clicks) // 10):
scrollWheelEvent = Quartz.CGEventCreateScrollWheelEvent(
None, # no source
Quartz.kCGScrollEventUnitLine, # units
2, # wheelCount (number of dimensions)
0, # vertical movement
10 if clicks >= 0 else -10) # horizontal movement
Quartz.CGEventPost(Quartz.kCGHIDEventTap, scrollWheelEvent)
scrollWheelEvent = Quartz.CGEventCreateScrollWheelEvent(
None, # no source
Quartz.kCGScrollEventUnitLine, # units
2, # wheelCount (number of dimensions)
0, # vertical movement
(clicks % 10) if clicks >= 0 else (-1 * clicks % 10)) # horizontal movement
Quartz.CGEventPost(Quartz.kCGHIDEventTap, scrollWheelEvent)
def _mouseDown(x, y, button):
if button == LEFT:
_sendMouseEvent(Quartz.kCGEventLeftMouseDown, x, y, Quartz.kCGMouseButtonLeft)
elif button == MIDDLE:
_sendMouseEvent(Quartz.kCGEventOtherMouseDown, x, y, Quartz.kCGMouseButtonCenter)
elif button == RIGHT:
_sendMouseEvent(Quartz.kCGEventRightMouseDown, x, y, Quartz.kCGMouseButtonRight)
else:
assert False, "button argument not in ('left', 'middle', 'right')"
def _mouseUp(x, y, button):
if button == LEFT:
_sendMouseEvent(Quartz.kCGEventLeftMouseUp, x, y, Quartz.kCGMouseButtonLeft)
elif button == MIDDLE:
_sendMouseEvent(Quartz.kCGEventOtherMouseUp, x, y, Quartz.kCGMouseButtonCenter)
elif button == RIGHT:
_sendMouseEvent(Quartz.kCGEventRightMouseUp, x, y, Quartz.kCGMouseButtonRight)
else:
assert False, "button argument not in ('left', 'middle', 'right')"
def _click(x, y, button):
if button == LEFT:
_sendMouseEvent(Quartz.kCGEventLeftMouseDown, x, y, Quartz.kCGMouseButtonLeft)
_sendMouseEvent(Quartz.kCGEventLeftMouseUp, x, y, Quartz.kCGMouseButtonLeft)
elif button == MIDDLE:
_sendMouseEvent(Quartz.kCGEventOtherMouseDown, x, y, Quartz.kCGMouseButtonCenter)
_sendMouseEvent(Quartz.kCGEventOtherMouseUp, x, y, Quartz.kCGMouseButtonCenter)
elif button == RIGHT:
_sendMouseEvent(Quartz.kCGEventRightMouseDown, x, y, Quartz.kCGMouseButtonRight)
_sendMouseEvent(Quartz.kCGEventRightMouseUp, x, y, Quartz.kCGMouseButtonRight)
else:
assert False, "button argument not in ('left', 'middle', 'right')"
def _multiClick(x, y, button, num, interval=0.0):
btn = None
down = None
up = None
if button == LEFT:
btn = Quartz.kCGMouseButtonLeft
down = Quartz.kCGEventLeftMouseDown
up = Quartz.kCGEventLeftMouseUp
elif button == MIDDLE:
btn = Quartz.kCGMouseButtonCenter
down = Quartz.kCGEventOtherMouseDown
up = Quartz.kCGEventOtherMouseUp
elif button == RIGHT:
btn = Quartz.kCGMouseButtonRight
down = Quartz.kCGEventRightMouseDown
up = Quartz.kCGEventRightMouseUp
else:
assert False, "button argument not in ('left', 'middle', 'right')"
return
for i in range(num):
_click(x, y, button)
time.sleep(interval)
def _sendMouseEvent(ev, x, y, button):
mouseEvent = Quartz.CGEventCreateMouseEvent(None, ev, (x, y), button)
Quartz.CGEventPost(Quartz.kCGHIDEventTap, mouseEvent)
def _dragTo(x, y, button):
if button == LEFT:
_sendMouseEvent(Quartz.kCGEventLeftMouseDragged , x, y, Quartz.kCGMouseButtonLeft)
elif button == MIDDLE:
_sendMouseEvent(Quartz.kCGEventOtherMouseDragged , x, y, Quartz.kCGMouseButtonCenter)
elif button == RIGHT:
_sendMouseEvent(Quartz.kCGEventRightMouseDragged , x, y, Quartz.kCGMouseButtonRight)
else:
assert False, "button argument not in ('left', 'middle', 'right')"
time.sleep(pyautogui.DARWIN_CATCH_UP_TIME) # needed to allow OS time to catch up.
def _moveTo(x, y):
_sendMouseEvent(Quartz.kCGEventMouseMoved, x, y, 0)
time.sleep(pyautogui.DARWIN_CATCH_UP_TIME) # needed to allow OS time to catch up.

View File

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

View File

@@ -0,0 +1,300 @@
# NOTE - It is a known issue that the keyboard-related functions don't work on Ubuntu VMs in Virtualbox.
import pyautogui
import sys
import os
from pyautogui import LEFT, MIDDLE, RIGHT
from Xlib.display import Display
from Xlib import X
from Xlib.ext.xtest import fake_input
import Xlib.XK
BUTTON_NAME_MAPPING = {LEFT: 1, MIDDLE: 2, RIGHT: 3, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7}
if sys.platform in ('java', 'darwin', 'win32'):
raise Exception('The pyautogui_x11 module should only be loaded on a Unix system that supports X11.')
#from pyautogui import *
"""
Much of this code is based on information gleaned from Paul Barton's PyKeyboard in PyUserInput from 2013, itself derived from Akkana Peck's pykey in 2008 ( http://www.shallowsky.com/software/crikey/pykey-0.1 ), itself derived from her "Crikey" lib.
"""
def _position():
"""Returns the current xy coordinates of the mouse cursor as a two-integer
tuple.
Returns:
(x, y) tuple of the current xy coordinates of the mouse cursor.
"""
coord = _display.screen().root.query_pointer()._data
return coord["root_x"], coord["root_y"]
def _size():
return _display.screen().width_in_pixels, _display.screen().height_in_pixels
def _vscroll(clicks, x=None, y=None):
clicks = int(clicks)
if clicks == 0:
return
elif clicks > 0:
button = 4 # scroll up
else:
button = 5 # scroll down
for i in range(abs(clicks)):
_click(x, y, button=button)
def _hscroll(clicks, x=None, y=None):
clicks = int(clicks)
if clicks == 0:
return
elif clicks > 0:
button = 7 # scroll right
else:
button = 6 # scroll left
for i in range(abs(clicks)):
_click(x, y, button=button)
def _scroll(clicks, x=None, y=None):
return _vscroll(clicks, x, y)
def _click(x, y, button):
assert button in BUTTON_NAME_MAPPING.keys(), "button argument not in ('left', 'middle', 'right', 4, 5, 6, 7)"
button = BUTTON_NAME_MAPPING[button]
_mouseDown(x, y, button)
_mouseUp(x, y, button)
def _moveTo(x, y):
fake_input(_display, X.MotionNotify, x=x, y=y)
_display.sync()
def _mouseDown(x, y, button):
_moveTo(x, y)
assert button in BUTTON_NAME_MAPPING.keys(), "button argument not in ('left', 'middle', 'right', 4, 5, 6, 7)"
button = BUTTON_NAME_MAPPING[button]
fake_input(_display, X.ButtonPress, button)
_display.sync()
def _mouseUp(x, y, button):
_moveTo(x, y)
assert button in BUTTON_NAME_MAPPING.keys(), "button argument not in ('left', 'middle', 'right', 4, 5, 6, 7)"
button = BUTTON_NAME_MAPPING[button]
fake_input(_display, X.ButtonRelease, button)
_display.sync()
def _keyDown(key):
"""Performs a keyboard key press without the release. This will put that
key in a held down state.
NOTE: For some reason, this does not seem to cause key repeats like would
happen if a keyboard key was held down on a text field.
Args:
key (str): The key to be pressed down. The valid names are listed in
pyautogui.KEY_NAMES.
Returns:
None
"""
if key not in keyboardMapping or keyboardMapping[key] is None:
return
if type(key) == int:
fake_input(_display, X.KeyPress, key)
_display.sync()
return
needsShift = pyautogui.isShiftCharacter(key)
if needsShift:
fake_input(_display, X.KeyPress, keyboardMapping['shift'])
fake_input(_display, X.KeyPress, keyboardMapping[key])
if needsShift:
fake_input(_display, X.KeyRelease, keyboardMapping['shift'])
_display.sync()
def _keyUp(key):
"""Performs a keyboard key release (without the press down beforehand).
Args:
key (str): The key to be released up. The valid names are listed in
pyautogui.KEY_NAMES.
Returns:
None
"""
"""
Release a given character key. Also works with character keycodes as
integers, but not keysyms.
"""
if key not in keyboardMapping or keyboardMapping[key] is None:
return
if type(key) == int:
keycode = key
else:
keycode = keyboardMapping[key]
fake_input(_display, X.KeyRelease, keycode)
_display.sync()
# Taken from PyKeyboard's ctor function.
_display = Display(os.environ['DISPLAY'])
""" Information for keyboardMapping derived from PyKeyboard's special_key_assignment() function.
The *KB dictionaries in pyautogui map a string that can be passed to keyDown(),
keyUp(), or press() into the code used for the OS-specific keyboard function.
They should always be lowercase, and the same keys should be used across all OSes."""
keyboardMapping = dict([(key, None) for key in pyautogui.KEY_NAMES])
keyboardMapping.update({
'backspace': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('BackSpace')),
'\b': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('BackSpace')),
'tab': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Tab')),
'enter': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Return')),
'return': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Return')),
'shift': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Shift_L')),
'ctrl': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Control_L')),
'alt': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Alt_L')),
'pause': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Pause')),
'capslock': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Caps_Lock')),
'esc': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Escape')),
'escape': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Escape')),
'pgup': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Page_Up')),
'pgdn': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Page_Down')),
'pageup': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Page_Up')),
'pagedown': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Page_Down')),
'end': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('End')),
'home': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Home')),
'left': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Left')),
'up': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Up')),
'right': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Right')),
'down': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Down')),
'select': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Select')),
'print': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Print')),
'execute': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Execute')),
'prtsc': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Print')),
'prtscr': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Print')),
'prntscrn': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Print')),
'printscreen': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Print')),
'insert': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Insert')),
'del': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Delete')),
'delete': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Delete')),
'help': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Help')),
'win': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Super_L')),
'winleft': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Super_L')),
'winright': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Super_R')),
'apps': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Menu')),
'num0': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_0')),
'num1': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_1')),
'num2': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_2')),
'num3': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_3')),
'num4': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_4')),
'num5': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_5')),
'num6': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_6')),
'num7': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_7')),
'num8': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_8')),
'num9': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_9')),
'multiply': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_Multiply')),
'add': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_Add')),
'separator': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_Separator')),
'subtract': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_Subtract')),
'decimal': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_Decimal')),
'divide': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('KP_Divide')),
'f1': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F1')),
'f2': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F2')),
'f3': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F3')),
'f4': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F4')),
'f5': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F5')),
'f6': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F6')),
'f7': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F7')),
'f8': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F8')),
'f9': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F9')),
'f10': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F10')),
'f11': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F11')),
'f12': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F12')),
'f13': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F13')),
'f14': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F14')),
'f15': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F15')),
'f16': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F16')),
'f17': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F17')),
'f18': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F18')),
'f19': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F19')),
'f20': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F20')),
'f21': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F21')),
'f22': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F22')),
'f23': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F23')),
'f24': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('F24')),
'numlock': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Num_Lock')),
'scrolllock': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Scroll_Lock')),
'shiftleft': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Shift_L')),
'shiftright': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Shift_R')),
'ctrlleft': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Control_L')),
'ctrlright': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Control_R')),
'altleft': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Alt_L')),
'altright': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Alt_R')),
# These are added because unlike a-zA-Z0-9, the single characters do not have a
' ': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('space')),
'space': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('space')),
'\t': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Tab')),
'\n': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Return')), # for some reason this needs to be cr, not lf
'\r': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Return')),
'\e': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Escape')),
'!': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('exclam')),
'#': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('numbersign')),
'%': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('percent')),
'$': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('dollar')),
'&': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('ampersand')),
'"': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('quotedbl')),
"'": _display.keysym_to_keycode(Xlib.XK.string_to_keysym('apostrophe')),
'(': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('parenleft')),
')': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('parenright')),
'*': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('asterisk')),
'=': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('equal')),
'+': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('plus')),
',': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('comma')),
'-': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('minus')),
'.': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('period')),
'/': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('slash')),
':': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('colon')),
';': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('semicolon')),
'<': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('less')),
'>': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('greater')),
'?': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('question')),
'@': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('at')),
'[': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('bracketleft')),
']': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('bracketright')),
'\\': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('backslash')),
'^': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('asciicircum')),
'_': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('underscore')),
'`': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('grave')),
'{': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('braceleft')),
'|': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('bar')),
'}': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('braceright')),
'~': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('asciitilde')),
})
# Trading memory for time" populate winKB so we don't have to call VkKeyScanA each time.
for c in """abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890""":
keyboardMapping[c] = _display.keysym_to_keycode(Xlib.XK.string_to_keysym(c))