You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ORPA-pyOpenRPA/WPy32-3720/python-3.7.2/Lib/site-packages/pywinauto/mouse.py

266 lines
10 KiB

6 years ago
# GUI Application automation and testing library
# Copyright (C) 2006-2018 Mark Mc Mahon and Contributors
# https://github.com/pywinauto/pywinauto/graphs/contributors
# http://pywinauto.readthedocs.io/en/latest/credits.html
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of pywinauto nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Cross-platform module to emulate mouse events like a real user"""
import sys
import time
if sys.platform == 'win32':
import pywintypes
from . import win32functions
from . import win32defines
from .timings import Timings
import win32api
import win32gui
from . import keyboard
else:
from Xlib.display import Display
from Xlib import X
from Xlib.ext.xtest import fake_input
BUTTON_MAPPING = {'left': 0, 'middle': 1, 'right': 2, 'up_scroll': 3,
'down_scroll': 4, 'left_scroll': 5, 'right_scroll': 6}
if sys.platform == 'win32':
def _set_cursor_pos(coords):
"""Wrapped SetCursorPos that handles non-active desktop case (coords is a tuple)"""
try:
win32api.SetCursorPos(coords)
except pywintypes.error as exc:
if str(exc) == "(0, 'SetCursorPos', 'No error message is available')":
raise RuntimeError("There is no active desktop required for moving mouse cursor!\n")
else:
raise exc
def _perform_click_input(
button="left",
coords=(None, None),
double=False,
button_down=True,
button_up=True,
wheel_dist=0,
pressed="",
key_down=True,
key_up=True,
):
"""Perform a click action using SendInput
All the *click_input() and *mouse_input() methods use this function.
Thanks to a bug report from Tomas Walch (twalch) on sourceforge and code
seen at http://msdn.microsoft.com/en-us/magazine/cc164126.aspx this
function now always works the same way whether the mouse buttons are
swapped or not.
For example if you send a right click to Notepad.Edit - it will always
bring up a popup menu rather than 'clicking' it.
"""
# Handle if the mouse buttons are swapped
if win32functions.GetSystemMetrics(win32defines.SM_SWAPBUTTON):
if button.lower() == 'left':
button = 'right'
elif button.lower() == 'right':
button = 'left'
events = []
if button.lower() == 'left':
events.append(win32defines.MOUSEEVENTF_MOVE)
if button_down:
events.append(win32defines.MOUSEEVENTF_LEFTDOWN)
if button_up:
events.append(win32defines.MOUSEEVENTF_LEFTUP)
elif button.lower() == 'right':
if button_down:
events.append(win32defines.MOUSEEVENTF_RIGHTDOWN)
if button_up:
events.append(win32defines.MOUSEEVENTF_RIGHTUP)
elif button.lower() == 'middle':
if button_down:
events.append(win32defines.MOUSEEVENTF_MIDDLEDOWN)
if button_up:
events.append(win32defines.MOUSEEVENTF_MIDDLEUP)
elif button.lower() == 'move':
events.append(win32defines.MOUSEEVENTF_MOVE)
events.append(win32defines.MOUSEEVENTF_ABSOLUTE)
elif button.lower() == 'x':
if button_down:
events.append(win32defines.MOUSEEVENTF_XDOWN)
if button_up:
events.append(win32defines.MOUSEEVENTF_XUP)
if button.lower() == 'wheel':
events.append(win32defines.MOUSEEVENTF_WHEEL)
# if we were asked to double click (and we are doing a full click
# not just up or down.
if double and button_down and button_up:
events *= 2
if button_down and (button.lower() not in ['move', 'wheel']):
# wait while previous click is not affecting our current click
while 0 < win32api.GetTickCount() - win32api.GetLastInputInfo() < win32gui.GetDoubleClickTime():
time.sleep(Timings.after_clickinput_wait)
# set the cursor position
_set_cursor_pos((coords[0], coords[1]))
time.sleep(Timings.after_setcursorpos_wait)
if win32api.GetCursorPos() != (coords[0], coords[1]):
_set_cursor_pos((coords[0], coords[1]))
time.sleep(Timings.after_setcursorpos_wait)
keyboard_keys = pressed.lower().split()
if ('control' in keyboard_keys) and key_down:
keyboard.VirtualKeyAction(keyboard.VK_CONTROL, up=False).run()
if ('shift' in keyboard_keys) and key_down:
keyboard.VirtualKeyAction(keyboard.VK_SHIFT, up=False).run()
if ('alt' in keyboard_keys) and key_down:
keyboard.VirtualKeyAction(keyboard.VK_MENU, up=False).run()
dw_flags = 0
for event in events:
dw_flags |= event
dw_data = 0
if button.lower() == 'wheel':
wheel_dist = wheel_dist * 120
dw_data = wheel_dist
if button.lower() == 'move':
x_res = win32functions.GetSystemMetrics(win32defines.SM_CXSCREEN)
y_res = win32functions.GetSystemMetrics(win32defines.SM_CYSCREEN)
x_coord = int(float(coords[0]) * (65535. / float(x_res - 1)))
y_coord = int(float(coords[1]) * (65535. / float(y_res - 1)))
win32api.mouse_event(dw_flags, x_coord, y_coord, dw_data)
else:
for event in events:
if event == win32defines.MOUSEEVENTF_MOVE:
x_res = win32functions.GetSystemMetrics(win32defines.SM_CXSCREEN)
y_res = win32functions.GetSystemMetrics(win32defines.SM_CYSCREEN)
x_coord = int(float(coords[0]) * (65535. / float(x_res - 1)))
y_coord = int(float(coords[1]) * (65535. / float(y_res - 1)))
win32api.mouse_event(
win32defines.MOUSEEVENTF_MOVE | win32defines.MOUSEEVENTF_ABSOLUTE,
x_coord, y_coord, dw_data)
else:
win32api.mouse_event(
event | win32defines.MOUSEEVENTF_ABSOLUTE,
coords[0], coords[1], dw_data)
time.sleep(Timings.after_clickinput_wait)
if ('control' in keyboard_keys) and key_up:
keyboard.VirtualKeyAction(keyboard.VK_CONTROL, down=False).run()
if ('shift' in keyboard_keys) and key_up:
keyboard.VirtualKeyAction(keyboard.VK_SHIFT, down=False).run()
if ('alt' in keyboard_keys) and key_up:
keyboard.VirtualKeyAction(keyboard.VK_MENU, down=False).run()
else:
_display = Display()
def _perform_click_input(button='left', coords=(0, 0),
button_down=True, button_up=True, double=False,
wheel_dist=0, pressed="", key_down=True, key_up=True):
"""Perform a click action using Python-xlib"""
#Move mouse
x = int(coords[0])
y = int(coords[1])
fake_input(_display, X.MotionNotify, x=x, y=y)
_display.sync()
if button == 'wheel':
if wheel_dist == 0:
return
if wheel_dist > 0:
button = 'up_scroll'
if wheel_dist < 0:
button = 'down_scroll'
for _ in range(abs(wheel_dist)):
_perform_click_input(button, coords)
else:
pointer_map = _display.get_pointer_mapping()
button = pointer_map[BUTTON_MAPPING[button]]
repeat = 1
if double:
repeat = 2
for _ in range(repeat):
if button_down:
fake_input(_display, X.ButtonPress, button)
_display.sync()
if button_up:
fake_input(_display, X.ButtonRelease, button)
_display.sync()
def click(button='left', coords=(0, 0)):
"""Click at the specified coordinates"""
_perform_click_input(button=button, coords=coords)
def double_click(button='left', coords=(0, 0)):
"""Double click at the specified coordinates"""
_perform_click_input(button=button, coords=coords, double=True)
def right_click(coords=(0, 0)):
"""Right click at the specified coords"""
_perform_click_input(button='right', coords=coords)
def move(coords=(0, 0)):
"""Move the mouse"""
_perform_click_input(button='move',coords=coords,button_down=False,button_up=False)
def press(button='left', coords=(0, 0)):
"""Press the mouse button"""
_perform_click_input(button=button, coords=coords, button_down=True, button_up=False)
def release(button='left', coords=(0, 0)):
"""Release the mouse button"""
_perform_click_input(button=button, coords=coords, button_down=False, button_up=True)
def scroll(coords=(0, 0), wheel_dist=1):
"""Do mouse wheel"""
if wheel_dist:
_perform_click_input(button='wheel', wheel_dist=wheel_dist, coords=coords)
def wheel_click(coords=(0, 0)):
"""Middle mouse button click at the specified coords"""
_perform_click_input(button='middle', coords=coords)