300 lines
15 KiB
Python
300 lines
15 KiB
Python
|
# 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')),
|
||
|
'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('Super_L')),
|
||
|
'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))
|