diff --git a/Orchestrator/Settings/SettingsOrchestratorExample.py b/Orchestrator/Settings/SettingsOrchestratorExample.py index 8ea03d75..cef3d46f 100644 --- a/Orchestrator/Settings/SettingsOrchestratorExample.py +++ b/Orchestrator/Settings/SettingsOrchestratorExample.py @@ -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) # { diff --git a/Orchestrator/Template_Settings_AccessUser.py b/Orchestrator/Template_Settings_AccessUser.py index 1b7febbd..9c167175 100644 --- a/Orchestrator/Template_Settings_AccessUser.py +++ b/Orchestrator/Template_Settings_AccessUser.py @@ -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 diff --git a/README.md b/README.md index fb31e5a7..d31d63f0 100644 --- a/README.md +++ b/README.md @@ -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":, + "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) \ No newline at end of file +Created by Ivan Maslov (Russia) \ No newline at end of file diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.3.dist-info/INSTALLER b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse-0.7.1.dist-info/INSTALLER similarity index 100% rename from Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.3.dist-info/INSTALLER rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse-0.7.1.dist-info/INSTALLER diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse-0.7.1.dist-info/LICENSE.txt b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse-0.7.1.dist-info/LICENSE.txt new file mode 100644 index 00000000..4f3cb7b8 --- /dev/null +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse-0.7.1.dist-info/LICENSE.txt @@ -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. diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse-0.7.1.dist-info/METADATA b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse-0.7.1.dist-info/METADATA new file mode 100644 index 00000000..c6dfc0d2 --- /dev/null +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse-0.7.1.dist-info/METADATA @@ -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. + + diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse-0.7.1.dist-info/RECORD b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse-0.7.1.dist-info/RECORD new file mode 100644 index 00000000..c46d9df0 --- /dev/null +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse-0.7.1.dist-info/RECORD @@ -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 diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pywinauto-0.6.6.dist-info/WHEEL b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse-0.7.1.dist-info/WHEEL similarity index 54% rename from Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pywinauto-0.6.6.dist-info/WHEEL rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse-0.7.1.dist-info/WHEEL index bb7f7dba..8b701e93 100644 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pywinauto-0.6.6.dist-info/WHEEL +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse-0.7.1.dist-info/WHEEL @@ -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 diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse-0.7.1.dist-info/top_level.txt b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse-0.7.1.dist-info/top_level.txt new file mode 100644 index 00000000..3e41be96 --- /dev/null +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse-0.7.1.dist-info/top_level.txt @@ -0,0 +1 @@ +mouse diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/__init__.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/__init__.py new file mode 100644 index 00000000..3a21f46e --- /dev/null +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/__init__.py @@ -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()) diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/__main__.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/__main__.py new file mode 100644 index 00000000..1a84defc --- /dev/null +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/__main__.py @@ -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()) \ No newline at end of file diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/_generic.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/_generic.py new file mode 100644 index 00000000..04f029e7 --- /dev/null +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/_generic.py @@ -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) diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/_mouse_event.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/_mouse_event.py new file mode 100644 index 00000000..38b89610 --- /dev/null +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/_mouse_event.py @@ -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']) diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/_mouse_tests.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/_mouse_tests.py new file mode 100644 index 00000000..b3e9f9ad --- /dev/null +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/_mouse_tests.py @@ -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() diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/_nixcommon.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/_nixcommon.py new file mode 100644 index 00000000..d240f998 --- /dev/null +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/_nixcommon.py @@ -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.') diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/_nixmouse.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/_nixmouse.py new file mode 100644 index 00000000..5e3b595d --- /dev/null +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/_nixmouse.py @@ -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) diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/_winmouse.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/_winmouse.py new file mode 100644 index 00000000..b5806a22 --- /dev/null +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/mouse/_winmouse.py @@ -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) diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pywinauto-0.6.6.dist-info/INSTALLER b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.13.dist-info/INSTALLER similarity index 100% rename from Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pywinauto-0.6.6.dist-info/INSTALLER rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.13.dist-info/INSTALLER diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.3.dist-info/METADATA b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.13.dist-info/METADATA similarity index 58% rename from Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.3.dist-info/METADATA rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.13.dist-info/METADATA index b9dc232e..37aee8b7 100644 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.3.dist-info/METADATA +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.13.dist-info/METADATA @@ -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 } ] diff --git a/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.1.3.dist-info/RECORD b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.13.dist-info/RECORD similarity index 96% rename from Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.1.3.dist-info/RECORD rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.13.dist-info/RECORD index 0703f47b..c2187512 100644 --- a/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.1.3.dist-info/RECORD +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.13.dist-info/RECORD @@ -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 diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.3.dist-info/WHEEL b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.13.dist-info/WHEEL similarity index 100% rename from Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.3.dist-info/WHEEL rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.13.dist-info/WHEEL diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.3.dist-info/top_level.txt b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.13.dist-info/top_level.txt similarity index 100% rename from Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.3.dist-info/top_level.txt rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.1.13.dist-info/top_level.txt diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Processor.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Processor.py index b1800f58..18f51448 100644 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Processor.py +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Processor.py @@ -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", diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/RobotRDPActive/Connector.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/RobotRDPActive/Connector.py index 0d969130..ff93abd7 100644 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/RobotRDPActive/Connector.py +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/RobotRDPActive/Connector.py @@ -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 \ No newline at end of file + 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) \ No newline at end of file diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/RobotRDPActive/Processor.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/RobotRDPActive/Processor.py index 3b670128..39e6d05e 100644 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/RobotRDPActive/Processor.py +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/RobotRDPActive/Processor.py @@ -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 diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Server.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Server.py index be70002d..6780730c 100644 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Server.py +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Server.py @@ -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 diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/ServerSettings.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/ServerSettings.py index e30e1c30..8bba61d8 100644 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/ServerSettings.py +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/ServerSettings.py @@ -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 \ No newline at end of file diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Web/Index.xhtml b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Web/Index.xhtml index db422ff4..7e51d4c4 100644 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Web/Index.xhtml +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Orchestrator/Web/Index.xhtml @@ -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 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 }) ; @@ -766,75 +782,20 @@

...

-

Robot RDP active list

+
- - - - @@ -766,75 +782,20 @@

...

-

Robot RDP active list

+
- - - - @@ -766,75 +782,20 @@

...

-

Robot RDP active list

+
- - - -