Ivan Maslov 4 years ago
commit 0e2caeb7db

@ -101,8 +101,19 @@ def Settings():
# "FlagAccess": True
# }
# ],
# "ControlPanelKeyAllowedList":[] # If empty - all is allowed
#}
# "ControlPanelKeyAllowedList":[], # If empty - all is allowed
# "RoleHierarchyAllowedDict": {
# "Orchestrator":{
# "Controls": {
# "RestartOrchestrator": {}, # Feature to restart orchestrator on virtual machine
# "LookMachineScreenshots": {} # Feature to look machina screenshots
# },
# "RDPActive": { # Robot RDP active module
# "ListRead": {} # Access to read RDP session list
# }
# }
# }
# }
},
"RuleMethodMatchURLBeforeList": [ #General MethodMatchURL list (no domain/user)
# {

@ -1,3 +1,20 @@
# Role model - if len of keys in dict is 0 - all access. If at least len is 1 - only this access
# "Orchestrator":{
# "Controls": {
# "RestartOrchestrator": {}, # Feature to restart orchestrator on virtual machine
# "LookMachineScreenshots": {} # Feature to look machina screenshots
# },
# "RDPActive": { # Robot RDP active module
# "ListRead": {} # Access to read RDP session list
# }
# }
# }
# USAGE in .py
# inRequest.
# inRequest.OpenRPA["DefUserRoleAccessAsk"](["Orchestrator","RDPActive","Controls"]) - return True or False
# inRequest.OpenRPA["DefUserRoleHierarchyGet"]() - Return dict of the role hierarchy or {}
# Init Section
gUserNameStr = "Login" # User name without domain name
gDomainNameStr = "" # DOMAIN or EMPTY str if no domain

@ -1,5 +1,5 @@
# OpenRPA
First open source RPA platform for business is released!
# pyOpenRPA
Powerfull OpenSource RPA tool for business (based on python 3). Best perfomance and absolutely free!
# How to run
Studio
@ -38,19 +38,29 @@ Resources\WPy64-3720\python-3.7.2.amd64\python.exe
Получить список элементов, который удовлетворяет условиям через расширенный движок поиска
[
{
"index":<Позиция элемента в родительском объекте>,
"depth_start" - глубина, с которой начинается поиск (по умолчанию 1)
"depth_end" - глубина, до которой ведется поиск (по умолчанию 1)
"class_name" - наименование класса, который требуется искать
"title" - наименование заголовка
"rich_text" - наименование rich_text
"index":<index in parent ui object>,
"depth_start" - search start depth (default is 1)
"depth_end" - search stop depth (по умолчанию 1)
"class_name" - class name attribute for search in ui objects
"title" - title attribute of the ui object
"rich_text" - attribute os the ui object rich_text
}
]
# Open RPA Wiki
- [Home](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/home)
- [04. Desktop app access (win32 & ui automation)](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/04.-Desktop-app-access-(win32-&-ui-automation))
## Content
In wiki you can find:
- [About OpenRPA, library dependencies and licensing](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/01.-About-OpenRPA,-library-dependencies-and-licensing)
- [Architecture (Studio, Robot, Orchestrator)](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/02.-Architecture-(Studio,-Robot,-Orchestrator))
- [How to install (system requirements)](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/03.-How-to-install-(system-requirements))
- [Tool Studio: How to use](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/04.1.-Tool-Studio:-How-to-use)
- [Tool Robot: How to use](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/04.2.-Tool-Robot:-How-to-use)
- Tool Orchestrator: How to use
- [Theory & practice: Web app access (Chrome, Firefox, Opera)](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/05.1.-Theory-&-practice:-Web-app-access-(Chrome,-Firefox,-Opera))
- [Theory & practice: Desktop app UI access (win32 and UI automation dlls)](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/05.2.-Theory-&-practice:-Desktop-app-UI-access-(win32-and-UI-automation-dlls))
- Theory & practice: Keyboard & mouse manipulation
- Theory & practice: Screen capture & image recognition
#Dependencies
* Python 3 x32 [psutil, pywinauto, wmi, PIL, keyboard, pyautogui, win32api (pywin32), selenium, openCV, tesseract, requests, lxml, PyMuPDF]
@ -60,4 +70,4 @@ Resources\WPy64-3720\python-3.7.2.amd64\python.exe
* JsRender by https://www.jsviews.com (switch to Handlebars)
* Handlebars
Created by Unicode Labs (Ivan Maslov)
Created by Ivan Maslov (Russia)

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 Lucas Boppre Niehues
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,62 @@
Metadata-Version: 2.1
Name: mouse
Version: 0.7.1
Summary: Hook and simulate mouse events on Windows and Linux
Home-page: https://github.com/boppreh/mouse
Author: BoppreH
Author-email: boppreh@gmail.com
License: MIT
Keywords: mouse hook simulate hotkey
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: Unix
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Utilities
Description-Content-Type: text/markdown
mouse
=====
Take full control of your mouse with this small Python library. Hook global events, register hotkeys, simulate mouse movement and clicks, and much more.
_Huge thanks to [Kirill Pavlov](http://kirillpavlov.com/) for donating the package name. If you are looking for the Cheddargetter.com client implementation, [`pip install mouse==0.5.0`](https://pypi.python.org/pypi/mouse/0.5.0)._
## Features
- Global event hook on all mice devices (captures events regardless of focus).
- **Listen** and **sends** mouse events.
- Works with **Windows** and **Linux** (requires sudo).
- **Pure Python**, no C modules to be compiled.
- **Zero dependencies**. Trivial to install and deploy, just copy the files.
- **Python 2 and 3**.
- Includes **high level API** (e.g. [record](#mouse.record) and [play](#mouse.play).
- Events automatically captured in separate thread, doesn't block main program.
- Tested and documented.
This program makes no attempt to hide itself, so don't use it for keyloggers.
## Usage
Install the [PyPI package](https://pypi.python.org/pypi/mouse/):
$ sudo pip install mouse
or clone the repository (no installation required, source files are sufficient):
$ git clone https://github.com/boppreh/mouse
Then check the [API docs](https://github.com/boppreh/mouse#api) to see what features are available.
## Known limitations:
- Events generated under Windows don't report device id (`event.device == None`). [#21](https://github.com/boppreh/keyboard/issues/21)
- To avoid depending on X the Linux parts reads raw device files (`/dev/input/input*`) but this requries root.
- Other applications, such as some games, may register hooks that swallow all key events. In this case `mouse` will be unable to report events.

@ -0,0 +1,22 @@
mouse-0.7.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
mouse-0.7.1.dist-info/LICENSE.txt,sha256=K_FKUlVV0FqAHC0sKJAVBPt2q-58LX6_tM_HUI198Pc,1077
mouse-0.7.1.dist-info/METADATA,sha256=7MmeikMZ3xgUFvcSNMnCnXugXuG0ag8QjFoOV1k9mr0,2455
mouse-0.7.1.dist-info/RECORD,,
mouse-0.7.1.dist-info/WHEEL,sha256=JZXtYepZFsf4IoivNpnSgKIc4qTHan08DRd56koo_DM,116
mouse-0.7.1.dist-info/top_level.txt,sha256=FiA9sXRt9_B8X6je4BlPesL9EakrmGZ0fDKPK09Ql6U,6
mouse/__init__.py,sha256=HGaiOxH8PuKnU2oCLN5pEN4yuvxH1JoxT1QXwITFlf0,9147
mouse/__main__.py,sha256=Rir1qIanuA6OUsVIywo71MgF1PrVCdZ77F1FPOu4JA0,625
mouse/__pycache__/__init__.cpython-37.pyc,,
mouse/__pycache__/__main__.cpython-37.pyc,,
mouse/__pycache__/_generic.cpython-37.pyc,,
mouse/__pycache__/_mouse_event.cpython-37.pyc,,
mouse/__pycache__/_mouse_tests.cpython-37.pyc,,
mouse/__pycache__/_nixcommon.cpython-37.pyc,,
mouse/__pycache__/_nixmouse.cpython-37.pyc,,
mouse/__pycache__/_winmouse.cpython-37.pyc,,
mouse/_generic.py,sha256=STzfL7AUAkcAq6XUyxpQiOYnBnQ1TZjWL1cSFSZ61_o,2132
mouse/_mouse_event.py,sha256=zRQGO6M6nbA-jvhI0yz4HzvQNcScF48PZ9iRegcTVjQ,422
mouse/_mouse_tests.py,sha256=gNa_NW5sRIsbLMG35ZfXal3eHS2mEpEPhysJRDq0gQA,10000
mouse/_nixcommon.py,sha256=FNXiCv7u_A0SzcYJQlYDJBSdIN6IUTVLG4g7oqXgj6o,5552
mouse/_nixmouse.py,sha256=3htKn9XkUApFqp3rGCT-ZQIqJFf4iGqoxxoO9MY2x4k,3576
mouse/_winmouse.py,sha256=lWAnfGq0etNjFR-vE9e3r9N7Amg5wU957B4ZS3YMTz0,6449

@ -1,5 +1,6 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.29.0)
Generator: bdist_wheel (0.33.6)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any

@ -0,0 +1,272 @@
# -*- coding: utf-8 -*-
"""
mouse
=====
Take full control of your mouse with this small Python library. Hook global events, register hotkeys, simulate mouse movement and clicks, and much more.
_Huge thanks to [Kirill Pavlov](http://kirillpavlov.com/) for donating the package name. If you are looking for the Cheddargetter.com client implementation, [`pip install mouse==0.5.0`](https://pypi.python.org/pypi/mouse/0.5.0)._
## Features
- Global event hook on all mice devices (captures events regardless of focus).
- **Listen** and **sends** mouse events.
- Works with **Windows** and **Linux** (requires sudo).
- **Pure Python**, no C modules to be compiled.
- **Zero dependencies**. Trivial to install and deploy, just copy the files.
- **Python 2 and 3**.
- Includes **high level API** (e.g. [record](#mouse.record) and [play](#mouse.play).
- Events automatically captured in separate thread, doesn't block main program.
- Tested and documented.
This program makes no attempt to hide itself, so don't use it for keyloggers.
## Usage
Install the [PyPI package](https://pypi.python.org/pypi/mouse/):
$ sudo pip install mouse
or clone the repository (no installation required, source files are sufficient):
$ git clone https://github.com/boppreh/mouse
Then check the [API docs](https://github.com/boppreh/mouse#api) to see what features are available.
## Known limitations:
- Events generated under Windows don't report device id (`event.device == None`). [#21](https://github.com/boppreh/keyboard/issues/21)
- To avoid depending on X the Linux parts reads raw device files (`/dev/input/input*`) but this requries root.
- Other applications, such as some games, may register hooks that swallow all key events. In this case `mouse` will be unable to report events.
"""
# TODO
# - infinite wait
# - mouse.on_move
version = '0.7.1'
import time as _time
import platform as _platform
if _platform.system() == 'Windows':
from. import _winmouse as _os_mouse
elif _platform.system() == 'Linux':
from. import _nixmouse as _os_mouse
else:
raise OSError("Unsupported platform '{}'".format(_platform.system()))
from ._mouse_event import ButtonEvent, MoveEvent, WheelEvent, LEFT, RIGHT, MIDDLE, X, X2, UP, DOWN, DOUBLE
from ._generic import GenericListener as _GenericListener
_pressed_events = set()
class _MouseListener(_GenericListener):
def init(self):
_os_mouse.init()
def pre_process_event(self, event):
if isinstance(event, ButtonEvent):
if event.event_type in (UP, DOUBLE):
_pressed_events.discard(event.button)
else:
_pressed_events.add(event.button)
return True
def listen(self):
_os_mouse.listen(self.queue)
_listener = _MouseListener()
def is_pressed(button=LEFT):
""" Returns True if the given button is currently pressed. """
_listener.start_if_necessary()
return button in _pressed_events
def press(button=LEFT):
""" Presses the given button (but doesn't release). """
_os_mouse.press(button)
def release(button=LEFT):
""" Releases the given button. """
_os_mouse.release(button)
def click(button=LEFT):
""" Sends a click with the given button. """
_os_mouse.press(button)
_os_mouse.release(button)
def double_click(button=LEFT):
""" Sends a double click with the given button. """
click(button)
click(button)
def right_click():
""" Sends a right click with the given button. """
click(RIGHT)
def wheel(delta=1):
""" Scrolls the wheel `delta` clicks. Sign indicates direction. """
_os_mouse.wheel(delta)
def move(x, y, absolute=True, duration=0):
"""
Moves the mouse. If `absolute`, to position (x, y), otherwise move relative
to the current position. If `duration` is non-zero, animates the movement.
"""
x = int(x)
y = int(y)
# Requires an extra system call on Linux, but `move_relative` is measured
# in millimiters so we would lose precision.
position_x, position_y = get_position()
if not absolute:
x = position_x + x
y = position_y + y
if duration:
start_x = position_x
start_y = position_y
dx = x - start_x
dy = y - start_y
if dx == 0 and dy == 0:
_time.sleep(duration)
else:
# 120 movements per second.
# Round and keep float to ensure float division in Python 2
steps = max(1.0, float(int(duration * 120.0)))
for i in range(int(steps)+1):
move(start_x + dx*i/steps, start_y + dy*i/steps)
_time.sleep(duration/steps)
else:
_os_mouse.move_to(x, y)
def drag(start_x, start_y, end_x, end_y, absolute=True, duration=0):
"""
Holds the left mouse button, moving from start to end position, then
releases. `absolute` and `duration` are parameters regarding the mouse
movement.
"""
if is_pressed():
release()
move(start_x, start_y, absolute, 0)
press()
move(end_x, end_y, absolute, duration)
release()
def on_button(callback, args=(), buttons=(LEFT, MIDDLE, RIGHT, X, X2), types=(UP, DOWN, DOUBLE)):
""" Invokes `callback` with `args` when the specified event happens. """
if not isinstance(buttons, (tuple, list)):
buttons = (buttons,)
if not isinstance(types, (tuple, list)):
types = (types,)
def handler(event):
if isinstance(event, ButtonEvent):
if event.event_type in types and event.button in buttons:
callback(*args)
_listener.add_handler(handler)
return handler
def on_click(callback, args=()):
""" Invokes `callback` with `args` when the left button is clicked. """
return on_button(callback, args, [LEFT], [UP])
def on_double_click(callback, args=()):
"""
Invokes `callback` with `args` when the left button is double clicked.
"""
return on_button(callback, args, [LEFT], [DOUBLE])
def on_right_click(callback, args=()):
""" Invokes `callback` with `args` when the right button is clicked. """
return on_button(callback, args, [RIGHT], [UP])
def on_middle_click(callback, args=()):
""" Invokes `callback` with `args` when the middle button is clicked. """
return on_button(callback, args, [MIDDLE], [UP])
def wait(button=LEFT, target_types=(UP, DOWN, DOUBLE)):
"""
Blocks program execution until the given button performs an event.
"""
from threading import Lock
lock = Lock()
lock.acquire()
handler = on_button(lock.release, (), [button], target_types)
lock.acquire()
_listener.remove_handler(handler)
def get_position():
""" Returns the (x, y) mouse position. """
return _os_mouse.get_position()
def hook(callback):
"""
Installs a global listener on all available mouses, invoking `callback`
each time it is moved, a key status changes or the wheel is spun. A mouse
event is passed as argument, with type either `mouse.ButtonEvent`,
`mouse.WheelEvent` or `mouse.MoveEvent`.
Returns the given callback for easier development.
"""
_listener.add_handler(callback)
return callback
def unhook(callback):
"""
Removes a previously installed hook.
"""
_listener.remove_handler(callback)
def unhook_all():
"""
Removes all hooks registered by this application. Note this may include
hooks installed by high level functions, such as `record`.
"""
del _listener.handlers[:]
def record(button=RIGHT, target_types=(DOWN,)):
"""
Records all mouse events until the user presses the given button.
Then returns the list of events recorded. Pairs well with `play(events)`.
Note: this is a blocking function.
Note: for more details on the mouse hook and events see `hook`.
"""
recorded = []
hook(recorded.append)
wait(button=button, target_types=target_types)
unhook(recorded.append)
return recorded
def play(events, speed_factor=1.0, include_clicks=True, include_moves=True, include_wheel=True):
"""
Plays a sequence of recorded events, maintaining the relative time
intervals. If speed_factor is <= 0 then the actions are replayed as fast
as the OS allows. Pairs well with `record()`.
The parameters `include_*` define if events of that type should be inluded
in the replay or ignored.
"""
last_time = None
for event in events:
if speed_factor > 0 and last_time is not None:
_time.sleep((event.time - last_time) / speed_factor)
last_time = event.time
if isinstance(event, ButtonEvent) and include_clicks:
if event.event_type == UP:
_os_mouse.release(event.button)
else:
_os_mouse.press(event.button)
elif isinstance(event, MoveEvent) and include_moves:
_os_mouse.move_to(event.x, event.y)
elif isinstance(event, WheelEvent) and include_wheel:
_os_mouse.wheel(event.delta)
replay = play
hold = press
if __name__ == '__main__':
print('Recording... Double click to stop and replay.')
play(record())

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
import mouse
import fileinput
import json
import sys
class_by_name = {
'ButtonEvent': mouse.ButtonEvent,
'WheelEvent': mouse.WheelEvent,
'MoveEvent': mouse.MoveEvent,
}
def print_event_json(event):
# Could use json.dumps(event.__dict__()), but this way we guarantee semantic order.
d = event._asdict()
d['event_class'] = event.__class__.__name__
print(json.dumps(d))
sys.stdout.flush()
mouse.hook(print_event_json)
def load(line):
d = json.loads(line)
class_ = class_by_name[d['event_class']]
del d['event_class']
return class_(**d)
mouse.play(load(line) for line in fileinput.input())

@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
from threading import Thread, Lock
import traceback
import functools
try:
from queue import Queue
except ImportError:
from Queue import Queue
class GenericListener(object):
lock = Lock()
def __init__(self):
self.handlers = []
self.listening = False
self.queue = Queue()
def invoke_handlers(self, event):
for handler in self.handlers:
try:
if handler(event):
# Stop processing this hotkey.
return 1
except Exception as e:
traceback.print_exc()
def start_if_necessary(self):
"""
Starts the listening thread if it wasn't already.
"""
self.lock.acquire()
try:
if not self.listening:
self.init()
self.listening = True
self.listening_thread = Thread(target=self.listen)
self.listening_thread.daemon = True
self.listening_thread.start()
self.processing_thread = Thread(target=self.process)
self.processing_thread.daemon = True
self.processing_thread.start()
finally:
self.lock.release()
def pre_process_event(self, event):
raise NotImplementedError('This method should be implemented in the child class.')
def process(self):
"""
Loops over the underlying queue of events and processes them in order.
"""
assert self.queue is not None
while True:
event = self.queue.get()
if self.pre_process_event(event):
self.invoke_handlers(event)
self.queue.task_done()
def add_handler(self, handler):
"""
Adds a function to receive each event captured, starting the capturing
process if necessary.
"""
self.start_if_necessary()
self.handlers.append(handler)
def remove_handler(self, handler):
""" Removes a previously added event handler. """
self.handlers.remove(handler)

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from collections import namedtuple
LEFT = 'left'
RIGHT = 'right'
MIDDLE = 'middle'
WHEEL = 'wheel'
X = 'x'
X2 = 'x2'
UP = 'up'
DOWN = 'down'
DOUBLE = 'double'
VERTICAL = 'vertical'
HORIZONTAL = 'horizontal'
ButtonEvent = namedtuple('ButtonEvent', ['event_type', 'button', 'time'])
WheelEvent = namedtuple('WheelEvent', ['delta', 'time'])
MoveEvent = namedtuple('MoveEvent', ['x', 'y', 'time'])

@ -0,0 +1,271 @@
# -*- coding: utf-8 -*-
import unittest
import time
from ._mouse_event import MoveEvent, ButtonEvent, WheelEvent, LEFT, RIGHT, MIDDLE, X, X2, UP, DOWN, DOUBLE
import mouse
class FakeOsMouse(object):
def __init__(self):
self.append = None
self.position = (0, 0)
self.queue = None
self.init = lambda: None
def listen(self, queue):
self.listening = True
self.queue = queue
def press(self, button):
self.append((DOWN, button))
def release(self, button):
self.append((UP, button))
def get_position(self):
return self.position
def move_to(self, x, y):
self.append(('move', (x, y)))
self.position = (x, y)
def wheel(self, delta):
self.append(('wheel', delta))
def move_relative(self, x, y):
self.position = (self.position[0] + x, self.position[1] + y)
class TestMouse(unittest.TestCase):
@staticmethod
def setUpClass():
mouse._os_mouse= FakeOsMouse()
mouse._listener.start_if_necessary()
assert mouse._os_mouse.listening
def setUp(self):
self.events = []
mouse._pressed_events.clear()
mouse._os_mouse.append = self.events.append
def tearDown(self):
mouse.unhook_all()
# Make sure there's no spill over between tests.
self.wait_for_events_queue()
def wait_for_events_queue(self):
mouse._listener.queue.join()
def flush_events(self):
self.wait_for_events_queue()
events = list(self.events)
# Ugly, but requried to work in Python2. Python3 has list.clear
del self.events[:]
return events
def press(self, button=LEFT):
mouse._os_mouse.queue.put(ButtonEvent(DOWN, button, time.time()))
self.wait_for_events_queue()
def release(self, button=LEFT):
mouse._os_mouse.queue.put(ButtonEvent(UP, button, time.time()))
self.wait_for_events_queue()
def double_click(self, button=LEFT):
mouse._os_mouse.queue.put(ButtonEvent(DOUBLE, button, time.time()))
self.wait_for_events_queue()
def click(self, button=LEFT):
self.press(button)
self.release(button)
def wheel(self, delta=1):
mouse._os_mouse.queue.put(WheelEvent(delta, time.time()))
self.wait_for_events_queue()
def move(self, x=0, y=0):
mouse._os_mouse.queue.put(MoveEvent(x, y, time.time()))
self.wait_for_events_queue()
def test_hook(self):
events = []
self.press()
mouse.hook(events.append)
self.press()
mouse.unhook(events.append)
self.press()
self.assertEqual(len(events), 1)
def test_is_pressed(self):
self.assertFalse(mouse.is_pressed())
self.press()
self.assertTrue(mouse.is_pressed())
self.release()
self.press(X2)
self.assertFalse(mouse.is_pressed())
self.assertTrue(mouse.is_pressed(X2))
self.press(X2)
self.assertTrue(mouse.is_pressed(X2))
self.release(X2)
self.release(X2)
self.assertFalse(mouse.is_pressed(X2))
def test_buttons(self):
mouse.press()
self.assertEqual(self.flush_events(), [(DOWN, LEFT)])
mouse.release()
self.assertEqual(self.flush_events(), [(UP, LEFT)])
mouse.click()
self.assertEqual(self.flush_events(), [(DOWN, LEFT), (UP, LEFT)])
mouse.double_click()
self.assertEqual(self.flush_events(), [(DOWN, LEFT), (UP, LEFT), (DOWN, LEFT), (UP, LEFT)])
mouse.right_click()
self.assertEqual(self.flush_events(), [(DOWN, RIGHT), (UP, RIGHT)])
mouse.click(RIGHT)
self.assertEqual(self.flush_events(), [(DOWN, RIGHT), (UP, RIGHT)])
mouse.press(X2)
self.assertEqual(self.flush_events(), [(DOWN, X2)])
def test_position(self):
self.assertEqual(mouse.get_position(), mouse._os_mouse.get_position())
def test_move(self):
mouse.move(0, 0)
self.assertEqual(mouse._os_mouse.get_position(), (0, 0))
mouse.move(100, 500)
self.assertEqual(mouse._os_mouse.get_position(), (100, 500))
mouse.move(1, 2, False)
self.assertEqual(mouse._os_mouse.get_position(), (101, 502))
mouse.move(0, 0)
mouse.move(100, 499, True, duration=0.01)
self.assertEqual(mouse._os_mouse.get_position(), (100, 499))
mouse.move(100, 1, False, duration=0.01)
self.assertEqual(mouse._os_mouse.get_position(), (200, 500))
mouse.move(0, 0, False, duration=0.01)
self.assertEqual(mouse._os_mouse.get_position(), (200, 500))
def triggers(self, fn, events, **kwargs):
self.triggered = False
def callback():
self.triggered = True
handler = fn(callback, **kwargs)
for event_type, arg in events:
if event_type == DOWN:
self.press(arg)
elif event_type == UP:
self.release(arg)
elif event_type == DOUBLE:
self.double_click(arg)
elif event_type == 'WHEEL':
self.wheel()
mouse._listener.remove_handler(handler)
return self.triggered
def test_on_button(self):
self.assertTrue(self.triggers(mouse.on_button, [(DOWN, LEFT)]))
self.assertTrue(self.triggers(mouse.on_button, [(DOWN, RIGHT)]))
self.assertTrue(self.triggers(mouse.on_button, [(DOWN, X)]))
self.assertFalse(self.triggers(mouse.on_button, [('WHEEL', '')]))
self.assertFalse(self.triggers(mouse.on_button, [(DOWN, X)], buttons=MIDDLE))
self.assertTrue(self.triggers(mouse.on_button, [(DOWN, MIDDLE)], buttons=MIDDLE))
self.assertTrue(self.triggers(mouse.on_button, [(DOWN, MIDDLE)], buttons=MIDDLE))
self.assertFalse(self.triggers(mouse.on_button, [(DOWN, MIDDLE)], buttons=MIDDLE, types=UP))
self.assertTrue(self.triggers(mouse.on_button, [(UP, MIDDLE)], buttons=MIDDLE, types=UP))
self.assertTrue(self.triggers(mouse.on_button, [(UP, MIDDLE)], buttons=[MIDDLE, LEFT], types=[UP, DOWN]))
self.assertTrue(self.triggers(mouse.on_button, [(DOWN, LEFT)], buttons=[MIDDLE, LEFT], types=[UP, DOWN]))
self.assertFalse(self.triggers(mouse.on_button, [(UP, X)], buttons=[MIDDLE, LEFT], types=[UP, DOWN]))
def test_ons(self):
self.assertTrue(self.triggers(mouse.on_click, [(UP, LEFT)]))
self.assertFalse(self.triggers(mouse.on_click, [(UP, RIGHT)]))
self.assertFalse(self.triggers(mouse.on_click, [(DOWN, LEFT)]))
self.assertFalse(self.triggers(mouse.on_click, [(DOWN, RIGHT)]))
self.assertTrue(self.triggers(mouse.on_double_click, [(DOUBLE, LEFT)]))
self.assertFalse(self.triggers(mouse.on_double_click, [(DOUBLE, RIGHT)]))
self.assertFalse(self.triggers(mouse.on_double_click, [(DOWN, RIGHT)]))
self.assertTrue(self.triggers(mouse.on_right_click, [(UP, RIGHT)]))
self.assertTrue(self.triggers(mouse.on_middle_click, [(UP, MIDDLE)]))
def test_wait(self):
# If this fails it blocks. Unfortunately, but I see no other way of testing.
from threading import Thread, Lock
lock = Lock()
lock.acquire()
def t():
mouse.wait()
lock.release()
Thread(target=t).start()
self.press()
lock.acquire()
def test_record_play(self):
from threading import Thread, Lock
lock = Lock()
lock.acquire()
def t():
self.recorded = mouse.record(RIGHT)
lock.release()
Thread(target=t).start()
self.click()
self.wheel(5)
self.move(100, 50)
self.press(RIGHT)
lock.acquire()
self.assertEqual(len(self.recorded), 5)
self.assertEqual(self.recorded[0]._replace(time=None), ButtonEvent(DOWN, LEFT, None))
self.assertEqual(self.recorded[1]._replace(time=None), ButtonEvent(UP, LEFT, None))
self.assertEqual(self.recorded[2]._replace(time=None), WheelEvent(5, None))
self.assertEqual(self.recorded[3]._replace(time=None), MoveEvent(100, 50, None))
self.assertEqual(self.recorded[4]._replace(time=None), ButtonEvent(DOWN, RIGHT, None))
mouse.play(self.recorded, speed_factor=0)
events = self.flush_events()
self.assertEqual(len(events), 5)
self.assertEqual(events[0], (DOWN, LEFT))
self.assertEqual(events[1], (UP, LEFT))
self.assertEqual(events[2], ('wheel', 5))
self.assertEqual(events[3], ('move', (100, 50)))
self.assertEqual(events[4], (DOWN, RIGHT))
mouse.play(self.recorded)
events = self.flush_events()
self.assertEqual(len(events), 5)
self.assertEqual(events[0], (DOWN, LEFT))
self.assertEqual(events[1], (UP, LEFT))
self.assertEqual(events[2], ('wheel', 5))
self.assertEqual(events[3], ('move', (100, 50)))
self.assertEqual(events[4], (DOWN, RIGHT))
mouse.play(self.recorded, include_clicks=False)
events = self.flush_events()
self.assertEqual(len(events), 2)
self.assertEqual(events[0], ('wheel', 5))
self.assertEqual(events[1], ('move', (100, 50)))
mouse.play(self.recorded, include_moves=False)
events = self.flush_events()
self.assertEqual(len(events), 4)
self.assertEqual(events[0], (DOWN, LEFT))
self.assertEqual(events[1], (UP, LEFT))
self.assertEqual(events[2], ('wheel', 5))
self.assertEqual(events[3], (DOWN, RIGHT))
mouse.play(self.recorded, include_wheel=False)
events = self.flush_events()
self.assertEqual(len(events), 4)
self.assertEqual(events[0], (DOWN, LEFT))
self.assertEqual(events[1], (UP, LEFT))
self.assertEqual(events[2], ('move', (100, 50)))
self.assertEqual(events[3], (DOWN, RIGHT))
if __name__ == '__main__':
unittest.main()

@ -0,0 +1,165 @@
# -*- coding: utf-8 -*-
import struct
import os
import atexit
from time import time as now
from threading import Thread
from glob import glob
try:
from queue import Queue
except ImportError:
from Queue import Queue
event_bin_format = 'llHHI'
# Taken from include/linux/input.h
# https://www.kernel.org/doc/Documentation/input/event-codes.txt
EV_SYN = 0x00
EV_KEY = 0x01
EV_REL = 0x02
EV_ABS = 0x03
EV_MSC = 0x04
def make_uinput():
import fcntl, struct
# Requires uinput driver, but it's usually available.
uinput = open("/dev/uinput", 'wb')
UI_SET_EVBIT = 0x40045564
fcntl.ioctl(uinput, UI_SET_EVBIT, EV_KEY)
UI_SET_KEYBIT = 0x40045565
for i in range(256):
fcntl.ioctl(uinput, UI_SET_KEYBIT, i)
BUS_USB = 0x03
uinput_user_dev = "80sHHHHi64i64i64i64i"
axis = [0] * 64 * 4
uinput.write(struct.pack(uinput_user_dev, b"Virtual Keyboard", BUS_USB, 1, 1, 1, 0, *axis))
uinput.flush() # Without this you may get Errno 22: Invalid argument.
UI_DEV_CREATE = 0x5501
fcntl.ioctl(uinput, UI_DEV_CREATE)
UI_DEV_DESTROY = 0x5502
#fcntl.ioctl(uinput, UI_DEV_DESTROY)
return uinput
class EventDevice(object):
def __init__(self, path):
self.path = path
self._input_file = None
self._output_file = None
@property
def input_file(self):
if self._input_file is None:
try:
self._input_file = open(self.path, 'rb')
except IOError as e:
if e.strerror == 'Permission denied':
print('Permission denied ({}). You must be sudo to access global events.'.format(self.path))
exit()
def try_close():
try:
self._input_file.close
except:
pass
atexit.register(try_close)
return self._input_file
@property
def output_file(self):
if self._output_file is None:
self._output_file = open(self.path, 'wb')
atexit.register(self._output_file.close)
return self._output_file
def read_event(self):
data = self.input_file.read(struct.calcsize(event_bin_format))
seconds, microseconds, type, code, value = struct.unpack(event_bin_format, data)
return seconds + microseconds / 1e6, type, code, value, self.path
def write_event(self, type, code, value):
integer, fraction = divmod(now(), 1)
seconds = int(integer)
microseconds = int(fraction * 1e6)
data_event = struct.pack(event_bin_format, seconds, microseconds, type, code, value)
# Send a sync event to ensure other programs update.
sync_event = struct.pack(event_bin_format, seconds, microseconds, EV_SYN, 0, 0)
self.output_file.write(data_event + sync_event)
self.output_file.flush()
class AggregatedEventDevice(object):
def __init__(self, devices, output=None):
self.event_queue = Queue()
self.devices = devices
self.output = output or self.devices[0]
def start_reading(device):
while True:
self.event_queue.put(device.read_event())
for device in self.devices:
thread = Thread(target=start_reading, args=[device])
thread.setDaemon(True)
thread.start()
def read_event(self):
return self.event_queue.get(block=True)
def write_event(self, type, code, value):
self.output.write_event(type, code, value)
import re
from collections import namedtuple
DeviceDescription = namedtuple('DeviceDescription', 'event_file is_mouse is_keyboard')
device_pattern = r"""N: Name="([^"]+?)".+?H: Handlers=([^\n]+)"""
def list_devices_from_proc(type_name):
try:
with open('/proc/bus/input/devices') as f:
description = f.read()
except FileNotFoundError:
return
devices = {}
for name, handlers in re.findall(device_pattern, description, re.DOTALL):
path = '/dev/input/event' + re.search(r'event(\d+)', handlers).group(1)
if type_name in handlers:
yield EventDevice(path)
def list_devices_from_by_id(type_name):
for path in glob('/dev/input/by-id/*-event-' + type_name):
yield EventDevice(path)
def aggregate_devices(type_name):
# Some systems have multiple keyboards with different range of allowed keys
# on each one, like a notebook with a "keyboard" device exclusive for the
# power button. Instead of figuring out which keyboard allows which key to
# send events, we create a fake device and send all events through there.
uinput = make_uinput()
fake_device = EventDevice('uinput Fake Device')
fake_device._input_file = uinput
fake_device._output_file = uinput
# We don't aggregate devices from different sources to avoid
# duplicates.
devices_from_proc = list(list_devices_from_proc(type_name))
if devices_from_proc:
return AggregatedEventDevice(devices_from_proc, output=fake_device)
# breaks on mouse for virtualbox
# was getting /dev/input/by-id/usb-VirtualBox_USB_Tablet-event-mouse
devices_from_by_id = list(list_devices_from_by_id(type_name))
if devices_from_by_id:
return AggregatedEventDevice(devices_from_by_id, output=fake_device)
# If no keyboards were found we can only use the fake device to send keys.
return fake_device
def ensure_root():
if os.geteuid() != 0:
raise ImportError('You must be root to use this library on linux.')

@ -0,0 +1,131 @@
# -*- coding: utf-8 -*-
import struct
from subprocess import check_output
import re
from ._nixcommon import EV_KEY, EV_REL, EV_MSC, EV_SYN, EV_ABS, aggregate_devices, ensure_root
from ._mouse_event import ButtonEvent, WheelEvent, MoveEvent, LEFT, RIGHT, MIDDLE, X, X2, UP, DOWN
import ctypes
import ctypes.util
from ctypes import c_uint32, c_uint, c_int, c_void_p, byref
display = None
window = None
x11 = None
def build_display():
global display, window, x11
if display and window and x11: return
x11 = ctypes.cdll.LoadLibrary(ctypes.util.find_library('X11'))
# Required because we will have multiple threads calling x11,
# such as the listener thread and then main using "move_to".
x11.XInitThreads()
# Explicitly set XOpenDisplay.restype to avoid segfault on 64 bit OS.
# http://stackoverflow.com/questions/35137007/get-mouse-position-on-linux-pure-python
x11.XOpenDisplay.restype = c_void_p
display = c_void_p(x11.XOpenDisplay(0))
window = x11.XDefaultRootWindow(display)
def get_position():
build_display()
root_id, child_id = c_void_p(), c_void_p()
root_x, root_y, win_x, win_y = c_int(), c_int(), c_int(), c_int()
mask = c_uint()
ret = x11.XQueryPointer(display, c_uint32(window), byref(root_id), byref(child_id),
byref(root_x), byref(root_y),
byref(win_x), byref(win_y), byref(mask))
return root_x.value, root_y.value
def move_to(x, y):
build_display()
x11.XWarpPointer(display, None, window, 0, 0, 0, 0, x, y)
x11.XFlush(display)
REL_X = 0x00
REL_Y = 0x01
REL_Z = 0x02
REL_HWHEEL = 0x06
REL_WHEEL = 0x08
ABS_X = 0x00
ABS_Y = 0x01
BTN_MOUSE = 0x110
BTN_LEFT = 0x110
BTN_RIGHT = 0x111
BTN_MIDDLE = 0x112
BTN_SIDE = 0x113
BTN_EXTRA = 0x114
button_by_code = {
BTN_LEFT: LEFT,
BTN_RIGHT: RIGHT,
BTN_MIDDLE: MIDDLE,
BTN_SIDE: X,
BTN_EXTRA: X2,
}
code_by_button = {button: code for code, button in button_by_code.items()}
device = None
def build_device():
global device
if device: return
ensure_root()
device = aggregate_devices('mouse')
init = build_device
def listen(queue):
build_device()
while True:
time, type, code, value, device_id = device.read_event()
if type == EV_SYN or type == EV_MSC:
continue
event = None
arg = None
if type == EV_KEY:
event = ButtonEvent(DOWN if value else UP, button_by_code.get(code, '?'), time)
elif type == EV_REL:
value, = struct.unpack('i', struct.pack('I', value))
if code == REL_WHEEL:
event = WheelEvent(value, time)
elif code in (REL_X, REL_Y):
x, y = get_position()
event = MoveEvent(x, y, time)
if event is None:
# Unknown event type.
continue
queue.put(event)
def press(button=LEFT):
build_device()
device.write_event(EV_KEY, code_by_button[button], 0x01)
def release(button=LEFT):
build_device()
device.write_event(EV_KEY, code_by_button[button], 0x00)
def move_relative(x, y):
build_device()
# Note relative events are not in terms of pixels, but millimeters.
if x < 0:
x += 2**32
if y < 0:
y += 2**32
device.write_event(EV_REL, REL_X, x)
device.write_event(EV_REL, REL_Y, y)
def wheel(delta=1):
build_device()
if delta < 0:
delta += 2**32
device.write_event(EV_REL, REL_WHEEL, delta)
if __name__ == '__main__':
#listen(print)
move_to(100, 200)

@ -0,0 +1,216 @@
# -*- coding: utf-8 -*-
import ctypes
import time
from ctypes import c_short, c_char, c_uint8, c_int32, c_int, c_uint, c_uint32, c_long, byref, Structure, CFUNCTYPE, POINTER
from ctypes.wintypes import DWORD, BOOL, HHOOK, MSG, LPWSTR, WCHAR, WPARAM, LPARAM
LPMSG = POINTER(MSG)
import atexit
from ._mouse_event import ButtonEvent, WheelEvent, MoveEvent, LEFT, RIGHT, MIDDLE, X, X2, UP, DOWN, DOUBLE, WHEEL, HORIZONTAL, VERTICAL
#user32 = ctypes.windll.user32
user32 = ctypes.WinDLL('user32', use_last_error = True)
class MSLLHOOKSTRUCT(Structure):
_fields_ = [("x", c_long),
("y", c_long),
('data', c_int32),
('reserved', c_int32),
("flags", DWORD),
("time", c_int),
]
LowLevelMouseProc = CFUNCTYPE(c_int, WPARAM, LPARAM, POINTER(MSLLHOOKSTRUCT))
SetWindowsHookEx = user32.SetWindowsHookExA
#SetWindowsHookEx.argtypes = [c_int, LowLevelMouseProc, c_int, c_int]
SetWindowsHookEx.restype = HHOOK
CallNextHookEx = user32.CallNextHookEx
#CallNextHookEx.argtypes = [c_int , c_int, c_int, POINTER(MSLLHOOKSTRUCT)]
CallNextHookEx.restype = c_int
UnhookWindowsHookEx = user32.UnhookWindowsHookEx
UnhookWindowsHookEx.argtypes = [HHOOK]
UnhookWindowsHookEx.restype = BOOL
GetMessage = user32.GetMessageW
GetMessage.argtypes = [LPMSG, c_int, c_int, c_int]
GetMessage.restype = BOOL
TranslateMessage = user32.TranslateMessage
TranslateMessage.argtypes = [LPMSG]
TranslateMessage.restype = BOOL
DispatchMessage = user32.DispatchMessageA
DispatchMessage.argtypes = [LPMSG]
GetDoubleClickTime = user32.GetDoubleClickTime
# Beware, as of 2016-01-30 the official docs have a very incomplete list.
# This one was compiled from experience and may be incomplete.
WM_MOUSEMOVE = 0x200
WM_LBUTTONDOWN = 0x201
WM_LBUTTONUP = 0x202
WM_LBUTTONDBLCLK = 0x203
WM_RBUTTONDOWN = 0x204
WM_RBUTTONUP = 0x205
WM_RBUTTONDBLCLK = 0x206
WM_MBUTTONDOWN = 0x207
WM_MBUTTONUP = 0x208
WM_MBUTTONDBLCLK = 0x209
WM_MOUSEWHEEL = 0x20A
WM_XBUTTONDOWN = 0x20B
WM_XBUTTONUP = 0x20C
WM_XBUTTONDBLCLK = 0x20D
WM_NCXBUTTONDOWN = 0x00AB
WM_NCXBUTTONUP = 0x00AC
WM_NCXBUTTONDBLCLK = 0x00AD
WM_MOUSEHWHEEL = 0x20E
WM_LBUTTONDOWN = 0x0201
WM_LBUTTONUP = 0x0202
WM_MOUSEMOVE = 0x0200
WM_MOUSEWHEEL = 0x020A
WM_MOUSEHWHEEL = 0x020E
WM_RBUTTONDOWN = 0x0204
WM_RBUTTONUP = 0x0205
buttons_by_wm_code = {
WM_LBUTTONDOWN: (DOWN, LEFT),
WM_LBUTTONUP: (UP, LEFT),
WM_LBUTTONDBLCLK: (DOUBLE, LEFT),
WM_RBUTTONDOWN: (DOWN, RIGHT),
WM_RBUTTONUP: (UP, RIGHT),
WM_RBUTTONDBLCLK: (DOUBLE, RIGHT),
WM_MBUTTONDOWN: (DOWN, MIDDLE),
WM_MBUTTONUP: (UP, MIDDLE),
WM_MBUTTONDBLCLK: (DOUBLE, MIDDLE),
WM_XBUTTONDOWN: (DOWN, X),
WM_XBUTTONUP: (UP, X),
WM_XBUTTONDBLCLK: (DOUBLE, X),
}
MOUSEEVENTF_ABSOLUTE = 0x8000
MOUSEEVENTF_MOVE = 0x1
MOUSEEVENTF_WHEEL = 0x800
MOUSEEVENTF_HWHEEL = 0x1000
MOUSEEVENTF_LEFTDOWN = 0x2
MOUSEEVENTF_LEFTUP = 0x4
MOUSEEVENTF_RIGHTDOWN = 0x8
MOUSEEVENTF_RIGHTUP = 0x10
MOUSEEVENTF_MIDDLEDOWN = 0x20
MOUSEEVENTF_MIDDLEUP = 0x40
MOUSEEVENTF_XDOWN = 0x0080
MOUSEEVENTF_XUP = 0x0100
simulated_mouse_codes = {
(WHEEL, HORIZONTAL): MOUSEEVENTF_HWHEEL,
(WHEEL, VERTICAL): MOUSEEVENTF_WHEEL,
(DOWN, LEFT): MOUSEEVENTF_LEFTDOWN,
(UP, LEFT): MOUSEEVENTF_LEFTUP,
(DOWN, RIGHT): MOUSEEVENTF_RIGHTDOWN,
(UP, RIGHT): MOUSEEVENTF_RIGHTUP,
(DOWN, MIDDLE): MOUSEEVENTF_MIDDLEDOWN,
(UP, MIDDLE): MOUSEEVENTF_MIDDLEUP,
(DOWN, X): MOUSEEVENTF_XDOWN,
(UP, X): MOUSEEVENTF_XUP,
}
NULL = c_int(0)
WHEEL_DELTA = 120
init = lambda: None
previous_button_event = None # defined in global scope
def listen(queue):
def low_level_mouse_handler(nCode, wParam, lParam):
global previous_button_event
struct = lParam.contents
# Can't use struct.time because it's usually zero.
t = time.time()
if wParam == WM_MOUSEMOVE:
event = MoveEvent(struct.x, struct.y, t)
elif wParam == WM_MOUSEWHEEL:
event = WheelEvent(struct.data / (WHEEL_DELTA * (2<<15)), t)
elif wParam in buttons_by_wm_code:
type, button = buttons_by_wm_code.get(wParam, ('?', '?'))
if wParam >= WM_XBUTTONDOWN:
button = {0x10000: X, 0x20000: X2}[struct.data]
event = ButtonEvent(type, button, t)
if (event.event_type == DOWN) and previous_button_event is not None:
# https://msdn.microsoft.com/en-us/library/windows/desktop/gg153548%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
if event.time - previous_button_event.time <= GetDoubleClickTime() / 1000.0:
event = ButtonEvent(DOUBLE, event.button, event.time)
previous_button_event = event
else:
# Unknown event type.
return CallNextHookEx(NULL, nCode, wParam, lParam)
queue.put(event)
return CallNextHookEx(NULL, nCode, wParam, lParam)
WH_MOUSE_LL = c_int(14)
mouse_callback = LowLevelMouseProc(low_level_mouse_handler)
mouse_hook = SetWindowsHookEx(WH_MOUSE_LL, mouse_callback, NULL, NULL)
# Register to remove the hook when the interpreter exits. Unfortunately a
# try/finally block doesn't seem to work here.
atexit.register(UnhookWindowsHookEx, mouse_hook)
msg = LPMSG()
while not GetMessage(msg, NULL, NULL, NULL):
TranslateMessage(msg)
DispatchMessage(msg)
def _translate_button(button):
if button == X or button == X2:
return X, {X: 0x10000, X2: 0x20000}[button]
else:
return button, 0
def press(button=LEFT):
button, data = _translate_button(button)
code = simulated_mouse_codes[(DOWN, button)]
user32.mouse_event(code, 0, 0, data, 0)
def release(button=LEFT):
button, data = _translate_button(button)
code = simulated_mouse_codes[(UP, button)]
user32.mouse_event(code, 0, 0, data, 0)
def wheel(delta=1):
code = simulated_mouse_codes[(WHEEL, VERTICAL)]
user32.mouse_event(code, 0, 0, int(delta * WHEEL_DELTA), 0)
def move_to(x, y):
user32.SetCursorPos(int(x), int(y))
def move_relative(x, y):
user32.mouse_event(MOUSEEVENTF_MOVE, int(x), int(y), 0, 0)
class POINT(Structure):
_fields_ = [("x", c_long), ("y", c_long)]
def get_position():
point = POINT()
user32.GetCursorPos(byref(point))
return (point.x, point.y)
if __name__ == '__main__':
def p(e):
print(e)
listen(p)

@ -1,18 +1,25 @@
Metadata-Version: 2.1
Name: pyOpenRPA
Version: 1.1.3
Version: 1.1.13
Summary: First open source RPA platform for business
Home-page: https://gitlab.com/UnicodeLabs/OpenRPA
Author: Ivan Maslov
Author-email: Ivan.Maslov@unicodelabs.ru
License: MIT
Keywords: OpenRPA RPA Robot Automation Robotization
Keywords: OpenRPA RPA Robot Automation Robotization OpenSource
Platform: UNKNOWN
Classifier: Development Status :: 3 - Alpha
Classifier: Development Status :: 5 - Production/Stable
Classifier: License :: OSI Approved :: MIT License
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.7
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: Software Development :: User Interfaces
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Home Automation
Description-Content-Type: text/markdown
Requires-Dist: pywinauto (>=0.6.6)
Requires-Dist: pywinauto (>=0.6.8)
Requires-Dist: WMI (>=1.4.9)
Requires-Dist: pillow (>=6.0.0)
Requires-Dist: keyboard (>=0.13.3)
@ -50,17 +57,17 @@ Resources\WPy64-3720\python-3.7.2.amd64\python.exe
# Module GUI activity List:
############################
Новая версия
Новая версия
############################
Получить список элементов, который удовлетворяет условиям через расширенный движок поиска
Получить список элементов, который удовлетворяет условиям через расширенный движок поиска
[
{
"index":<Позиция элемента в родительском объекте>,
"depth_start" - глубина, с которой начинается поиск (по умолчанию 1)
"depth_end" - глубина, до которой ведется поиск (по умолчанию 1)
"class_name" - наименование класса, который требуется искать
"title" - наименование заголовка
"rich_text" - наименование rich_text
"index":<Позиция элемента в родительском объекте>,
"depth_start" - глубина, с которой начинается поиск (по умолчанию 1)
"depth_end" - глубина, до которой ведется поиск (по умолчанию 1)
"class_name" - наименование класса, который требуется искать
"title" - наименование заголовка
"rich_text" - наименование rich_text
}
]

@ -1,8 +1,8 @@
pyOpenRPA-1.1.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pyOpenRPA-1.1.3.dist-info/METADATA,sha256=ObJb3J2niW85Wzoh8Uy_TC99RYMif_Ipn-QwE7NSv_8,3541
pyOpenRPA-1.1.3.dist-info/RECORD,,
pyOpenRPA-1.1.3.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97
pyOpenRPA-1.1.3.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10
pyOpenRPA-1.1.13.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pyOpenRPA-1.1.13.dist-info/METADATA,sha256=rjIGRZpHzGWnt9LvY4CqdNByJhS4FqqdMUdzP_2BWmk,3352
pyOpenRPA-1.1.13.dist-info/RECORD,,
pyOpenRPA-1.1.13.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97
pyOpenRPA-1.1.13.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10
pyOpenRPA/.idea/inspectionProfiles/profiles_settings.xml,sha256=YXLFmX7rPNGcnKK1uX1uKYPN0fpgskYNe7t0BV7cqkY,174
pyOpenRPA/.idea/misc.xml,sha256=ySjeaQ1DfqxaRTlFGT_3zW5r9mWuwxoAK_AX4QiuAZM,203
pyOpenRPA/.idea/modules.xml,sha256=Q__U1JIA2cjxbLRXAv-SfYY00fZA0TNlpkkbY4s3ncg,277
@ -11,12 +11,12 @@ pyOpenRPA/.idea/vcs.xml,sha256=2HygA1oRAwc3VBf-irxHrX5JJG9DXuQwrN0BlubhoKY,191
pyOpenRPA/.idea/workspace.xml,sha256=kcCP7x0iSOAWJdy7YtntGrgsQ04QIq0b6_9w04DKxfg,2555
pyOpenRPA/Info.md,sha256=u4Nv-PjniSF0Zlbtr6jEJX2vblK3_1zhSLNUgOdtDaA,85
pyOpenRPA/Orchestrator/Orchestrator.py,sha256=iVp7DlLZHsURBOBegfDG4LanqSrI0A5a6GebP1cBOnI,8301
pyOpenRPA/Orchestrator/Processor.py,sha256=mPSv3xO1ah1BzhQdfltt77_tJrmKP9CAfwqeFAqeTFY,11364
pyOpenRPA/Orchestrator/Processor.py,sha256=ur0jDDteyBzfXR4DXnpUfBwNEW-M2nEtgyd-HQoPVtQ,11376
pyOpenRPA/Orchestrator/RobotRDPActive/CMDStr.py,sha256=6otw1WnR2_evvQ5LGyOVh0BLk_nTdilViGub7p56fXQ,1531
pyOpenRPA/Orchestrator/RobotRDPActive/Clipboard.py,sha256=YB5HJL-Qf4IlVrFHyRv_ZMJ0Vo4vjyYqWKjvrTnf1k4,1564
pyOpenRPA/Orchestrator/RobotRDPActive/Connector.py,sha256=8H_7KTUy_9m4FwbXIlDBUdX4-z3RtsaQRmYzSVdpBIU,25171
pyOpenRPA/Orchestrator/RobotRDPActive/Connector.py,sha256=MkxTVaOVITl1V3EvH3oNx2gbCx3EeRS9Gb_83rmjdjg,25553
pyOpenRPA/Orchestrator/RobotRDPActive/ConnectorExceptions.py,sha256=wwH9JOoMFFxDKQ7IyNyh1OkFkZ23o1cD8Jm3n31ycII,657
pyOpenRPA/Orchestrator/RobotRDPActive/Processor.py,sha256=goBIuwTmpdiAkimhrsqy3Y41BeljUsMQO8TaZgpx0I0,8650
pyOpenRPA/Orchestrator/RobotRDPActive/Processor.py,sha256=HcysWMmxMxSjaUybqovoCZToGrvzC0WFSVZbw6nfa68,9254
pyOpenRPA/Orchestrator/RobotRDPActive/RobotRDPActive.py,sha256=_dZQWv1lUMV8VwzeL2GclU4ZodNcYiEF7uKLrsYZjOI,10137
pyOpenRPA/Orchestrator/RobotRDPActive/Scheduler.py,sha256=21N0ilFzWI1mj3X5S9tPMgwvG7BviuBxfTuqBY85Hy4,9144
pyOpenRPA/Orchestrator/RobotRDPActive/Template.rdp,sha256=JEMVYkEmNcfg_p8isdIyvj9E-2ZB5mj-R3MkcNMKxkA,2426
@ -33,10 +33,10 @@ pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Scheduler.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Timer.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Server.py,sha256=gqJO6FRDKTBZytJVdJgPF1PvOf05qYUyKDBJJkEpLzk,22755
pyOpenRPA/Orchestrator/ServerSettings.py,sha256=mpPAxAe6PvmKaZlreaoQAy_5wV80edz_0qc-iFrEmBQ,7123
pyOpenRPA/Orchestrator/Server.py,sha256=F7AZX_5n1EPY0dD4vTH90sR-x3nM41Qv3j3Qcba_W1w,25356
pyOpenRPA/Orchestrator/ServerSettings.py,sha256=8Y6uqYIevE_VCNF5exiDMKfZ74YuYJJzagrtHjM2jNs,8419
pyOpenRPA/Orchestrator/Timer.py,sha256=HvYtEeH2Q5WVVjgds9XaBpWRmvZgwgBXurJDdVVq_T0,2097
pyOpenRPA/Orchestrator/Web/Index.xhtml,sha256=giviLTJ1GJyVayvPski2GkcB6Wd2MFYVw5yK6gSsx84,38272
pyOpenRPA/Orchestrator/Web/Index.xhtml,sha256=5yakmckWxrwz_HKjUmYOCQaO7mJmKTl9r9k_kDV0eCY,37432
pyOpenRPA/Orchestrator/Web/favicon.ico,sha256=0vdsnwKGh6pgB0FDB5mOKO7RwbxQ9F13Zg16F1pkvXs,5430
pyOpenRPA/Orchestrator/__init__.py,sha256=qVH8fEPgXk54rmy-ol0PnT8GF5OlGE0a8mExwJ4tFqY,124
pyOpenRPA/Orchestrator/__main__.py,sha256=cOd8WU77VGgzTZUB0WmWpPmdYyMZY1zVyuU9yx26MKs,144
@ -300,6 +300,6 @@ pyOpenRPA/Tools/Terminator.py,sha256=VcjX3gFXiCGu3MMCidhrTNsmC9wsAqfjRJdTSU9fLnU
pyOpenRPA/Tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Tools/__pycache__/Terminator.cpython-37.pyc,,
pyOpenRPA/Tools/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/__init__.py,sha256=zLXCLfZm0anOTnxES7ijiJFJqTniSxBCuqjNArOBU5Q,174
pyOpenRPA/__init__.py,sha256=MLl4coStn9rfw3D3uxDlH6uWJFlRPjAXs2Scbs-T3KA,175
pyOpenRPA/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/test.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0

@ -56,7 +56,7 @@ import psutil
# "Type":"ProcessStop",
# "Name":"",
# "FlagForce":True,
# "User":"" #Empty, user or %username%
# "User":"" #Empty - all users, user or %username%
# },
# {
# "Type":"PythonStart",

@ -21,6 +21,8 @@ gRecoveryWindowRUNRetryIntervalSecInt = 3 # Retry interval for retry
gRecoveryCMDResponsibleRetryCountInt = 3 # Retry iteration count is CMD is not responsible
gRecoveryCMDResponsibleRetryIntervalSecInt = 3 # Retry interval for retry
gKeyboardHotkeyDelaySecFloat = 0.6 # Const for delay - important for work with RDP!!!!
#Connect to RDP session
"""
{
@ -312,16 +314,15 @@ def SystemCMDRun(inSessionHexStr, inCMDCommandStr = "echo 1", inModeStr="CROSSCH
lCMDPostFixStr = f"& (echo {lCrosscheckKeyStr} | clip)"
elif inModeStr == "LISTEN":
lCMDPostFixStr = f"| clip"
keyboard.press_and_release('win+r')
time.sleep(1) # Wait for RUN window will appear
lRDPWindow.type_keys("^(a)") # Select all
keyboard.press_and_release("backspace") # Delete selected all
time.sleep(0.5) # Wait for RUN window will appear ctrl+a+backspace is async - so we need some timeout...
KeyboardHotkey("win","r") # win+r
KeyboardHotkey("ctrl","a") # Select all
keyboard.send("backspace") # Delete selected all
time.sleep(gKeyboardHotkeyDelaySecFloat) # Wait for RUN window will appear ctrl+a+backspace is async - so we need some timeout...
lInputStr = f"cmd /c ({inCMDCommandStr}) {lCMDPostFixStr}" # Generate the output string for RUN window
keyboard.write(lInputStr) # Write new text
time.sleep(0.5)
lRDPWindow.type_keys("^(a)") # Select all
lRDPWindow.type_keys("^(c)") # Copy data
time.sleep(gKeyboardHotkeyDelaySecFloat)
KeyboardHotkey("ctrl","a") # Select all
KeyboardHotkey("ctrl","c") # Copy data
# Check the clipboard
lClipboardWaitTimeStartSec = time.time()
lClipboardStr = Clipboard.TextGet() # Get text from clipboard
@ -392,4 +393,12 @@ def SystemRDPWarningClickOk():
UIDesktop.UIOSelector_Get_UIO([{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "OK", "class_name": "Button"}]).click()
except Exception as e:
pass
pass
# Bugfix with RDP work
def KeyboardHotkey(inModifierKeyStr,inKeyStr, inDelaySecFloat=gKeyboardHotkeyDelaySecFloat):
keyboard.press(inModifierKeyStr)
time.sleep(inDelaySecFloat)
keyboard.send(inKeyStr)
time.sleep(inDelaySecFloat)
keyboard.release(inModifierKeyStr)
time.sleep(inDelaySecFloat)

@ -11,28 +11,30 @@ gSettings = None # Gsettings will be initialized after the import module
# Create new RDPSession in RobotRDPActive
def RDPSessionConnect(inRDPSessionKeyStr, inHostStr, inPortStr, inLoginStr, inPasswordStr):
global gSettings
lRDPConfigurationItem = { # Init the configuration item
"Host": inHostStr, # Host address, example "77.77.22.22"
"Port": inPortStr, # RDP Port, example "3389"
"Login": inLoginStr, # Login, example "test"
"Password": inPasswordStr, # Password, example "test"
"Screen": {
"Width": 1680, # Width of the remote desktop in pixels, example 1680
"Height": 1050, # Height of the remote desktop in pixels, example 1050
# "640x480" or "1680x1050" or "FullScreen". If Resolution not exists set full screen, example
"FlagUseAllMonitors": False, # True or False, example False
"DepthBit": "32" # "32" or "24" or "16" or "15", example "32"
},
"SharedDriveList": ["c"], # List of the Root sesion hard drives, example ["c"]
###### Will updated in program ############
"SessionHex": "77777sdfsdf77777dsfdfsf77777777", # Hex is created when robot runs, example ""
"SessionIsWindowExistBool": False, # Flag if the RDP window is exist, old name "FlagSessionIsActive". Check every n seconds , example False
"SessionIsWindowResponsibleBool": False, # Flag if RDP window is responsible (recieve commands). Check every nn seconds. If window is Responsible - window is Exist too , example False
"SessionIsIgnoredBool": False # Flag to ignore RDP window False - dont ignore, True - ignore, example False
}
gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr] = lRDPConfigurationItem # Add item in RDPList
Connector.Session(lRDPConfigurationItem) # Create the RDP session
Connector.SystemRDPWarningClickOk() # Click all warning messages
# ATTENTION - dont connect if RDP session is exist
if inRDPSessionKeyStr not in gSettings["RobotRDPActive"]["RDPList"]:
lRDPConfigurationItem = { # Init the configuration item
"Host": inHostStr, # Host address, example "77.77.22.22"
"Port": inPortStr, # RDP Port, example "3389"
"Login": inLoginStr, # Login, example "test"
"Password": inPasswordStr, # Password, example "test"
"Screen": {
"Width": 1680, # Width of the remote desktop in pixels, example 1680
"Height": 1050, # Height of the remote desktop in pixels, example 1050
# "640x480" or "1680x1050" or "FullScreen". If Resolution not exists set full screen, example
"FlagUseAllMonitors": False, # True or False, example False
"DepthBit": "32" # "32" or "24" or "16" or "15", example "32"
},
"SharedDriveList": ["c"], # List of the Root sesion hard drives, example ["c"]
###### Will updated in program ############
"SessionHex": "77777sdfsdf77777dsfdfsf77777777", # Hex is created when robot runs, example ""
"SessionIsWindowExistBool": False, # Flag if the RDP window is exist, old name "FlagSessionIsActive". Check every n seconds , example False
"SessionIsWindowResponsibleBool": False, # Flag if RDP window is responsible (recieve commands). Check every nn seconds. If window is Responsible - window is Exist too , example False
"SessionIsIgnoredBool": False # Flag to ignore RDP window False - dont ignore, True - ignore, example False
}
gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr] = lRDPConfigurationItem # Add item in RDPList
Connector.Session(lRDPConfigurationItem) # Create the RDP session
Connector.SystemRDPWarningClickOk() # Click all warning messages
return True
# Disconnect the RDP session
@ -56,6 +58,13 @@ def RDPSessionReconnect(inRDPSessionKeyStr):
Connector.Session(lRDPConfigurationItem)
return True
# Stop track the RDP session. Current def dont kill RDP session - only stop to track it (it can give )
def RDPSessionMonitorStop(inRDPSessionKeyStr):
global gSettings
lResult = True
gSettings["RobotRDPActive"]["RDPList"].pop(inRDPSessionKeyStr,None) # Remove item from RDPList
return lResult
# Logoff the RDP session
def RDPSessionLogoff(inRDPSessionKeyStr):
global gSettings
@ -64,8 +73,8 @@ def RDPSessionLogoff(inRDPSessionKeyStr):
# Calculate the session Hex
lSessionHex = gSettings["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
if lSessionHex:
# Run CMD
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="CROSSCHECK", inLogger=gSettings["Logger"], inRDPConfigurationItem=gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr])
# Run CMD - dont crosscheck because CMD dont return value to the clipboard when logoff
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN", inLogger=gSettings["Logger"], inRDPConfigurationItem=gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr])
gSettings["RobotRDPActive"]["RDPList"].pop(inRDPSessionKeyStr,None) # Remove item from RDPList
return lResult

@ -22,6 +22,8 @@ from http import cookies
global gSettingsDict
from . import ServerSettings
import copy
#Authenticate function ()
# return dict
# {
@ -33,10 +35,6 @@ def AuthenticateVerify(inRequest):
######################################
#Way 1 - try to find AuthToken
lCookies = cookies.SimpleCookie(inRequest.headers.get("Cookie", ""))
inRequest.OpenRPA = {}
inRequest.OpenRPA["AuthToken"] = None
inRequest.OpenRPA["Domain"] = None
inRequest.OpenRPA["User"] = None
#pdb.set_trace()
if "AuthToken" in lCookies:
lCookieAuthToken = lCookies.get("AuthToken", "").value
@ -193,6 +191,34 @@ def UserAccessCheckBefore(inMethod, inRequest):
return lResult
# HTTPRequestHandler class
class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
# Def to check User Role access grants
def UserRoleAccessAsk(self, inRoleKeyList):
lResult = True # Init flag
lRoleHierarchyDict = self.UserRoleHierarchyGet() # get the Hierarchy
# Try to get value from key list
lKeyValue = lRoleHierarchyDict # Init the base
for lItem in inRoleKeyList:
if type(lKeyValue) is dict:
if lItem in lKeyValue: # Has key
lKeyValue = lKeyValue[lItem] # Get the value and go to the next loop iteration
else: # Else branch - true or false
if len(lKeyValue)>0: # False - if Dict has some elements
lResult = False # Set the False Flag
else:
lResult = True # Set the True flag
break # Stop the loop
else: # Has element with no detalization - return True
lResult = True # Set the flag
break # Close the loop
return lResult # Return the result
# Def to get hierarchy of the current user roles
# if return {} - all is available
def UserRoleHierarchyGet(self):
lDomainUpperStr = self.OpenRPA["Domain"].upper()
lUserUpperStr = self.OpenRPA["User"].upper()
return gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lDomainUpperStr, lUserUpperStr), {}).get("RoleHierarchyAllowedDict", {})
#Tech def
#return {"headers":[],"body":"","statuscode":111}
def URLItemCheckDo(self, inURLItem, inMethod):
@ -287,6 +313,12 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
# Write content as utf-8 data
self.wfile.write(inResponseDict["Body"])
def do_GET(self):
self.OpenRPA = {}
self.OpenRPA["AuthToken"] = None
self.OpenRPA["Domain"] = None
self.OpenRPA["User"] = None
self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def
self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def
# Prepare result dict
lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None}
self.OpenRPAResponseDict = lResponseDict
@ -350,6 +382,13 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
self.end_headers()
# POST
def do_POST(self):
lL = gSettingsDict["Logger"]
self.OpenRPA = {}
self.OpenRPA["AuthToken"] = None
self.OpenRPA["Domain"] = None
self.OpenRPA["User"] = None
self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def
self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def
# Prepare result dict
#pdb.set_trace()
lResponseDict = {"Headers": {}, "SetCookies":{}, "Body": b"", "StatusCode": None}
@ -360,8 +399,12 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
lIsSuperToken = False # Is supertoken
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
# Get Flag is supertoken (True|False)
lIsSuperToken = gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(
self.OpenRPA["AuthToken"], {}).get("FlagDoNotExpire", False)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
if lFlagAccessUserBlock:
@ -401,6 +444,9 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
# Send headers
self.send_header('Content-type','application/json')
self.end_headers()
# Logging info about processor activity if not SuperToken ()
if not lIsSuperToken:
if lL: lL.info(f"Server:: User activity from web. Domain: {self.OpenRPA['Domain']}, Username: {self.OpenRPA['User']}, Activity: {lInputObject}")
# Send message back to client
message = json.dumps(Processor.ActivityListOrDict(lInputObject))
# Write content as utf-8 data

@ -1,4 +1,5 @@
import json
from inspect import signature # For detect count of def args
#ControlPanelDict
from desktopmagic.screengrab_win32 import (
getDisplayRects, saveScreenToBmp, saveRectToBmp, getScreenAsImage,
@ -39,7 +40,16 @@ def Monitor_ControlPanelDictGet(inRequest,inGlobalDict):
lUACBool = False # UAC Check is not passed - False for user
if lUACBool: # Run function if UAC is TRUE
# Выполнить вызов и записать результат
lItemResultDict = lItem["RenderFunction"](inGlobalDict)
# Call def (inRequest, inGSettings) or def (inGSettings)
lItemResultDict = None
lDEFSignature = signature(lItem["RenderFunction"]) # Get signature of the def
lDEFARGLen = len(lDEFSignature.parameters.keys()) # get count of the def args
if lDEFARGLen == 1: # def (inGSettings)
lItemResultDict = lItem["RenderFunction"](inGlobalDict)
elif lDEFARGLen == 2: # def (inRequest, inGSettings)
lItemResultDict = lItem["RenderFunction"](inRequest, inGlobalDict)
elif lDEFARGLen == 0: # def ()
lItemResultDict = lItem["RenderFunction"]()
# RunFunction
lResultJSON["RenderRobotList"].append(lItemResultDict)
# Send message back to client
@ -47,6 +57,16 @@ def Monitor_ControlPanelDictGet(inRequest,inGlobalDict):
# Write content as utf-8 data
inResponseDict["Body"] = bytes(message, "utf8")
# UserAccess get rights hierarchy dict in json
def UserRoleHierarchyGet(inRequest,inGlobalDict):
inResponseDict = inRequest.OpenRPAResponseDict
# Create result JSON
lResultDict = inRequest.OpenRPA["DefUserRoleHierarchyGet"]() # Get the User Role Hierarchy list
# Send message back to client
message = json.dumps(lResultDict)
# Write content as utf-8 data
inResponseDict["Body"] = bytes(message, "utf8")
def GetScreenshot(inRequest,inGlobalDict):
# Get Screenshot
def SaveScreenshot(inFilePath):
@ -90,7 +110,8 @@ def SettingsUpdate(inGlobalConfiguration):
{"Method":"GET", "URL": "/3rdParty/Handlebars/handlebars-v4.1.2.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Handlebars\\handlebars-v4.1.2.js"), "ResponseContentType": "application/javascript"},
{"Method": "GET", "URL": "/Monitor/ControlPanelDictGet", "MatchType": "Equal", "ResponseDefRequestGlobal": Monitor_ControlPanelDictGet, "ResponseContentType": "application/json"},
{"Method": "GET", "URL": "/GetScreenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": GetScreenshot, "ResponseContentType": "image/png"},
{"Method": "GET", "URL": "/Orchestrator/RobotRDPActive/ControlPanelDictGet", "MatchType": "Equal","ResponseDefRequestGlobal": RobotRDPActive_ControlPanelDictGet, "ResponseContentType": "application/json"}
{"Method": "GET", "URL": "/Orchestrator/RobotRDPActive/ControlPanelDictGet", "MatchType": "Equal","ResponseDefRequestGlobal": RobotRDPActive_ControlPanelDictGet, "ResponseContentType": "application/json"},
{"Method": "POST", "URL": "/Orchestrator/UserRoleHierarchyGet", "MatchType": "Equal","ResponseDefRequestGlobal": UserRoleHierarchyGet, "ResponseContentType": "application/json"}
]
inGlobalConfiguration["Server"]["URLList"]=inGlobalConfiguration["Server"]["URLList"]+lURLList
return inGlobalConfiguration

@ -388,37 +388,6 @@
dataType: "text"
});
}
///////////////////////////////
///Scheduler functions
///////////////////////////////
mGlobal.Scheduler = {}
mGlobal.Scheduler.ActivityTimeListShow = function() {
lData = [
{
"Type":"GlobalDictKeyListValueGet",
"KeyList":["Scheduler","ActivityTimeList"]
}
]
$.ajax({
type: "POST",
url: 'Utils/Processor',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
lResponseJSON[0]["Result"].forEach(function(lItem){lItem["processPathName"]=("processPath" in lItem ? lItem["processPath"] : lItem["processName"])})
///Отправить запрос на формирование таблицы
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-info-table-planloglist",lResponseJSON[0]);
///Установить HTML код
$('.ui.modal.basic .content').html(lHTMLCode);
$('.ui.modal.basic').modal('show');
},
dataType: "text"
});
}
///////////////////////////////
///Processor functions
///////////////////////////////
@ -492,15 +461,8 @@
dataType: "text"
});
}
mGlobal.Processor.LogListShow = function() {
lData = [
{
"Type":"GlobalDictKeyListValueGet",
"KeyList":["Processor","LogList"]
}
]
///Обнулить таблицу
$('.ui.modal.basic .content').html("");
mGlobal.Processor.Send = function(inData) {
lData = inData
$.ajax({
type: "POST",
url: 'Utils/Processor',
@ -509,11 +471,7 @@
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
///Отправить запрос на формирование таблицы
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-info-table-activitylogschedulelist",lResponseJSON["actionListResult"][0])
///Установить HTML код
$('.ui.modal.basic .content').html(lHTMLCode);
$('.ui.modal.basic').modal('show');
///TODO Show error if exist error
},
dataType: "text"
});
@ -646,6 +604,64 @@
///Установить HTML код
lElementParentElement.insertAdjacentHTML("beforeend",lHTMLCode);
}
mGlobal.UserRoleHierarchyDict = null // Put here the user role hierarchy
// UAC Ask
mGlobal.UserRoleAsk=function(inList) {
var lResult = true; // Init flag
var lRoleHierarchyDict = mGlobal.UserRoleHierarchyDict; // get the Hierarchy
// Try to get value from key list
var lKeyValue = lRoleHierarchyDict; // Init the base
var lListLength = inList.length;
for (var i = 0; i<lListLength; i++) {
var lItem = inList[i]; // get the item
if (typeof lKeyValue == "object") {
if (lItem in lKeyValue) { // Has key
lKeyValue = lKeyValue[lItem]; // Get the value and go to the next loop iteration
} else { // Else branch - true or false
if (Object.keys(lKeyValue).length > 0) { // false - if Dict has some elements
lResult = false; // Set the False Flag
} else {
lResult = true; // Set the true flag
}
break; // Stop the loop
}
} else { // Has element with no detalization - return true
lResult = true; // Set the flag
break; // Close the loop
}
}
return lResult; // Return the result
}
// Check user roles and update the Orchestrator UI
mGlobal.UserRoleUpdate=function() {
$.ajax({
type: "POST",
url: 'Orchestrator/UserRoleHierarchyGet',
data: "",
success:
function(lData,l2,l3)
{
var lUACAsk = mGlobal.UserRoleAsk // Alias
var lResponseDict=JSON.parse(lData)
mGlobal.UserRoleHierarchyDict = lResponseDict // set the user role hierarchy
//Turn on the Lookmachine screenshot button
if (lUACAsk(["Orchestrator","Controls","LookMachineScreenshots"])) {
$(".openrpa-control-lookmachinescreenshot").show() //Show button
}
//Turn on the restart orchestrator button
if (lUACAsk(["Orchestrator","Controls","RestartOrchestrator"])) {
$(".openrpa-control-restartorchestrator").show() //Show button
}
//Turn on the rdp session list
if (lUACAsk(["Orchestrator","RDPActive","ListRead"])) {
$(".openrpa-rdpactive-title").show() //Show section
$(".openrpa-robotrdpactive-control-panel-general").show() //Show section
}
},
dataType: "text"
});
}
mGlobal.UserRoleUpdate() // Cal the update User Roles function
})
;
</script>
@ -766,75 +782,20 @@
<h2 class="ui header inverted">...</h2>
</div>
<div class="nine wide column">
<h2 class="ui header inverted">Robot RDP active list</h2>
<h2 class="ui header inverted openrpa-rdpactive-title" style="display:none;">Robot RDP active list</h2>
</div>
</div>
<div class="row">
<div class="five wide column">
<button class="ui labeled icon button" onclick="mGlobal.Monitor.ScreenshotModal.Show();">
<button class="ui labeled icon button openrpa-control-lookmachinescreenshot" onclick="mGlobal.Monitor.ScreenshotModal.Show();" style="display: none;">
<i class="desktop icon"></i>
Look machine screenshot
</button>
<button class="ui labeled icon button red" onclick="mGlobal.Controller.OrchestratorRestart();">
<button class="ui labeled icon button red openrpa-control-restartorchestrator" onclick="mGlobal.Controller.OrchestratorRestart(); " style="display: none;>
<i class="redo icon"></i>
Restart Orchestrator
</button>
<button class="ui labeled icon button" onclick="mGlobal.Scheduler.ActivityTimeListShow();">
<i class="info icon"></i>
Scheduler activity time list
<script class="openrpa-hidden-info-table-planloglist" style="display:none" type="text/x-handlebars-template">
<table class="ui celled table">
<thead>
<tr>
<th>#</th>
<th>Activity type</th>
<th>Time</th>
<th>Process path/Process name</th>
</tr>
</thead>
<tbody>
{{#Result}}
<tr>
<td>{{@index}}</td>
<td>{{TimeHH:MM}}{{TimeHH:MMStart}}</td>
<td>{{TimeHH:MMStop}}</td>
<td>{{Activity}}</td>
</tr>
{{/Result}}
</tbody>
</table>
</script>
</button>
<button class="ui labeled icon button" onclick="mGlobal.Processor.LogListShow();">
<i class="info icon"></i>
Processor logs
<script class="openrpa-hidden-info-table-activitylogschedulelist" style="display:none" type="text/x-handlebars-template">
<table class="ui celled table">
<thead>
<tr>
<th>#</th>
<th>Activity type</th>
<th>Process</th>
<th>Activity DateTime plan</th>
<th>Activity DateTime fact</th>
</tr>
</thead>
<tbody>
{{#result}}
<tr>
<td>{{@index}}</td>
<td>{{activityType}}</td>
<td>{{processPath}}</td>
<td>{{activityDateTime}}</td>
<td class="negative
">{{activityStartDateTime}}</td>
</tr>
{{/result}}
</tbody>
</table>
</script>
</button>
<script class="openrpa-hidden-monitor-table-general" style="display:none" type="text/x-handlebars-template">
<table class="ui celled table">
@ -912,7 +873,7 @@
</div>
<div class="two wide column">
</div>
<div class="nine wide column openrpa-robotrdpactive-control-panel-general">
<div class="nine wide column openrpa-robotrdpactive-control-panel-general" style="display:none;">
<div class="ui info message">
<button class="ui icon button labeled " onclick="mGlobal.RobotRDPActive.fControlPanelRefresh();">
<i class="sync alternate icon"></i>

@ -3,7 +3,7 @@ r"""
The OpenRPA package (from UnicodeLabs)
"""
__version__ = 'v1.1.3'
__version__ = 'v1.1.13'
__all__ = []
__author__ = 'Ivan Maslov <ivan.maslov@unicodelabs.ru>'
#from .Core import Robot

@ -1,13 +0,0 @@
At it's simplest it allows you to send mouse and keyboard
actions to windows dialogs and controls, but It has support for more complex
controls also.
Useful links
-------------
- Home page: http://pywinauto.github.io/
- Docs Intro: https://pywinauto.readthedocs.io/en/latest/
- Getting Started Guide: https://pywinauto.readthedocs.io/en/latest/getting_started.html
- StackOverflow tag: https://stackoverflow.com/questions/tagged/pywinauto

@ -1 +0,0 @@
{"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: Microsoft :: Windows", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Testing", "Topic :: Software Development :: User Interfaces", "Topic :: Software Development :: Quality Assurance"], "extensions": {"python.details": {"contacts": [{"email": "pywinauto-users@lists.sourceforge.net", "name": "Mark Mc Mahon and Contributors", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "http://pywinauto.github.io/"}}}, "extras": [], "generator": "bdist_wheel (0.29.0)", "keywords": ["windows", "gui", "automation", "GuiAuto", "testing", "test", "desktop", "mouse", "keyboard"], "license": "BSD 3-clause", "metadata_version": "2.0", "name": "pywinauto", "platform": "win32", "run_requires": [{"requires": ["comtypes", "six"]}], "summary": "A set of Python modules to automate the Microsoft Windows GUI", "version": "0.6.6"}

@ -0,0 +1,27 @@
Copyright (c) 2017, Mark Mc Mahon and Contributors
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.

@ -1,6 +1,6 @@
Metadata-Version: 2.0
Metadata-Version: 2.1
Name: pywinauto
Version: 0.6.6
Version: 0.6.8
Summary: A set of Python modules to automate the Microsoft Windows GUI
Home-page: http://pywinauto.github.io/
Author: Mark Mc Mahon and Contributors
@ -23,9 +23,9 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: Software Development :: User Interfaces
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Dist: comtypes
Requires-Dist: six
Requires-Dist: comtypes
Requires-Dist: pywin32
At it's simplest it allows you to send mouse and keyboard
actions to windows dialogs and controls, but It has support for more complex

@ -1,11 +1,10 @@
pywinauto-0.6.6.dist-info/DESCRIPTION.rst,sha256=k2uqeFUEl_g6xxBeVuZEfpJGuEOwcWLWkYAPOCoNkrk,443
pywinauto-0.6.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pywinauto-0.6.6.dist-info/METADATA,sha256=0BOLG3k-RTQbPt5MoG8G7P0yDwqhu2hQddg1D03wNgA,1660
pywinauto-0.6.6.dist-info/RECORD,,
pywinauto-0.6.6.dist-info/WHEEL,sha256=Ds0ba8WsPJtjBPzEMyPOBG3qfPa6B4mlzB-vhzorIZs,97
pywinauto-0.6.6.dist-info/metadata.json,sha256=0I2fhQRsICsiE-qQSyHVGUikMukbxGqL_67vZLVOkPs,1363
pywinauto-0.6.6.dist-info/top_level.txt,sha256=7E8mqRxGiLpAamWQi4ClxZvTp1jx3P0shUi_Tu0zk44,10
pywinauto/__init__.py,sha256=BJ2Pni41MWP3DgzGAFhpNvFajGujGcVUxMnf6n5s1tI,6950
pywinauto-0.6.8.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pywinauto-0.6.8.dist-info/LICENSE,sha256=GKmZqVt7I9hsQQtFNORNafbYzhPDpTcZsGq4ldii5zo,1504
pywinauto-0.6.8.dist-info/METADATA,sha256=7x_-XwBl2UsjPrl_4e5bNgDVwA_FMH83WidT-ii0xb0,1723
pywinauto-0.6.8.dist-info/RECORD,,
pywinauto-0.6.8.dist-info/WHEEL,sha256=53VSps8MltPLN_x9Ib61FU2ZSaJKzgrWQqu9rS-Dkgk,116
pywinauto-0.6.8.dist-info/top_level.txt,sha256=7E8mqRxGiLpAamWQi4ClxZvTp1jx3P0shUi_Tu0zk44,10
pywinauto/__init__.py,sha256=xY7VLfy-UvPNHKJSlzekAoG9Sue8zdNdFIdjS-_zTFs,7231
pywinauto/__pycache__/__init__.cpython-37.pyc,,
pywinauto/__pycache__/actionlogger.cpython-37.pyc,,
pywinauto/__pycache__/application.cpython-37.pyc,,
@ -33,9 +32,9 @@ pywinauto/__pycache__/win32functions.cpython-37.pyc,,
pywinauto/__pycache__/win32structures.cpython-37.pyc,,
pywinauto/__pycache__/xml_helpers.cpython-37.pyc,,
pywinauto/actionlogger.py,sha256=JVny3VSQIzcSH6ESfUPkxPozSJrxMMOvlwzNiUzO-_E,5632
pywinauto/application.py,sha256=r1gE55O91UXteKme9rFqBUP1QmbYyt4tmpXNQAHHt7I,55887
pywinauto/application.py,sha256=_KIIkl_ZZNFDZo_phPhYBX1YuNZh4pFW5A1gdYvTXeo,58047
pywinauto/backend.py,sha256=hLgO3HsnCJUYNoPfU8CwD11yMKjUZiPuXlC080JNufE,4186
pywinauto/base_wrapper.py,sha256=wx_8TIg_RbXX_zvpxGyL8nUWcvfQHVtVK6tAl8gcC_A,37561
pywinauto/base_wrapper.py,sha256=qAIvH6wKd6okBBDHY21gnK7A2DQj5H43qV4heQqQxc4,37590
pywinauto/clipboard.py,sha256=VpKW7WQ3BF57cmLkWA0Of16RG6BCuLSqGX0sW2nN1ds,4329
pywinauto/controlproperties.py,sha256=YQ1lbHxWvMf38PGB0JYdN8rhh9PYoe8iwaWbtw3EU1w,9329
pywinauto/controls/__init__.py,sha256=0cuXVxqppu3vQIJfjgxB_J__3Vtr3EvbDEx7TaRY64A,2241
@ -46,26 +45,26 @@ pywinauto/controls/__pycache__/menuwrapper.cpython-37.pyc,,
pywinauto/controls/__pycache__/uia_controls.cpython-37.pyc,,
pywinauto/controls/__pycache__/uiawrapper.cpython-37.pyc,,
pywinauto/controls/__pycache__/win32_controls.cpython-37.pyc,,
pywinauto/controls/common_controls.py,sha256=zyx1EyyoSQ_pvl6snIPOzIp6WZuPXOYNAzYqM4Qh5GA,141066
pywinauto/controls/hwndwrapper.py,sha256=46cKLxKhYL6-BzN33KA8kG7wOy1-JGEJ68qVQLiCYts,68153
pywinauto/controls/menuwrapper.py,sha256=SS5UoaezIMknz_405021QUV0ixClkqCUfuck_EnsgIA,23477
pywinauto/controls/uia_controls.py,sha256=rmME_GCfDbohEBNnHJE_mLStshBvPX_-r8T_Xa6XuH8,53699
pywinauto/controls/uiawrapper.py,sha256=aEVJYh6aB6VIg9sBrHwyQ3LOKTMnFLruVCMmSxy0dfQ,30770
pywinauto/controls/common_controls.py,sha256=4a_RyQcDl4N2JW8F_9sK-utJWJK-ujwqXF4vEhAaFe0,138614
pywinauto/controls/hwndwrapper.py,sha256=nDiCY-DnVHrD2o49WTRv7-x_2kB9Xf9nBb3gWJkgl5I,68222
pywinauto/controls/menuwrapper.py,sha256=TlgHXxMm6pUB75VDW6R-X5octoSpauXM0t7pRIJ8bPE,23497
pywinauto/controls/uia_controls.py,sha256=ei-u10dGxMRjR7SQupD3dxrvlbiqHm90ggb9WyracJA,54886
pywinauto/controls/uiawrapper.py,sha256=w7wsUnbsSStm32H5t2jEI-P9sdbMVOS8OYASHJnmhDk,31386
pywinauto/controls/win32_controls.py,sha256=Iz-28a0b_TPR8XiSTIkr8areRXyxuXQ0gOqshIPcrhU,35099
pywinauto/element_info.py,sha256=L-s3E6xdVAxgfCFZXAQlMbaHl5OEtG_xFM845gFz5zc,6067
pywinauto/findbestmatch.py,sha256=xAJaaiqAnBmQwCrhiqga-AmI5FxR0gZuXE1v1k1tyRA,20605
pywinauto/findwindows.py,sha256=wYQgISnlHOAhuvxA0bG9shLSTwu9pKNg1_ApYJi1pHw,14290
pywinauto/findbestmatch.py,sha256=izVEqpMSXgFhdMLd3OxN6Sexfo6MGVHTPEwkFxhDDpU,20748
pywinauto/findwindows.py,sha256=OMn7J5i4vk2xiVINPQ4daaMZ5MDCAplgnt4MXHo2dGY,14470
pywinauto/fuzzydict.py,sha256=mNFpET8ckSpMen4LdRRYyGRR4LToMbQw-gqNG3lWCqM,6073
pywinauto/handleprops.py,sha256=WavBoIYV0WTLpq5YUXDQS0-kMv3GChpwk2etbMFZA_k,14748
pywinauto/keyboard.py,sha256=Q_hT07R48cC830HzBZTaM2o2XOMtLsucVG_KalAfgz4,22865
pywinauto/handleprops.py,sha256=85UJyb6LfUVNim5biyB9Fz-oICo3lq1S_-jPxxgs28c,14685
pywinauto/keyboard.py,sha256=tJ4MSH7WVvmPrinMDycRr_uWm7AEtiFrfYjFjVgOwW0,24562
pywinauto/linux/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pywinauto/linux/__pycache__/__init__.cpython-37.pyc,,
pywinauto/linux/__pycache__/clipboard.cpython-37.pyc,,
pywinauto/linux/__pycache__/keyboard.cpython-37.pyc,,
pywinauto/linux/clipboard.py,sha256=X4wR0r1_X8fdLF0KphNskV_vV2c0_toNyyt2m-TY6nQ,3568
pywinauto/linux/keyboard.py,sha256=kvc5EZY8lML2WoCwV5er9SyzsF2NjQ4Abpum-YYT5-U,17380
pywinauto/linux/keyboard.py,sha256=z540dSwdCvmoyRSpCaJainPOTawbY76eo8i_UW2qyYQ,17458
pywinauto/mouse.py,sha256=-Rh9zY1KUfzVcKblvQixH0WKxf2lW9__yrsI-pRhpe0,10647
pywinauto/remote_memory_block.py,sha256=fC0HyKKrsFlwS-1QlwQZif3RFqK4hr1RkIwajkbzGM4,12204
pywinauto/remote_memory_block.py,sha256=eox-bC9ZpliwQw3gZuiPku8_oQ9sGNeKfrSOM2pNyJs,12168
pywinauto/sysinfo.py,sha256=NgLfiQ3XNaRGnapzSfYSafwn5my24FjE1uHTU66P4VM,3052
pywinauto/taskbar.py,sha256=vjHNAdOaQwyZvqJaLMvMB7teJBMOeCgXeedJpZrZGp4,5232
pywinauto/tests/__init__.py,sha256=DZXsho8W7nBWDSw5Qb-qao9CNpfOwTCKOtxG0dJRgos,5452
@ -97,11 +96,11 @@ pywinauto/tests/repeatedhotkey.py,sha256=6xFNznYzzIebpkX2dLUW6rIkTOBIe5la1qVohi3
pywinauto/tests/translation.py,sha256=0qVEsh42uqu1K5MDZfcQunPngSRanPfSLgL99An1W8g,6070
pywinauto/tests/truncation.py,sha256=MD5UTKnVtZPZyfP3Ejx5ZMBDrDYY089xY05a8SMtMjc,20006
pywinauto/timings.py,sha256=58c9xNODE5LjQYNhqoLpbLfNeJ9Lu0J8GZLw2d2tkMY,15668
pywinauto/uia_defines.py,sha256=-4w4hhRCd4O_748nEp5w5kKl-d0vb17aymVr3rdZTQ0,9819
pywinauto/uia_defines.py,sha256=ynA52N4tmKn8KBlqGP0EJ8etpygvYTyZhQNJ-vdOBRw,9979
pywinauto/uia_element_info.py,sha256=g2E9O4qSyXYmj80MqFD7mOin_nHXowM_-fVJVO0oV88,13762
pywinauto/win32_element_info.py,sha256=bJ9CIP4RPdGIZVB_HaZQg2Z_92QG2hWYw1aGkoBtTxI,9369
pywinauto/win32_hooks.py,sha256=X2Le46OJxmco94b0n830RN6Tpnk2BzMTtRVOYdwllWc,24289
pywinauto/win32defines.py,sha256=i-uScB7nzZRk0fiDNk6TqlhGraRESmjLx-GkBlgOOp4,499259
pywinauto/win32functions.py,sha256=uHpPx61qsWL_awp6Kq0D-ERN5GsAvHjC34pN-rx1xQQ,14987
pywinauto/win32structures.py,sha256=G9diB0fpPv95J8DQLt6z5D1033Ajw_FZUCojrS0xliA,42128
pywinauto/win32_hooks.py,sha256=_oG2uuMswls-9jxaGm_XRAstM6E9S38cQ6ZzBEoiYg0,24238
pywinauto/win32defines.py,sha256=zltu4uEoY397OBLDKI_Vo0R79719_uqHOjL0QuTO3rc,630639
pywinauto/win32functions.py,sha256=fHHeG9kARY_3a05qXoI9hbIIXua6Kj3IJUu6my0W6Fw,24133
pywinauto/win32structures.py,sha256=CGxoTtM-fH_AyxpxGhRl28YsVJfBM1jv3_aLUXDo0ng,41700
pywinauto/xml_helpers.py,sha256=uiairq6vJiduprD6KMIvc72qBuplPC-PQqduJVVVZnc,17263

@ -1,5 +1,6 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.29.0)
Generator: bdist_wheel (0.33.4)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any

@ -32,7 +32,7 @@
"""Python package for automating GUI manipulation on Windows"""
__version__ = "0.6.6"
__version__ = "0.6.8"
import sys # noqa: E402
import warnings # noqa: E402
@ -89,11 +89,9 @@ if sys.platform == 'win32':
from . import findwindows
WindowAmbiguousError = findwindows.WindowAmbiguousError
WindowNotFoundError = findwindows.WindowNotFoundError
ElementNotFoundError = findwindows.ElementNotFoundError
if UIA_support:
ElementNotFoundError = findwindows.ElementNotFoundError
ElementAmbiguousError = findwindows.ElementAmbiguousError
ElementAmbiguousError = findwindows.ElementAmbiguousError
from . import findbestmatch
from . import backend as backends
@ -106,13 +104,14 @@ if sys.platform == 'win32':
class Desktop(object):
"""Simple class to call something like ``Desktop().WindowName.ControlName.method()``"""
def __init__(self, backend=None):
def __init__(self, backend=None, allow_magic_lookup=True):
"""Create desktop element description"""
if not backend:
backend = backends.registry.name
if backend not in backends.registry.backends:
raise ValueError('Backend "{0}" is not registered!'.format(backend))
self.backend = backends.registry.backends[backend]
self.allow_magic_lookup = allow_magic_lookup
def window(self, **kwargs):
"""Create WindowSpecification object for top-level window"""
@ -121,7 +120,7 @@ if sys.platform == 'win32':
if 'backend' in kwargs:
raise ValueError('Using another backend than set in Desktop constructor is not allowed!')
kwargs['backend'] = self.backend.name
return WindowSpecification(kwargs)
return WindowSpecification(kwargs, allow_magic_lookup=self.allow_magic_lookup)
def windows(self, **kwargs):
"""Return a list of wrapped top level windows"""
@ -145,9 +144,12 @@ if sys.platform == 'win32':
def __getattribute__(self, attr_name):
"""Attribute access for this class"""
allow_magic_lookup = object.__getattribute__(self, "allow_magic_lookup") # Beware of recursions here!
try:
return object.__getattribute__(self, attr_name)
except AttributeError:
if not allow_magic_lookup:
raise
return self[attr_name] # delegate it to __get_item__
def from_point(self, x, y):

@ -141,11 +141,12 @@ class WindowSpecification(object):
'active': ('is_active',),
}
def __init__(self, search_criteria):
def __init__(self, search_criteria, allow_magic_lookup=True):
"""
Initialize the class
:param search_criteria: the criteria to match a dialog
:param allow_magic_lookup: whether attribute access must turn into child_window(best_match=...) search as fallback
"""
# kwargs will contain however to find this window
if 'backend' not in search_criteria:
@ -158,6 +159,7 @@ class WindowSpecification(object):
self.criteria = [search_criteria, ]
self.actions = ActionLogger()
self.backend = registry.backends[search_criteria['backend']]
self.allow_magic_lookup = allow_magic_lookup
if self.backend.name == 'win32':
# Non PEP-8 aliases for partial backward compatibility
@ -173,7 +175,7 @@ class WindowSpecification(object):
self.window_ = deprecated(self.child_window, deprecated_name='window_')
def __call__(self, *args, **kwargs):
"""No __call__ so return a usefull error"""
"""No __call__ so return a useful error"""
if "best_match" in self.criteria[-1]:
raise AttributeError("Neither GUI element (wrapper) " \
"nor wrapper method '{0}' were found (typo?)".
@ -182,8 +184,8 @@ class WindowSpecification(object):
message = (
"You tried to execute a function call on a WindowSpecification "
"instance. You probably have a typo for one of the methods of "
"this class.\n"
"The criteria leading up to this is: " + str(self.criteria))
"this class or of the targeted wrapper object.\n"
"The criteria leading up to this are: " + str(self.criteria))
raise AttributeError(message)
@ -277,7 +279,7 @@ class WindowSpecification(object):
if 'top_level_only' not in criteria:
criteria['top_level_only'] = False
new_item = WindowSpecification(self.criteria[0])
new_item = WindowSpecification(self.criteria[0], allow_magic_lookup=self.allow_magic_lookup)
new_item.criteria.extend(self.criteria[1:])
new_item.criteria.append(criteria)
@ -307,7 +309,7 @@ class WindowSpecification(object):
"""
# if we already have 2 levels of criteria (dlg, control)
# then resolve the control and do a getitem on it for the
if len(self.criteria) >= 2:
if len(self.criteria) >= 2: # FIXME - this is surprising
ctrls = self.__resolve_control(self.criteria)
@ -324,7 +326,7 @@ class WindowSpecification(object):
# if we get here then we must have only had one criteria so far
# so create a new :class:`WindowSpecification` for this control
new_item = WindowSpecification(self.criteria[0])
new_item = WindowSpecification(self.criteria[0], allow_magic_lookup=self.allow_magic_lookup)
# add our new criteria
new_item.criteria.append({"best_match": key})
@ -345,6 +347,21 @@ class WindowSpecification(object):
Otherwise delegate functionality to :func:`__getitem__` - which
sets the appropriate criteria for the control.
"""
allow_magic_lookup = object.__getattribute__(self, "allow_magic_lookup") # Beware of recursions here!
if not allow_magic_lookup:
try:
return object.__getattribute__(self, attr_name)
except AttributeError:
wrapper_object = self.wrapper_object()
try:
return getattr(wrapper_object, attr_name)
except AttributeError:
message = (
'Attribute "%s" exists neither on %s object nor on'
'targeted %s element wrapper (typo? or set allow_magic_lookup to True?)' %
(attr_name, self.__class__, wrapper_object.__class__))
raise AttributeError(message)
if attr_name in ['__dict__', '__members__', '__methods__', '__class__', '__name__']:
return object.__getattribute__(self, attr_name)
@ -354,10 +371,10 @@ class WindowSpecification(object):
if attr_name in self.__dict__:
return self.__dict__[attr_name]
# if we already have 2 levels of criteria (dlg, conrol)
# if we already have 2 levels of criteria (dlg, control)
# this third must be an attribute so resolve and get the
# attribute and return it
if len(self.criteria) >= 2:
if len(self.criteria) >= 2: # FIXME - this is surprising
ctrls = self.__resolve_control(self.criteria)
@ -366,6 +383,7 @@ class WindowSpecification(object):
except AttributeError:
return self.child_window(best_match=attr_name)
else:
# FIXME - I don't get this part at all, why is it win32-specific and why not keep the same logic as above?
# if we have been asked for an attribute of the dialog
# then resolve the window and return the attribute
desktop_wrapper = self.backend.generic_wrapper_class(self.backend.element_info_class())
@ -870,7 +888,7 @@ class Application(object):
.. automethod:: __getitem__
"""
def __init__(self, backend="win32", datafilename=None):
def __init__(self, backend="win32", datafilename=None, allow_magic_lookup=True):
"""
Initialize the Application object
@ -886,6 +904,7 @@ class Application(object):
if backend not in registry.backends:
raise ValueError('Backend "{0}" is not registered!'.format(backend))
self.backend = registry.backends[backend]
self.allow_magic_lookup = allow_magic_lookup
if self.backend.name == 'win32':
# Non PEP-8 aliases for partial backward compatibility
self.Start = deprecated(self.start)
@ -906,6 +925,10 @@ class Application(object):
self.match_history = pickle.load(datafile)
self.use_history = True
def __iter__(self):
"""Raise to avoid infinite loops"""
raise NotImplementedError("Object is not iterable, try to use .windows()")
def connect(self, **kwargs):
"""Connect to an already running process
@ -1139,7 +1162,7 @@ class Application(object):
else:
criteria['title'] = windows[0].name
return WindowSpecification(criteria)
return WindowSpecification(criteria, allow_magic_lookup=self.allow_magic_lookup)
def active(self):
"""Return WindowSpecification for an active window of the application"""
@ -1163,7 +1186,7 @@ class Application(object):
else:
criteria['title'] = windows[0].name
return WindowSpecification(criteria)
return WindowSpecification(criteria, allow_magic_lookup=self.allow_magic_lookup)
def windows(self, **kwargs):
"""Return a list of wrapped top level windows of the application"""
@ -1205,7 +1228,7 @@ class Application(object):
else:
# add the restriction for this particular application
kwargs['app'] = self
win_spec = WindowSpecification(kwargs)
win_spec = WindowSpecification(kwargs, allow_magic_lookup=self.allow_magic_lookup)
return win_spec
Window_ = window_ = window
@ -1216,6 +1239,17 @@ class Application(object):
return self.window(best_match=key)
def __getattribute__(self, attr_name):
allow_magic_lookup = object.__getattribute__(self, "allow_magic_lookup") # Beware of recursions here!
if not allow_magic_lookup:
try:
return object.__getattribute__(self, attr_name)
except AttributeError:
message = (
'Attribute "%s" doesn\'t exist on %s object'
' (typo? or set allow_magic_lookup to True?)' %
(attr_name, self.__class__))
raise AttributeError(message)
"""Find the specified dialog of the application"""
if attr_name in ['__dict__', '__members__', '__methods__', '__class__']:
return object.__getattribute__(self, attr_name)

@ -38,7 +38,6 @@ import ctypes
import locale
import re
import time
import win32process
import win32gui
import win32con
import win32api
@ -925,7 +924,8 @@ class BaseWrapper(object):
with_tabs = False,
with_newlines = False,
turn_off_numlock = True,
set_foreground = True):
set_foreground = True,
vk_packet = True):
"""
Type keys to the element using keyboard.send_keys
@ -945,7 +945,7 @@ class BaseWrapper(object):
# attach the Python process with the process that self is in
if self.element_info.handle:
window_thread_id, _ = win32process.GetWindowThreadProcessId(int(self.handle))
window_thread_id = win32functions.GetWindowThreadProcessId(self.handle, None)
win32functions.AttachThreadInput(win32functions.GetCurrentThreadId(), window_thread_id, win32defines.TRUE)
# TODO: check return value of AttachThreadInput properly
else:
@ -967,7 +967,8 @@ class BaseWrapper(object):
with_spaces,
with_tabs,
with_newlines,
turn_off_numlock)
turn_off_numlock,
vk_packet)
# detach the python process from the window's process
if self.element_info.handle:

@ -53,7 +53,6 @@ import warnings
import locale
import six
from .. import sysinfo
from .. import win32functions
from .. import win32defines
from .. import win32structures
@ -68,9 +67,6 @@ from ..handleprops import is64bitprocess
from ..sysinfo import is_x64_Python
from .. import deprecated
if sysinfo.UIA_support:
from ..uia_defines import IUIA
# Todo: I should return iterators from things like items() and texts()
# to save building full lists all the time
@ -135,7 +131,7 @@ class _listview_item(object):
item.iItem = self.item_index
item.iSubItem = self.subitem_index
item.stateMask = win32structures.UINT(-1)
item.stateMask = wintypes.UINT(-1)
item.cchTextMax = 2000
item.pszText = remote_mem.Address() + \
@ -501,9 +497,9 @@ class _listview_item(object):
lvitem = self.listview_ctrl.LVITEM()
lvitem.mask = win32structures.UINT(win32defines.LVIF_STATE)
lvitem.state = win32structures.UINT(index_to_state_image_mask(1)) # win32structures.UINT(0x1000)
lvitem.stateMask = win32structures.UINT(win32defines.LVIS_STATEIMAGEMASK)
lvitem.mask = wintypes.UINT(win32defines.LVIF_STATE)
lvitem.state = wintypes.UINT(index_to_state_image_mask(1)) # wintypes.UINT(0x1000)
lvitem.stateMask = wintypes.UINT(win32defines.LVIS_STATEIMAGEMASK)
remote_mem = RemoteMemoryBlock(self.listview_ctrl)
remote_mem.Write(lvitem)
@ -530,9 +526,9 @@ class _listview_item(object):
lvitem = self.listview_ctrl.LVITEM()
lvitem.mask = win32structures.UINT(win32defines.LVIF_STATE)
lvitem.state = win32structures.UINT(index_to_state_image_mask(2)) # win32structures.UINT(0x2000)
lvitem.stateMask = win32structures.UINT(win32defines.LVIS_STATEIMAGEMASK)
lvitem.mask = wintypes.UINT(win32defines.LVIF_STATE)
lvitem.state = wintypes.UINT(index_to_state_image_mask(2)) # wintypes.UINT(0x2000)
lvitem.stateMask = wintypes.UINT(win32defines.LVIS_STATEIMAGEMASK)
remote_mem = RemoteMemoryBlock(self.listview_ctrl)
remote_mem.Write(lvitem)
@ -591,12 +587,12 @@ class _listview_item(object):
# first we need to change the state of the item
lvitem = self.listview_ctrl.LVITEM()
lvitem.mask = win32structures.UINT(win32defines.LVIF_STATE)
lvitem.mask = wintypes.UINT(win32defines.LVIF_STATE)
if to_select:
lvitem.state = win32structures.UINT(win32defines.LVIS_FOCUSED | win32defines.LVIS_SELECTED)
lvitem.state = wintypes.UINT(win32defines.LVIS_FOCUSED | win32defines.LVIS_SELECTED)
lvitem.stateMask = win32structures.UINT(win32defines.LVIS_FOCUSED | win32defines.LVIS_SELECTED)
lvitem.stateMask = wintypes.UINT(win32defines.LVIS_FOCUSED | win32defines.LVIS_SELECTED)
remote_mem = RemoteMemoryBlock(self.listview_ctrl)
remote_mem.Write(lvitem, size=ctypes.sizeof(lvitem))
@ -721,10 +717,6 @@ class ListViewWrapper(hwndwrapper.HwndWrapper):
"TSysListView",
"ListView.*WndClass",
]
if sysinfo.UIA_support:
#controltypes is empty to make wrapper search result unique
#possible control types: IUIA().UIA_dll.UIA_ListControlTypeId
controltypes = []
#----------------------------------------------------------------
def __init__(self, hwnd):
@ -1424,7 +1416,7 @@ class _treeview_element(object):
item.pszText = remote_mem.Address() + ctypes.sizeof(item) + 16
item.cchTextMax = 2000
item.hItem = self.elem
item.stateMask = win32structures.UINT(-1)
item.stateMask = wintypes.UINT(-1)
# Write the local TVITEM structure to the remote memory block
remote_mem.Write(item)
@ -1460,8 +1452,6 @@ class TreeViewWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "TreeView"
windowclasses = [
"SysTreeView32", r"WindowsForms\d*\.SysTreeView32\..*", "TTreeView", "TreeList.TreeListCtrl"]
if sysinfo.UIA_support:
controltypes = [IUIA().UIA_dll.UIA_TreeControlTypeId]
#----------------------------------------------------------------
def __init__(self, hwnd):
@ -1751,8 +1741,6 @@ class HeaderWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "Header"
windowclasses = ["SysHeader32", "msvb_lib_header"]
if sysinfo.UIA_support:
controltypes = [IUIA().UIA_dll.UIA_HeaderControlTypeId]
#----------------------------------------------------------------
def __init__(self, hwnd):
@ -1894,8 +1882,6 @@ class StatusBarWrapper(hwndwrapper.HwndWrapper):
"msctls_statusbar32",
".*StatusBar",
r"WindowsForms\d*\.msctls_statusbar32\..*"]
if sysinfo.UIA_support:
controltypes = [IUIA().UIA_dll.UIA_StatusBarControlTypeId]
#----------------------------------------------------------------
def __init__(self, hwnd):
@ -2065,8 +2051,6 @@ class TabControlWrapper(hwndwrapper.HwndWrapper):
windowclasses = [
"SysTabControl32",
r"WindowsForms\d*\.SysTabControl32\..*"]
if sysinfo.UIA_support:
controltypes = [IUIA().UIA_dll.UIA_TabControlTypeId]
#----------------------------------------------------------------
def __init__(self, hwnd):
@ -2878,10 +2862,6 @@ class ReBarWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "ReBar"
windowclasses = ["ReBarWindow32", ]
if sysinfo.UIA_support:
#controltypes is empty to make wrapper search result unique
#possible control types: IUIA().UIA_dll.UIA_PaneControlTypeId
controltypes = []
#----------------------------------------------------------------
def __init__(self, hwnd):
@ -3086,8 +3066,6 @@ class UpDownWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "UpDown"
windowclasses = ["msctls_updown32", "msctls_updown", ]
if sysinfo.UIA_support:
controltypes = [IUIA().UIA_dll.UIA_SpinnerControlTypeId]
#----------------------------------------------------------------
def __init__(self, hwnd):
@ -3195,8 +3173,6 @@ class TrackbarWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "Trackbar"
windowclasses = ["msctls_trackbar", ]
if sysinfo.UIA_support:
controltypes = [IUIA().UIA_dll.UIA_SliderControlTypeId]
def get_range_min(self):
"""Get min available trackbar value"""
@ -3293,10 +3269,6 @@ class AnimationWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "Animation"
windowclasses = ["SysAnimate32", ]
if sysinfo.UIA_support:
#controltypes is empty to make wrapper search result unique
#possible control types: IUIA().UIA_dll.UIA_PaneControlTypeId
controltypes = []
#====================================================================
@ -3306,10 +3278,6 @@ class ComboBoxExWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "ComboBoxEx"
windowclasses = ["ComboBoxEx32", ]
if sysinfo.UIA_support:
#controltypes is empty to make wrapper search result unique
#possible control types: IUIA().UIA_dll.UIA_PaneControlTypeId
controltypes = []
has_title = False
@ -3321,10 +3289,6 @@ class DateTimePickerWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "DateTimePicker"
windowclasses = ["SysDateTimePick32",
r"WindowsForms\d*\.SysDateTimePick32\..*", ]
if sysinfo.UIA_support:
#controltypes is empty to make wrapper search result unique
#possible control types: IUIA().UIA_dll.UIA_PaneControlTypeId
controltypes = []
has_title = False
#----------------------------------------------------------------
@ -3387,10 +3351,6 @@ class HotkeyWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "Hotkey"
windowclasses = ["msctls_hotkey32", ]
if sysinfo.UIA_support:
#controltypes is empty to make wrapper search result unique
#possible control types: IUIA().UIA_dll.UIA_PaneControlTypeId
controltypes = []
has_title = False
@ -3401,10 +3361,6 @@ class IPAddressWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "IPAddress"
windowclasses = ["SysIPAddress32", ]
if sysinfo.UIA_support:
#controltypes is empty to make wrapper search result unique
#possible control types: IUIA().UIA_dll.UIA_PaneControlTypeId
controltypes = []
has_title = False
@ -3415,8 +3371,6 @@ class CalendarWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "Calendar"
windowclasses = ["SysMonthCal32", ]
if sysinfo.UIA_support:
controltypes = [IUIA().UIA_dll.UIA_CalendarControlTypeId]
has_title = False
place_in_calendar = {
@ -3719,10 +3673,6 @@ class PagerWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "Pager"
windowclasses = ["SysPager", ]
if sysinfo.UIA_support:
#controltypes is empty to make wrapper search result unique
#possible control types: IUIA().UIA_dll.UIA_PaneControlTypeId
controltypes = []
#----------------------------------------------------------------
def get_position(self):
@ -3748,8 +3698,6 @@ class ProgressWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "Progress"
windowclasses = ["msctls_progress", "msctls_progress32", ]
if sysinfo.UIA_support:
controltypes = [IUIA().UIA_dll.UIA_ProgressBarControlTypeId]
has_title = False
#----------------------------------------------------------------

@ -493,7 +493,7 @@ class HwndWrapper(BaseWrapper):
(e.g. VK_LEFT, VK_DELETE), a KeySequenceError is raised. Consider using
the method send_keystrokes for such input.
"""
input_locale_id = ctypes.windll.User32.GetKeyboardLayout(0)
input_locale_id = win32functions.GetKeyboardLayout(0)
keys = keyboard.parse_keys(chars, with_spaces, with_tabs, with_newlines)
for key in keys:
@ -506,11 +506,11 @@ class HwndWrapper(BaseWrapper):
if unicode_char:
_, char = key_info[:2]
vk = ctypes.windll.User32.VkKeyScanExW(char, input_locale_id) & 0xFF
scan = keyboard.MapVirtualKey(vk, 0)
vk = win32functions.VkKeyScanExW(chr(char), input_locale_id) & 0xFF
scan = win32functions.MapVirtualKeyW(vk, 0)
else:
vk, scan = key_info[:2]
char = keyboard.MapVirtualKey(vk, 2)
char = win32functions.MapVirtualKeyW(vk, 2)
if char > 0:
lparam = 1 << 0 | scan << 16 | (flags & 1) << 24
@ -541,22 +541,21 @@ class HwndWrapper(BaseWrapper):
.. _`type_keys`: pywinauto.base_wrapper.html#pywinauto.base_wrapper.BaseWrapper.type_keys
"""
user32 = ctypes.windll.User32
PBYTE256 = ctypes.c_ubyte * 256
win32gui.SendMessage(self.handle, win32con.WM_ACTIVATE,
win32con.WA_ACTIVE, 0)
target_thread_id = user32.GetWindowThreadProcessId(self.handle, None)
current_thread_id = win32api.GetCurrentThreadId()
attach_success = user32.AttachThreadInput(target_thread_id, current_thread_id, True) != 0
target_thread_id = win32functions.GetWindowThreadProcessId(self.handle, None)
current_thread_id = win32functions.GetCurrentThreadId()
attach_success = win32functions.AttachThreadInput(target_thread_id, current_thread_id, True) != 0
if not attach_success:
warnings.warn('Failed to attach app\'s thread to the current thread\'s message queue',
UserWarning, stacklevel=2)
keyboard_state_stack = [PBYTE256()]
user32.GetKeyboardState(ctypes.byref(keyboard_state_stack[-1]))
win32functions.GetKeyboardState(keyboard_state_stack[-1])
input_locale_id = ctypes.windll.User32.GetKeyboardLayout(0)
input_locale_id = win32functions.GetKeyboardLayout(0)
context_code = 0
keys = keyboard.parse_keys(keystrokes, with_spaces, with_tabs, with_newlines)
@ -578,11 +577,11 @@ class HwndWrapper(BaseWrapper):
shift_state = 0
unicode_codepoint = flags & keyboard.KEYEVENTF_UNICODE != 0
if unicode_codepoint:
char = scan
vk_with_flags = user32.VkKeyScanExW(char, input_locale_id)
char = chr(scan)
vk_with_flags = win32functions.VkKeyScanExW(char, input_locale_id)
vk = vk_with_flags & 0xFF
shift_state = (vk_with_flags & 0xFF00) >> 8
scan = keyboard.MapVirtualKey(vk, 0)
scan = win32functions.MapVirtualKeyW(vk, 0)
if key.down and vk > 0:
new_keyboard_state = copy.deepcopy(keyboard_state_stack[-1])
@ -602,8 +601,8 @@ class HwndWrapper(BaseWrapper):
context_code << 29 |
0 << 31)
user32.SetKeyboardState(ctypes.byref(keyboard_state_stack[-1]))
win32api.PostMessage(self.handle, down_msg, vk, lparam)
win32functions.SetKeyboardState(keyboard_state_stack[-1])
win32functions.PostMessage(self.handle, down_msg, vk, lparam)
if vk == keyboard.VK_MENU:
context_code = 1
@ -621,8 +620,8 @@ class HwndWrapper(BaseWrapper):
1 << 30 |
1 << 31)
win32api.PostMessage(self.handle, up_msg, vk, lparam)
user32.SetKeyboardState(ctypes.byref(keyboard_state_stack[-1]))
win32functions.PostMessage(self.handle, up_msg, vk, lparam)
win32functions.SetKeyboardState(keyboard_state_stack[-1])
if vk == keyboard.VK_MENU:
context_code = 0
@ -636,10 +635,10 @@ class HwndWrapper(BaseWrapper):
UserWarning, stacklevel=2)
else:
warnings.warn(e.strerror, UserWarning, stacklevel=2)
user32.SetKeyboardState(ctypes.byref(keyboard_state_stack[0]))
win32functions.SetKeyboardState(keyboard_state_stack[0])
if attach_success:
user32.AttachThreadInput(target_thread_id, current_thread_id, False)
win32functions.AttachThreadInput(target_thread_id, current_thread_id, False)
# -----------------------------------------------------------
def send_message_timeout(
@ -1256,7 +1255,7 @@ class HwndWrapper(BaseWrapper):
"""Return a handle to the active window within the process"""
gui_info = win32structures.GUITHREADINFO()
gui_info.cbSize = ctypes.sizeof(gui_info)
window_thread_id, _ = win32process.GetWindowThreadProcessId(int(self.handle))
window_thread_id = win32functions.GetWindowThreadProcessId(self.handle, None)
ret = win32functions.GetGUIThreadInfo(
window_thread_id,
ctypes.byref(gui_info))
@ -1278,7 +1277,7 @@ class HwndWrapper(BaseWrapper):
"""
gui_info = win32structures.GUITHREADINFO()
gui_info.cbSize = ctypes.sizeof(gui_info)
window_thread_id, _ = win32process.GetWindowThreadProcessId(self.handle)
window_thread_id = win32functions.GetWindowThreadProcessId(self.handle, None)
ret = win32functions.GetGUIThreadInfo(
window_thread_id,
ctypes.byref(gui_info))
@ -1335,7 +1334,7 @@ class HwndWrapper(BaseWrapper):
def has_keyboard_focus(self):
"""Check the keyboard focus on this control."""
control_thread = win32process.GetWindowThreadProcessId(self.handle)[0]
control_thread = win32functions.GetWindowThreadProcessId(self.handle, None)
win32process.AttachThreadInput(control_thread, win32api.GetCurrentThreadId(), 1)
focused = win32gui.GetFocus()
win32process.AttachThreadInput(control_thread, win32api.GetCurrentThreadId(), 0)
@ -1346,9 +1345,9 @@ class HwndWrapper(BaseWrapper):
def set_keyboard_focus(self):
"""Set the keyboard focus to this control."""
control_thread = win32process.GetWindowThreadProcessId(self.handle)[0]
control_thread = win32functions.GetWindowThreadProcessId(self.handle, None)
win32process.AttachThreadInput(control_thread, win32api.GetCurrentThreadId(), 1)
win32gui.SetFocus(self.handle)
win32functions.SetFocus(self.handle)
win32process.AttachThreadInput(control_thread, win32api.GetCurrentThreadId(), 0)
win32functions.WaitGuiThreadIdle(self.handle)
@ -1602,12 +1601,13 @@ class DialogWrapper(HwndWrapper):
#win32defines.SMTO_BLOCK)
# get a handle we can wait on
_, pid = win32process.GetWindowThreadProcessId(int(self.handle))
pid = ctypes.c_ulong()
win32functions.GetWindowThreadProcessId(self.handle, ctypes.byref(pid))
try:
process_wait_handle = win32api.OpenProcess(
win32con.SYNCHRONIZE | win32con.PROCESS_TERMINATE,
0,
pid)
pid.value)
except win32gui.error:
return True # already closed
@ -1723,7 +1723,7 @@ def _perform_click(
# figure out the flags and pack coordinates
flags, click_point = _calc_flags_and_coords(pressed, coords)
#control_thread = win32functions.GetWindowThreadProcessId(ctrl, 0)
#control_thread = win32functions.GetWindowThreadProcessId(ctrl, None)
#win32functions.AttachThreadInput(win32functions.GetCurrentThreadId(), control_thread, win32defines.TRUE)
# TODO: check return value of AttachThreadInput properly

@ -283,7 +283,7 @@ class MenuItem(object):
# if the item is not visible - work up along it's parents
# until we find an item we CAN click on
if rect == (0, 0, 0, 0) and self.menu.owner_item:
if rect == win32structures.RECT(0, 0, 0, 0) and self.menu.owner_item:
self.menu.owner_item.click_input()
rect = self.rectangle()

@ -200,7 +200,11 @@ class ComboBoxWrapper(uiawrapper.UIAWrapper):
# -----------------------------------------------------------
def texts(self):
"""Return the text of the items in the combobox"""
texts = []
texts = self._texts_from_item_container()
if len(texts):
# flatten the list
return [ t for lst in texts for t in lst ]
# ComboBox has to be expanded to populate a list of its children items
try:
super(ComboBoxWrapper, self).expand()
@ -370,6 +374,11 @@ class EditWrapper(uiawrapper.UIAWrapper):
"""Return the current value of the element"""
return self.iface_value.CurrentValue
# -----------------------------------------------------------
def is_editable(self):
"""Return the edit possibility of the element"""
return not self.iface_value.CurrentIsReadOnly
# -----------------------------------------------------------
def texts(self):
"""Get the text of the edit control"""
@ -846,10 +855,19 @@ class ListViewWrapper(uiawrapper.UIAWrapper):
raise ValueError("Element '{0}' not found".format(row))
elif isinstance(row, six.integer_types):
# Get the item by a row index
# TODO: Can't get virtualized items that way
# TODO: See TODO section of item_count() method for details
list_items = self.children(content_only=True)
itm = list_items[self.__resolve_row_index(row)]
try:
com_elem = 0
for _ in range(0, self.__resolve_row_index(row) + 1):
com_elem = self.iface_item_container.FindItemByProperty(com_elem, 0, uia_defs.vt_empty)
# Try to load element using VirtualizedItem pattern
try:
get_elem_interface(com_elem, "VirtualizedItem").Realize()
except NoPatternInterfaceError:
pass
itm = uiawrapper.UIAWrapper(uia_element_info.UIAElementInfo(com_elem))
except (NoPatternInterfaceError, ValueError, AttributeError):
list_items = self.children(content_only=True)
itm = list_items[self.__resolve_row_index(row)]
else:
raise TypeError("String type or integer is expected")
@ -960,18 +978,18 @@ class MenuWrapper(uiawrapper.UIAWrapper):
return item
# -----------------------------------------------------------
@staticmethod
def _activate(item):
def _activate(self, item, is_last):
"""Activate the specified item"""
if not item.is_active():
item.set_focus()
try:
item.expand()
except(NoPatternInterfaceError):
pass
if self.element_info.framework_id == 'WinForm' and not is_last:
item.select()
# -----------------------------------------------------------
def _sub_item_by_text(self, menu, name, exact):
def _sub_item_by_text(self, menu, name, exact, is_last):
"""Find a menu sub-item by the specified text"""
sub_item = None
items = menu.items()
@ -987,18 +1005,18 @@ class MenuWrapper(uiawrapper.UIAWrapper):
texts.append(i.window_text())
sub_item = findbestmatch.find_best_match(name, texts, items)
self._activate(sub_item)
self._activate(sub_item, is_last)
return sub_item
# -----------------------------------------------------------
def _sub_item_by_idx(self, menu, idx):
def _sub_item_by_idx(self, menu, idx, is_last):
"""Find a menu sub-item by the specified index"""
sub_item = None
items = menu.items()
if items:
sub_item = items[idx]
self._activate(sub_item)
self._activate(sub_item, is_last)
return sub_item
# -----------------------------------------------------------
@ -1011,35 +1029,39 @@ class MenuWrapper(uiawrapper.UIAWrapper):
Note: $ - specifier is not supported
"""
# Get the path parts
part0, parts = path.split("->", 1)
part0 = part0.strip()
if len(part0) == 0:
menu_items = [p.strip() for p in path.split("->")]
items_cnt = len(menu_items)
if items_cnt == 0:
raise IndexError()
for item in menu_items:
if not item:
raise IndexError("Empty item name between '->' separators")
def next_level_menu(parent_menu, item_name, is_last):
if item_name.startswith("#"):
return self._sub_item_by_idx(parent_menu, int(item_name[1:]), is_last)
else:
return self._sub_item_by_text(parent_menu, item_name, exact, is_last)
# Find a top level menu item and select it. After selecting this item
# a new Menu control is created and placed on the dialog. It can be
# a direct child or a descendant.
# Sometimes we need to re-discover Menu again
try:
menu = None
if part0.startswith("#"):
menu = self._sub_item_by_idx(self, int(part0[1:]))
else:
menu = self._sub_item_by_text(self, part0, exact)
menu = next_level_menu(self, menu_items[0], items_cnt == 1)
if items_cnt == 1:
return menu
if not menu.items():
self._activate(menu)
self._activate(menu, False)
timings.wait_until(
timings.Timings.window_find_timeout,
timings.Timings.window_find_retry,
lambda: len(self.top_level_parent().descendants(control_type="Menu")) > 0)
menu = self.top_level_parent().descendants(control_type="Menu")[0]
for cur_part in [p.strip() for p in parts.split("->")]:
if cur_part.startswith("#"):
menu = self._sub_item_by_idx(menu, int(cur_part[1:]))
else:
menu = self._sub_item_by_text(menu, cur_part, exact)
for i in range(1, items_cnt):
menu = next_level_menu(menu, menu_items[i], items_cnt == i + 1)
except(AttributeError):
raise IndexError()

@ -782,5 +782,19 @@ class UIAWrapper(BaseWrapper):
return self
# -----------------------------------------------------------
def _texts_from_item_container(self):
"""Get texts through the ItemContainer interface"""
texts = []
try:
com_elem = self.iface_item_container.FindItemByProperty(0, 0, uia_defs.vt_empty)
while com_elem:
itm = UIAWrapper(UIAElementInfo(com_elem))
texts.append(itm.texts())
com_elem = self.iface_item_container.FindItemByProperty(com_elem, 0, uia_defs.vt_empty)
except (uia_defs.NoPatternInterfaceError):
pass
return texts
backend.register('uia', UIAElementInfo, UIAWrapper)

@ -331,8 +331,9 @@ def get_control_names(control, allcontrols, textcontrols):
if non_text_names:
names.extend(non_text_names)
# return the names - and make sure there are no duplicates
return set(names)
# return the names - and make sure there are no duplicates or empty values
cleaned_names = set(names) - set([None, ""])
return cleaned_names
#====================================================================
@ -493,6 +494,8 @@ def find_best_control_matches(search_text, controls):
"""
name_control_map = build_unique_dict(controls)
#print ">>>>>>>", repr(name_control_map).decode("ascii", "ignore")
# # collect all the possible names for all controls
# # and build a list of them
# for ctrl in controls:

@ -189,9 +189,10 @@ def find_elements(class_name=None,
if top_level_only:
# find the top level elements
element = backend_obj.element_info_class()
# vryabov: we don't use title=title below, because it fixes issue 779:
# https://github.com/pywinauto/pywinauto/issues/779
elements = element.children(process=process,
class_name=class_name,
title=title,
control_type=control_type,
cache_enable=True)
@ -206,8 +207,9 @@ def find_elements(class_name=None,
parent = backend_obj.element_info_class()
# look for ALL children of that parent
# vryabov: we don't use title=title below, because it fixes issue 779:
# https://github.com/pywinauto/pywinauto/issues/779
elements = parent.descendants(class_name=class_name,
title=title,
control_type=control_type,
cache_enable=True,
depth=depth)

@ -35,14 +35,18 @@ These are implemented in a procedural way so as to to be
useful to other modules with the least conceptual overhead
"""
import ctypes
import warnings
import win32process
import win32api
import win32con
import win32gui
import pywintypes
from ctypes import wintypes
from ctypes import WINFUNCTYPE
from ctypes import c_int
from ctypes import byref
from ctypes import sizeof
from ctypes import create_unicode_buffer
from . import win32functions
from . import win32defines
from . import win32structures
@ -58,7 +62,7 @@ def text(handle):
if class_name == 'MSCTFIME UI':
return 'M'
if class_name is None:
return None
return ''
#length = win32functions.SendMessage(handle, win32defines.WM_GETTEXTLENGTH, 0, 0)
# XXX: there are some very rare cases when WM_GETTEXTLENGTH hangs!
@ -71,11 +75,11 @@ def text(handle):
0,
win32defines.SMTO_ABORTIFHUNG,
500,
ctypes.byref(c_length)
byref(c_length)
)
if result == 0:
ActionLogger().log('WARNING! Cannot retrieve text length for handle = ' + str(handle))
return None
return ''
else:
length = c_length.value
@ -85,10 +89,10 @@ def text(handle):
if length > 0:
length += 1
buffer_ = ctypes.create_unicode_buffer(length)
buffer_ = create_unicode_buffer(length)
ret = win32functions.SendMessage(
handle, win32defines.WM_GETTEXT, length, ctypes.byref(buffer_))
handle, win32defines.WM_GETTEXT, length, byref(buffer_))
if ret:
textval = buffer_.value
@ -101,7 +105,7 @@ def classname(handle):
"""Return the class name of the window"""
if handle is None:
return None
class_name = ctypes.create_unicode_buffer(u"", 257)
class_name = create_unicode_buffer(u"", 257)
win32functions.GetClassName(handle, class_name, 256)
return class_name.value
@ -145,13 +149,13 @@ def contexthelpid(handle):
#=========================================================================
def iswindow(handle):
"""Return True if the handle is a window"""
return False if handle is None else bool(win32functions.IsWindow(handle))
return False if handle is None else bool(win32functions.IsWindow(handle))
#=========================================================================
def isvisible(handle):
"""Return True if the window is visible"""
return False if handle is None else bool(win32functions.IsWindowVisible(handle))
return False if handle is None else bool(win32functions.IsWindowVisible(handle))
#=========================================================================
@ -192,8 +196,8 @@ def is64bitbinary(filename):
binary_type = win32file.GetBinaryType(filename)
return binary_type != win32file.SCS_32BIT_BINARY
except Exception as exc:
warnings.warn('Cannot get binary type for file "{}". Error: {}' \
''.format(filename, exc), RuntimeWarning, stacklevel=2)
warnings.warn('Cannot get binary type for file "{}". Error: {}'
.format(filename, exc), RuntimeWarning, stacklevel=2)
return None
@ -201,24 +205,24 @@ def is64bitbinary(filename):
def clientrect(handle):
"""Return the client rectangle of the control"""
client_rect = win32structures.RECT()
win32functions.GetClientRect(handle, ctypes.byref(client_rect))
win32functions.GetClientRect(handle, byref(client_rect))
return client_rect
#=========================================================================
def rectangle(handle):
"""Return the rectangle of the window"""
# GetWindowRect returns 4-tuple
try:
return win32structures.RECT(*win32gui.GetWindowRect(handle))
except pywintypes.error:
return win32structures.RECT()
rect = win32structures.RECT()
win32functions.GetWindowRect(handle, byref(rect))
return rect
#=========================================================================
def font(handle):
"""Return the font as a LOGFONTW of the window"""
# get the font handle
if handle is None:
handle = 0 # make sure we don't pass window handle down as None
font_handle = win32functions.SendMessage(
handle, win32defines.WM_GETFONT, 0, 0)
@ -244,15 +248,10 @@ def font(handle):
font_handle = win32functions.GetStockObject(
win32defines.ANSI_VAR_FONT)
else:
fontval = win32structures.LOGFONTW()
ret = win32functions.GetObject(
font_handle, ctypes.sizeof(fontval), ctypes.byref(fontval))
# Get the Logfont structure of the font of the control
fontval = win32structures.LOGFONTW()
ret = win32functions.GetObject(
font_handle, ctypes.sizeof(fontval), ctypes.byref(fontval))
font_handle, sizeof(fontval), byref(fontval))
# The function could not get the font - this is probably
# because the control does not have associated Font/Text
@ -271,11 +270,11 @@ def font(handle):
# get the title font based on the system metrics rather
# than the font of the control itself
ncms = win32structures.NONCLIENTMETRICSW()
ncms.cbSize = ctypes.sizeof(ncms)
ncms.cbSize = sizeof(ncms)
win32functions.SystemParametersInfo(
win32defines.SPI_GETNONCLIENTMETRICS,
ctypes.sizeof(ncms),
ctypes.byref(ncms),
sizeof(ncms),
byref(ncms),
0)
# with either of the following 2 flags set the font of the
@ -293,8 +292,9 @@ def font(handle):
#=========================================================================
def processid(handle):
"""Return the ID of process that controls this window"""
_, process_id = win32process.GetWindowThreadProcessId(int(handle))
return process_id
pid = wintypes.DWORD()
win32functions.GetWindowThreadProcessId(handle, byref(pid))
return pid.value
#=========================================================================
@ -327,10 +327,10 @@ def children(handle):
return True
# define the child proc type
enum_child_proc_t = ctypes.WINFUNCTYPE(
ctypes.c_int, # return type
win32structures.HWND, # the window handle
win32structures.LPARAM) # extra information
enum_child_proc_t = WINFUNCTYPE(
c_int, # return type
wintypes.HWND, # the window handle
wintypes.LPARAM) # extra information
# update the proc to the correct type
proc = enum_child_proc_t(enum_child_proc)

@ -64,6 +64,8 @@ below. The module is also available on Linux.
{VK_F19}, {VK_EXECUTE}, {VK_PLAY}, {VK_RMENU}, {VK_F13}, {VK_F12}, {LWIN},
{VK_DOWN}, {VK_F17}, {VK_F16}, {VK_F15}, {VK_F14}
~ is a shorter alias for {ENTER}
**Modifiers:**
- ``'+': {VK_SHIFT}``
@ -96,10 +98,19 @@ Use curly brackers to escape modifiers and type reserved symbols as single keys:
send_keys('{^}a{^}c{%}') # type string "^a^c%" (Ctrl will not be pressed)
send_keys('{{}ENTER{}}') # type string "{ENTER}" without pressing Enter key
For Windows only, pywinauto defaults to sending a virtual key packet
(VK_PACKET) for textual input. For applications that do not handle VK_PACKET
appropriately, the ``vk_packet`` option may be set to ``False``. In this case
pywinauto will attempt to send the virtual key code of the requested key. This
option only affects the behavior of keys matching [-=[]\;',./a-zA-Z0-9 ]. Note
that upper and lower case are included for a-z. Both reference the same
virtual key for convenience.
"""
from __future__ import unicode_literals
import sys
import string
from . import deprecated
@ -113,6 +124,7 @@ else:
import six
from . import win32structures
from . import win32functions
__all__ = ['KeySequenceError', 'send_keys']
@ -120,17 +132,6 @@ else:
DEBUG = 0
GetMessageExtraInfo = ctypes.windll.user32.GetMessageExtraInfo
MapVirtualKey = ctypes.windll.user32.MapVirtualKeyW
SendInput = ctypes.windll.user32.SendInput
UINT = ctypes.c_uint
SendInput.restype = UINT
SendInput.argtypes = [UINT, ctypes.c_void_p, ctypes.c_int]
VkKeyScan = ctypes.windll.user32.VkKeyScanW
VkKeyScan.restype = ctypes.c_short
VkKeyScan.argtypes = [ctypes.c_wchar]
INPUT_KEYBOARD = 1
KEYEVENTF_EXTENDEDKEY = 1
KEYEVENTF_KEYUP = 2
@ -310,6 +311,29 @@ else:
'%': VK_MENU,
}
# Virtual keys that map to an ASCII character
# See https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
ascii_vk = {
' ': 0x20,
'=': 0xbb,
',': 0xbc,
'-': 0xbd,
'.': 0xbe,
# According to the above reference, the following characters vary per region.
# This mapping applies to US keyboards
';': 0xba,
'/': 0xbf,
'`': 0xc0,
'[': 0xdb,
'\\': 0xdc,
']': 0xdd,
'\'': 0xde,
}
# [0-9A-Z] map exactly to their ASCII counterparts
ascii_vk.update(dict((c, ord(c)) for c in string.ascii_uppercase + string.digits))
# map [a-z] to their uppercase ASCII counterparts
ascii_vk.update(dict((c, ord(c.upper())) for c in string.ascii_lowercase))
class KeySequenceError(Exception):
@ -368,7 +392,7 @@ else:
# it seems to return 0 every time but it's required by MSDN specification
# so call it just in case
inp.ki.dwExtraInfo = GetMessageExtraInfo()
inp.ki.dwExtraInfo = win32functions.GetMessageExtraInfo()
# if we are releasing - then let it up
if self.up:
@ -381,7 +405,7 @@ else:
inputs = self.GetInput()
# SendInput() supports all Unicode symbols
num_inserted_events = SendInput(len(inputs), ctypes.byref(inputs),
num_inserted_events = win32functions.SendInput(len(inputs), ctypes.byref(inputs),
ctypes.sizeof(win32structures.INPUT))
if num_inserted_events != len(inputs):
raise RuntimeError('SendInput() inserted only ' + str(num_inserted_events) +
@ -447,7 +471,7 @@ else:
# return self.key, 0, 0
# this works for Tic Tac Toe i.e. +{RIGHT} SHIFT + RIGHT
return self.key, MapVirtualKey(self.key, 0), flags
return self.key, win32functions.MapVirtualKeyW(self.key, 0), flags
def run(self):
"""Execute the action"""
@ -468,9 +492,9 @@ else:
The vk and scan code are generated differently.
"""
vkey_scan = LoByte(VkKeyScan(self.key))
vkey_scan = LoByte(win32functions.VkKeyScanW(self.key))
return (vkey_scan, MapVirtualKey(vkey_scan, 0), 0)
return (vkey_scan, win32functions.MapVirtualKeyW(vkey_scan, 0), 0)
def key_description(self):
"""Return a description of the key"""
@ -500,7 +524,7 @@ else:
__repr__ = __str__
def handle_code(code):
def handle_code(code, vk_packet):
"""Handle a key or sequence of keys in braces"""
code_keys = []
# it is a known code (e.g. {DOWN}, {ENTER}, etc)
@ -509,7 +533,10 @@ else:
# it is an escaped modifier e.g. {%}, {^}, {+}
elif len(code) == 1:
code_keys.append(KeyAction(code))
if not vk_packet and code in ascii_vk:
code_keys.append(VirtualKeyAction(ascii_vk[code]))
else:
code_keys.append(KeyAction(code))
# it is a repetition or a pause {DOWN 5}, {PAUSE 1.3}
elif ' ' in code:
@ -535,7 +562,7 @@ else:
[VirtualKeyAction(CODES[to_repeat])] * count)
# otherwise parse the keys and we get back a KeyAction
else:
to_repeat = parse_keys(to_repeat)
to_repeat = parse_keys(to_repeat, vk_packet=vk_packet)
if isinstance(to_repeat, list):
keys = to_repeat * count
else:
@ -550,7 +577,8 @@ else:
with_spaces=False,
with_tabs=False,
with_newlines=False,
modifiers=None):
modifiers=None,
vk_packet=True):
"""Return the parsed keys"""
keys = []
if not modifiers:
@ -579,8 +607,10 @@ else:
end_pos = string.find(")", index)
if end_pos == -1:
raise KeySequenceError('`)` not found')
keys.extend(
parse_keys(string[index:end_pos], modifiers=modifiers))
keys.extend(parse_keys(
string[index:end_pos],
modifiers=modifiers,
vk_packet=vk_packet))
index = end_pos + 1
# Escape or named key
@ -597,7 +627,7 @@ else:
if any(key_event in code.lower() for key_event in key_events):
code, current_key_event = code.split(' ')
should_escape_next_keys = True
current_keys = handle_code(code)
current_keys = handle_code(code, vk_packet)
if current_key_event is not None:
if isinstance(current_keys[0].key, six.string_types):
current_keys[0] = EscapedKeyAction(current_keys[0].key)
@ -636,6 +666,11 @@ else:
elif modifiers or should_escape_next_keys:
keys.append(EscapedKeyAction(c))
# if user disables the vk_packet option, always try to send a
# virtual key of the actual keystroke
elif not vk_packet and c in ascii_vk:
keys.append(VirtualKeyAction(ascii_vk[c]))
else:
keys.append(KeyAction(c))
@ -667,9 +702,12 @@ else:
with_spaces=False,
with_tabs=False,
with_newlines=False,
turn_off_numlock=True):
turn_off_numlock=True,
vk_packet=True):
"""Parse the keys and type them"""
keys = parse_keys(keys, with_spaces, with_tabs, with_newlines)
keys = parse_keys(
keys, with_spaces, with_tabs, with_newlines,
vk_packet=vk_packet)
for k in keys:
k.run()

@ -382,7 +382,7 @@ class PauseAction(KeyAction):
__repr__ = __str__
def handle_code(code):
def handle_code(code, vk_packet=True):
"""Handle a key or sequence of keys in braces"""
code_keys = []
# it is a known code (e.g. {DOWN}, {ENTER}, etc)
@ -433,7 +433,8 @@ def parse_keys(string,
with_spaces = False,
with_tabs = False,
with_newlines = False,
modifiers = None):
modifiers = None,
vk_packet=True):
"""Return the parsed keys"""
keys = []
if not modifiers:
@ -523,7 +524,8 @@ def send_keys(keys,
with_spaces=False,
with_tabs=False,
with_newlines=False,
turn_off_numlock=True):
turn_off_numlock=True,
vk_packet=True):
"""Parse the keys and type them"""
keys = parse_keys(keys, with_spaces, with_tabs, with_newlines)
for k in keys:

@ -35,10 +35,15 @@ Win32 API functions to perform custom marshalling
from __future__ import print_function
import sys
import ctypes
import win32api
import win32process
from ctypes import wintypes
from ctypes import c_void_p
from ctypes import pointer
from ctypes import sizeof
from ctypes import byref
from ctypes import c_size_t
from ctypes import WinError
from . import win32functions
from . import win32defines
from . import win32structures
@ -70,10 +75,12 @@ class RemoteMemoryBlock(object):
self._as_parameter_ = self.mem_address
_, process_id = win32process.GetWindowThreadProcessId(self.handle)
pid = wintypes.DWORD()
win32functions.GetWindowThreadProcessId(self.handle, byref(pid))
process_id = pid.value
if not process_id:
raise AccessDenied(
str(ctypes.WinError()) + " Cannot get process ID from handle.")
str(WinError()) + " Cannot get process ID from handle.")
self.process = win32functions.OpenProcess(
win32defines.PROCESS_VM_OPERATION |
@ -85,12 +92,12 @@ class RemoteMemoryBlock(object):
if not self.process:
raise AccessDenied(
str(ctypes.WinError()) + "process: %d",
str(WinError()) + "process: %d",
process_id)
self.mem_address = win32functions.VirtualAllocEx(
ctypes.c_void_p(self.process), # remote process
ctypes.c_void_p(0), # let Valloc decide where
c_void_p(self.process), # remote process
c_void_p(0), # let Valloc decide where
win32structures.ULONG_PTR(self.size + 4), # how much to allocate
win32defines.MEM_RESERVE | \
win32defines.MEM_COMMIT, # allocation type
@ -100,7 +107,7 @@ class RemoteMemoryBlock(object):
self.mem_address = self.mem_address.value
if self.mem_address == 0:
raise ctypes.WinError()
raise WinError()
if hex(self.mem_address) == '0xffffffff80000000' or hex(self.mem_address).upper() == '0xFFFFFFFF00000000':
raise Exception('Incorrect allocation: ' + hex(self.mem_address))
@ -108,11 +115,11 @@ class RemoteMemoryBlock(object):
self._as_parameter_ = self.mem_address
# write guard signature at the end of memory block
signature = win32structures.LONG(0x66666666)
signature = wintypes.LONG(0x66666666)
ret = win32functions.WriteProcessMemory(
ctypes.c_void_p(self.process),
ctypes.c_void_p(self.mem_address + self.size),
ctypes.pointer(signature),
c_void_p(self.process),
c_void_p(self.mem_address + self.size),
pointer(signature),
win32structures.ULONG_PTR(4),
win32structures.ULONG_PTR(0)
)
@ -129,7 +136,7 @@ class RemoteMemoryBlock(object):
if ret == 0:
ActionLogger().log('Warning: cannot close process handle!')
#raise ctypes.WinError()
#raise WinError()
#----------------------------------------------------------------
def CleanUp(self):
@ -140,17 +147,17 @@ class RemoteMemoryBlock(object):
self.CheckGuardSignature()
ret = win32functions.VirtualFreeEx(
ctypes.c_void_p(self.process),
ctypes.c_void_p(self.mem_address),
c_void_p(self.process),
c_void_p(self.mem_address),
win32structures.ULONG_PTR(0),
win32structures.DWORD(win32defines.MEM_RELEASE))
wintypes.DWORD(win32defines.MEM_RELEASE))
if ret == 0:
print('Error: CleanUp: VirtualFreeEx() returned zero for address ', hex(self.mem_address))
last_error = win32api.GetLastError()
print('LastError = ', last_error, ': ', win32api.FormatMessage(last_error).rstrip())
sys.stdout.flush()
self._CloseHandle()
raise ctypes.WinError()
raise WinError()
self.mem_address = 0
self._CloseHandle()
else:
@ -180,7 +187,7 @@ class RemoteMemoryBlock(object):
if size:
nSize = win32structures.ULONG_PTR(size)
else:
nSize = win32structures.ULONG_PTR(ctypes.sizeof(data))
nSize = win32structures.ULONG_PTR(sizeof(data))
if self.size < nSize.value:
raise Exception(('Write: RemoteMemoryBlock is too small ({0} bytes),' +
@ -190,19 +197,19 @@ class RemoteMemoryBlock(object):
raise Exception('Write: RemoteMemoryBlock has incorrect address = ' + hex(address))
ret = win32functions.WriteProcessMemory(
ctypes.c_void_p(self.process),
ctypes.c_void_p(address),
ctypes.pointer(data),
c_void_p(self.process),
c_void_p(address),
pointer(data),
nSize,
win32structures.ULONG_PTR(0)
)
if ret == 0:
ActionLogger().log('Error: Write failed: address = ', address)
ActionLogger().log('Error: Write failed: address = ' + str(address))
last_error = win32api.GetLastError()
ActionLogger().log('Error: LastError = ', last_error, ': ',
ActionLogger().log('Error: LastError = ' + str(last_error) + ': ' +
win32api.FormatMessage(last_error).rstrip())
raise ctypes.WinError()
raise WinError()
self.CheckGuardSignature()
#----------------------------------------------------------------
@ -216,7 +223,7 @@ class RemoteMemoryBlock(object):
if size:
nSize = win32structures.ULONG_PTR(size)
else:
nSize = win32structures.ULONG_PTR(ctypes.sizeof(data))
nSize = win32structures.ULONG_PTR(sizeof(data))
if self.size < nSize.value:
raise Exception(('Read: RemoteMemoryBlock is too small ({0} bytes),' +
@ -225,14 +232,14 @@ class RemoteMemoryBlock(object):
if hex(address).lower().startswith('0xffffff'):
raise Exception('Read: RemoteMemoryBlock has incorrect address =' + hex(address))
lpNumberOfBytesRead = ctypes.c_size_t(0)
lpNumberOfBytesRead = c_size_t(0)
ret = win32functions.ReadProcessMemory(
ctypes.c_void_p(self.process),
ctypes.c_void_p(address),
ctypes.byref(data),
c_void_p(self.process),
c_void_p(address),
byref(data),
nSize,
ctypes.byref(lpNumberOfBytesRead)
byref(lpNumberOfBytesRead)
)
# disabled as it often returns an error - but
@ -240,27 +247,27 @@ class RemoteMemoryBlock(object):
if ret == 0:
# try again
ret = win32functions.ReadProcessMemory(
ctypes.c_void_p(self.process),
ctypes.c_void_p(address),
ctypes.byref(data),
c_void_p(self.process),
c_void_p(address),
byref(data),
nSize,
ctypes.byref(lpNumberOfBytesRead)
byref(lpNumberOfBytesRead)
)
if ret == 0:
last_error = win32api.GetLastError()
if last_error != win32defines.ERROR_PARTIAL_COPY:
ActionLogger().log('Read: WARNING! self.mem_address =' +
hex(self.mem_address) + ' data address =' + str(ctypes.byref(data)))
hex(self.mem_address) + ' data address =' + str(byref(data)))
ActionLogger().log('LastError = ' + str(last_error) +
': ' + win32api.FormatMessage(last_error).rstrip())
else:
ActionLogger().log('Error: ERROR_PARTIAL_COPY')
ActionLogger().log('\nRead: WARNING! self.mem_address =' +
hex(self.mem_address) + ' data address =' + str(ctypes.byref(data)))
hex(self.mem_address) + ' data address =' + str(byref(data)))
ActionLogger().log('lpNumberOfBytesRead =' +
str(lpNumberOfBytesRead) + ' nSize =' + str(nSize))
raise ctypes.WinError()
raise WinError()
else:
ActionLogger().log('Warning! Read OK: 2nd attempt!')
#else:
@ -273,18 +280,18 @@ class RemoteMemoryBlock(object):
def CheckGuardSignature(self):
"""read guard signature at the end of memory block"""
signature = win32structures.LONG(0)
lpNumberOfBytesRead = ctypes.c_size_t(0)
lpNumberOfBytesRead = c_size_t(0)
ret = win32functions.ReadProcessMemory(
ctypes.c_void_p(self.process),
ctypes.c_void_p(self.mem_address + self.size),
ctypes.pointer(signature), # 0x66666666
c_void_p(self.process),
c_void_p(self.mem_address + self.size),
pointer(signature), # 0x66666666
win32structures.ULONG_PTR(4),
ctypes.byref(lpNumberOfBytesRead))
byref(lpNumberOfBytesRead))
if ret == 0:
ActionLogger().log('Error: Failed to read guard signature: address = ' +
hex(self.mem_address) + ', size = ' + str(self.size) +
', lpNumberOfBytesRead = ' + str(lpNumberOfBytesRead))
raise ctypes.WinError()
raise WinError()
else:
if hex(signature.value) != '0x66666666':
raise Exception('---------------------------------------- ' +

@ -82,8 +82,8 @@ class IUIA(object):
end_len = len('ControlTypeId')
self._control_types = [attr[start_len:-end_len] for attr in dir(self.UIA_dll) if attr.endswith('ControlTypeId')]
self.known_control_types = {} # string id: numeric id
self.known_control_type_ids = {} # numeric id: string id
self.known_control_types = { 'InvalidControlType': 0 } # string id: numeric id
self.known_control_type_ids = { 0: 'InvalidControlType' } # numeric id: string id
for ctrl_type in self._control_types:
type_id_name = 'UIA_' + ctrl_type + 'ControlTypeId'
@ -218,6 +218,8 @@ scroll_no_amount = IUIA().ui_automation_client.ScrollAmount_NoAmount
scroll_large_increment = IUIA().ui_automation_client.ScrollAmount_LargeIncrement
scroll_small_increment = IUIA().ui_automation_client.ScrollAmount_SmallIncrement
vt_empty = IUIA().ui_automation_client.VARIANT.empty.vt
vt_null = IUIA().ui_automation_client.VARIANT.null.vt
def get_elem_interface(element_info, pattern_name):
"""A helper to retrieve an element interface by the specified pattern name

@ -79,7 +79,6 @@ windll.user32.SetWindowsHookExA.restype = wintypes.HHOOK
windll.user32.SetWindowsHookExA.argtypes = [c_int, HOOKCB, wintypes.HINSTANCE, wintypes.DWORD]
windll.user32.SetWindowsHookExW.restype = wintypes.HHOOK
windll.user32.SetWindowsHookExW.argtypes = [c_int, HOOKCB, wintypes.HINSTANCE, wintypes.DWORD]
windll.user32.GetMessageW.argtypes = [POINTER(wintypes.MSG), wintypes.HWND, c_uint, c_uint]
windll.user32.TranslateMessage.argtypes = [POINTER(wintypes.MSG)]
windll.user32.DispatchMessageW.argtypes = [POINTER(wintypes.MSG)]
@ -452,7 +451,7 @@ class Hook(object):
al = ActionLogger()
al.log("_process_kbd_msg_type, bad event_type: {0}".format(event_type))
if event_type == 'key down':
if event_type == 'key down' and current_key not in self.pressed_keys:
self.pressed_keys.append(current_key)
elif event_type == 'key up':
if current_key in self.pressed_keys:

@ -31,192 +31,678 @@
"""Defines Windows(tm) functions"""
import ctypes
from ctypes import LibraryLoader
from ctypes import WinDLL
from ctypes import wintypes
from . import win32defines, win32structures
from .actionlogger import ActionLogger
from ctypes import c_uint, c_short, c_long
from ctypes import c_short
from ctypes import WINFUNCTYPE
from ctypes import c_void_p
from ctypes import c_int
from ctypes import byref
from ctypes import POINTER
from ctypes import c_ubyte
from ctypes import c_size_t
# Quote: "If you want cached libs without polluting ctypes.cdll or
# ctypes.windll, just create your own instance such as
# windll = ctypes.LibraryLoader(ctypes.WinDLL)."
# see https://bugs.python.org/issue22552
windll = LibraryLoader(WinDLL)
import sys
if sys.platform == "cygwin":
windll = ctypes.cdll
HRESULT = c_long
UINT = c_uint
SHORT = c_short
CreateBrushIndirect = ctypes.windll.gdi32.CreateBrushIndirect
CreateDC = ctypes.windll.gdi32.CreateDCW
CreateFontIndirect = ctypes.windll.gdi32.CreateFontIndirectW
CreatePen = ctypes.windll.gdi32.CreatePen
DeleteDC = ctypes.windll.gdi32.DeleteDC
GetObject = ctypes.windll.gdi32.GetObjectW
DeleteObject = ctypes.windll.gdi32.DeleteObject
DrawText = ctypes.windll.user32.DrawTextW
TextOut = ctypes.windll.gdi32.TextOutW
Rectangle = ctypes.windll.gdi32.Rectangle
SelectObject = ctypes.windll.gdi32.SelectObject
GetStockObject = ctypes.windll.gdi32.GetStockObject
GetSystemMetrics = ctypes.windll.user32.GetSystemMetrics
GetSystemMetrics.restype = ctypes.c_int
GetSystemMetrics.argtypes = (ctypes.c_int, )
GetTextMetrics = ctypes.windll.gdi32.GetTextMetricsW
EnumChildWindows = ctypes.windll.user32.EnumChildWindows
EnumDesktopWindows = ctypes.windll.user32.EnumDesktopWindows
EnumWindows = ctypes.windll.user32.EnumWindows
GetDC = ctypes.windll.user32.GetDC
GetDesktopWindow = ctypes.windll.user32.GetDesktopWindow
SendInput = ctypes.windll.user32.SendInput
SetCursorPos = ctypes.windll.user32.SetCursorPos
GetCursorPos = ctypes.windll.user32.GetCursorPos
GetCaretPos = ctypes.windll.user32.GetCaretPos
CreateBrushIndirect = windll.gdi32.CreateBrushIndirect
CreateBrushIndirect.restype = wintypes.HBRUSH
CreateBrushIndirect.argtypes = [
c_void_p,
]
CreateDC = windll.gdi32.CreateDCW
CreateDC.restype = wintypes.HDC
CreateDC.argtypes = [
wintypes.LPCWSTR,
wintypes.LPCWSTR,
wintypes.LPCWSTR,
c_void_p,
]
CreateFontIndirect = windll.gdi32.CreateFontIndirectW
CreateFontIndirect.restype = wintypes.HFONT
CreateFontIndirect.argtypes = [
POINTER(win32structures.LOGFONTW),
]
CreatePen = windll.gdi32.CreatePen
CreatePen.restype = wintypes.HPEN
CreatePen.argtypes = [
c_int,
c_int,
wintypes.COLORREF,
]
DeleteDC = windll.gdi32.DeleteDC
DeleteDC.restype = wintypes.BOOL
DeleteDC.argtypes = [
wintypes.HDC,
]
GetObject = windll.gdi32.GetObjectW
GetObject.restype = c_int
GetObject.argtypes = [
wintypes.HANDLE,
c_int,
wintypes.LPVOID,
]
DeleteObject = windll.gdi32.DeleteObject
DeleteObject.restype = wintypes.BOOL
DeleteObject.argtypes = [
wintypes.HGDIOBJ,
]
DrawText = windll.user32.DrawTextW
DrawText.restype = c_int
DrawText.argtypes = [
wintypes.HDC,
wintypes.LPCWSTR,
c_int,
POINTER(wintypes.RECT),
wintypes.UINT,
]
TextOut = windll.gdi32.TextOutW
TextOut.restype = wintypes.BOOL
TextOut.argtypes = [
wintypes.HDC,
c_int,
c_int,
wintypes.LPCWSTR,
c_int,
]
Rectangle = windll.gdi32.Rectangle
Rectangle.restype = wintypes.BOOL
Rectangle.argtypes = [
wintypes.HDC,
c_int,
c_int,
c_int,
c_int,
]
SelectObject = windll.gdi32.SelectObject
SelectObject.restype = wintypes.HGDIOBJ
SelectObject.argtypes = [
wintypes.HDC,
wintypes.HGDIOBJ,
]
GetStockObject = windll.gdi32.GetStockObject
GetStockObject.restype = wintypes.HGDIOBJ
GetStockObject.argtypes = [
c_int,
]
GetSystemMetrics = windll.user32.GetSystemMetrics
GetSystemMetrics.restype = c_int
GetSystemMetrics.argtypes = [
c_int,
]
GetTextMetrics = windll.gdi32.GetTextMetricsW
GetTextMetrics.restype = wintypes.BOOL
GetTextMetrics.argtypes = [
wintypes.HDC,
POINTER(win32structures.TEXTMETRICW),
]
EnumChildWindows = windll.user32.EnumChildWindows
EnumChildWindows.restype = wintypes.BOOL
EnumChildWindows.argtypes = [
wintypes.HWND,
WINFUNCTYPE(wintypes.BOOL, wintypes.HWND, wintypes.LPARAM),
wintypes.LPARAM,
]
EnumDesktopWindows = windll.user32.EnumDesktopWindows
EnumDesktopWindows.restype = wintypes.BOOL
EnumDesktopWindows.argtypes = [
wintypes.LPVOID,
WINFUNCTYPE(wintypes.BOOL, wintypes.HWND, wintypes.LPARAM),
wintypes.LPARAM,
]
EnumWindows = windll.user32.EnumWindows
EnumWindows.restype = wintypes.BOOL
EnumWindows.argtypes = [
WINFUNCTYPE(wintypes.BOOL, wintypes.HWND, wintypes.LPARAM),
wintypes.LPARAM,
]
GetDC = windll.user32.GetDC
GetDC.restype = wintypes.LPVOID
GetDC.argtypes = [
wintypes.HWND,
]
GetDesktopWindow = windll.user32.GetDesktopWindow
GetDesktopWindow.restype = wintypes.HWND
GetDesktopWindow.argtypes = [
]
SendInput = windll.user32.SendInput
SendInput.restype = wintypes.UINT
SendInput.argtypes = [
wintypes.UINT,
c_void_p, # using POINTER(win32structures.INPUT) needs rework in keyboard.py
c_int,
]
SetCursorPos = windll.user32.SetCursorPos
SetCursorPos.restype = wintypes.BOOL
SetCursorPos.argtypes = [
c_int,
c_int,
]
GetCursorPos = windll.user32.GetCursorPos
GetCursorPos.restype = wintypes.BOOL
GetCursorPos.argtypes = [
POINTER(wintypes.POINT),
]
GetCaretPos = windll.user32.GetCaretPos
GetCaretPos.restype = wintypes.BOOL
GetCaretPos.argtypes = [
POINTER(wintypes.POINT),
]
GetKeyboardState = windll.user32.GetKeyboardState
GetKeyboardState.restype = wintypes.BOOL
GetKeyboardState.argtypes = [
POINTER(c_ubyte),
]
SetKeyboardState = windll.user32.SetKeyboardState
SetKeyboardState.restype = wintypes.BOOL
SetKeyboardState.argtypes = [
POINTER(c_ubyte),
]
GetKeyboardLayout = windll.user32.GetKeyboardLayout
GetKeyboardLayout.restype = wintypes.HKL
GetKeyboardLayout.argtypes = [
wintypes.DWORD,
]
VkKeyScanW = windll.user32.VkKeyScanW
VkKeyScanW.restype = SHORT
VkKeyScanW.argtypes = [
wintypes.WCHAR,
]
VkKeyScanExW = windll.user32.VkKeyScanExW
VkKeyScanExW.restype = SHORT
VkKeyScanExW.argtypes = [
wintypes.WCHAR,
wintypes.HKL,
]
GetMessageExtraInfo = windll.user32.GetMessageExtraInfo
MapVirtualKeyW = windll.user32.MapVirtualKeyW
# menu functions
DrawMenuBar = ctypes.windll.user32.DrawMenuBar
GetMenu = ctypes.windll.user32.GetMenu
GetMenuBarInfo = ctypes.windll.user32.GetMenuBarInfo
GetMenuInfo = ctypes.windll.user32.GetMenuInfo
GetMenuItemCount = ctypes.windll.user32.GetMenuItemCount
GetMenuItemInfo = ctypes.windll.user32.GetMenuItemInfoW
SetMenuItemInfo = ctypes.windll.user32.SetMenuItemInfoW
GetMenuItemRect = ctypes.windll.user32.GetMenuItemRect
CheckMenuItem = ctypes.windll.user32.CheckMenuItem
GetMenuState = ctypes.windll.user32.GetMenuState
GetSubMenu = ctypes.windll.user32.GetSubMenu
GetSystemMenu = ctypes.windll.user32.GetSystemMenu
HiliteMenuItem = ctypes.windll.user32.HiliteMenuItem
IsMenu = ctypes.windll.user32.IsMenu
MenuItemFromPoint = ctypes.windll.user32.MenuItemFromPoint
BringWindowToTop = ctypes.windll.user32.BringWindowToTop
GetVersion = ctypes.windll.kernel32.GetVersion
GetParent = ctypes.windll.user32.GetParent
GetWindow = ctypes.windll.user32.GetWindow
ShowWindow = ctypes.windll.user32.ShowWindow
GetWindowContextHelpId = ctypes.windll.user32.GetWindowContextHelpId
GetWindowLong = ctypes.windll.user32.GetWindowLongW
GetWindowPlacement = ctypes.windll.user32.GetWindowPlacement
GetWindowRect = ctypes.windll.user32.GetWindowRect
GetWindowText = ctypes.windll.user32.GetWindowTextW
GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
GetClassName = ctypes.windll.user32.GetClassNameW
GetClassName.argtypes = [win32structures.HWND, wintypes.LPWSTR, ctypes.c_int]
GetClassName.restrype = ctypes.c_int
GetClientRect = ctypes.windll.user32.GetClientRect
IsChild = ctypes.windll.user32.IsChild
IsWindow = ctypes.windll.user32.IsWindow
IsWindow.argtypes = [win32structures.HWND]
IsWindow.restype = win32structures.BOOL
IsWindowUnicode = ctypes.windll.user32.IsWindowUnicode
IsWindowUnicode.argtypes = [win32structures.HWND]
IsWindowUnicode.restype = win32structures.BOOL
IsWindowVisible = ctypes.windll.user32.IsWindowVisible
IsWindowVisible.argtypes = [win32structures.HWND]
IsWindowVisible.restype = win32structures.BOOL
IsWindowEnabled = ctypes.windll.user32.IsWindowEnabled
IsWindowEnabled.argtypes = [win32structures.HWND]
IsWindowEnabled.restype = win32structures.BOOL
ClientToScreen = ctypes.windll.user32.ClientToScreen
ScreenToClient = ctypes.windll.user32.ScreenToClient
GetCurrentThreadId = ctypes.windll.Kernel32.GetCurrentThreadId
GetWindowThreadProcessId = ctypes.windll.user32.GetWindowThreadProcessId
GetGUIThreadInfo = ctypes.windll.user32.GetGUIThreadInfo
AttachThreadInput = ctypes.windll.user32.AttachThreadInput
AttachThreadInput.restype = win32structures.BOOL
AttachThreadInput.argtypes = [win32structures.DWORD, win32structures.DWORD, win32structures.BOOL]
#GetWindowThreadProcessId = ctypes.windll.user32.GetWindowThreadProcessId
GetLastError = ctypes.windll.kernel32.GetLastError
OpenProcess = ctypes.windll.kernel32.OpenProcess
CloseHandle = ctypes.windll.kernel32.CloseHandle
CreateProcess = ctypes.windll.kernel32.CreateProcessW
TerminateProcess = ctypes.windll.kernel32.TerminateProcess
ExitProcess = ctypes.windll.kernel32.ExitProcess
ReadProcessMemory = ctypes.windll.kernel32.ReadProcessMemory
GlobalAlloc = ctypes.windll.kernel32.GlobalAlloc
GlobalLock = ctypes.windll.kernel32.GlobalLock
GlobalUnlock = ctypes.windll.kernel32.GlobalUnlock
SendMessage = ctypes.windll.user32.SendMessageW
SendMessageTimeout = ctypes.windll.user32.SendMessageTimeoutW
SendMessageTimeout.argtypes = [win32structures.HWND, win32structures.UINT, win32structures.WPARAM,
win32structures.LPARAM, win32structures.UINT, win32structures.UINT,
win32structures.PDWORD_PTR]
SendMessageTimeout.restype = win32structures.LRESULT
SendMessageA = ctypes.windll.user32.SendMessageA
PostMessage = ctypes.windll.user32.PostMessageW
GetMessage = ctypes.windll.user32.GetMessageW
RegisterWindowMessage = ctypes.windll.user32.RegisterWindowMessageW
RegisterWindowMessage.restype = UINT
MoveWindow = ctypes.windll.user32.MoveWindow
EnableWindow = ctypes.windll.user32.EnableWindow
SetActiveWindow = ctypes.windll.user32.SetActiveWindow
GetFocus = ctypes.windll.user32.GetFocus
SetFocus = ctypes.windll.user32.SetFocus
SetForegroundWindow = ctypes.windll.user32.SetForegroundWindow
GetForegroundWindow = ctypes.windll.user32.GetForegroundWindow
SetWindowLong = ctypes.windll.user32.SetWindowLongW
DrawMenuBar = windll.user32.DrawMenuBar
DrawMenuBar.restype = wintypes.BOOL
DrawMenuBar.argstype = [
wintypes.HWND,
]
GetMenu = windll.user32.GetMenu
GetMenu.restype = wintypes.HMENU
GetMenu.argtypes = [
wintypes.HWND,
]
GetMenuBarInfo = windll.user32.GetMenuBarInfo
GetMenuBarInfo.restype = wintypes.BOOL
GetMenuBarInfo.argtypes = [
wintypes.HWND,
wintypes.LONG,
wintypes.LONG,
POINTER(win32structures.MENUBARINFO),
]
GetMenuInfo = windll.user32.GetMenuInfo
GetMenuInfo.restype = wintypes.BOOL
GetMenuInfo.argtypes = [
wintypes.HWND,
POINTER(win32structures.MENUINFO),
]
GetMenuItemCount = windll.user32.GetMenuItemCount
GetMenuItemCount.restype = c_int
GetMenuItemCount.argtypes = [
wintypes.HMENU,
]
GetMenuItemInfo = windll.user32.GetMenuItemInfoW
GetMenuItemInfo.restype = wintypes.BOOL
GetMenuItemInfo.argtypes = [
wintypes.HMENU,
wintypes.UINT,
wintypes.BOOL,
POINTER(win32structures.MENUITEMINFOW),
]
SetMenuItemInfo = windll.user32.SetMenuItemInfoW
SetMenuItemInfo.restype = wintypes.BOOL
SetMenuItemInfo.argtypes = [
wintypes.HMENU,
wintypes.UINT,
wintypes.BOOL,
POINTER(win32structures.MENUITEMINFOW),
]
GetMenuItemRect = windll.user32.GetMenuItemRect
GetMenuItemRect.restype = wintypes.BOOL
GetMenuItemRect.argtypes = [
wintypes.HWND,
wintypes.HMENU,
wintypes.UINT,
POINTER(wintypes.RECT),
]
CheckMenuItem = windll.user32.CheckMenuItem
CheckMenuItem.restype = wintypes.DWORD
CheckMenuItem.argtypes = [
wintypes.HMENU,
wintypes.UINT,
wintypes.UINT,
]
GetMenuState = windll.user32.GetMenuState
GetMenuState.restype = wintypes.UINT
GetMenuState.argtypes = [
wintypes.HMENU,
wintypes.UINT,
wintypes.UINT,
]
GetSubMenu = windll.user32.GetSubMenu
GetSubMenu.restype = wintypes.HMENU
GetSubMenu.argtypes = [
wintypes.HMENU,
c_int,
]
GetSystemMenu = windll.user32.GetSystemMenu
GetSystemMenu.restype = wintypes.HMENU
GetSystemMenu.argtypes = [
wintypes.HWND,
wintypes.BOOL,
]
HiliteMenuItem = windll.user32.HiliteMenuItem
HiliteMenuItem.restype = wintypes.BOOL
HiliteMenuItem.argtypes = [
wintypes.HWND,
wintypes.HMENU,
wintypes.UINT,
wintypes.UINT,
]
IsMenu = windll.user32.IsMenu
IsMenu.restype = wintypes.BOOL
IsMenu.argtypes = [
wintypes.HMENU,
]
MenuItemFromPoint = windll.user32.MenuItemFromPoint
MenuItemFromPoint.restype = c_int
MenuItemFromPoint.argtypes = [
wintypes.HWND,
wintypes.HMENU,
POINTER(wintypes.POINT),
]
BringWindowToTop = windll.user32.BringWindowToTop
BringWindowToTop.restype = wintypes.BOOL
BringWindowToTop.argtypes = [
wintypes.HWND,
]
GetParent = windll.user32.GetParent
GetParent.restype = wintypes.HWND
GetParent.argtypes = [
wintypes.HWND,
]
GetWindow = windll.user32.GetWindow
GetWindow.restype = wintypes.HWND
GetWindow.argtypes = [
wintypes.HWND,
wintypes.UINT,
]
ShowWindow = windll.user32.ShowWindow
ShowWindow.restype = wintypes.BOOL
ShowWindow.argtypes = [
wintypes.HWND,
c_int,
]
GetWindowContextHelpId = windll.user32.GetWindowContextHelpId
GetWindowContextHelpId.restype = wintypes.DWORD
GetWindowContextHelpId.argtypes = [
wintypes.HWND,
]
GetWindowLong = windll.user32.GetWindowLongW
GetWindowLong.restype = wintypes.LONG
GetWindowLong.argtypes = [
wintypes.HWND,
c_int,
]
GetWindowPlacement = windll.user32.GetWindowPlacement
GetWindowPlacement.restype = wintypes.BOOL
GetWindowPlacement.argtypes = [
wintypes.HWND,
POINTER(win32structures.WINDOWPLACEMENT),
]
GetWindowRect = windll.user32.GetWindowRect
GetWindowRect.restype = wintypes.BOOL
GetWindowRect.argtypes = [
wintypes.HWND,
POINTER(wintypes.RECT),
]
GetWindowText = windll.user32.GetWindowTextW
GetWindowText.restype = c_int
GetWindowText.argtypes = [
wintypes.HWND,
wintypes.LPWSTR,
c_int,
]
GetWindowTextLength = windll.user32.GetWindowTextLengthW
GetWindowTextLength.restype = c_int
GetWindowTextLength.argtypes = [
wintypes.HWND,
]
GetClassName = windll.user32.GetClassNameW
GetClassName.restype = c_int
GetClassName.argtypes = [
wintypes.HWND,
wintypes.LPWSTR,
c_int,
]
GetClientRect = windll.user32.GetClientRect
GetClientRect.restype = wintypes.BOOL
GetClientRect.argtypes = [
wintypes.HWND,
POINTER(wintypes.RECT),
]
IsChild = windll.user32.IsChild
IsChild.restype = wintypes.BOOL
IsChild.argtypes = [
wintypes.HWND,
wintypes.HWND,
]
IsWindow = windll.user32.IsWindow
IsWindow.restype = wintypes.BOOL
IsWindow.argtypes = [
wintypes.HWND,
]
IsWindowUnicode = windll.user32.IsWindowUnicode
IsWindowUnicode.restype = wintypes.BOOL
IsWindowUnicode.argtypes = [
wintypes.HWND,
]
IsWindowVisible = windll.user32.IsWindowVisible
IsWindowVisible.restype = wintypes.BOOL
IsWindowVisible.argtypes = [
wintypes.HWND,
]
IsWindowEnabled = windll.user32.IsWindowEnabled
IsWindowEnabled.restype = wintypes.BOOL
IsWindowEnabled.argtypes = [
wintypes.HWND,
]
ClientToScreen = windll.user32.ClientToScreen
ClientToScreen.restype = wintypes.BOOL
ClientToScreen.argtypes = [
wintypes.HWND,
POINTER(wintypes.POINT),
]
ScreenToClient = windll.user32.ScreenToClient
ScreenToClient.restype = wintypes.BOOL
ScreenToClient.argtypes = [
wintypes.HWND,
POINTER(wintypes.POINT),
]
GetCurrentThreadId = windll.kernel32.GetCurrentThreadId
GetCurrentThreadId.restype = wintypes.DWORD
GetCurrentThreadId.argtypes = [
]
GetWindowThreadProcessId = windll.user32.GetWindowThreadProcessId
GetWindowThreadProcessId.restype = wintypes.DWORD
GetWindowThreadProcessId.argtypes = [
wintypes.HWND,
POINTER(wintypes.DWORD),
]
GetGUIThreadInfo = windll.user32.GetGUIThreadInfo
GetGUIThreadInfo.restype = wintypes.BOOL
GetGUIThreadInfo.argtypes = [
wintypes.DWORD,
POINTER(win32structures.GUITHREADINFO),
]
AttachThreadInput = windll.user32.AttachThreadInput
AttachThreadInput.restype = wintypes.BOOL
AttachThreadInput.argtypes = [
wintypes.DWORD,
wintypes.DWORD,
wintypes.BOOL
]
OpenProcess = windll.kernel32.OpenProcess
OpenProcess.restype = wintypes.HANDLE
OpenProcess.argtypes = [
wintypes.DWORD,
wintypes.BOOL,
wintypes.DWORD,
]
CloseHandle = windll.kernel32.CloseHandle
CloseHandle.restype = wintypes.BOOL
CloseHandle.argtypes = [
wintypes.HANDLE,
]
CreateProcess = windll.kernel32.CreateProcessW
CreateProcess.restype = wintypes.BOOL
CreateProcess.argtypes = [
wintypes.LPCWSTR,
wintypes.LPWSTR,
POINTER(win32structures.SECURITY_ATTRIBUTES),
POINTER(win32structures.SECURITY_ATTRIBUTES),
wintypes.BOOL,
wintypes.DWORD,
wintypes.LPVOID,
wintypes.LPCWSTR,
POINTER(win32structures.STARTUPINFOW),
POINTER(win32structures.PROCESS_INFORMATION),
]
TerminateProcess = windll.kernel32.TerminateProcess
TerminateProcess.restype = wintypes.BOOL
TerminateProcess.argtypes = [
wintypes.HANDLE,
wintypes.UINT,
]
ExitProcess = windll.kernel32.ExitProcess
ExitProcess.restype = None
ExitProcess.argtypes = [
wintypes.UINT,
]
ReadProcessMemory = windll.kernel32.ReadProcessMemory
ReadProcessMemory.restype = wintypes.BOOL
ReadProcessMemory.argtypes = [
wintypes.HANDLE,
wintypes.LPVOID,
wintypes.LPVOID,
c_size_t,
POINTER(c_size_t),
]
GlobalAlloc = windll.kernel32.GlobalAlloc
GlobalLock = windll.kernel32.GlobalLock
GlobalUnlock = windll.kernel32.GlobalUnlock
SendMessage = windll.user32.SendMessageW
SendMessage.restype = wintypes.LPARAM
SendMessage.argtypes = [
wintypes.HWND,
wintypes.UINT,
wintypes.WPARAM,
wintypes.LPVOID,
]
SendMessageTimeout = windll.user32.SendMessageTimeoutW
SendMessageTimeout.restype = wintypes.LPARAM
SendMessageTimeout.argtypes = [
wintypes.HWND,
wintypes.UINT,
wintypes.WPARAM,
wintypes.LPARAM,
wintypes.UINT,
wintypes.UINT,
win32structures.PDWORD_PTR,
]
PostMessage = windll.user32.PostMessageW
PostMessage.restype = wintypes.BOOL
PostMessage.argtypes = [
wintypes.HWND,
wintypes.UINT,
wintypes.WPARAM,
wintypes.LPARAM,
]
GetMessage = windll.user32.GetMessageW
GetMessage.restype = wintypes.BOOL
GetMessage.argtypes = [
POINTER(wintypes.MSG),
wintypes.HWND,
wintypes.UINT,
wintypes.UINT,
]
RegisterWindowMessage = windll.user32.RegisterWindowMessageW
RegisterWindowMessage.restype = wintypes.UINT
RegisterWindowMessage.argtypes = [
wintypes.LPCWSTR,
]
MoveWindow = windll.user32.MoveWindow
MoveWindow.restype = wintypes.BOOL
MoveWindow.argtypes = [
wintypes.HWND,
c_int,
c_int,
c_int,
c_int,
wintypes.BOOL,
]
EnableWindow = windll.user32.EnableWindow
EnableWindow.restype = wintypes.BOOL
EnableWindow.argtypes = [
wintypes.HWND,
wintypes.BOOL,
]
SetFocus = windll.user32.SetFocus
SetFocus.restype = wintypes.HWND
SetFocus.argtypes = [
wintypes.HWND,
]
SetWindowLong = windll.user32.SetWindowLongW
SetWindowLong.restype = wintypes.LONG
SetWindowLong.argtypes = [
wintypes.HWND,
c_int,
wintypes.LONG,
]
try:
SetWindowLongPtr = ctypes.windll.user32.SetWindowLongPtrW
SetWindowLongPtr.argtypes = [win32structures.HWND, ctypes.c_int, win32structures.LONG_PTR]
SetWindowLongPtr.restype = win32structures.LONG_PTR
SetWindowLongPtr = windll.user32.SetWindowLongPtrW
SetWindowLongPtr.argtypes = [wintypes.HWND, c_int, wintypes.LONG_PTR]
SetWindowLongPtr.restype = wintypes.LONG_PTR
except AttributeError:
SetWindowLongPtr = SetWindowLong
SystemParametersInfo = ctypes.windll.user32.SystemParametersInfoW
VirtualAllocEx = ctypes.windll.kernel32.VirtualAllocEx
VirtualAllocEx.restype = ctypes.c_void_p
VirtualFreeEx = ctypes.windll.kernel32.VirtualFreeEx
DebugBreakProcess = ctypes.windll.kernel32.DebugBreakProcess
VirtualAlloc = ctypes.windll.kernel32.VirtualAlloc
VirtualFree = ctypes.windll.kernel32.VirtualFree
WriteProcessMemory = ctypes.windll.kernel32.WriteProcessMemory
GetActiveWindow = ctypes.windll.user32.GetActiveWindow
GetLastActivePopup = ctypes.windll.user32.GetLastActivePopup
FindWindow = ctypes.windll.user32.FindWindowW
GetTopWindow = ctypes.windll.user32.GetTopWindow
SetCapture = ctypes.windll.user32.SetCapture
ReleaseCapture = ctypes.windll.user32.ReleaseCapture
ShowOwnedPopups = ctypes.windll.user32.ShowOwnedPopups
WindowFromPoint = ctypes.windll.user32.WindowFromPoint
WideCharToMultiByte = ctypes.windll.kernel32.WideCharToMultiByte
GetACP = ctypes.windll.kernel32.GetACP
WaitForSingleObject = ctypes.windll.kernel32.WaitForSingleObject
WaitForInputIdle = ctypes.windll.user32.WaitForInputIdle
IsHungAppWindow = ctypes.windll.user32.IsHungAppWindow
IsHungAppWindow.restype = win32structures.BOOL
IsHungAppWindow.argtypes = [win32structures.HWND]
GetModuleFileNameEx = ctypes.windll.psapi.GetModuleFileNameExW
GetClipboardData = ctypes.windll.user32.GetClipboardData
OpenClipboard = ctypes.windll.user32.OpenClipboard
EmptyClipboard = ctypes.windll.user32.EmptyClipboard
CloseClipboard = ctypes.windll.user32.CloseClipboard
CountClipboardFormats = ctypes.windll.user32.CountClipboardFormats
EnumClipboardFormats = ctypes.windll.user32.EnumClipboardFormats
GetClipboardFormatName = ctypes.windll.user32.GetClipboardFormatNameW
SystemParametersInfo = windll.user32.SystemParametersInfoW
SystemParametersInfo.restype = wintypes.UINT
SystemParametersInfo.argtypes = [
wintypes.UINT,
wintypes.UINT,
wintypes.LPVOID, # should map well to PVOID
wintypes.UINT,
]
VirtualAllocEx = windll.kernel32.VirtualAllocEx
VirtualAllocEx.restype = wintypes.LPVOID
VirtualAllocEx.argtypes = [
wintypes.HANDLE,
wintypes.LPVOID,
c_size_t,
wintypes.DWORD,
wintypes.DWORD,
]
VirtualFreeEx = windll.kernel32.VirtualFreeEx
VirtualFreeEx.restype = wintypes.BOOL
VirtualFreeEx.argtypes = [
wintypes.HANDLE,
wintypes.LPVOID,
c_size_t,
wintypes.DWORD,
]
VirtualAlloc = windll.kernel32.VirtualAlloc
VirtualAlloc.restype = wintypes.LPVOID
VirtualAlloc.argtypes = [
wintypes.LPVOID,
c_size_t,
wintypes.DWORD,
wintypes.DWORD,
]
VirtualFree = windll.kernel32.VirtualFree
VirtualFree.retype = wintypes.BOOL
VirtualFree.argtypes = [
wintypes.LPVOID,
c_size_t,
wintypes.DWORD,
]
WriteProcessMemory = windll.kernel32.WriteProcessMemory
WriteProcessMemory.restype = wintypes.BOOL
WriteProcessMemory.argtypes = [
wintypes.HANDLE,
wintypes.LPVOID,
wintypes.LPVOID,
c_size_t,
POINTER(c_size_t),
]
ReleaseCapture = windll.user32.ReleaseCapture
ReleaseCapture.restype = wintypes.BOOL
ReleaseCapture.argtypes = [
]
WindowFromPoint = windll.user32.WindowFromPoint
WindowFromPoint.restype = wintypes.HWND
WindowFromPoint.argtypes = [
wintypes.POINT,
]
WaitForSingleObject = windll.kernel32.WaitForSingleObject
WaitForSingleObject.restype = wintypes.DWORD
WaitForSingleObject.argtypes = [
wintypes.HANDLE,
wintypes.DWORD,
]
WaitForInputIdle = windll.user32.WaitForInputIdle
WaitForInputIdle.restype = wintypes.DWORD
WaitForInputIdle.argtypes = [
wintypes.HANDLE,
wintypes.DWORD,
]
IsHungAppWindow = windll.user32.IsHungAppWindow
IsHungAppWindow.restype = wintypes.BOOL
IsHungAppWindow.argtypes = [
wintypes.HWND,
]
GetModuleFileNameEx = windll.psapi.GetModuleFileNameExW
GetModuleFileNameEx.restype = wintypes.DWORD
GetModuleFileNameEx.argtypes = [
wintypes.HANDLE,
wintypes.HMODULE,
wintypes.LPWSTR,
wintypes.DWORD,
]
GetClipboardData = windll.user32.GetClipboardData
GetClipboardData.restype = wintypes.HANDLE
GetClipboardData.argtypes = [
wintypes.UINT,
]
OpenClipboard = windll.user32.OpenClipboard
OpenClipboard.restype = wintypes.BOOL
OpenClipboard.argtypes = [
wintypes.HWND,
]
EmptyClipboard = windll.user32.EmptyClipboard
EmptyClipboard.restype = wintypes.BOOL
EmptyClipboard.argtypes = [
]
CloseClipboard = windll.user32.CloseClipboard
CloseClipboard.restype = wintypes.BOOL
CloseClipboard.argtypes = [
]
CountClipboardFormats = windll.user32.CountClipboardFormats
CountClipboardFormats.restype = c_int
CountClipboardFormats.argtypes = [
]
EnumClipboardFormats = windll.user32.EnumClipboardFormats
EnumClipboardFormats.restype = wintypes.UINT
EnumClipboardFormats.argtypes = [
wintypes.UINT,
]
GetClipboardFormatName = windll.user32.GetClipboardFormatNameW
GetClipboardFormatName.restype = c_int
GetClipboardFormatName.argtypes = [
wintypes.UINT,
wintypes.LPWSTR,
c_int,
]
# DPIAware API funcs are not available on WinXP
try:
IsProcessDPIAware = ctypes.windll.user32.IsProcessDPIAware
SetProcessDPIAware = ctypes.windll.user32.SetProcessDPIAware
IsProcessDPIAware = windll.user32.IsProcessDPIAware
SetProcessDPIAware = windll.user32.SetProcessDPIAware
except AttributeError:
IsProcessDPIAware = None
SetProcessDPIAware = None
@ -230,7 +716,7 @@ except AttributeError:
# Process_Per_Monitor_DPI_Aware = 2
# } Process_DPI_Awareness;
try:
shcore = ctypes.windll.LoadLibrary("Shcore.dll")
shcore = windll.LoadLibrary("Shcore.dll")
SetProcessDpiAwareness = shcore.SetProcessDpiAwareness
GetProcessDpiAwareness = shcore.GetProcessDpiAwareness
Process_DPI_Awareness = {
@ -252,26 +738,17 @@ elif SetProcessDPIAware:
ActionLogger().log("Call SetProcessDPIAware")
SetProcessDPIAware()
GetQueueStatus = ctypes.windll.user32.GetQueueStatus
GetQueueStatus = windll.user32.GetQueueStatus
LoadString = ctypes.windll.user32.LoadStringW
LoadString = windll.user32.LoadStringW
#def VkKeyScanW(p1):
# # C:/PROGRA~1/MICROS~4/VC98/Include/winuser.h 4225
# return VkKeyScanW._api_(p1)
#VkKeyScan = stdcall(SHORT, 'user32', [c_wchar]) (VkKeyScanW)
#
#def MapVirtualKeyExW(p1, p2, p3):
# # C:/PROGRA~1/MICROS~4/VC98/Include/winuser.h 4376
# return MapVirtualKeyExW._api_(p1, p2, p3)
#MapVirtualKeyEx = stdcall(
# UINT, 'user32', [c_uint, c_uint, c_long]) (MapVirtualKeyExW)
#
#def MapVirtualKeyW(p1, p2):
# # C:/PROGRA~1/MICROS~4/VC98/Include/winuser.h 4355
# return MapVirtualKeyW._api_(p1, p2)
#MapVirtualKey = stdcall(UINT, 'user32', [c_uint, c_uint]) (MapVirtualKeyW)
#====================================================================
@ -297,7 +774,7 @@ def LoWord(value):
def WaitGuiThreadIdle(handle):
"""Wait until the thread of the specified handle is ready"""
process_id = wintypes.DWORD(0)
GetWindowThreadProcessId(handle, ctypes.POINTER(wintypes.DWORD)(process_id))
GetWindowThreadProcessId(handle, byref(process_id))
# ask the control if it has finished processing the message
hprocess = OpenProcess(
@ -327,10 +804,10 @@ def GetDpiAwarenessByPid(pid):
return dpi_awareness
try:
dpi_awareness = ctypes.c_int()
dpi_awareness = c_int()
hRes = GetProcessDpiAwareness(
hProcess,
ctypes.byref(dpi_awareness))
byref(dpi_awareness))
CloseHandle(hProcess)
if hRes == 0:
return dpi_awareness.value

@ -32,19 +32,18 @@
"""Definition of Windows structures"""
import six
import ctypes
from ctypes import Structure as Struct
from ctypes import \
c_int, c_uint, c_long, c_ulong, c_void_p, c_wchar, c_char, \
c_ubyte, c_ushort, \
c_int, c_long, c_void_p, c_char, memmove, addressof, \
POINTER, sizeof, alignment, Union, c_longlong, c_size_t, wintypes
from .win32defines import LF_FACESIZE
from . import sysinfo
class Structure(ctypes.Structure):
class StructureMixIn(object):
"""Override the Structure class from ctypes to add printing and comparison"""
"""Define printing and comparison behaviors to be used for the Structure class from ctypes"""
#----------------------------------------------------------------
def __str__(self):
@ -52,47 +51,59 @@ class Structure(ctypes.Structure):
fields in exceptList will not be printed"""
lines = []
for f in self._fields_:
name = f[0]
lines.append("%20s\t%s"% (name, getattr(self, name)))
for field_name, _ in getattr(self, "_fields_", []):
lines.append("%20s\t%s"% (field_name, getattr(self, field_name)))
return "\n".join(lines)
#----------------------------------------------------------------
def __eq__(self, other_struct):
"""Return True if the two structures have the same coordinates"""
if isinstance(other_struct, ctypes.Structure):
def __eq__(self, other):
"""Return True if the two instances have the same coordinates"""
fields = getattr(self, "_fields_", [])
if isinstance(other, Struct):
try:
# pretend they are two structures - check that they both
# have the same value for all fields
are_equal = True
for field in self._fields_:
name = field[0]
if getattr(self, name) != getattr(other_struct, name):
are_equal = False
break
return are_equal
if len(fields) != len(getattr(other, "_fields_", [])):
return False
for field_name, _ in fields:
if getattr(self, field_name) != getattr(other, field_name):
return False
return True
except AttributeError:
return False
if isinstance(other_struct, (list, tuple)):
elif isinstance(other, (list, tuple)):
# Now try to see if we have been passed in a list or tuple
if len(fields) != len(other):
return False
try:
are_equal = True
for i, field in enumerate(self._fields_):
name = field[0]
if getattr(self, name) != other_struct[i]:
are_equal = False
break
return are_equal
for i, (field_name, _) in enumerate(fields):
if getattr(self, field_name) != other[i]:
return False
return True
except Exception:
return False
return False
#----------------------------------------------------------------
def __ne__(self, other):
"""Return False if the two instances have the same coordinates"""
return not self.__eq__(other)
__hash__ = None
class Structure(Struct, StructureMixIn):
"""Override the Structure class from ctypes to add printing and comparison"""
pass
##====================================================================
#def PrintCtypesStruct(struct, exceptList = []):
# """Print out the fields of the ctypes Structure
@ -110,7 +121,7 @@ class Structure(ctypes.Structure):
# e.g. RECT.__reduce__ = _reduce
def _construct(typ, buf):
obj = typ.__new__(typ)
ctypes.memmove(ctypes.addressof(obj), buf, len(buf))
memmove(addressof(obj), buf, len(buf))
return obj
def _reduce(self):
@ -119,21 +130,21 @@ def _reduce(self):
#LPTTTOOLINFOW = POINTER(tagTOOLINFOW)
#PTOOLINFOW = POINTER(tagTOOLINFOW)
BOOL = c_int
BYTE = c_ubyte
BOOL = wintypes.BOOL
BYTE = wintypes.BYTE
CHAR = c_char
DWORD = c_ulong
HANDLE = c_void_p
HBITMAP = c_long
LONG = c_long
LPVOID = c_void_p
DWORD = wintypes.DWORD
HANDLE = wintypes.HANDLE
HBITMAP = HANDLE
LONG = wintypes.LONG
LPVOID = wintypes.LPVOID
PVOID = c_void_p
UINT = c_uint
WCHAR = c_wchar
WORD = c_ushort
UINT = wintypes.UINT
WCHAR = wintypes.WCHAR
WORD = wintypes.WORD
LRESULT = wintypes.LPARAM
COLORREF = DWORD
COLORREF = wintypes.COLORREF
LPBYTE = POINTER(BYTE)
LPWSTR = c_size_t #POINTER(WCHAR)
DWORD_PTR = UINT_PTR = ULONG_PTR = c_size_t
@ -143,26 +154,20 @@ if sysinfo.is_x64_Python():
else:
INT_PTR = LONG_PTR = c_long
HBITMAP = LONG_PTR #LONG
HINSTANCE = LONG_PTR #LONG
HMENU = LONG_PTR #LONG
HBRUSH = LONG_PTR #LONG
HBRUSH = wintypes.HBRUSH # LONG_PTR #LONG
HTREEITEM = LONG_PTR #LONG
HWND = LONG_PTR #LONG
HWND = wintypes.HWND
# TODO: switch to ctypes.wintypes.LPARAM and ctypes.wintypes.WPARAM
# Notice that wintypes definition of LPARAM/WPARAM differs between 32/64 bit
LPARAM = LONG_PTR
WPARAM = UINT_PTR
LPARAM = wintypes.LPARAM
WPARAM = wintypes.WPARAM
class POINT(Structure):
_pack_ = 4
_fields_ = [
# C:/PROGRA~1/MIAF9D~1/VC98/Include/windef.h 307
('x', LONG),
('y', LONG),
]
class POINT(wintypes.POINT, StructureMixIn):
"""Wrap the POINT structure and add extra functionality"""
def __iter__(self):
"""Allow iteration through coordinates"""
@ -178,25 +183,18 @@ class POINT(Structure):
else:
raise IndexError("Illegal index")
assert sizeof(POINT) == 8, sizeof(POINT)
assert alignment(POINT) == 4, alignment(POINT)
# ====================================================================
class RECT(Structure):
class RECT(wintypes.RECT, StructureMixIn):
"""Wrap the RECT structure and add extra functionality"""
_fields_ = [
# C:/PROGRA~1/MIAF9D~1/VC98/Include/windef.h 287
('left', LONG),
('top', LONG),
('right', LONG),
('bottom', LONG),
]
# ----------------------------------------------------------------
def __init__(self, otherRect_or_left = 0, top = 0, right = 0, bottom = 0):
def __init__(self, otherRect_or_left=0, top=0, right=0, bottom=0):
"""Provide a constructor for RECT structures
A RECT can be constructed by:
@ -220,20 +218,6 @@ class RECT(Structure):
self.top = long_int(top)
self.bottom = long_int(bottom)
# # ----------------------------------------------------------------
# def __eq__(self, otherRect):
# "return true if the two rectangles have the same coordinates"
#
# try:
# return \
# self.left == otherRect.left and \
# self.top == otherRect.top and \
# self.right == otherRect.right and \
# self.bottom == otherRect.bottom
# except AttributeError:
# return False
# ----------------------------------------------------------------
def __str__(self):
"""Return a string representation of the RECT"""
@ -286,18 +270,17 @@ class RECT(Structure):
def mid_point(self):
"""Return a POINT structure representing the mid point"""
pt = POINT()
pt.x = self.left + int(float(self.width())/2.)
pt.y = self.top + int(float(self.height())/2.)
pt.x = self.left + int(float(self.width()) / 2.)
pt.y = self.top + int(float(self.height()) / 2.)
return pt
#def __hash__(self):
# return hash (self.left, self.top, self.right, self.bottom)
__reduce__ = _reduce
RECT.__reduce__ = _reduce
assert sizeof(RECT) == 16, sizeof(RECT)
assert alignment(RECT) == 4, alignment(RECT)
class SETTEXTEX(Structure):
_pack_ = 1
_fields_ = [

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 Lucas Boppre Niehues
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,62 @@
Metadata-Version: 2.1
Name: mouse
Version: 0.7.1
Summary: Hook and simulate mouse events on Windows and Linux
Home-page: https://github.com/boppreh/mouse
Author: BoppreH
Author-email: boppreh@gmail.com
License: MIT
Keywords: mouse hook simulate hotkey
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: Unix
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Utilities
Description-Content-Type: text/markdown
mouse
=====
Take full control of your mouse with this small Python library. Hook global events, register hotkeys, simulate mouse movement and clicks, and much more.
_Huge thanks to [Kirill Pavlov](http://kirillpavlov.com/) for donating the package name. If you are looking for the Cheddargetter.com client implementation, [`pip install mouse==0.5.0`](https://pypi.python.org/pypi/mouse/0.5.0)._
## Features
- Global event hook on all mice devices (captures events regardless of focus).
- **Listen** and **sends** mouse events.
- Works with **Windows** and **Linux** (requires sudo).
- **Pure Python**, no C modules to be compiled.
- **Zero dependencies**. Trivial to install and deploy, just copy the files.
- **Python 2 and 3**.
- Includes **high level API** (e.g. [record](#mouse.record) and [play](#mouse.play).
- Events automatically captured in separate thread, doesn't block main program.
- Tested and documented.
This program makes no attempt to hide itself, so don't use it for keyloggers.
## Usage
Install the [PyPI package](https://pypi.python.org/pypi/mouse/):
$ sudo pip install mouse
or clone the repository (no installation required, source files are sufficient):
$ git clone https://github.com/boppreh/mouse
Then check the [API docs](https://github.com/boppreh/mouse#api) to see what features are available.
## Known limitations:
- Events generated under Windows don't report device id (`event.device == None`). [#21](https://github.com/boppreh/keyboard/issues/21)
- To avoid depending on X the Linux parts reads raw device files (`/dev/input/input*`) but this requries root.
- Other applications, such as some games, may register hooks that swallow all key events. In this case `mouse` will be unable to report events.

@ -0,0 +1,22 @@
mouse-0.7.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
mouse-0.7.1.dist-info/LICENSE.txt,sha256=K_FKUlVV0FqAHC0sKJAVBPt2q-58LX6_tM_HUI198Pc,1077
mouse-0.7.1.dist-info/METADATA,sha256=7MmeikMZ3xgUFvcSNMnCnXugXuG0ag8QjFoOV1k9mr0,2455
mouse-0.7.1.dist-info/RECORD,,
mouse-0.7.1.dist-info/WHEEL,sha256=JZXtYepZFsf4IoivNpnSgKIc4qTHan08DRd56koo_DM,116
mouse-0.7.1.dist-info/top_level.txt,sha256=FiA9sXRt9_B8X6je4BlPesL9EakrmGZ0fDKPK09Ql6U,6
mouse/__init__.py,sha256=HGaiOxH8PuKnU2oCLN5pEN4yuvxH1JoxT1QXwITFlf0,9147
mouse/__main__.py,sha256=Rir1qIanuA6OUsVIywo71MgF1PrVCdZ77F1FPOu4JA0,625
mouse/__pycache__/__init__.cpython-37.pyc,,
mouse/__pycache__/__main__.cpython-37.pyc,,
mouse/__pycache__/_generic.cpython-37.pyc,,
mouse/__pycache__/_mouse_event.cpython-37.pyc,,
mouse/__pycache__/_mouse_tests.cpython-37.pyc,,
mouse/__pycache__/_nixcommon.cpython-37.pyc,,
mouse/__pycache__/_nixmouse.cpython-37.pyc,,
mouse/__pycache__/_winmouse.cpython-37.pyc,,
mouse/_generic.py,sha256=STzfL7AUAkcAq6XUyxpQiOYnBnQ1TZjWL1cSFSZ61_o,2132
mouse/_mouse_event.py,sha256=zRQGO6M6nbA-jvhI0yz4HzvQNcScF48PZ9iRegcTVjQ,422
mouse/_mouse_tests.py,sha256=gNa_NW5sRIsbLMG35ZfXal3eHS2mEpEPhysJRDq0gQA,10000
mouse/_nixcommon.py,sha256=FNXiCv7u_A0SzcYJQlYDJBSdIN6IUTVLG4g7oqXgj6o,5552
mouse/_nixmouse.py,sha256=3htKn9XkUApFqp3rGCT-ZQIqJFf4iGqoxxoO9MY2x4k,3576
mouse/_winmouse.py,sha256=lWAnfGq0etNjFR-vE9e3r9N7Amg5wU957B4ZS3YMTz0,6449

@ -0,0 +1,6 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.6)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any

@ -0,0 +1,272 @@
# -*- coding: utf-8 -*-
"""
mouse
=====
Take full control of your mouse with this small Python library. Hook global events, register hotkeys, simulate mouse movement and clicks, and much more.
_Huge thanks to [Kirill Pavlov](http://kirillpavlov.com/) for donating the package name. If you are looking for the Cheddargetter.com client implementation, [`pip install mouse==0.5.0`](https://pypi.python.org/pypi/mouse/0.5.0)._
## Features
- Global event hook on all mice devices (captures events regardless of focus).
- **Listen** and **sends** mouse events.
- Works with **Windows** and **Linux** (requires sudo).
- **Pure Python**, no C modules to be compiled.
- **Zero dependencies**. Trivial to install and deploy, just copy the files.
- **Python 2 and 3**.
- Includes **high level API** (e.g. [record](#mouse.record) and [play](#mouse.play).
- Events automatically captured in separate thread, doesn't block main program.
- Tested and documented.
This program makes no attempt to hide itself, so don't use it for keyloggers.
## Usage
Install the [PyPI package](https://pypi.python.org/pypi/mouse/):
$ sudo pip install mouse
or clone the repository (no installation required, source files are sufficient):
$ git clone https://github.com/boppreh/mouse
Then check the [API docs](https://github.com/boppreh/mouse#api) to see what features are available.
## Known limitations:
- Events generated under Windows don't report device id (`event.device == None`). [#21](https://github.com/boppreh/keyboard/issues/21)
- To avoid depending on X the Linux parts reads raw device files (`/dev/input/input*`) but this requries root.
- Other applications, such as some games, may register hooks that swallow all key events. In this case `mouse` will be unable to report events.
"""
# TODO
# - infinite wait
# - mouse.on_move
version = '0.7.1'
import time as _time
import platform as _platform
if _platform.system() == 'Windows':
from. import _winmouse as _os_mouse
elif _platform.system() == 'Linux':
from. import _nixmouse as _os_mouse
else:
raise OSError("Unsupported platform '{}'".format(_platform.system()))
from ._mouse_event import ButtonEvent, MoveEvent, WheelEvent, LEFT, RIGHT, MIDDLE, X, X2, UP, DOWN, DOUBLE
from ._generic import GenericListener as _GenericListener
_pressed_events = set()
class _MouseListener(_GenericListener):
def init(self):
_os_mouse.init()
def pre_process_event(self, event):
if isinstance(event, ButtonEvent):
if event.event_type in (UP, DOUBLE):
_pressed_events.discard(event.button)
else:
_pressed_events.add(event.button)
return True
def listen(self):
_os_mouse.listen(self.queue)
_listener = _MouseListener()
def is_pressed(button=LEFT):
""" Returns True if the given button is currently pressed. """
_listener.start_if_necessary()
return button in _pressed_events
def press(button=LEFT):
""" Presses the given button (but doesn't release). """
_os_mouse.press(button)
def release(button=LEFT):
""" Releases the given button. """
_os_mouse.release(button)
def click(button=LEFT):
""" Sends a click with the given button. """
_os_mouse.press(button)
_os_mouse.release(button)
def double_click(button=LEFT):
""" Sends a double click with the given button. """
click(button)
click(button)
def right_click():
""" Sends a right click with the given button. """
click(RIGHT)
def wheel(delta=1):
""" Scrolls the wheel `delta` clicks. Sign indicates direction. """
_os_mouse.wheel(delta)
def move(x, y, absolute=True, duration=0):
"""
Moves the mouse. If `absolute`, to position (x, y), otherwise move relative
to the current position. If `duration` is non-zero, animates the movement.
"""
x = int(x)
y = int(y)
# Requires an extra system call on Linux, but `move_relative` is measured
# in millimiters so we would lose precision.
position_x, position_y = get_position()
if not absolute:
x = position_x + x
y = position_y + y
if duration:
start_x = position_x
start_y = position_y
dx = x - start_x
dy = y - start_y
if dx == 0 and dy == 0:
_time.sleep(duration)
else:
# 120 movements per second.
# Round and keep float to ensure float division in Python 2
steps = max(1.0, float(int(duration * 120.0)))
for i in range(int(steps)+1):
move(start_x + dx*i/steps, start_y + dy*i/steps)
_time.sleep(duration/steps)
else:
_os_mouse.move_to(x, y)
def drag(start_x, start_y, end_x, end_y, absolute=True, duration=0):
"""
Holds the left mouse button, moving from start to end position, then
releases. `absolute` and `duration` are parameters regarding the mouse
movement.
"""
if is_pressed():
release()
move(start_x, start_y, absolute, 0)
press()
move(end_x, end_y, absolute, duration)
release()
def on_button(callback, args=(), buttons=(LEFT, MIDDLE, RIGHT, X, X2), types=(UP, DOWN, DOUBLE)):
""" Invokes `callback` with `args` when the specified event happens. """
if not isinstance(buttons, (tuple, list)):
buttons = (buttons,)
if not isinstance(types, (tuple, list)):
types = (types,)
def handler(event):
if isinstance(event, ButtonEvent):
if event.event_type in types and event.button in buttons:
callback(*args)
_listener.add_handler(handler)
return handler
def on_click(callback, args=()):
""" Invokes `callback` with `args` when the left button is clicked. """
return on_button(callback, args, [LEFT], [UP])
def on_double_click(callback, args=()):
"""
Invokes `callback` with `args` when the left button is double clicked.
"""
return on_button(callback, args, [LEFT], [DOUBLE])
def on_right_click(callback, args=()):
""" Invokes `callback` with `args` when the right button is clicked. """
return on_button(callback, args, [RIGHT], [UP])
def on_middle_click(callback, args=()):
""" Invokes `callback` with `args` when the middle button is clicked. """
return on_button(callback, args, [MIDDLE], [UP])
def wait(button=LEFT, target_types=(UP, DOWN, DOUBLE)):
"""
Blocks program execution until the given button performs an event.
"""
from threading import Lock
lock = Lock()
lock.acquire()
handler = on_button(lock.release, (), [button], target_types)
lock.acquire()
_listener.remove_handler(handler)
def get_position():
""" Returns the (x, y) mouse position. """
return _os_mouse.get_position()
def hook(callback):
"""
Installs a global listener on all available mouses, invoking `callback`
each time it is moved, a key status changes or the wheel is spun. A mouse
event is passed as argument, with type either `mouse.ButtonEvent`,
`mouse.WheelEvent` or `mouse.MoveEvent`.
Returns the given callback for easier development.
"""
_listener.add_handler(callback)
return callback
def unhook(callback):
"""
Removes a previously installed hook.
"""
_listener.remove_handler(callback)
def unhook_all():
"""
Removes all hooks registered by this application. Note this may include
hooks installed by high level functions, such as `record`.
"""
del _listener.handlers[:]
def record(button=RIGHT, target_types=(DOWN,)):
"""
Records all mouse events until the user presses the given button.
Then returns the list of events recorded. Pairs well with `play(events)`.
Note: this is a blocking function.
Note: for more details on the mouse hook and events see `hook`.
"""
recorded = []
hook(recorded.append)
wait(button=button, target_types=target_types)
unhook(recorded.append)
return recorded
def play(events, speed_factor=1.0, include_clicks=True, include_moves=True, include_wheel=True):
"""
Plays a sequence of recorded events, maintaining the relative time
intervals. If speed_factor is <= 0 then the actions are replayed as fast
as the OS allows. Pairs well with `record()`.
The parameters `include_*` define if events of that type should be inluded
in the replay or ignored.
"""
last_time = None
for event in events:
if speed_factor > 0 and last_time is not None:
_time.sleep((event.time - last_time) / speed_factor)
last_time = event.time
if isinstance(event, ButtonEvent) and include_clicks:
if event.event_type == UP:
_os_mouse.release(event.button)
else:
_os_mouse.press(event.button)
elif isinstance(event, MoveEvent) and include_moves:
_os_mouse.move_to(event.x, event.y)
elif isinstance(event, WheelEvent) and include_wheel:
_os_mouse.wheel(event.delta)
replay = play
hold = press
if __name__ == '__main__':
print('Recording... Double click to stop and replay.')
play(record())

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
import mouse
import fileinput
import json
import sys
class_by_name = {
'ButtonEvent': mouse.ButtonEvent,
'WheelEvent': mouse.WheelEvent,
'MoveEvent': mouse.MoveEvent,
}
def print_event_json(event):
# Could use json.dumps(event.__dict__()), but this way we guarantee semantic order.
d = event._asdict()
d['event_class'] = event.__class__.__name__
print(json.dumps(d))
sys.stdout.flush()
mouse.hook(print_event_json)
def load(line):
d = json.loads(line)
class_ = class_by_name[d['event_class']]
del d['event_class']
return class_(**d)
mouse.play(load(line) for line in fileinput.input())

@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
from threading import Thread, Lock
import traceback
import functools
try:
from queue import Queue
except ImportError:
from Queue import Queue
class GenericListener(object):
lock = Lock()
def __init__(self):
self.handlers = []
self.listening = False
self.queue = Queue()
def invoke_handlers(self, event):
for handler in self.handlers:
try:
if handler(event):
# Stop processing this hotkey.
return 1
except Exception as e:
traceback.print_exc()
def start_if_necessary(self):
"""
Starts the listening thread if it wasn't already.
"""
self.lock.acquire()
try:
if not self.listening:
self.init()
self.listening = True
self.listening_thread = Thread(target=self.listen)
self.listening_thread.daemon = True
self.listening_thread.start()
self.processing_thread = Thread(target=self.process)
self.processing_thread.daemon = True
self.processing_thread.start()
finally:
self.lock.release()
def pre_process_event(self, event):
raise NotImplementedError('This method should be implemented in the child class.')
def process(self):
"""
Loops over the underlying queue of events and processes them in order.
"""
assert self.queue is not None
while True:
event = self.queue.get()
if self.pre_process_event(event):
self.invoke_handlers(event)
self.queue.task_done()
def add_handler(self, handler):
"""
Adds a function to receive each event captured, starting the capturing
process if necessary.
"""
self.start_if_necessary()
self.handlers.append(handler)
def remove_handler(self, handler):
""" Removes a previously added event handler. """
self.handlers.remove(handler)

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from collections import namedtuple
LEFT = 'left'
RIGHT = 'right'
MIDDLE = 'middle'
WHEEL = 'wheel'
X = 'x'
X2 = 'x2'
UP = 'up'
DOWN = 'down'
DOUBLE = 'double'
VERTICAL = 'vertical'
HORIZONTAL = 'horizontal'
ButtonEvent = namedtuple('ButtonEvent', ['event_type', 'button', 'time'])
WheelEvent = namedtuple('WheelEvent', ['delta', 'time'])
MoveEvent = namedtuple('MoveEvent', ['x', 'y', 'time'])

@ -0,0 +1,271 @@
# -*- coding: utf-8 -*-
import unittest
import time
from ._mouse_event import MoveEvent, ButtonEvent, WheelEvent, LEFT, RIGHT, MIDDLE, X, X2, UP, DOWN, DOUBLE
import mouse
class FakeOsMouse(object):
def __init__(self):
self.append = None
self.position = (0, 0)
self.queue = None
self.init = lambda: None
def listen(self, queue):
self.listening = True
self.queue = queue
def press(self, button):
self.append((DOWN, button))
def release(self, button):
self.append((UP, button))
def get_position(self):
return self.position
def move_to(self, x, y):
self.append(('move', (x, y)))
self.position = (x, y)
def wheel(self, delta):
self.append(('wheel', delta))
def move_relative(self, x, y):
self.position = (self.position[0] + x, self.position[1] + y)
class TestMouse(unittest.TestCase):
@staticmethod
def setUpClass():
mouse._os_mouse= FakeOsMouse()
mouse._listener.start_if_necessary()
assert mouse._os_mouse.listening
def setUp(self):
self.events = []
mouse._pressed_events.clear()
mouse._os_mouse.append = self.events.append
def tearDown(self):
mouse.unhook_all()
# Make sure there's no spill over between tests.
self.wait_for_events_queue()
def wait_for_events_queue(self):
mouse._listener.queue.join()
def flush_events(self):
self.wait_for_events_queue()
events = list(self.events)
# Ugly, but requried to work in Python2. Python3 has list.clear
del self.events[:]
return events
def press(self, button=LEFT):
mouse._os_mouse.queue.put(ButtonEvent(DOWN, button, time.time()))
self.wait_for_events_queue()
def release(self, button=LEFT):
mouse._os_mouse.queue.put(ButtonEvent(UP, button, time.time()))
self.wait_for_events_queue()
def double_click(self, button=LEFT):
mouse._os_mouse.queue.put(ButtonEvent(DOUBLE, button, time.time()))
self.wait_for_events_queue()
def click(self, button=LEFT):
self.press(button)
self.release(button)
def wheel(self, delta=1):
mouse._os_mouse.queue.put(WheelEvent(delta, time.time()))
self.wait_for_events_queue()
def move(self, x=0, y=0):
mouse._os_mouse.queue.put(MoveEvent(x, y, time.time()))
self.wait_for_events_queue()
def test_hook(self):
events = []
self.press()
mouse.hook(events.append)
self.press()
mouse.unhook(events.append)
self.press()
self.assertEqual(len(events), 1)
def test_is_pressed(self):
self.assertFalse(mouse.is_pressed())
self.press()
self.assertTrue(mouse.is_pressed())
self.release()
self.press(X2)
self.assertFalse(mouse.is_pressed())
self.assertTrue(mouse.is_pressed(X2))
self.press(X2)
self.assertTrue(mouse.is_pressed(X2))
self.release(X2)
self.release(X2)
self.assertFalse(mouse.is_pressed(X2))
def test_buttons(self):
mouse.press()
self.assertEqual(self.flush_events(), [(DOWN, LEFT)])
mouse.release()
self.assertEqual(self.flush_events(), [(UP, LEFT)])
mouse.click()
self.assertEqual(self.flush_events(), [(DOWN, LEFT), (UP, LEFT)])
mouse.double_click()
self.assertEqual(self.flush_events(), [(DOWN, LEFT), (UP, LEFT), (DOWN, LEFT), (UP, LEFT)])
mouse.right_click()
self.assertEqual(self.flush_events(), [(DOWN, RIGHT), (UP, RIGHT)])
mouse.click(RIGHT)
self.assertEqual(self.flush_events(), [(DOWN, RIGHT), (UP, RIGHT)])
mouse.press(X2)
self.assertEqual(self.flush_events(), [(DOWN, X2)])
def test_position(self):
self.assertEqual(mouse.get_position(), mouse._os_mouse.get_position())
def test_move(self):
mouse.move(0, 0)
self.assertEqual(mouse._os_mouse.get_position(), (0, 0))
mouse.move(100, 500)
self.assertEqual(mouse._os_mouse.get_position(), (100, 500))
mouse.move(1, 2, False)
self.assertEqual(mouse._os_mouse.get_position(), (101, 502))
mouse.move(0, 0)
mouse.move(100, 499, True, duration=0.01)
self.assertEqual(mouse._os_mouse.get_position(), (100, 499))
mouse.move(100, 1, False, duration=0.01)
self.assertEqual(mouse._os_mouse.get_position(), (200, 500))
mouse.move(0, 0, False, duration=0.01)
self.assertEqual(mouse._os_mouse.get_position(), (200, 500))
def triggers(self, fn, events, **kwargs):
self.triggered = False
def callback():
self.triggered = True
handler = fn(callback, **kwargs)
for event_type, arg in events:
if event_type == DOWN:
self.press(arg)
elif event_type == UP:
self.release(arg)
elif event_type == DOUBLE:
self.double_click(arg)
elif event_type == 'WHEEL':
self.wheel()
mouse._listener.remove_handler(handler)
return self.triggered
def test_on_button(self):
self.assertTrue(self.triggers(mouse.on_button, [(DOWN, LEFT)]))
self.assertTrue(self.triggers(mouse.on_button, [(DOWN, RIGHT)]))
self.assertTrue(self.triggers(mouse.on_button, [(DOWN, X)]))
self.assertFalse(self.triggers(mouse.on_button, [('WHEEL', '')]))
self.assertFalse(self.triggers(mouse.on_button, [(DOWN, X)], buttons=MIDDLE))
self.assertTrue(self.triggers(mouse.on_button, [(DOWN, MIDDLE)], buttons=MIDDLE))
self.assertTrue(self.triggers(mouse.on_button, [(DOWN, MIDDLE)], buttons=MIDDLE))
self.assertFalse(self.triggers(mouse.on_button, [(DOWN, MIDDLE)], buttons=MIDDLE, types=UP))
self.assertTrue(self.triggers(mouse.on_button, [(UP, MIDDLE)], buttons=MIDDLE, types=UP))
self.assertTrue(self.triggers(mouse.on_button, [(UP, MIDDLE)], buttons=[MIDDLE, LEFT], types=[UP, DOWN]))
self.assertTrue(self.triggers(mouse.on_button, [(DOWN, LEFT)], buttons=[MIDDLE, LEFT], types=[UP, DOWN]))
self.assertFalse(self.triggers(mouse.on_button, [(UP, X)], buttons=[MIDDLE, LEFT], types=[UP, DOWN]))
def test_ons(self):
self.assertTrue(self.triggers(mouse.on_click, [(UP, LEFT)]))
self.assertFalse(self.triggers(mouse.on_click, [(UP, RIGHT)]))
self.assertFalse(self.triggers(mouse.on_click, [(DOWN, LEFT)]))
self.assertFalse(self.triggers(mouse.on_click, [(DOWN, RIGHT)]))
self.assertTrue(self.triggers(mouse.on_double_click, [(DOUBLE, LEFT)]))
self.assertFalse(self.triggers(mouse.on_double_click, [(DOUBLE, RIGHT)]))
self.assertFalse(self.triggers(mouse.on_double_click, [(DOWN, RIGHT)]))
self.assertTrue(self.triggers(mouse.on_right_click, [(UP, RIGHT)]))
self.assertTrue(self.triggers(mouse.on_middle_click, [(UP, MIDDLE)]))
def test_wait(self):
# If this fails it blocks. Unfortunately, but I see no other way of testing.
from threading import Thread, Lock
lock = Lock()
lock.acquire()
def t():
mouse.wait()
lock.release()
Thread(target=t).start()
self.press()
lock.acquire()
def test_record_play(self):
from threading import Thread, Lock
lock = Lock()
lock.acquire()
def t():
self.recorded = mouse.record(RIGHT)
lock.release()
Thread(target=t).start()
self.click()
self.wheel(5)
self.move(100, 50)
self.press(RIGHT)
lock.acquire()
self.assertEqual(len(self.recorded), 5)
self.assertEqual(self.recorded[0]._replace(time=None), ButtonEvent(DOWN, LEFT, None))
self.assertEqual(self.recorded[1]._replace(time=None), ButtonEvent(UP, LEFT, None))
self.assertEqual(self.recorded[2]._replace(time=None), WheelEvent(5, None))
self.assertEqual(self.recorded[3]._replace(time=None), MoveEvent(100, 50, None))
self.assertEqual(self.recorded[4]._replace(time=None), ButtonEvent(DOWN, RIGHT, None))
mouse.play(self.recorded, speed_factor=0)
events = self.flush_events()
self.assertEqual(len(events), 5)
self.assertEqual(events[0], (DOWN, LEFT))
self.assertEqual(events[1], (UP, LEFT))
self.assertEqual(events[2], ('wheel', 5))
self.assertEqual(events[3], ('move', (100, 50)))
self.assertEqual(events[4], (DOWN, RIGHT))
mouse.play(self.recorded)
events = self.flush_events()
self.assertEqual(len(events), 5)
self.assertEqual(events[0], (DOWN, LEFT))
self.assertEqual(events[1], (UP, LEFT))
self.assertEqual(events[2], ('wheel', 5))
self.assertEqual(events[3], ('move', (100, 50)))
self.assertEqual(events[4], (DOWN, RIGHT))
mouse.play(self.recorded, include_clicks=False)
events = self.flush_events()
self.assertEqual(len(events), 2)
self.assertEqual(events[0], ('wheel', 5))
self.assertEqual(events[1], ('move', (100, 50)))
mouse.play(self.recorded, include_moves=False)
events = self.flush_events()
self.assertEqual(len(events), 4)
self.assertEqual(events[0], (DOWN, LEFT))
self.assertEqual(events[1], (UP, LEFT))
self.assertEqual(events[2], ('wheel', 5))
self.assertEqual(events[3], (DOWN, RIGHT))
mouse.play(self.recorded, include_wheel=False)
events = self.flush_events()
self.assertEqual(len(events), 4)
self.assertEqual(events[0], (DOWN, LEFT))
self.assertEqual(events[1], (UP, LEFT))
self.assertEqual(events[2], ('move', (100, 50)))
self.assertEqual(events[3], (DOWN, RIGHT))
if __name__ == '__main__':
unittest.main()

@ -0,0 +1,165 @@
# -*- coding: utf-8 -*-
import struct
import os
import atexit
from time import time as now
from threading import Thread
from glob import glob
try:
from queue import Queue
except ImportError:
from Queue import Queue
event_bin_format = 'llHHI'
# Taken from include/linux/input.h
# https://www.kernel.org/doc/Documentation/input/event-codes.txt
EV_SYN = 0x00
EV_KEY = 0x01
EV_REL = 0x02
EV_ABS = 0x03
EV_MSC = 0x04
def make_uinput():
import fcntl, struct
# Requires uinput driver, but it's usually available.
uinput = open("/dev/uinput", 'wb')
UI_SET_EVBIT = 0x40045564
fcntl.ioctl(uinput, UI_SET_EVBIT, EV_KEY)
UI_SET_KEYBIT = 0x40045565
for i in range(256):
fcntl.ioctl(uinput, UI_SET_KEYBIT, i)
BUS_USB = 0x03
uinput_user_dev = "80sHHHHi64i64i64i64i"
axis = [0] * 64 * 4
uinput.write(struct.pack(uinput_user_dev, b"Virtual Keyboard", BUS_USB, 1, 1, 1, 0, *axis))
uinput.flush() # Without this you may get Errno 22: Invalid argument.
UI_DEV_CREATE = 0x5501
fcntl.ioctl(uinput, UI_DEV_CREATE)
UI_DEV_DESTROY = 0x5502
#fcntl.ioctl(uinput, UI_DEV_DESTROY)
return uinput
class EventDevice(object):
def __init__(self, path):
self.path = path
self._input_file = None
self._output_file = None
@property
def input_file(self):
if self._input_file is None:
try:
self._input_file = open(self.path, 'rb')
except IOError as e:
if e.strerror == 'Permission denied':
print('Permission denied ({}). You must be sudo to access global events.'.format(self.path))
exit()
def try_close():
try:
self._input_file.close
except:
pass
atexit.register(try_close)
return self._input_file
@property
def output_file(self):
if self._output_file is None:
self._output_file = open(self.path, 'wb')
atexit.register(self._output_file.close)
return self._output_file
def read_event(self):
data = self.input_file.read(struct.calcsize(event_bin_format))
seconds, microseconds, type, code, value = struct.unpack(event_bin_format, data)
return seconds + microseconds / 1e6, type, code, value, self.path
def write_event(self, type, code, value):
integer, fraction = divmod(now(), 1)
seconds = int(integer)
microseconds = int(fraction * 1e6)
data_event = struct.pack(event_bin_format, seconds, microseconds, type, code, value)
# Send a sync event to ensure other programs update.
sync_event = struct.pack(event_bin_format, seconds, microseconds, EV_SYN, 0, 0)
self.output_file.write(data_event + sync_event)
self.output_file.flush()
class AggregatedEventDevice(object):
def __init__(self, devices, output=None):
self.event_queue = Queue()
self.devices = devices
self.output = output or self.devices[0]
def start_reading(device):
while True:
self.event_queue.put(device.read_event())
for device in self.devices:
thread = Thread(target=start_reading, args=[device])
thread.setDaemon(True)
thread.start()
def read_event(self):
return self.event_queue.get(block=True)
def write_event(self, type, code, value):
self.output.write_event(type, code, value)
import re
from collections import namedtuple
DeviceDescription = namedtuple('DeviceDescription', 'event_file is_mouse is_keyboard')
device_pattern = r"""N: Name="([^"]+?)".+?H: Handlers=([^\n]+)"""
def list_devices_from_proc(type_name):
try:
with open('/proc/bus/input/devices') as f:
description = f.read()
except FileNotFoundError:
return
devices = {}
for name, handlers in re.findall(device_pattern, description, re.DOTALL):
path = '/dev/input/event' + re.search(r'event(\d+)', handlers).group(1)
if type_name in handlers:
yield EventDevice(path)
def list_devices_from_by_id(type_name):
for path in glob('/dev/input/by-id/*-event-' + type_name):
yield EventDevice(path)
def aggregate_devices(type_name):
# Some systems have multiple keyboards with different range of allowed keys
# on each one, like a notebook with a "keyboard" device exclusive for the
# power button. Instead of figuring out which keyboard allows which key to
# send events, we create a fake device and send all events through there.
uinput = make_uinput()
fake_device = EventDevice('uinput Fake Device')
fake_device._input_file = uinput
fake_device._output_file = uinput
# We don't aggregate devices from different sources to avoid
# duplicates.
devices_from_proc = list(list_devices_from_proc(type_name))
if devices_from_proc:
return AggregatedEventDevice(devices_from_proc, output=fake_device)
# breaks on mouse for virtualbox
# was getting /dev/input/by-id/usb-VirtualBox_USB_Tablet-event-mouse
devices_from_by_id = list(list_devices_from_by_id(type_name))
if devices_from_by_id:
return AggregatedEventDevice(devices_from_by_id, output=fake_device)
# If no keyboards were found we can only use the fake device to send keys.
return fake_device
def ensure_root():
if os.geteuid() != 0:
raise ImportError('You must be root to use this library on linux.')

@ -0,0 +1,131 @@
# -*- coding: utf-8 -*-
import struct
from subprocess import check_output
import re
from ._nixcommon import EV_KEY, EV_REL, EV_MSC, EV_SYN, EV_ABS, aggregate_devices, ensure_root
from ._mouse_event import ButtonEvent, WheelEvent, MoveEvent, LEFT, RIGHT, MIDDLE, X, X2, UP, DOWN
import ctypes
import ctypes.util
from ctypes import c_uint32, c_uint, c_int, c_void_p, byref
display = None
window = None
x11 = None
def build_display():
global display, window, x11
if display and window and x11: return
x11 = ctypes.cdll.LoadLibrary(ctypes.util.find_library('X11'))
# Required because we will have multiple threads calling x11,
# such as the listener thread and then main using "move_to".
x11.XInitThreads()
# Explicitly set XOpenDisplay.restype to avoid segfault on 64 bit OS.
# http://stackoverflow.com/questions/35137007/get-mouse-position-on-linux-pure-python
x11.XOpenDisplay.restype = c_void_p
display = c_void_p(x11.XOpenDisplay(0))
window = x11.XDefaultRootWindow(display)
def get_position():
build_display()
root_id, child_id = c_void_p(), c_void_p()
root_x, root_y, win_x, win_y = c_int(), c_int(), c_int(), c_int()
mask = c_uint()
ret = x11.XQueryPointer(display, c_uint32(window), byref(root_id), byref(child_id),
byref(root_x), byref(root_y),
byref(win_x), byref(win_y), byref(mask))
return root_x.value, root_y.value
def move_to(x, y):
build_display()
x11.XWarpPointer(display, None, window, 0, 0, 0, 0, x, y)
x11.XFlush(display)
REL_X = 0x00
REL_Y = 0x01
REL_Z = 0x02
REL_HWHEEL = 0x06
REL_WHEEL = 0x08
ABS_X = 0x00
ABS_Y = 0x01
BTN_MOUSE = 0x110
BTN_LEFT = 0x110
BTN_RIGHT = 0x111
BTN_MIDDLE = 0x112
BTN_SIDE = 0x113
BTN_EXTRA = 0x114
button_by_code = {
BTN_LEFT: LEFT,
BTN_RIGHT: RIGHT,
BTN_MIDDLE: MIDDLE,
BTN_SIDE: X,
BTN_EXTRA: X2,
}
code_by_button = {button: code for code, button in button_by_code.items()}
device = None
def build_device():
global device
if device: return
ensure_root()
device = aggregate_devices('mouse')
init = build_device
def listen(queue):
build_device()
while True:
time, type, code, value, device_id = device.read_event()
if type == EV_SYN or type == EV_MSC:
continue
event = None
arg = None
if type == EV_KEY:
event = ButtonEvent(DOWN if value else UP, button_by_code.get(code, '?'), time)
elif type == EV_REL:
value, = struct.unpack('i', struct.pack('I', value))
if code == REL_WHEEL:
event = WheelEvent(value, time)
elif code in (REL_X, REL_Y):
x, y = get_position()
event = MoveEvent(x, y, time)
if event is None:
# Unknown event type.
continue
queue.put(event)
def press(button=LEFT):
build_device()
device.write_event(EV_KEY, code_by_button[button], 0x01)
def release(button=LEFT):
build_device()
device.write_event(EV_KEY, code_by_button[button], 0x00)
def move_relative(x, y):
build_device()
# Note relative events are not in terms of pixels, but millimeters.
if x < 0:
x += 2**32
if y < 0:
y += 2**32
device.write_event(EV_REL, REL_X, x)
device.write_event(EV_REL, REL_Y, y)
def wheel(delta=1):
build_device()
if delta < 0:
delta += 2**32
device.write_event(EV_REL, REL_WHEEL, delta)
if __name__ == '__main__':
#listen(print)
move_to(100, 200)

@ -0,0 +1,216 @@
# -*- coding: utf-8 -*-
import ctypes
import time
from ctypes import c_short, c_char, c_uint8, c_int32, c_int, c_uint, c_uint32, c_long, byref, Structure, CFUNCTYPE, POINTER
from ctypes.wintypes import DWORD, BOOL, HHOOK, MSG, LPWSTR, WCHAR, WPARAM, LPARAM
LPMSG = POINTER(MSG)
import atexit
from ._mouse_event import ButtonEvent, WheelEvent, MoveEvent, LEFT, RIGHT, MIDDLE, X, X2, UP, DOWN, DOUBLE, WHEEL, HORIZONTAL, VERTICAL
#user32 = ctypes.windll.user32
user32 = ctypes.WinDLL('user32', use_last_error = True)
class MSLLHOOKSTRUCT(Structure):
_fields_ = [("x", c_long),
("y", c_long),
('data', c_int32),
('reserved', c_int32),
("flags", DWORD),
("time", c_int),
]
LowLevelMouseProc = CFUNCTYPE(c_int, WPARAM, LPARAM, POINTER(MSLLHOOKSTRUCT))
SetWindowsHookEx = user32.SetWindowsHookExA
#SetWindowsHookEx.argtypes = [c_int, LowLevelMouseProc, c_int, c_int]
SetWindowsHookEx.restype = HHOOK
CallNextHookEx = user32.CallNextHookEx
#CallNextHookEx.argtypes = [c_int , c_int, c_int, POINTER(MSLLHOOKSTRUCT)]
CallNextHookEx.restype = c_int
UnhookWindowsHookEx = user32.UnhookWindowsHookEx
UnhookWindowsHookEx.argtypes = [HHOOK]
UnhookWindowsHookEx.restype = BOOL
GetMessage = user32.GetMessageW
GetMessage.argtypes = [LPMSG, c_int, c_int, c_int]
GetMessage.restype = BOOL
TranslateMessage = user32.TranslateMessage
TranslateMessage.argtypes = [LPMSG]
TranslateMessage.restype = BOOL
DispatchMessage = user32.DispatchMessageA
DispatchMessage.argtypes = [LPMSG]
GetDoubleClickTime = user32.GetDoubleClickTime
# Beware, as of 2016-01-30 the official docs have a very incomplete list.
# This one was compiled from experience and may be incomplete.
WM_MOUSEMOVE = 0x200
WM_LBUTTONDOWN = 0x201
WM_LBUTTONUP = 0x202
WM_LBUTTONDBLCLK = 0x203
WM_RBUTTONDOWN = 0x204
WM_RBUTTONUP = 0x205
WM_RBUTTONDBLCLK = 0x206
WM_MBUTTONDOWN = 0x207
WM_MBUTTONUP = 0x208
WM_MBUTTONDBLCLK = 0x209
WM_MOUSEWHEEL = 0x20A
WM_XBUTTONDOWN = 0x20B
WM_XBUTTONUP = 0x20C
WM_XBUTTONDBLCLK = 0x20D
WM_NCXBUTTONDOWN = 0x00AB
WM_NCXBUTTONUP = 0x00AC
WM_NCXBUTTONDBLCLK = 0x00AD
WM_MOUSEHWHEEL = 0x20E
WM_LBUTTONDOWN = 0x0201
WM_LBUTTONUP = 0x0202
WM_MOUSEMOVE = 0x0200
WM_MOUSEWHEEL = 0x020A
WM_MOUSEHWHEEL = 0x020E
WM_RBUTTONDOWN = 0x0204
WM_RBUTTONUP = 0x0205
buttons_by_wm_code = {
WM_LBUTTONDOWN: (DOWN, LEFT),
WM_LBUTTONUP: (UP, LEFT),
WM_LBUTTONDBLCLK: (DOUBLE, LEFT),
WM_RBUTTONDOWN: (DOWN, RIGHT),
WM_RBUTTONUP: (UP, RIGHT),
WM_RBUTTONDBLCLK: (DOUBLE, RIGHT),
WM_MBUTTONDOWN: (DOWN, MIDDLE),
WM_MBUTTONUP: (UP, MIDDLE),
WM_MBUTTONDBLCLK: (DOUBLE, MIDDLE),
WM_XBUTTONDOWN: (DOWN, X),
WM_XBUTTONUP: (UP, X),
WM_XBUTTONDBLCLK: (DOUBLE, X),
}
MOUSEEVENTF_ABSOLUTE = 0x8000
MOUSEEVENTF_MOVE = 0x1
MOUSEEVENTF_WHEEL = 0x800
MOUSEEVENTF_HWHEEL = 0x1000
MOUSEEVENTF_LEFTDOWN = 0x2
MOUSEEVENTF_LEFTUP = 0x4
MOUSEEVENTF_RIGHTDOWN = 0x8
MOUSEEVENTF_RIGHTUP = 0x10
MOUSEEVENTF_MIDDLEDOWN = 0x20
MOUSEEVENTF_MIDDLEUP = 0x40
MOUSEEVENTF_XDOWN = 0x0080
MOUSEEVENTF_XUP = 0x0100
simulated_mouse_codes = {
(WHEEL, HORIZONTAL): MOUSEEVENTF_HWHEEL,
(WHEEL, VERTICAL): MOUSEEVENTF_WHEEL,
(DOWN, LEFT): MOUSEEVENTF_LEFTDOWN,
(UP, LEFT): MOUSEEVENTF_LEFTUP,
(DOWN, RIGHT): MOUSEEVENTF_RIGHTDOWN,
(UP, RIGHT): MOUSEEVENTF_RIGHTUP,
(DOWN, MIDDLE): MOUSEEVENTF_MIDDLEDOWN,
(UP, MIDDLE): MOUSEEVENTF_MIDDLEUP,
(DOWN, X): MOUSEEVENTF_XDOWN,
(UP, X): MOUSEEVENTF_XUP,
}
NULL = c_int(0)
WHEEL_DELTA = 120
init = lambda: None
previous_button_event = None # defined in global scope
def listen(queue):
def low_level_mouse_handler(nCode, wParam, lParam):
global previous_button_event
struct = lParam.contents
# Can't use struct.time because it's usually zero.
t = time.time()
if wParam == WM_MOUSEMOVE:
event = MoveEvent(struct.x, struct.y, t)
elif wParam == WM_MOUSEWHEEL:
event = WheelEvent(struct.data / (WHEEL_DELTA * (2<<15)), t)
elif wParam in buttons_by_wm_code:
type, button = buttons_by_wm_code.get(wParam, ('?', '?'))
if wParam >= WM_XBUTTONDOWN:
button = {0x10000: X, 0x20000: X2}[struct.data]
event = ButtonEvent(type, button, t)
if (event.event_type == DOWN) and previous_button_event is not None:
# https://msdn.microsoft.com/en-us/library/windows/desktop/gg153548%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
if event.time - previous_button_event.time <= GetDoubleClickTime() / 1000.0:
event = ButtonEvent(DOUBLE, event.button, event.time)
previous_button_event = event
else:
# Unknown event type.
return CallNextHookEx(NULL, nCode, wParam, lParam)
queue.put(event)
return CallNextHookEx(NULL, nCode, wParam, lParam)
WH_MOUSE_LL = c_int(14)
mouse_callback = LowLevelMouseProc(low_level_mouse_handler)
mouse_hook = SetWindowsHookEx(WH_MOUSE_LL, mouse_callback, NULL, NULL)
# Register to remove the hook when the interpreter exits. Unfortunately a
# try/finally block doesn't seem to work here.
atexit.register(UnhookWindowsHookEx, mouse_hook)
msg = LPMSG()
while not GetMessage(msg, NULL, NULL, NULL):
TranslateMessage(msg)
DispatchMessage(msg)
def _translate_button(button):
if button == X or button == X2:
return X, {X: 0x10000, X2: 0x20000}[button]
else:
return button, 0
def press(button=LEFT):
button, data = _translate_button(button)
code = simulated_mouse_codes[(DOWN, button)]
user32.mouse_event(code, 0, 0, data, 0)
def release(button=LEFT):
button, data = _translate_button(button)
code = simulated_mouse_codes[(UP, button)]
user32.mouse_event(code, 0, 0, data, 0)
def wheel(delta=1):
code = simulated_mouse_codes[(WHEEL, VERTICAL)]
user32.mouse_event(code, 0, 0, int(delta * WHEEL_DELTA), 0)
def move_to(x, y):
user32.SetCursorPos(int(x), int(y))
def move_relative(x, y):
user32.mouse_event(MOUSEEVENTF_MOVE, int(x), int(y), 0, 0)
class POINT(Structure):
_fields_ = [("x", c_long), ("y", c_long)]
def get_position():
point = POINT()
user32.GetCursorPos(byref(point))
return (point.x, point.y)
if __name__ == '__main__':
def p(e):
print(e)
listen(p)

@ -1,18 +1,25 @@
Metadata-Version: 2.1
Name: pyOpenRPA
Version: 1.1.3
Version: 1.1.13
Summary: First open source RPA platform for business
Home-page: https://gitlab.com/UnicodeLabs/OpenRPA
Author: Ivan Maslov
Author-email: Ivan.Maslov@unicodelabs.ru
License: MIT
Keywords: OpenRPA RPA Robot Automation Robotization
Keywords: OpenRPA RPA Robot Automation Robotization OpenSource
Platform: UNKNOWN
Classifier: Development Status :: 3 - Alpha
Classifier: Development Status :: 5 - Production/Stable
Classifier: License :: OSI Approved :: MIT License
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.7
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: Software Development :: User Interfaces
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Home Automation
Description-Content-Type: text/markdown
Requires-Dist: pywinauto (>=0.6.6)
Requires-Dist: pywinauto (>=0.6.8)
Requires-Dist: WMI (>=1.4.9)
Requires-Dist: pillow (>=6.0.0)
Requires-Dist: keyboard (>=0.13.3)
@ -50,17 +57,17 @@ Resources\WPy64-3720\python-3.7.2.amd64\python.exe
# Module GUI activity List:
############################
Новая версия
Новая версия
############################
Получить список элементов, который удовлетворяет условиям через расширенный движок поиска
Получить список элементов, который удовлетворяет условиям через расширенный движок поиска
[
{
"index":<Позиция элемента в родительском объекте>,
"depth_start" - глубина, с которой начинается поиск (по умолчанию 1)
"depth_end" - глубина, до которой ведется поиск (по умолчанию 1)
"class_name" - наименование класса, который требуется искать
"title" - наименование заголовка
"rich_text" - наименование rich_text
"index":<Позиция элемента в родительском объекте>,
"depth_start" - глубина, с которой начинается поиск (по умолчанию 1)
"depth_end" - глубина, до которой ведется поиск (по умолчанию 1)
"class_name" - наименование класса, который требуется искать
"title" - наименование заголовка
"rich_text" - наименование rich_text
}
]

@ -1,8 +1,8 @@
pyOpenRPA-1.1.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pyOpenRPA-1.1.3.dist-info/METADATA,sha256=ObJb3J2niW85Wzoh8Uy_TC99RYMif_Ipn-QwE7NSv_8,3541
pyOpenRPA-1.1.3.dist-info/RECORD,,
pyOpenRPA-1.1.3.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97
pyOpenRPA-1.1.3.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10
pyOpenRPA-1.1.13.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pyOpenRPA-1.1.13.dist-info/METADATA,sha256=rjIGRZpHzGWnt9LvY4CqdNByJhS4FqqdMUdzP_2BWmk,3352
pyOpenRPA-1.1.13.dist-info/RECORD,,
pyOpenRPA-1.1.13.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97
pyOpenRPA-1.1.13.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10
pyOpenRPA/.idea/inspectionProfiles/profiles_settings.xml,sha256=YXLFmX7rPNGcnKK1uX1uKYPN0fpgskYNe7t0BV7cqkY,174
pyOpenRPA/.idea/misc.xml,sha256=ySjeaQ1DfqxaRTlFGT_3zW5r9mWuwxoAK_AX4QiuAZM,203
pyOpenRPA/.idea/modules.xml,sha256=Q__U1JIA2cjxbLRXAv-SfYY00fZA0TNlpkkbY4s3ncg,277
@ -11,12 +11,12 @@ pyOpenRPA/.idea/vcs.xml,sha256=2HygA1oRAwc3VBf-irxHrX5JJG9DXuQwrN0BlubhoKY,191
pyOpenRPA/.idea/workspace.xml,sha256=kcCP7x0iSOAWJdy7YtntGrgsQ04QIq0b6_9w04DKxfg,2555
pyOpenRPA/Info.md,sha256=u4Nv-PjniSF0Zlbtr6jEJX2vblK3_1zhSLNUgOdtDaA,85
pyOpenRPA/Orchestrator/Orchestrator.py,sha256=iVp7DlLZHsURBOBegfDG4LanqSrI0A5a6GebP1cBOnI,8301
pyOpenRPA/Orchestrator/Processor.py,sha256=mPSv3xO1ah1BzhQdfltt77_tJrmKP9CAfwqeFAqeTFY,11364
pyOpenRPA/Orchestrator/Processor.py,sha256=ur0jDDteyBzfXR4DXnpUfBwNEW-M2nEtgyd-HQoPVtQ,11376
pyOpenRPA/Orchestrator/RobotRDPActive/CMDStr.py,sha256=6otw1WnR2_evvQ5LGyOVh0BLk_nTdilViGub7p56fXQ,1531
pyOpenRPA/Orchestrator/RobotRDPActive/Clipboard.py,sha256=YB5HJL-Qf4IlVrFHyRv_ZMJ0Vo4vjyYqWKjvrTnf1k4,1564
pyOpenRPA/Orchestrator/RobotRDPActive/Connector.py,sha256=8H_7KTUy_9m4FwbXIlDBUdX4-z3RtsaQRmYzSVdpBIU,25171
pyOpenRPA/Orchestrator/RobotRDPActive/Connector.py,sha256=MkxTVaOVITl1V3EvH3oNx2gbCx3EeRS9Gb_83rmjdjg,25553
pyOpenRPA/Orchestrator/RobotRDPActive/ConnectorExceptions.py,sha256=wwH9JOoMFFxDKQ7IyNyh1OkFkZ23o1cD8Jm3n31ycII,657
pyOpenRPA/Orchestrator/RobotRDPActive/Processor.py,sha256=goBIuwTmpdiAkimhrsqy3Y41BeljUsMQO8TaZgpx0I0,8650
pyOpenRPA/Orchestrator/RobotRDPActive/Processor.py,sha256=HcysWMmxMxSjaUybqovoCZToGrvzC0WFSVZbw6nfa68,9254
pyOpenRPA/Orchestrator/RobotRDPActive/RobotRDPActive.py,sha256=_dZQWv1lUMV8VwzeL2GclU4ZodNcYiEF7uKLrsYZjOI,10137
pyOpenRPA/Orchestrator/RobotRDPActive/Scheduler.py,sha256=21N0ilFzWI1mj3X5S9tPMgwvG7BviuBxfTuqBY85Hy4,9144
pyOpenRPA/Orchestrator/RobotRDPActive/Template.rdp,sha256=JEMVYkEmNcfg_p8isdIyvj9E-2ZB5mj-R3MkcNMKxkA,2426
@ -33,10 +33,10 @@ pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Scheduler.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/Timer.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/RobotRDPActive/__pycache__/__main__.cpython-37.pyc,,
pyOpenRPA/Orchestrator/Server.py,sha256=gqJO6FRDKTBZytJVdJgPF1PvOf05qYUyKDBJJkEpLzk,22755
pyOpenRPA/Orchestrator/ServerSettings.py,sha256=mpPAxAe6PvmKaZlreaoQAy_5wV80edz_0qc-iFrEmBQ,7123
pyOpenRPA/Orchestrator/Server.py,sha256=F7AZX_5n1EPY0dD4vTH90sR-x3nM41Qv3j3Qcba_W1w,25356
pyOpenRPA/Orchestrator/ServerSettings.py,sha256=8Y6uqYIevE_VCNF5exiDMKfZ74YuYJJzagrtHjM2jNs,8419
pyOpenRPA/Orchestrator/Timer.py,sha256=HvYtEeH2Q5WVVjgds9XaBpWRmvZgwgBXurJDdVVq_T0,2097
pyOpenRPA/Orchestrator/Web/Index.xhtml,sha256=giviLTJ1GJyVayvPski2GkcB6Wd2MFYVw5yK6gSsx84,38272
pyOpenRPA/Orchestrator/Web/Index.xhtml,sha256=5yakmckWxrwz_HKjUmYOCQaO7mJmKTl9r9k_kDV0eCY,37432
pyOpenRPA/Orchestrator/Web/favicon.ico,sha256=0vdsnwKGh6pgB0FDB5mOKO7RwbxQ9F13Zg16F1pkvXs,5430
pyOpenRPA/Orchestrator/__init__.py,sha256=qVH8fEPgXk54rmy-ol0PnT8GF5OlGE0a8mExwJ4tFqY,124
pyOpenRPA/Orchestrator/__main__.py,sha256=cOd8WU77VGgzTZUB0WmWpPmdYyMZY1zVyuU9yx26MKs,144
@ -300,6 +300,6 @@ pyOpenRPA/Tools/Terminator.py,sha256=VcjX3gFXiCGu3MMCidhrTNsmC9wsAqfjRJdTSU9fLnU
pyOpenRPA/Tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pyOpenRPA/Tools/__pycache__/Terminator.cpython-37.pyc,,
pyOpenRPA/Tools/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/__init__.py,sha256=zLXCLfZm0anOTnxES7ijiJFJqTniSxBCuqjNArOBU5Q,174
pyOpenRPA/__init__.py,sha256=MLl4coStn9rfw3D3uxDlH6uWJFlRPjAXs2Scbs-T3KA,175
pyOpenRPA/__pycache__/__init__.cpython-37.pyc,,
pyOpenRPA/test.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0

@ -56,7 +56,7 @@ import psutil
# "Type":"ProcessStop",
# "Name":"",
# "FlagForce":True,
# "User":"" #Empty, user or %username%
# "User":"" #Empty - all users, user or %username%
# },
# {
# "Type":"PythonStart",

@ -21,6 +21,8 @@ gRecoveryWindowRUNRetryIntervalSecInt = 3 # Retry interval for retry
gRecoveryCMDResponsibleRetryCountInt = 3 # Retry iteration count is CMD is not responsible
gRecoveryCMDResponsibleRetryIntervalSecInt = 3 # Retry interval for retry
gKeyboardHotkeyDelaySecFloat = 0.6 # Const for delay - important for work with RDP!!!!
#Connect to RDP session
"""
{
@ -312,16 +314,15 @@ def SystemCMDRun(inSessionHexStr, inCMDCommandStr = "echo 1", inModeStr="CROSSCH
lCMDPostFixStr = f"& (echo {lCrosscheckKeyStr} | clip)"
elif inModeStr == "LISTEN":
lCMDPostFixStr = f"| clip"
keyboard.press_and_release('win+r')
time.sleep(1) # Wait for RUN window will appear
lRDPWindow.type_keys("^(a)") # Select all
keyboard.press_and_release("backspace") # Delete selected all
time.sleep(0.5) # Wait for RUN window will appear ctrl+a+backspace is async - so we need some timeout...
KeyboardHotkey("win","r") # win+r
KeyboardHotkey("ctrl","a") # Select all
keyboard.send("backspace") # Delete selected all
time.sleep(gKeyboardHotkeyDelaySecFloat) # Wait for RUN window will appear ctrl+a+backspace is async - so we need some timeout...
lInputStr = f"cmd /c ({inCMDCommandStr}) {lCMDPostFixStr}" # Generate the output string for RUN window
keyboard.write(lInputStr) # Write new text
time.sleep(0.5)
lRDPWindow.type_keys("^(a)") # Select all
lRDPWindow.type_keys("^(c)") # Copy data
time.sleep(gKeyboardHotkeyDelaySecFloat)
KeyboardHotkey("ctrl","a") # Select all
KeyboardHotkey("ctrl","c") # Copy data
# Check the clipboard
lClipboardWaitTimeStartSec = time.time()
lClipboardStr = Clipboard.TextGet() # Get text from clipboard
@ -392,4 +393,12 @@ def SystemRDPWarningClickOk():
UIDesktop.UIOSelector_Get_UIO([{"title": "Remote Desktop Connection", "class_name": "#32770", "backend": "win32"},
{"title": "OK", "class_name": "Button"}]).click()
except Exception as e:
pass
pass
# Bugfix with RDP work
def KeyboardHotkey(inModifierKeyStr,inKeyStr, inDelaySecFloat=gKeyboardHotkeyDelaySecFloat):
keyboard.press(inModifierKeyStr)
time.sleep(inDelaySecFloat)
keyboard.send(inKeyStr)
time.sleep(inDelaySecFloat)
keyboard.release(inModifierKeyStr)
time.sleep(inDelaySecFloat)

@ -11,28 +11,30 @@ gSettings = None # Gsettings will be initialized after the import module
# Create new RDPSession in RobotRDPActive
def RDPSessionConnect(inRDPSessionKeyStr, inHostStr, inPortStr, inLoginStr, inPasswordStr):
global gSettings
lRDPConfigurationItem = { # Init the configuration item
"Host": inHostStr, # Host address, example "77.77.22.22"
"Port": inPortStr, # RDP Port, example "3389"
"Login": inLoginStr, # Login, example "test"
"Password": inPasswordStr, # Password, example "test"
"Screen": {
"Width": 1680, # Width of the remote desktop in pixels, example 1680
"Height": 1050, # Height of the remote desktop in pixels, example 1050
# "640x480" or "1680x1050" or "FullScreen". If Resolution not exists set full screen, example
"FlagUseAllMonitors": False, # True or False, example False
"DepthBit": "32" # "32" or "24" or "16" or "15", example "32"
},
"SharedDriveList": ["c"], # List of the Root sesion hard drives, example ["c"]
###### Will updated in program ############
"SessionHex": "77777sdfsdf77777dsfdfsf77777777", # Hex is created when robot runs, example ""
"SessionIsWindowExistBool": False, # Flag if the RDP window is exist, old name "FlagSessionIsActive". Check every n seconds , example False
"SessionIsWindowResponsibleBool": False, # Flag if RDP window is responsible (recieve commands). Check every nn seconds. If window is Responsible - window is Exist too , example False
"SessionIsIgnoredBool": False # Flag to ignore RDP window False - dont ignore, True - ignore, example False
}
gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr] = lRDPConfigurationItem # Add item in RDPList
Connector.Session(lRDPConfigurationItem) # Create the RDP session
Connector.SystemRDPWarningClickOk() # Click all warning messages
# ATTENTION - dont connect if RDP session is exist
if inRDPSessionKeyStr not in gSettings["RobotRDPActive"]["RDPList"]:
lRDPConfigurationItem = { # Init the configuration item
"Host": inHostStr, # Host address, example "77.77.22.22"
"Port": inPortStr, # RDP Port, example "3389"
"Login": inLoginStr, # Login, example "test"
"Password": inPasswordStr, # Password, example "test"
"Screen": {
"Width": 1680, # Width of the remote desktop in pixels, example 1680
"Height": 1050, # Height of the remote desktop in pixels, example 1050
# "640x480" or "1680x1050" or "FullScreen". If Resolution not exists set full screen, example
"FlagUseAllMonitors": False, # True or False, example False
"DepthBit": "32" # "32" or "24" or "16" or "15", example "32"
},
"SharedDriveList": ["c"], # List of the Root sesion hard drives, example ["c"]
###### Will updated in program ############
"SessionHex": "77777sdfsdf77777dsfdfsf77777777", # Hex is created when robot runs, example ""
"SessionIsWindowExistBool": False, # Flag if the RDP window is exist, old name "FlagSessionIsActive". Check every n seconds , example False
"SessionIsWindowResponsibleBool": False, # Flag if RDP window is responsible (recieve commands). Check every nn seconds. If window is Responsible - window is Exist too , example False
"SessionIsIgnoredBool": False # Flag to ignore RDP window False - dont ignore, True - ignore, example False
}
gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr] = lRDPConfigurationItem # Add item in RDPList
Connector.Session(lRDPConfigurationItem) # Create the RDP session
Connector.SystemRDPWarningClickOk() # Click all warning messages
return True
# Disconnect the RDP session
@ -56,6 +58,13 @@ def RDPSessionReconnect(inRDPSessionKeyStr):
Connector.Session(lRDPConfigurationItem)
return True
# Stop track the RDP session. Current def dont kill RDP session - only stop to track it (it can give )
def RDPSessionMonitorStop(inRDPSessionKeyStr):
global gSettings
lResult = True
gSettings["RobotRDPActive"]["RDPList"].pop(inRDPSessionKeyStr,None) # Remove item from RDPList
return lResult
# Logoff the RDP session
def RDPSessionLogoff(inRDPSessionKeyStr):
global gSettings
@ -64,8 +73,8 @@ def RDPSessionLogoff(inRDPSessionKeyStr):
# Calculate the session Hex
lSessionHex = gSettings["RobotRDPActive"]["RDPList"].get(inRDPSessionKeyStr,{}).get("SessionHex", None)
if lSessionHex:
# Run CMD
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="CROSSCHECK", inLogger=gSettings["Logger"], inRDPConfigurationItem=gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr])
# Run CMD - dont crosscheck because CMD dont return value to the clipboard when logoff
Connector.SessionCMDRun(inSessionHex=lSessionHex, inCMDCommandStr=lCMDStr, inModeStr="RUN", inLogger=gSettings["Logger"], inRDPConfigurationItem=gSettings["RobotRDPActive"]["RDPList"][inRDPSessionKeyStr])
gSettings["RobotRDPActive"]["RDPList"].pop(inRDPSessionKeyStr,None) # Remove item from RDPList
return lResult

@ -22,6 +22,8 @@ from http import cookies
global gSettingsDict
from . import ServerSettings
import copy
#Authenticate function ()
# return dict
# {
@ -33,10 +35,6 @@ def AuthenticateVerify(inRequest):
######################################
#Way 1 - try to find AuthToken
lCookies = cookies.SimpleCookie(inRequest.headers.get("Cookie", ""))
inRequest.OpenRPA = {}
inRequest.OpenRPA["AuthToken"] = None
inRequest.OpenRPA["Domain"] = None
inRequest.OpenRPA["User"] = None
#pdb.set_trace()
if "AuthToken" in lCookies:
lCookieAuthToken = lCookies.get("AuthToken", "").value
@ -193,6 +191,34 @@ def UserAccessCheckBefore(inMethod, inRequest):
return lResult
# HTTPRequestHandler class
class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
# Def to check User Role access grants
def UserRoleAccessAsk(self, inRoleKeyList):
lResult = True # Init flag
lRoleHierarchyDict = self.UserRoleHierarchyGet() # get the Hierarchy
# Try to get value from key list
lKeyValue = lRoleHierarchyDict # Init the base
for lItem in inRoleKeyList:
if type(lKeyValue) is dict:
if lItem in lKeyValue: # Has key
lKeyValue = lKeyValue[lItem] # Get the value and go to the next loop iteration
else: # Else branch - true or false
if len(lKeyValue)>0: # False - if Dict has some elements
lResult = False # Set the False Flag
else:
lResult = True # Set the True flag
break # Stop the loop
else: # Has element with no detalization - return True
lResult = True # Set the flag
break # Close the loop
return lResult # Return the result
# Def to get hierarchy of the current user roles
# if return {} - all is available
def UserRoleHierarchyGet(self):
lDomainUpperStr = self.OpenRPA["Domain"].upper()
lUserUpperStr = self.OpenRPA["User"].upper()
return gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("RuleDomainUserDict", {}).get((lDomainUpperStr, lUserUpperStr), {}).get("RoleHierarchyAllowedDict", {})
#Tech def
#return {"headers":[],"body":"","statuscode":111}
def URLItemCheckDo(self, inURLItem, inMethod):
@ -287,6 +313,12 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
# Write content as utf-8 data
self.wfile.write(inResponseDict["Body"])
def do_GET(self):
self.OpenRPA = {}
self.OpenRPA["AuthToken"] = None
self.OpenRPA["Domain"] = None
self.OpenRPA["User"] = None
self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def
self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def
# Prepare result dict
lResponseDict = {"Headers": {}, "SetCookies": {}, "Body": b"", "StatusCode": None}
self.OpenRPAResponseDict = lResponseDict
@ -350,6 +382,13 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
self.end_headers()
# POST
def do_POST(self):
lL = gSettingsDict["Logger"]
self.OpenRPA = {}
self.OpenRPA["AuthToken"] = None
self.OpenRPA["Domain"] = None
self.OpenRPA["User"] = None
self.OpenRPA["DefUserRoleAccessAsk"]=self.UserRoleAccessAsk # Alias for def
self.OpenRPA["DefUserRoleHierarchyGet"]=self.UserRoleHierarchyGet # Alias for def
# Prepare result dict
#pdb.set_trace()
lResponseDict = {"Headers": {}, "SetCookies":{}, "Body": b"", "StatusCode": None}
@ -360,8 +399,12 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
#####################################
lFlagAccessUserBlock=False
lAuthenticateDict = {"Domain": "", "User": ""}
lIsSuperToken = False # Is supertoken
if gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("FlagCredentialsAsk", False):
lAuthenticateDict = AuthenticateVerify(self)
# Get Flag is supertoken (True|False)
lIsSuperToken = gSettingsDict.get("Server", {}).get("AccessUsers", {}).get("AuthTokensDict", {}).get(
self.OpenRPA["AuthToken"], {}).get("FlagDoNotExpire", False)
if not lAuthenticateDict["User"]:
lFlagAccessUserBlock=True
if lFlagAccessUserBlock:
@ -401,6 +444,9 @@ class testHTTPServer_RequestHandler(BaseHTTPRequestHandler):
# Send headers
self.send_header('Content-type','application/json')
self.end_headers()
# Logging info about processor activity if not SuperToken ()
if not lIsSuperToken:
if lL: lL.info(f"Server:: User activity from web. Domain: {self.OpenRPA['Domain']}, Username: {self.OpenRPA['User']}, Activity: {lInputObject}")
# Send message back to client
message = json.dumps(Processor.ActivityListOrDict(lInputObject))
# Write content as utf-8 data

@ -1,4 +1,5 @@
import json
from inspect import signature # For detect count of def args
#ControlPanelDict
from desktopmagic.screengrab_win32 import (
getDisplayRects, saveScreenToBmp, saveRectToBmp, getScreenAsImage,
@ -39,7 +40,16 @@ def Monitor_ControlPanelDictGet(inRequest,inGlobalDict):
lUACBool = False # UAC Check is not passed - False for user
if lUACBool: # Run function if UAC is TRUE
# Выполнить вызов и записать результат
lItemResultDict = lItem["RenderFunction"](inGlobalDict)
# Call def (inRequest, inGSettings) or def (inGSettings)
lItemResultDict = None
lDEFSignature = signature(lItem["RenderFunction"]) # Get signature of the def
lDEFARGLen = len(lDEFSignature.parameters.keys()) # get count of the def args
if lDEFARGLen == 1: # def (inGSettings)
lItemResultDict = lItem["RenderFunction"](inGlobalDict)
elif lDEFARGLen == 2: # def (inRequest, inGSettings)
lItemResultDict = lItem["RenderFunction"](inRequest, inGlobalDict)
elif lDEFARGLen == 0: # def ()
lItemResultDict = lItem["RenderFunction"]()
# RunFunction
lResultJSON["RenderRobotList"].append(lItemResultDict)
# Send message back to client
@ -47,6 +57,16 @@ def Monitor_ControlPanelDictGet(inRequest,inGlobalDict):
# Write content as utf-8 data
inResponseDict["Body"] = bytes(message, "utf8")
# UserAccess get rights hierarchy dict in json
def UserRoleHierarchyGet(inRequest,inGlobalDict):
inResponseDict = inRequest.OpenRPAResponseDict
# Create result JSON
lResultDict = inRequest.OpenRPA["DefUserRoleHierarchyGet"]() # Get the User Role Hierarchy list
# Send message back to client
message = json.dumps(lResultDict)
# Write content as utf-8 data
inResponseDict["Body"] = bytes(message, "utf8")
def GetScreenshot(inRequest,inGlobalDict):
# Get Screenshot
def SaveScreenshot(inFilePath):
@ -90,7 +110,8 @@ def SettingsUpdate(inGlobalConfiguration):
{"Method":"GET", "URL": "/3rdParty/Handlebars/handlebars-v4.1.2.js", "MatchType": "EqualCase", "ResponseFilePath": os.path.join(lOrchestratorFolder, "..\\Resources\\Web\\Handlebars\\handlebars-v4.1.2.js"), "ResponseContentType": "application/javascript"},
{"Method": "GET", "URL": "/Monitor/ControlPanelDictGet", "MatchType": "Equal", "ResponseDefRequestGlobal": Monitor_ControlPanelDictGet, "ResponseContentType": "application/json"},
{"Method": "GET", "URL": "/GetScreenshot", "MatchType": "BeginWith", "ResponseDefRequestGlobal": GetScreenshot, "ResponseContentType": "image/png"},
{"Method": "GET", "URL": "/Orchestrator/RobotRDPActive/ControlPanelDictGet", "MatchType": "Equal","ResponseDefRequestGlobal": RobotRDPActive_ControlPanelDictGet, "ResponseContentType": "application/json"}
{"Method": "GET", "URL": "/Orchestrator/RobotRDPActive/ControlPanelDictGet", "MatchType": "Equal","ResponseDefRequestGlobal": RobotRDPActive_ControlPanelDictGet, "ResponseContentType": "application/json"},
{"Method": "POST", "URL": "/Orchestrator/UserRoleHierarchyGet", "MatchType": "Equal","ResponseDefRequestGlobal": UserRoleHierarchyGet, "ResponseContentType": "application/json"}
]
inGlobalConfiguration["Server"]["URLList"]=inGlobalConfiguration["Server"]["URLList"]+lURLList
return inGlobalConfiguration

@ -388,37 +388,6 @@
dataType: "text"
});
}
///////////////////////////////
///Scheduler functions
///////////////////////////////
mGlobal.Scheduler = {}
mGlobal.Scheduler.ActivityTimeListShow = function() {
lData = [
{
"Type":"GlobalDictKeyListValueGet",
"KeyList":["Scheduler","ActivityTimeList"]
}
]
$.ajax({
type: "POST",
url: 'Utils/Processor',
data: JSON.stringify(lData),
success:
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
lResponseJSON[0]["Result"].forEach(function(lItem){lItem["processPathName"]=("processPath" in lItem ? lItem["processPath"] : lItem["processName"])})
///Отправить запрос на формирование таблицы
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-info-table-planloglist",lResponseJSON[0]);
///Установить HTML код
$('.ui.modal.basic .content').html(lHTMLCode);
$('.ui.modal.basic').modal('show');
},
dataType: "text"
});
}
///////////////////////////////
///Processor functions
///////////////////////////////
@ -492,15 +461,8 @@
dataType: "text"
});
}
mGlobal.Processor.LogListShow = function() {
lData = [
{
"Type":"GlobalDictKeyListValueGet",
"KeyList":["Processor","LogList"]
}
]
///Обнулить таблицу
$('.ui.modal.basic .content').html("");
mGlobal.Processor.Send = function(inData) {
lData = inData
$.ajax({
type: "POST",
url: 'Utils/Processor',
@ -509,11 +471,7 @@
function(lData,l2,l3)
{
var lResponseJSON=JSON.parse(lData)
///Отправить запрос на формирование таблицы
lHTMLCode=mGlobal.GeneralGenerateHTMLCodeHandlebars(".openrpa-hidden-info-table-activitylogschedulelist",lResponseJSON["actionListResult"][0])
///Установить HTML код
$('.ui.modal.basic .content').html(lHTMLCode);
$('.ui.modal.basic').modal('show');
///TODO Show error if exist error
},
dataType: "text"
});
@ -646,6 +604,64 @@
///Установить HTML код
lElementParentElement.insertAdjacentHTML("beforeend",lHTMLCode);
}
mGlobal.UserRoleHierarchyDict = null // Put here the user role hierarchy
// UAC Ask
mGlobal.UserRoleAsk=function(inList) {
var lResult = true; // Init flag
var lRoleHierarchyDict = mGlobal.UserRoleHierarchyDict; // get the Hierarchy
// Try to get value from key list
var lKeyValue = lRoleHierarchyDict; // Init the base
var lListLength = inList.length;
for (var i = 0; i<lListLength; i++) {
var lItem = inList[i]; // get the item
if (typeof lKeyValue == "object") {
if (lItem in lKeyValue) { // Has key
lKeyValue = lKeyValue[lItem]; // Get the value and go to the next loop iteration
} else { // Else branch - true or false
if (Object.keys(lKeyValue).length > 0) { // false - if Dict has some elements
lResult = false; // Set the False Flag
} else {
lResult = true; // Set the true flag
}
break; // Stop the loop
}
} else { // Has element with no detalization - return true
lResult = true; // Set the flag
break; // Close the loop
}
}
return lResult; // Return the result
}
// Check user roles and update the Orchestrator UI
mGlobal.UserRoleUpdate=function() {
$.ajax({
type: "POST",
url: 'Orchestrator/UserRoleHierarchyGet',
data: "",
success:
function(lData,l2,l3)
{
var lUACAsk = mGlobal.UserRoleAsk // Alias
var lResponseDict=JSON.parse(lData)
mGlobal.UserRoleHierarchyDict = lResponseDict // set the user role hierarchy
//Turn on the Lookmachine screenshot button
if (lUACAsk(["Orchestrator","Controls","LookMachineScreenshots"])) {
$(".openrpa-control-lookmachinescreenshot").show() //Show button
}
//Turn on the restart orchestrator button
if (lUACAsk(["Orchestrator","Controls","RestartOrchestrator"])) {
$(".openrpa-control-restartorchestrator").show() //Show button
}
//Turn on the rdp session list
if (lUACAsk(["Orchestrator","RDPActive","ListRead"])) {
$(".openrpa-rdpactive-title").show() //Show section
$(".openrpa-robotrdpactive-control-panel-general").show() //Show section
}
},
dataType: "text"
});
}
mGlobal.UserRoleUpdate() // Cal the update User Roles function
})
;
</script>
@ -766,75 +782,20 @@
<h2 class="ui header inverted">...</h2>
</div>
<div class="nine wide column">
<h2 class="ui header inverted">Robot RDP active list</h2>
<h2 class="ui header inverted openrpa-rdpactive-title" style="display:none;">Robot RDP active list</h2>
</div>
</div>
<div class="row">
<div class="five wide column">
<button class="ui labeled icon button" onclick="mGlobal.Monitor.ScreenshotModal.Show();">
<button class="ui labeled icon button openrpa-control-lookmachinescreenshot" onclick="mGlobal.Monitor.ScreenshotModal.Show();" style="display: none;">
<i class="desktop icon"></i>
Look machine screenshot
</button>
<button class="ui labeled icon button red" onclick="mGlobal.Controller.OrchestratorRestart();">
<button class="ui labeled icon button red openrpa-control-restartorchestrator" onclick="mGlobal.Controller.OrchestratorRestart(); " style="display: none;>
<i class="redo icon"></i>
Restart Orchestrator
</button>
<button class="ui labeled icon button" onclick="mGlobal.Scheduler.ActivityTimeListShow();">
<i class="info icon"></i>
Scheduler activity time list
<script class="openrpa-hidden-info-table-planloglist" style="display:none" type="text/x-handlebars-template">
<table class="ui celled table">
<thead>
<tr>
<th>#</th>
<th>Activity type</th>
<th>Time</th>
<th>Process path/Process name</th>
</tr>
</thead>
<tbody>
{{#Result}}
<tr>
<td>{{@index}}</td>
<td>{{TimeHH:MM}}{{TimeHH:MMStart}}</td>
<td>{{TimeHH:MMStop}}</td>
<td>{{Activity}}</td>
</tr>
{{/Result}}
</tbody>
</table>
</script>
</button>
<button class="ui labeled icon button" onclick="mGlobal.Processor.LogListShow();">
<i class="info icon"></i>
Processor logs
<script class="openrpa-hidden-info-table-activitylogschedulelist" style="display:none" type="text/x-handlebars-template">
<table class="ui celled table">
<thead>
<tr>
<th>#</th>
<th>Activity type</th>
<th>Process</th>
<th>Activity DateTime plan</th>
<th>Activity DateTime fact</th>
</tr>
</thead>
<tbody>
{{#result}}
<tr>
<td>{{@index}}</td>
<td>{{activityType}}</td>
<td>{{processPath}}</td>
<td>{{activityDateTime}}</td>
<td class="negative
">{{activityStartDateTime}}</td>
</tr>
{{/result}}
</tbody>
</table>
</script>
</button>
<script class="openrpa-hidden-monitor-table-general" style="display:none" type="text/x-handlebars-template">
<table class="ui celled table">
@ -912,7 +873,7 @@
</div>
<div class="two wide column">
</div>
<div class="nine wide column openrpa-robotrdpactive-control-panel-general">
<div class="nine wide column openrpa-robotrdpactive-control-panel-general" style="display:none;">
<div class="ui info message">
<button class="ui icon button labeled " onclick="mGlobal.RobotRDPActive.fControlPanelRefresh();">
<i class="sync alternate icon"></i>

@ -3,7 +3,7 @@ r"""
The OpenRPA package (from UnicodeLabs)
"""
__version__ = 'v1.1.3'
__version__ = 'v1.1.13'
__all__ = []
__author__ = 'Ivan Maslov <ivan.maslov@unicodelabs.ru>'
#from .Core import Robot

@ -1,13 +0,0 @@
At it's simplest it allows you to send mouse and keyboard
actions to windows dialogs and controls, but It has support for more complex
controls also.
Useful links
-------------
- Home page: http://pywinauto.github.io/
- Docs Intro: https://pywinauto.readthedocs.io/en/latest/
- Getting Started Guide: https://pywinauto.readthedocs.io/en/latest/getting_started.html
- StackOverflow tag: https://stackoverflow.com/questions/tagged/pywinauto

@ -1 +0,0 @@
{"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: Microsoft :: Windows", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Testing", "Topic :: Software Development :: User Interfaces", "Topic :: Software Development :: Quality Assurance"], "extensions": {"python.details": {"contacts": [{"email": "pywinauto-users@lists.sourceforge.net", "name": "Mark Mc Mahon and Contributors", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "http://pywinauto.github.io/"}}}, "extras": [], "generator": "bdist_wheel (0.29.0)", "keywords": ["windows", "gui", "automation", "GuiAuto", "testing", "test", "desktop", "mouse", "keyboard"], "license": "BSD 3-clause", "metadata_version": "2.0", "name": "pywinauto", "platform": "win32", "run_requires": [{"requires": ["comtypes", "six"]}], "summary": "A set of Python modules to automate the Microsoft Windows GUI", "version": "0.6.6"}

@ -0,0 +1,27 @@
Copyright (c) 2017, Mark Mc Mahon and Contributors
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.

@ -1,6 +1,6 @@
Metadata-Version: 2.0
Metadata-Version: 2.1
Name: pywinauto
Version: 0.6.6
Version: 0.6.8
Summary: A set of Python modules to automate the Microsoft Windows GUI
Home-page: http://pywinauto.github.io/
Author: Mark Mc Mahon and Contributors
@ -23,9 +23,9 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: Software Development :: User Interfaces
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Dist: comtypes
Requires-Dist: six
Requires-Dist: comtypes
Requires-Dist: pywin32
At it's simplest it allows you to send mouse and keyboard
actions to windows dialogs and controls, but It has support for more complex

@ -1,11 +1,10 @@
pywinauto-0.6.6.dist-info/DESCRIPTION.rst,sha256=k2uqeFUEl_g6xxBeVuZEfpJGuEOwcWLWkYAPOCoNkrk,443
pywinauto-0.6.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pywinauto-0.6.6.dist-info/METADATA,sha256=0BOLG3k-RTQbPt5MoG8G7P0yDwqhu2hQddg1D03wNgA,1660
pywinauto-0.6.6.dist-info/RECORD,,
pywinauto-0.6.6.dist-info/WHEEL,sha256=Ds0ba8WsPJtjBPzEMyPOBG3qfPa6B4mlzB-vhzorIZs,97
pywinauto-0.6.6.dist-info/metadata.json,sha256=0I2fhQRsICsiE-qQSyHVGUikMukbxGqL_67vZLVOkPs,1363
pywinauto-0.6.6.dist-info/top_level.txt,sha256=7E8mqRxGiLpAamWQi4ClxZvTp1jx3P0shUi_Tu0zk44,10
pywinauto/__init__.py,sha256=BJ2Pni41MWP3DgzGAFhpNvFajGujGcVUxMnf6n5s1tI,6950
pywinauto-0.6.8.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pywinauto-0.6.8.dist-info/LICENSE,sha256=GKmZqVt7I9hsQQtFNORNafbYzhPDpTcZsGq4ldii5zo,1504
pywinauto-0.6.8.dist-info/METADATA,sha256=7x_-XwBl2UsjPrl_4e5bNgDVwA_FMH83WidT-ii0xb0,1723
pywinauto-0.6.8.dist-info/RECORD,,
pywinauto-0.6.8.dist-info/WHEEL,sha256=53VSps8MltPLN_x9Ib61FU2ZSaJKzgrWQqu9rS-Dkgk,116
pywinauto-0.6.8.dist-info/top_level.txt,sha256=7E8mqRxGiLpAamWQi4ClxZvTp1jx3P0shUi_Tu0zk44,10
pywinauto/__init__.py,sha256=xY7VLfy-UvPNHKJSlzekAoG9Sue8zdNdFIdjS-_zTFs,7231
pywinauto/__pycache__/__init__.cpython-37.pyc,,
pywinauto/__pycache__/actionlogger.cpython-37.pyc,,
pywinauto/__pycache__/application.cpython-37.pyc,,
@ -33,9 +32,9 @@ pywinauto/__pycache__/win32functions.cpython-37.pyc,,
pywinauto/__pycache__/win32structures.cpython-37.pyc,,
pywinauto/__pycache__/xml_helpers.cpython-37.pyc,,
pywinauto/actionlogger.py,sha256=JVny3VSQIzcSH6ESfUPkxPozSJrxMMOvlwzNiUzO-_E,5632
pywinauto/application.py,sha256=r1gE55O91UXteKme9rFqBUP1QmbYyt4tmpXNQAHHt7I,55887
pywinauto/application.py,sha256=_KIIkl_ZZNFDZo_phPhYBX1YuNZh4pFW5A1gdYvTXeo,58047
pywinauto/backend.py,sha256=hLgO3HsnCJUYNoPfU8CwD11yMKjUZiPuXlC080JNufE,4186
pywinauto/base_wrapper.py,sha256=wx_8TIg_RbXX_zvpxGyL8nUWcvfQHVtVK6tAl8gcC_A,37561
pywinauto/base_wrapper.py,sha256=qAIvH6wKd6okBBDHY21gnK7A2DQj5H43qV4heQqQxc4,37590
pywinauto/clipboard.py,sha256=VpKW7WQ3BF57cmLkWA0Of16RG6BCuLSqGX0sW2nN1ds,4329
pywinauto/controlproperties.py,sha256=YQ1lbHxWvMf38PGB0JYdN8rhh9PYoe8iwaWbtw3EU1w,9329
pywinauto/controls/__init__.py,sha256=0cuXVxqppu3vQIJfjgxB_J__3Vtr3EvbDEx7TaRY64A,2241
@ -46,26 +45,26 @@ pywinauto/controls/__pycache__/menuwrapper.cpython-37.pyc,,
pywinauto/controls/__pycache__/uia_controls.cpython-37.pyc,,
pywinauto/controls/__pycache__/uiawrapper.cpython-37.pyc,,
pywinauto/controls/__pycache__/win32_controls.cpython-37.pyc,,
pywinauto/controls/common_controls.py,sha256=zyx1EyyoSQ_pvl6snIPOzIp6WZuPXOYNAzYqM4Qh5GA,141066
pywinauto/controls/hwndwrapper.py,sha256=46cKLxKhYL6-BzN33KA8kG7wOy1-JGEJ68qVQLiCYts,68153
pywinauto/controls/menuwrapper.py,sha256=SS5UoaezIMknz_405021QUV0ixClkqCUfuck_EnsgIA,23477
pywinauto/controls/uia_controls.py,sha256=rmME_GCfDbohEBNnHJE_mLStshBvPX_-r8T_Xa6XuH8,53699
pywinauto/controls/uiawrapper.py,sha256=aEVJYh6aB6VIg9sBrHwyQ3LOKTMnFLruVCMmSxy0dfQ,30770
pywinauto/controls/common_controls.py,sha256=4a_RyQcDl4N2JW8F_9sK-utJWJK-ujwqXF4vEhAaFe0,138614
pywinauto/controls/hwndwrapper.py,sha256=nDiCY-DnVHrD2o49WTRv7-x_2kB9Xf9nBb3gWJkgl5I,68222
pywinauto/controls/menuwrapper.py,sha256=TlgHXxMm6pUB75VDW6R-X5octoSpauXM0t7pRIJ8bPE,23497
pywinauto/controls/uia_controls.py,sha256=ei-u10dGxMRjR7SQupD3dxrvlbiqHm90ggb9WyracJA,54886
pywinauto/controls/uiawrapper.py,sha256=w7wsUnbsSStm32H5t2jEI-P9sdbMVOS8OYASHJnmhDk,31386
pywinauto/controls/win32_controls.py,sha256=Iz-28a0b_TPR8XiSTIkr8areRXyxuXQ0gOqshIPcrhU,35099
pywinauto/element_info.py,sha256=L-s3E6xdVAxgfCFZXAQlMbaHl5OEtG_xFM845gFz5zc,6067
pywinauto/findbestmatch.py,sha256=xAJaaiqAnBmQwCrhiqga-AmI5FxR0gZuXE1v1k1tyRA,20605
pywinauto/findwindows.py,sha256=wYQgISnlHOAhuvxA0bG9shLSTwu9pKNg1_ApYJi1pHw,14290
pywinauto/findbestmatch.py,sha256=izVEqpMSXgFhdMLd3OxN6Sexfo6MGVHTPEwkFxhDDpU,20748
pywinauto/findwindows.py,sha256=OMn7J5i4vk2xiVINPQ4daaMZ5MDCAplgnt4MXHo2dGY,14470
pywinauto/fuzzydict.py,sha256=mNFpET8ckSpMen4LdRRYyGRR4LToMbQw-gqNG3lWCqM,6073
pywinauto/handleprops.py,sha256=WavBoIYV0WTLpq5YUXDQS0-kMv3GChpwk2etbMFZA_k,14748
pywinauto/keyboard.py,sha256=Q_hT07R48cC830HzBZTaM2o2XOMtLsucVG_KalAfgz4,22865
pywinauto/handleprops.py,sha256=85UJyb6LfUVNim5biyB9Fz-oICo3lq1S_-jPxxgs28c,14685
pywinauto/keyboard.py,sha256=tJ4MSH7WVvmPrinMDycRr_uWm7AEtiFrfYjFjVgOwW0,24562
pywinauto/linux/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pywinauto/linux/__pycache__/__init__.cpython-37.pyc,,
pywinauto/linux/__pycache__/clipboard.cpython-37.pyc,,
pywinauto/linux/__pycache__/keyboard.cpython-37.pyc,,
pywinauto/linux/clipboard.py,sha256=X4wR0r1_X8fdLF0KphNskV_vV2c0_toNyyt2m-TY6nQ,3568
pywinauto/linux/keyboard.py,sha256=kvc5EZY8lML2WoCwV5er9SyzsF2NjQ4Abpum-YYT5-U,17380
pywinauto/linux/keyboard.py,sha256=z540dSwdCvmoyRSpCaJainPOTawbY76eo8i_UW2qyYQ,17458
pywinauto/mouse.py,sha256=-Rh9zY1KUfzVcKblvQixH0WKxf2lW9__yrsI-pRhpe0,10647
pywinauto/remote_memory_block.py,sha256=fC0HyKKrsFlwS-1QlwQZif3RFqK4hr1RkIwajkbzGM4,12204
pywinauto/remote_memory_block.py,sha256=eox-bC9ZpliwQw3gZuiPku8_oQ9sGNeKfrSOM2pNyJs,12168
pywinauto/sysinfo.py,sha256=NgLfiQ3XNaRGnapzSfYSafwn5my24FjE1uHTU66P4VM,3052
pywinauto/taskbar.py,sha256=vjHNAdOaQwyZvqJaLMvMB7teJBMOeCgXeedJpZrZGp4,5232
pywinauto/tests/__init__.py,sha256=DZXsho8W7nBWDSw5Qb-qao9CNpfOwTCKOtxG0dJRgos,5452
@ -97,11 +96,11 @@ pywinauto/tests/repeatedhotkey.py,sha256=6xFNznYzzIebpkX2dLUW6rIkTOBIe5la1qVohi3
pywinauto/tests/translation.py,sha256=0qVEsh42uqu1K5MDZfcQunPngSRanPfSLgL99An1W8g,6070
pywinauto/tests/truncation.py,sha256=MD5UTKnVtZPZyfP3Ejx5ZMBDrDYY089xY05a8SMtMjc,20006
pywinauto/timings.py,sha256=58c9xNODE5LjQYNhqoLpbLfNeJ9Lu0J8GZLw2d2tkMY,15668
pywinauto/uia_defines.py,sha256=-4w4hhRCd4O_748nEp5w5kKl-d0vb17aymVr3rdZTQ0,9819
pywinauto/uia_defines.py,sha256=ynA52N4tmKn8KBlqGP0EJ8etpygvYTyZhQNJ-vdOBRw,9979
pywinauto/uia_element_info.py,sha256=g2E9O4qSyXYmj80MqFD7mOin_nHXowM_-fVJVO0oV88,13762
pywinauto/win32_element_info.py,sha256=bJ9CIP4RPdGIZVB_HaZQg2Z_92QG2hWYw1aGkoBtTxI,9369
pywinauto/win32_hooks.py,sha256=X2Le46OJxmco94b0n830RN6Tpnk2BzMTtRVOYdwllWc,24289
pywinauto/win32defines.py,sha256=i-uScB7nzZRk0fiDNk6TqlhGraRESmjLx-GkBlgOOp4,499259
pywinauto/win32functions.py,sha256=uHpPx61qsWL_awp6Kq0D-ERN5GsAvHjC34pN-rx1xQQ,14987
pywinauto/win32structures.py,sha256=G9diB0fpPv95J8DQLt6z5D1033Ajw_FZUCojrS0xliA,42128
pywinauto/win32_hooks.py,sha256=_oG2uuMswls-9jxaGm_XRAstM6E9S38cQ6ZzBEoiYg0,24238
pywinauto/win32defines.py,sha256=zltu4uEoY397OBLDKI_Vo0R79719_uqHOjL0QuTO3rc,630639
pywinauto/win32functions.py,sha256=fHHeG9kARY_3a05qXoI9hbIIXua6Kj3IJUu6my0W6Fw,24133
pywinauto/win32structures.py,sha256=CGxoTtM-fH_AyxpxGhRl28YsVJfBM1jv3_aLUXDo0ng,41700
pywinauto/xml_helpers.py,sha256=uiairq6vJiduprD6KMIvc72qBuplPC-PQqduJVVVZnc,17263

@ -0,0 +1,6 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.4)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any

@ -32,7 +32,7 @@
"""Python package for automating GUI manipulation on Windows"""
__version__ = "0.6.6"
__version__ = "0.6.8"
import sys # noqa: E402
import warnings # noqa: E402
@ -89,11 +89,9 @@ if sys.platform == 'win32':
from . import findwindows
WindowAmbiguousError = findwindows.WindowAmbiguousError
WindowNotFoundError = findwindows.WindowNotFoundError
ElementNotFoundError = findwindows.ElementNotFoundError
if UIA_support:
ElementNotFoundError = findwindows.ElementNotFoundError
ElementAmbiguousError = findwindows.ElementAmbiguousError
ElementAmbiguousError = findwindows.ElementAmbiguousError
from . import findbestmatch
from . import backend as backends
@ -106,13 +104,14 @@ if sys.platform == 'win32':
class Desktop(object):
"""Simple class to call something like ``Desktop().WindowName.ControlName.method()``"""
def __init__(self, backend=None):
def __init__(self, backend=None, allow_magic_lookup=True):
"""Create desktop element description"""
if not backend:
backend = backends.registry.name
if backend not in backends.registry.backends:
raise ValueError('Backend "{0}" is not registered!'.format(backend))
self.backend = backends.registry.backends[backend]
self.allow_magic_lookup = allow_magic_lookup
def window(self, **kwargs):
"""Create WindowSpecification object for top-level window"""
@ -121,7 +120,7 @@ if sys.platform == 'win32':
if 'backend' in kwargs:
raise ValueError('Using another backend than set in Desktop constructor is not allowed!')
kwargs['backend'] = self.backend.name
return WindowSpecification(kwargs)
return WindowSpecification(kwargs, allow_magic_lookup=self.allow_magic_lookup)
def windows(self, **kwargs):
"""Return a list of wrapped top level windows"""
@ -145,9 +144,12 @@ if sys.platform == 'win32':
def __getattribute__(self, attr_name):
"""Attribute access for this class"""
allow_magic_lookup = object.__getattribute__(self, "allow_magic_lookup") # Beware of recursions here!
try:
return object.__getattribute__(self, attr_name)
except AttributeError:
if not allow_magic_lookup:
raise
return self[attr_name] # delegate it to __get_item__
def from_point(self, x, y):

@ -141,11 +141,12 @@ class WindowSpecification(object):
'active': ('is_active',),
}
def __init__(self, search_criteria):
def __init__(self, search_criteria, allow_magic_lookup=True):
"""
Initialize the class
:param search_criteria: the criteria to match a dialog
:param allow_magic_lookup: whether attribute access must turn into child_window(best_match=...) search as fallback
"""
# kwargs will contain however to find this window
if 'backend' not in search_criteria:
@ -158,6 +159,7 @@ class WindowSpecification(object):
self.criteria = [search_criteria, ]
self.actions = ActionLogger()
self.backend = registry.backends[search_criteria['backend']]
self.allow_magic_lookup = allow_magic_lookup
if self.backend.name == 'win32':
# Non PEP-8 aliases for partial backward compatibility
@ -173,7 +175,7 @@ class WindowSpecification(object):
self.window_ = deprecated(self.child_window, deprecated_name='window_')
def __call__(self, *args, **kwargs):
"""No __call__ so return a usefull error"""
"""No __call__ so return a useful error"""
if "best_match" in self.criteria[-1]:
raise AttributeError("Neither GUI element (wrapper) " \
"nor wrapper method '{0}' were found (typo?)".
@ -182,8 +184,8 @@ class WindowSpecification(object):
message = (
"You tried to execute a function call on a WindowSpecification "
"instance. You probably have a typo for one of the methods of "
"this class.\n"
"The criteria leading up to this is: " + str(self.criteria))
"this class or of the targeted wrapper object.\n"
"The criteria leading up to this are: " + str(self.criteria))
raise AttributeError(message)
@ -277,7 +279,7 @@ class WindowSpecification(object):
if 'top_level_only' not in criteria:
criteria['top_level_only'] = False
new_item = WindowSpecification(self.criteria[0])
new_item = WindowSpecification(self.criteria[0], allow_magic_lookup=self.allow_magic_lookup)
new_item.criteria.extend(self.criteria[1:])
new_item.criteria.append(criteria)
@ -307,7 +309,7 @@ class WindowSpecification(object):
"""
# if we already have 2 levels of criteria (dlg, control)
# then resolve the control and do a getitem on it for the
if len(self.criteria) >= 2:
if len(self.criteria) >= 2: # FIXME - this is surprising
ctrls = self.__resolve_control(self.criteria)
@ -324,7 +326,7 @@ class WindowSpecification(object):
# if we get here then we must have only had one criteria so far
# so create a new :class:`WindowSpecification` for this control
new_item = WindowSpecification(self.criteria[0])
new_item = WindowSpecification(self.criteria[0], allow_magic_lookup=self.allow_magic_lookup)
# add our new criteria
new_item.criteria.append({"best_match": key})
@ -345,6 +347,21 @@ class WindowSpecification(object):
Otherwise delegate functionality to :func:`__getitem__` - which
sets the appropriate criteria for the control.
"""
allow_magic_lookup = object.__getattribute__(self, "allow_magic_lookup") # Beware of recursions here!
if not allow_magic_lookup:
try:
return object.__getattribute__(self, attr_name)
except AttributeError:
wrapper_object = self.wrapper_object()
try:
return getattr(wrapper_object, attr_name)
except AttributeError:
message = (
'Attribute "%s" exists neither on %s object nor on'
'targeted %s element wrapper (typo? or set allow_magic_lookup to True?)' %
(attr_name, self.__class__, wrapper_object.__class__))
raise AttributeError(message)
if attr_name in ['__dict__', '__members__', '__methods__', '__class__', '__name__']:
return object.__getattribute__(self, attr_name)
@ -354,10 +371,10 @@ class WindowSpecification(object):
if attr_name in self.__dict__:
return self.__dict__[attr_name]
# if we already have 2 levels of criteria (dlg, conrol)
# if we already have 2 levels of criteria (dlg, control)
# this third must be an attribute so resolve and get the
# attribute and return it
if len(self.criteria) >= 2:
if len(self.criteria) >= 2: # FIXME - this is surprising
ctrls = self.__resolve_control(self.criteria)
@ -366,6 +383,7 @@ class WindowSpecification(object):
except AttributeError:
return self.child_window(best_match=attr_name)
else:
# FIXME - I don't get this part at all, why is it win32-specific and why not keep the same logic as above?
# if we have been asked for an attribute of the dialog
# then resolve the window and return the attribute
desktop_wrapper = self.backend.generic_wrapper_class(self.backend.element_info_class())
@ -870,7 +888,7 @@ class Application(object):
.. automethod:: __getitem__
"""
def __init__(self, backend="win32", datafilename=None):
def __init__(self, backend="win32", datafilename=None, allow_magic_lookup=True):
"""
Initialize the Application object
@ -886,6 +904,7 @@ class Application(object):
if backend not in registry.backends:
raise ValueError('Backend "{0}" is not registered!'.format(backend))
self.backend = registry.backends[backend]
self.allow_magic_lookup = allow_magic_lookup
if self.backend.name == 'win32':
# Non PEP-8 aliases for partial backward compatibility
self.Start = deprecated(self.start)
@ -906,6 +925,10 @@ class Application(object):
self.match_history = pickle.load(datafile)
self.use_history = True
def __iter__(self):
"""Raise to avoid infinite loops"""
raise NotImplementedError("Object is not iterable, try to use .windows()")
def connect(self, **kwargs):
"""Connect to an already running process
@ -1139,7 +1162,7 @@ class Application(object):
else:
criteria['title'] = windows[0].name
return WindowSpecification(criteria)
return WindowSpecification(criteria, allow_magic_lookup=self.allow_magic_lookup)
def active(self):
"""Return WindowSpecification for an active window of the application"""
@ -1163,7 +1186,7 @@ class Application(object):
else:
criteria['title'] = windows[0].name
return WindowSpecification(criteria)
return WindowSpecification(criteria, allow_magic_lookup=self.allow_magic_lookup)
def windows(self, **kwargs):
"""Return a list of wrapped top level windows of the application"""
@ -1205,7 +1228,7 @@ class Application(object):
else:
# add the restriction for this particular application
kwargs['app'] = self
win_spec = WindowSpecification(kwargs)
win_spec = WindowSpecification(kwargs, allow_magic_lookup=self.allow_magic_lookup)
return win_spec
Window_ = window_ = window
@ -1216,6 +1239,17 @@ class Application(object):
return self.window(best_match=key)
def __getattribute__(self, attr_name):
allow_magic_lookup = object.__getattribute__(self, "allow_magic_lookup") # Beware of recursions here!
if not allow_magic_lookup:
try:
return object.__getattribute__(self, attr_name)
except AttributeError:
message = (
'Attribute "%s" doesn\'t exist on %s object'
' (typo? or set allow_magic_lookup to True?)' %
(attr_name, self.__class__))
raise AttributeError(message)
"""Find the specified dialog of the application"""
if attr_name in ['__dict__', '__members__', '__methods__', '__class__']:
return object.__getattribute__(self, attr_name)

@ -38,7 +38,6 @@ import ctypes
import locale
import re
import time
import win32process
import win32gui
import win32con
import win32api
@ -925,7 +924,8 @@ class BaseWrapper(object):
with_tabs = False,
with_newlines = False,
turn_off_numlock = True,
set_foreground = True):
set_foreground = True,
vk_packet = True):
"""
Type keys to the element using keyboard.send_keys
@ -945,7 +945,7 @@ class BaseWrapper(object):
# attach the Python process with the process that self is in
if self.element_info.handle:
window_thread_id, _ = win32process.GetWindowThreadProcessId(int(self.handle))
window_thread_id = win32functions.GetWindowThreadProcessId(self.handle, None)
win32functions.AttachThreadInput(win32functions.GetCurrentThreadId(), window_thread_id, win32defines.TRUE)
# TODO: check return value of AttachThreadInput properly
else:
@ -967,7 +967,8 @@ class BaseWrapper(object):
with_spaces,
with_tabs,
with_newlines,
turn_off_numlock)
turn_off_numlock,
vk_packet)
# detach the python process from the window's process
if self.element_info.handle:

@ -53,7 +53,6 @@ import warnings
import locale
import six
from .. import sysinfo
from .. import win32functions
from .. import win32defines
from .. import win32structures
@ -68,9 +67,6 @@ from ..handleprops import is64bitprocess
from ..sysinfo import is_x64_Python
from .. import deprecated
if sysinfo.UIA_support:
from ..uia_defines import IUIA
# Todo: I should return iterators from things like items() and texts()
# to save building full lists all the time
@ -135,7 +131,7 @@ class _listview_item(object):
item.iItem = self.item_index
item.iSubItem = self.subitem_index
item.stateMask = win32structures.UINT(-1)
item.stateMask = wintypes.UINT(-1)
item.cchTextMax = 2000
item.pszText = remote_mem.Address() + \
@ -501,9 +497,9 @@ class _listview_item(object):
lvitem = self.listview_ctrl.LVITEM()
lvitem.mask = win32structures.UINT(win32defines.LVIF_STATE)
lvitem.state = win32structures.UINT(index_to_state_image_mask(1)) # win32structures.UINT(0x1000)
lvitem.stateMask = win32structures.UINT(win32defines.LVIS_STATEIMAGEMASK)
lvitem.mask = wintypes.UINT(win32defines.LVIF_STATE)
lvitem.state = wintypes.UINT(index_to_state_image_mask(1)) # wintypes.UINT(0x1000)
lvitem.stateMask = wintypes.UINT(win32defines.LVIS_STATEIMAGEMASK)
remote_mem = RemoteMemoryBlock(self.listview_ctrl)
remote_mem.Write(lvitem)
@ -530,9 +526,9 @@ class _listview_item(object):
lvitem = self.listview_ctrl.LVITEM()
lvitem.mask = win32structures.UINT(win32defines.LVIF_STATE)
lvitem.state = win32structures.UINT(index_to_state_image_mask(2)) # win32structures.UINT(0x2000)
lvitem.stateMask = win32structures.UINT(win32defines.LVIS_STATEIMAGEMASK)
lvitem.mask = wintypes.UINT(win32defines.LVIF_STATE)
lvitem.state = wintypes.UINT(index_to_state_image_mask(2)) # wintypes.UINT(0x2000)
lvitem.stateMask = wintypes.UINT(win32defines.LVIS_STATEIMAGEMASK)
remote_mem = RemoteMemoryBlock(self.listview_ctrl)
remote_mem.Write(lvitem)
@ -591,12 +587,12 @@ class _listview_item(object):
# first we need to change the state of the item
lvitem = self.listview_ctrl.LVITEM()
lvitem.mask = win32structures.UINT(win32defines.LVIF_STATE)
lvitem.mask = wintypes.UINT(win32defines.LVIF_STATE)
if to_select:
lvitem.state = win32structures.UINT(win32defines.LVIS_FOCUSED | win32defines.LVIS_SELECTED)
lvitem.state = wintypes.UINT(win32defines.LVIS_FOCUSED | win32defines.LVIS_SELECTED)
lvitem.stateMask = win32structures.UINT(win32defines.LVIS_FOCUSED | win32defines.LVIS_SELECTED)
lvitem.stateMask = wintypes.UINT(win32defines.LVIS_FOCUSED | win32defines.LVIS_SELECTED)
remote_mem = RemoteMemoryBlock(self.listview_ctrl)
remote_mem.Write(lvitem, size=ctypes.sizeof(lvitem))
@ -721,10 +717,6 @@ class ListViewWrapper(hwndwrapper.HwndWrapper):
"TSysListView",
"ListView.*WndClass",
]
if sysinfo.UIA_support:
#controltypes is empty to make wrapper search result unique
#possible control types: IUIA().UIA_dll.UIA_ListControlTypeId
controltypes = []
#----------------------------------------------------------------
def __init__(self, hwnd):
@ -1424,7 +1416,7 @@ class _treeview_element(object):
item.pszText = remote_mem.Address() + ctypes.sizeof(item) + 16
item.cchTextMax = 2000
item.hItem = self.elem
item.stateMask = win32structures.UINT(-1)
item.stateMask = wintypes.UINT(-1)
# Write the local TVITEM structure to the remote memory block
remote_mem.Write(item)
@ -1460,8 +1452,6 @@ class TreeViewWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "TreeView"
windowclasses = [
"SysTreeView32", r"WindowsForms\d*\.SysTreeView32\..*", "TTreeView", "TreeList.TreeListCtrl"]
if sysinfo.UIA_support:
controltypes = [IUIA().UIA_dll.UIA_TreeControlTypeId]
#----------------------------------------------------------------
def __init__(self, hwnd):
@ -1751,8 +1741,6 @@ class HeaderWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "Header"
windowclasses = ["SysHeader32", "msvb_lib_header"]
if sysinfo.UIA_support:
controltypes = [IUIA().UIA_dll.UIA_HeaderControlTypeId]
#----------------------------------------------------------------
def __init__(self, hwnd):
@ -1894,8 +1882,6 @@ class StatusBarWrapper(hwndwrapper.HwndWrapper):
"msctls_statusbar32",
".*StatusBar",
r"WindowsForms\d*\.msctls_statusbar32\..*"]
if sysinfo.UIA_support:
controltypes = [IUIA().UIA_dll.UIA_StatusBarControlTypeId]
#----------------------------------------------------------------
def __init__(self, hwnd):
@ -2065,8 +2051,6 @@ class TabControlWrapper(hwndwrapper.HwndWrapper):
windowclasses = [
"SysTabControl32",
r"WindowsForms\d*\.SysTabControl32\..*"]
if sysinfo.UIA_support:
controltypes = [IUIA().UIA_dll.UIA_TabControlTypeId]
#----------------------------------------------------------------
def __init__(self, hwnd):
@ -2878,10 +2862,6 @@ class ReBarWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "ReBar"
windowclasses = ["ReBarWindow32", ]
if sysinfo.UIA_support:
#controltypes is empty to make wrapper search result unique
#possible control types: IUIA().UIA_dll.UIA_PaneControlTypeId
controltypes = []
#----------------------------------------------------------------
def __init__(self, hwnd):
@ -3086,8 +3066,6 @@ class UpDownWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "UpDown"
windowclasses = ["msctls_updown32", "msctls_updown", ]
if sysinfo.UIA_support:
controltypes = [IUIA().UIA_dll.UIA_SpinnerControlTypeId]
#----------------------------------------------------------------
def __init__(self, hwnd):
@ -3195,8 +3173,6 @@ class TrackbarWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "Trackbar"
windowclasses = ["msctls_trackbar", ]
if sysinfo.UIA_support:
controltypes = [IUIA().UIA_dll.UIA_SliderControlTypeId]
def get_range_min(self):
"""Get min available trackbar value"""
@ -3293,10 +3269,6 @@ class AnimationWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "Animation"
windowclasses = ["SysAnimate32", ]
if sysinfo.UIA_support:
#controltypes is empty to make wrapper search result unique
#possible control types: IUIA().UIA_dll.UIA_PaneControlTypeId
controltypes = []
#====================================================================
@ -3306,10 +3278,6 @@ class ComboBoxExWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "ComboBoxEx"
windowclasses = ["ComboBoxEx32", ]
if sysinfo.UIA_support:
#controltypes is empty to make wrapper search result unique
#possible control types: IUIA().UIA_dll.UIA_PaneControlTypeId
controltypes = []
has_title = False
@ -3321,10 +3289,6 @@ class DateTimePickerWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "DateTimePicker"
windowclasses = ["SysDateTimePick32",
r"WindowsForms\d*\.SysDateTimePick32\..*", ]
if sysinfo.UIA_support:
#controltypes is empty to make wrapper search result unique
#possible control types: IUIA().UIA_dll.UIA_PaneControlTypeId
controltypes = []
has_title = False
#----------------------------------------------------------------
@ -3387,10 +3351,6 @@ class HotkeyWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "Hotkey"
windowclasses = ["msctls_hotkey32", ]
if sysinfo.UIA_support:
#controltypes is empty to make wrapper search result unique
#possible control types: IUIA().UIA_dll.UIA_PaneControlTypeId
controltypes = []
has_title = False
@ -3401,10 +3361,6 @@ class IPAddressWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "IPAddress"
windowclasses = ["SysIPAddress32", ]
if sysinfo.UIA_support:
#controltypes is empty to make wrapper search result unique
#possible control types: IUIA().UIA_dll.UIA_PaneControlTypeId
controltypes = []
has_title = False
@ -3415,8 +3371,6 @@ class CalendarWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "Calendar"
windowclasses = ["SysMonthCal32", ]
if sysinfo.UIA_support:
controltypes = [IUIA().UIA_dll.UIA_CalendarControlTypeId]
has_title = False
place_in_calendar = {
@ -3719,10 +3673,6 @@ class PagerWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "Pager"
windowclasses = ["SysPager", ]
if sysinfo.UIA_support:
#controltypes is empty to make wrapper search result unique
#possible control types: IUIA().UIA_dll.UIA_PaneControlTypeId
controltypes = []
#----------------------------------------------------------------
def get_position(self):
@ -3748,8 +3698,6 @@ class ProgressWrapper(hwndwrapper.HwndWrapper):
friendlyclassname = "Progress"
windowclasses = ["msctls_progress", "msctls_progress32", ]
if sysinfo.UIA_support:
controltypes = [IUIA().UIA_dll.UIA_ProgressBarControlTypeId]
has_title = False
#----------------------------------------------------------------

@ -493,7 +493,7 @@ class HwndWrapper(BaseWrapper):
(e.g. VK_LEFT, VK_DELETE), a KeySequenceError is raised. Consider using
the method send_keystrokes for such input.
"""
input_locale_id = ctypes.windll.User32.GetKeyboardLayout(0)
input_locale_id = win32functions.GetKeyboardLayout(0)
keys = keyboard.parse_keys(chars, with_spaces, with_tabs, with_newlines)
for key in keys:
@ -506,11 +506,11 @@ class HwndWrapper(BaseWrapper):
if unicode_char:
_, char = key_info[:2]
vk = ctypes.windll.User32.VkKeyScanExW(char, input_locale_id) & 0xFF
scan = keyboard.MapVirtualKey(vk, 0)
vk = win32functions.VkKeyScanExW(chr(char), input_locale_id) & 0xFF
scan = win32functions.MapVirtualKeyW(vk, 0)
else:
vk, scan = key_info[:2]
char = keyboard.MapVirtualKey(vk, 2)
char = win32functions.MapVirtualKeyW(vk, 2)
if char > 0:
lparam = 1 << 0 | scan << 16 | (flags & 1) << 24
@ -541,22 +541,21 @@ class HwndWrapper(BaseWrapper):
.. _`type_keys`: pywinauto.base_wrapper.html#pywinauto.base_wrapper.BaseWrapper.type_keys
"""
user32 = ctypes.windll.User32
PBYTE256 = ctypes.c_ubyte * 256
win32gui.SendMessage(self.handle, win32con.WM_ACTIVATE,
win32con.WA_ACTIVE, 0)
target_thread_id = user32.GetWindowThreadProcessId(self.handle, None)
current_thread_id = win32api.GetCurrentThreadId()
attach_success = user32.AttachThreadInput(target_thread_id, current_thread_id, True) != 0
target_thread_id = win32functions.GetWindowThreadProcessId(self.handle, None)
current_thread_id = win32functions.GetCurrentThreadId()
attach_success = win32functions.AttachThreadInput(target_thread_id, current_thread_id, True) != 0
if not attach_success:
warnings.warn('Failed to attach app\'s thread to the current thread\'s message queue',
UserWarning, stacklevel=2)
keyboard_state_stack = [PBYTE256()]
user32.GetKeyboardState(ctypes.byref(keyboard_state_stack[-1]))
win32functions.GetKeyboardState(keyboard_state_stack[-1])
input_locale_id = ctypes.windll.User32.GetKeyboardLayout(0)
input_locale_id = win32functions.GetKeyboardLayout(0)
context_code = 0
keys = keyboard.parse_keys(keystrokes, with_spaces, with_tabs, with_newlines)
@ -578,11 +577,11 @@ class HwndWrapper(BaseWrapper):
shift_state = 0
unicode_codepoint = flags & keyboard.KEYEVENTF_UNICODE != 0
if unicode_codepoint:
char = scan
vk_with_flags = user32.VkKeyScanExW(char, input_locale_id)
char = chr(scan)
vk_with_flags = win32functions.VkKeyScanExW(char, input_locale_id)
vk = vk_with_flags & 0xFF
shift_state = (vk_with_flags & 0xFF00) >> 8
scan = keyboard.MapVirtualKey(vk, 0)
scan = win32functions.MapVirtualKeyW(vk, 0)
if key.down and vk > 0:
new_keyboard_state = copy.deepcopy(keyboard_state_stack[-1])
@ -602,8 +601,8 @@ class HwndWrapper(BaseWrapper):
context_code << 29 |
0 << 31)
user32.SetKeyboardState(ctypes.byref(keyboard_state_stack[-1]))
win32api.PostMessage(self.handle, down_msg, vk, lparam)
win32functions.SetKeyboardState(keyboard_state_stack[-1])
win32functions.PostMessage(self.handle, down_msg, vk, lparam)
if vk == keyboard.VK_MENU:
context_code = 1
@ -621,8 +620,8 @@ class HwndWrapper(BaseWrapper):
1 << 30 |
1 << 31)
win32api.PostMessage(self.handle, up_msg, vk, lparam)
user32.SetKeyboardState(ctypes.byref(keyboard_state_stack[-1]))
win32functions.PostMessage(self.handle, up_msg, vk, lparam)
win32functions.SetKeyboardState(keyboard_state_stack[-1])
if vk == keyboard.VK_MENU:
context_code = 0
@ -636,10 +635,10 @@ class HwndWrapper(BaseWrapper):
UserWarning, stacklevel=2)
else:
warnings.warn(e.strerror, UserWarning, stacklevel=2)
user32.SetKeyboardState(ctypes.byref(keyboard_state_stack[0]))
win32functions.SetKeyboardState(keyboard_state_stack[0])
if attach_success:
user32.AttachThreadInput(target_thread_id, current_thread_id, False)
win32functions.AttachThreadInput(target_thread_id, current_thread_id, False)
# -----------------------------------------------------------
def send_message_timeout(
@ -1256,7 +1255,7 @@ class HwndWrapper(BaseWrapper):
"""Return a handle to the active window within the process"""
gui_info = win32structures.GUITHREADINFO()
gui_info.cbSize = ctypes.sizeof(gui_info)
window_thread_id, _ = win32process.GetWindowThreadProcessId(int(self.handle))
window_thread_id = win32functions.GetWindowThreadProcessId(self.handle, None)
ret = win32functions.GetGUIThreadInfo(
window_thread_id,
ctypes.byref(gui_info))
@ -1278,7 +1277,7 @@ class HwndWrapper(BaseWrapper):
"""
gui_info = win32structures.GUITHREADINFO()
gui_info.cbSize = ctypes.sizeof(gui_info)
window_thread_id, _ = win32process.GetWindowThreadProcessId(self.handle)
window_thread_id = win32functions.GetWindowThreadProcessId(self.handle, None)
ret = win32functions.GetGUIThreadInfo(
window_thread_id,
ctypes.byref(gui_info))
@ -1335,7 +1334,7 @@ class HwndWrapper(BaseWrapper):
def has_keyboard_focus(self):
"""Check the keyboard focus on this control."""
control_thread = win32process.GetWindowThreadProcessId(self.handle)[0]
control_thread = win32functions.GetWindowThreadProcessId(self.handle, None)
win32process.AttachThreadInput(control_thread, win32api.GetCurrentThreadId(), 1)
focused = win32gui.GetFocus()
win32process.AttachThreadInput(control_thread, win32api.GetCurrentThreadId(), 0)
@ -1346,9 +1345,9 @@ class HwndWrapper(BaseWrapper):
def set_keyboard_focus(self):
"""Set the keyboard focus to this control."""
control_thread = win32process.GetWindowThreadProcessId(self.handle)[0]
control_thread = win32functions.GetWindowThreadProcessId(self.handle, None)
win32process.AttachThreadInput(control_thread, win32api.GetCurrentThreadId(), 1)
win32gui.SetFocus(self.handle)
win32functions.SetFocus(self.handle)
win32process.AttachThreadInput(control_thread, win32api.GetCurrentThreadId(), 0)
win32functions.WaitGuiThreadIdle(self.handle)
@ -1602,12 +1601,13 @@ class DialogWrapper(HwndWrapper):
#win32defines.SMTO_BLOCK)
# get a handle we can wait on
_, pid = win32process.GetWindowThreadProcessId(int(self.handle))
pid = ctypes.c_ulong()
win32functions.GetWindowThreadProcessId(self.handle, ctypes.byref(pid))
try:
process_wait_handle = win32api.OpenProcess(
win32con.SYNCHRONIZE | win32con.PROCESS_TERMINATE,
0,
pid)
pid.value)
except win32gui.error:
return True # already closed
@ -1723,7 +1723,7 @@ def _perform_click(
# figure out the flags and pack coordinates
flags, click_point = _calc_flags_and_coords(pressed, coords)
#control_thread = win32functions.GetWindowThreadProcessId(ctrl, 0)
#control_thread = win32functions.GetWindowThreadProcessId(ctrl, None)
#win32functions.AttachThreadInput(win32functions.GetCurrentThreadId(), control_thread, win32defines.TRUE)
# TODO: check return value of AttachThreadInput properly

@ -283,7 +283,7 @@ class MenuItem(object):
# if the item is not visible - work up along it's parents
# until we find an item we CAN click on
if rect == (0, 0, 0, 0) and self.menu.owner_item:
if rect == win32structures.RECT(0, 0, 0, 0) and self.menu.owner_item:
self.menu.owner_item.click_input()
rect = self.rectangle()

@ -200,7 +200,11 @@ class ComboBoxWrapper(uiawrapper.UIAWrapper):
# -----------------------------------------------------------
def texts(self):
"""Return the text of the items in the combobox"""
texts = []
texts = self._texts_from_item_container()
if len(texts):
# flatten the list
return [ t for lst in texts for t in lst ]
# ComboBox has to be expanded to populate a list of its children items
try:
super(ComboBoxWrapper, self).expand()
@ -370,6 +374,11 @@ class EditWrapper(uiawrapper.UIAWrapper):
"""Return the current value of the element"""
return self.iface_value.CurrentValue
# -----------------------------------------------------------
def is_editable(self):
"""Return the edit possibility of the element"""
return not self.iface_value.CurrentIsReadOnly
# -----------------------------------------------------------
def texts(self):
"""Get the text of the edit control"""
@ -846,10 +855,19 @@ class ListViewWrapper(uiawrapper.UIAWrapper):
raise ValueError("Element '{0}' not found".format(row))
elif isinstance(row, six.integer_types):
# Get the item by a row index
# TODO: Can't get virtualized items that way
# TODO: See TODO section of item_count() method for details
list_items = self.children(content_only=True)
itm = list_items[self.__resolve_row_index(row)]
try:
com_elem = 0
for _ in range(0, self.__resolve_row_index(row) + 1):
com_elem = self.iface_item_container.FindItemByProperty(com_elem, 0, uia_defs.vt_empty)
# Try to load element using VirtualizedItem pattern
try:
get_elem_interface(com_elem, "VirtualizedItem").Realize()
except NoPatternInterfaceError:
pass
itm = uiawrapper.UIAWrapper(uia_element_info.UIAElementInfo(com_elem))
except (NoPatternInterfaceError, ValueError, AttributeError):
list_items = self.children(content_only=True)
itm = list_items[self.__resolve_row_index(row)]
else:
raise TypeError("String type or integer is expected")
@ -960,18 +978,18 @@ class MenuWrapper(uiawrapper.UIAWrapper):
return item
# -----------------------------------------------------------
@staticmethod
def _activate(item):
def _activate(self, item, is_last):
"""Activate the specified item"""
if not item.is_active():
item.set_focus()
try:
item.expand()
except(NoPatternInterfaceError):
pass
if self.element_info.framework_id == 'WinForm' and not is_last:
item.select()
# -----------------------------------------------------------
def _sub_item_by_text(self, menu, name, exact):
def _sub_item_by_text(self, menu, name, exact, is_last):
"""Find a menu sub-item by the specified text"""
sub_item = None
items = menu.items()
@ -987,18 +1005,18 @@ class MenuWrapper(uiawrapper.UIAWrapper):
texts.append(i.window_text())
sub_item = findbestmatch.find_best_match(name, texts, items)
self._activate(sub_item)
self._activate(sub_item, is_last)
return sub_item
# -----------------------------------------------------------
def _sub_item_by_idx(self, menu, idx):
def _sub_item_by_idx(self, menu, idx, is_last):
"""Find a menu sub-item by the specified index"""
sub_item = None
items = menu.items()
if items:
sub_item = items[idx]
self._activate(sub_item)
self._activate(sub_item, is_last)
return sub_item
# -----------------------------------------------------------
@ -1011,35 +1029,39 @@ class MenuWrapper(uiawrapper.UIAWrapper):
Note: $ - specifier is not supported
"""
# Get the path parts
part0, parts = path.split("->", 1)
part0 = part0.strip()
if len(part0) == 0:
menu_items = [p.strip() for p in path.split("->")]
items_cnt = len(menu_items)
if items_cnt == 0:
raise IndexError()
for item in menu_items:
if not item:
raise IndexError("Empty item name between '->' separators")
def next_level_menu(parent_menu, item_name, is_last):
if item_name.startswith("#"):
return self._sub_item_by_idx(parent_menu, int(item_name[1:]), is_last)
else:
return self._sub_item_by_text(parent_menu, item_name, exact, is_last)
# Find a top level menu item and select it. After selecting this item
# a new Menu control is created and placed on the dialog. It can be
# a direct child or a descendant.
# Sometimes we need to re-discover Menu again
try:
menu = None
if part0.startswith("#"):
menu = self._sub_item_by_idx(self, int(part0[1:]))
else:
menu = self._sub_item_by_text(self, part0, exact)
menu = next_level_menu(self, menu_items[0], items_cnt == 1)
if items_cnt == 1:
return menu
if not menu.items():
self._activate(menu)
self._activate(menu, False)
timings.wait_until(
timings.Timings.window_find_timeout,
timings.Timings.window_find_retry,
lambda: len(self.top_level_parent().descendants(control_type="Menu")) > 0)
menu = self.top_level_parent().descendants(control_type="Menu")[0]
for cur_part in [p.strip() for p in parts.split("->")]:
if cur_part.startswith("#"):
menu = self._sub_item_by_idx(menu, int(cur_part[1:]))
else:
menu = self._sub_item_by_text(menu, cur_part, exact)
for i in range(1, items_cnt):
menu = next_level_menu(menu, menu_items[i], items_cnt == i + 1)
except(AttributeError):
raise IndexError()

@ -782,5 +782,19 @@ class UIAWrapper(BaseWrapper):
return self
# -----------------------------------------------------------
def _texts_from_item_container(self):
"""Get texts through the ItemContainer interface"""
texts = []
try:
com_elem = self.iface_item_container.FindItemByProperty(0, 0, uia_defs.vt_empty)
while com_elem:
itm = UIAWrapper(UIAElementInfo(com_elem))
texts.append(itm.texts())
com_elem = self.iface_item_container.FindItemByProperty(com_elem, 0, uia_defs.vt_empty)
except (uia_defs.NoPatternInterfaceError):
pass
return texts
backend.register('uia', UIAElementInfo, UIAWrapper)

@ -331,8 +331,9 @@ def get_control_names(control, allcontrols, textcontrols):
if non_text_names:
names.extend(non_text_names)
# return the names - and make sure there are no duplicates
return set(names)
# return the names - and make sure there are no duplicates or empty values
cleaned_names = set(names) - set([None, ""])
return cleaned_names
#====================================================================
@ -493,6 +494,8 @@ def find_best_control_matches(search_text, controls):
"""
name_control_map = build_unique_dict(controls)
#print ">>>>>>>", repr(name_control_map).decode("ascii", "ignore")
# # collect all the possible names for all controls
# # and build a list of them
# for ctrl in controls:

@ -189,9 +189,10 @@ def find_elements(class_name=None,
if top_level_only:
# find the top level elements
element = backend_obj.element_info_class()
# vryabov: we don't use title=title below, because it fixes issue 779:
# https://github.com/pywinauto/pywinauto/issues/779
elements = element.children(process=process,
class_name=class_name,
title=title,
control_type=control_type,
cache_enable=True)
@ -206,8 +207,9 @@ def find_elements(class_name=None,
parent = backend_obj.element_info_class()
# look for ALL children of that parent
# vryabov: we don't use title=title below, because it fixes issue 779:
# https://github.com/pywinauto/pywinauto/issues/779
elements = parent.descendants(class_name=class_name,
title=title,
control_type=control_type,
cache_enable=True,
depth=depth)

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save