From 88ce6933567d9954b99f6764d1be61191f83ee3e Mon Sep 17 00:00:00 2001 From: JeffreyChen Date: Sat, 18 Apr 2026 00:13:04 +0800 Subject: [PATCH 1/4] Enforce CLAUDE.md: restrict executor, pin deps, drop dead code - Remove Python builtins injection into executor event_dict so only AC_-prefixed allowlist is callable via JSON/socket payloads. - Pin core and platform dependencies in pyproject.toml and align PySide6 between pyproject, requirements, and dev_requirements. - Make create_project_dir's lock module-level and cover all writes. - Replace get_dir_files_as_list's mutable getcwd() default with None sentinel evaluated per call. - Remove unused imports and deduplicate __all__. --- CLAUDE.md | 135 ++++++++++++++++++ dev_requirements.txt | 6 +- je_auto_control/__init__.py | 4 +- je_auto_control/gui/main_widget.py | 9 +- je_auto_control/gui/main_window.py | 1 - je_auto_control/osx/screen/osx_screen.py | 2 +- .../utils/executor/action_executor.py | 6 - .../utils/file_process/get_dir_file_list.py | 8 +- .../utils/project/create_project_structure.py | 19 +-- .../change_xml_structure.py | 2 +- .../windows/window/windows_window_manage.py | 2 +- je_auto_control/wrapper/auto_control_image.py | 2 +- pyproject.toml | 14 +- requirements.txt | 6 +- 14 files changed, 172 insertions(+), 44 deletions(-) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..23aec59 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,135 @@ +# CLAUDE.md — AutoControl + +## Project Overview + +AutoControl (`je_auto_control`) is a cross-platform Python GUI automation framework supporting Windows (Win32 API), macOS (pyobjc/Quartz), and Linux (X11). It provides mouse/keyboard control, image recognition, screen capture, action scripting, and report generation through a unified API. + +- **Package name**: `je_auto_control` +- **Python**: >= 3.10 +- **License**: MIT +- **Author**: JE-Chen + +## Architecture & Design Patterns + +### Strategy Pattern — Platform Abstraction + +`wrapper/platform_wrapper.py` auto-detects the OS and loads the correct backend. All wrapper modules (`auto_control_mouse.py`, `auto_control_keyboard.py`, etc.) delegate to the platform-specific implementation. New platform support is added by implementing the backend interface — no wrapper changes needed. + +### Facade Pattern — Unified API Surface + +`je_auto_control/__init__.py` re-exports all public functions from wrapper and utility modules, providing a single entry point. Users import only `je_auto_control` and access all features. + +### Command Pattern — JSON Action Executor + +`utils/executor/action_executor.py` maps string command names (e.g., `AC_click_mouse`) to callable functions. JSON action files define sequences of commands with parameters, enabling recording, serialization, and replay of automation flows. + +### Observer Pattern — Callback Executor + +`utils/callback/callback_function_executor.py` allows registering callback functions that fire after automation actions complete, supporting event-driven chaining. + +### Template Method — Report Generation + +`utils/generate_report/` provides HTML, JSON, and XML report generators sharing a common structure: collect test records, format output, write file. Each format implements its own rendering. + +## Directory Structure + +``` +je_auto_control/ +├── wrapper/ # Platform-agnostic API (Strategy consumers) +├── windows/ # Win32 backend (ctypes) +├── osx/ # macOS backend (pyobjc/Quartz) +├── linux_with_x11/ # Linux X11 backend (python-Xlib) +├── gui/ # PySide6 GUI application +└── utils/ + ├── executor/ # JSON action executor (Command pattern) + ├── callback/ # Callback executor (Observer pattern) + ├── cv2_utils/ # OpenCV: screenshot, template matching, video + ├── socket_server/ # TCP server for remote automation + ├── shell_process/ # Shell command manager + ├── generate_report/ # HTML/JSON/XML report generators + ├── test_record/ # Test action recording + ├── json/ # JSON action file I/O + ├── project/ # Project scaffolding + ├── package_manager/ # Dynamic package loading + ├── logging/ # Logging + └── exception/ # Custom exceptions +``` + +## Development Commands + +```bash +# Install dependencies +pip install -r dev_requirements.txt + +# Install with GUI support +pip install -e .[gui] + +# Run unit tests +python -m pytest test/unit_test/ + +# Run integration tests +python -m pytest test/integrated_test/ + +# Build package +python -m build +``` + +## Coding Standards + +### Security First + +- **Input validation**: Validate all external inputs (user input, file content, network data, JSON action commands) at system boundaries. Sanitize file paths to prevent path traversal. Never trust data from TCP socket clients without validation. +- **Injection prevention**: When executing shell commands (`shell_process`), never construct command strings from unsanitized input. Use parameterized approaches or allowlists. +- **Deserialization safety**: JSON action files and socket server payloads must be validated against expected schemas before execution. Reject unknown command names. +- **No secrets in code**: Never commit credentials, API keys, tokens, or `.env` files. Keep secrets out of logs and reports. +- **Principle of least privilege**: Socket server should bind to localhost by default. Document security implications of exposing to network. +- **Dependency awareness**: Pin dependency versions. Review transitive dependencies for known vulnerabilities. + +### Performance Best Practices + +- **Lazy imports**: Platform-specific backends are loaded only for the current OS — do not import all backends unconditionally. +- **Avoid redundant screenshots**: Image recognition operations should reuse screen captures when performing multiple searches on the same frame. +- **Buffer management**: Screen recording and video capture must properly release resources (file handles, codec buffers) in `finally` blocks or context managers. +- **Thread safety**: Socket server and recording threads must use proper synchronization. Avoid shared mutable state without locks. +- **Minimize allocations in hot paths**: Mouse/keyboard event dispatch should avoid unnecessary object creation per event. + +### Software Engineering Principles + +- **SOLID**: Each module has a single responsibility. Platform backends are open for extension (new OS) without modifying wrappers. Depend on abstractions (wrapper API), not concrete implementations (Win32/X11/Quartz). +- **DRY**: Common logic belongs in `wrapper/` or `utils/`, not duplicated across platform backends. +- **YAGNI**: Do not add speculative features. Implement what is needed now. +- **Fail fast**: Raise clear, specific exceptions (`AutoControlMouseException`, `AutoControlKeyboardException`, etc.) at the point of failure. Do not silently swallow errors. +- **Immutable data where possible**: Action lists and configuration should be treated as read-only once loaded. + +### Code Style + +- Follow PEP 8. +- Use type hints for all public function signatures. +- Keep functions focused and short — one function, one task. +- Prefer composition over inheritance for extending functionality. +- Remove dead code immediately — no commented-out blocks, no unused imports, no unreachable branches. + +## Commit Conventions + +- Write concise commit messages focused on **why**, not what. +- **Do not mention any AI tools, assistants, or models in commit messages** — no "Co-Authored-By" AI attributions, no references to AI-generated code. +- Use imperative mood: "Add feature", "Fix bug", "Remove unused code". +- Examples: + - `Add image threshold parameter validation` + - `Fix mouse scroll direction on macOS` + - `Remove deprecated screen capture fallback` + +## Testing + +- **Unit tests**: `test/unit_test/` — test individual functions in isolation. +- **Integration tests**: `test/integrated_test/` — test cross-module workflows. +- **Manual tests**: `test/manual_test/` — require human verification (GUI, visual). +- **GUI tests**: `test/gui_test/` — PySide6 interface tests. +- All tests must pass before merging. Ensure cross-platform compatibility. + +## Key Conventions + +- All public API functions are exported from `je_auto_control/__init__.py` and listed in `__all__`. +- JSON action command names use `AC_` prefix (e.g., `AC_click_mouse`). +- Platform backends follow naming: `{platform}_{function}.py` (e.g., `win32_ctype_mouse_control.py`). +- Virtual key mappings are in `core/utils/*_vk.py` per platform. diff --git a/dev_requirements.txt b/dev_requirements.txt index 7d49704..e6cf0ec 100644 --- a/dev_requirements.txt +++ b/dev_requirements.txt @@ -4,6 +4,6 @@ build twine sphinx sphinx-rtd-theme -Pyside6==6.10.1 -qt-material -mss +PySide6==6.11.0 +qt-material==2.17 +mss==10.1.0 diff --git a/je_auto_control/__init__.py b/je_auto_control/__init__.py index c25e439..25148f9 100644 --- a/je_auto_control/__init__.py +++ b/je_auto_control/__init__.py @@ -99,7 +99,7 @@ from je_auto_control.wrapper.auto_control_mouse import send_mouse_event_to_window from je_auto_control.wrapper.auto_control_mouse import set_mouse_position from je_auto_control.wrapper.auto_control_mouse import special_mouse_keys_table -# test_record +# record from je_auto_control.wrapper.auto_control_record import record from je_auto_control.wrapper.auto_control_record import stop_record # import screen @@ -120,7 +120,7 @@ "AutoControlScreenException", "ImageNotFoundException", "AutoControlJsonActionException", "AutoControlRecordException", "AutoControlActionNullException", "AutoControlActionException", "record", "stop_record", "read_action_json", "write_action_json", "execute_action", "execute_files", "executor", - "add_command_to_executor", "test_record_instance", "screenshot", "pil_screenshot", + "add_command_to_executor", "test_record_instance", "pil_screenshot", "generate_html", "generate_html_report", "generate_json", "generate_json_report", "generate_xml", "generate_xml_report", "get_dir_files_as_list", "create_project_dir", "start_autocontrol_socket_server", "callback_executor", "package_manager", "ShellManager", "default_shell_manager", diff --git a/je_auto_control/gui/main_widget.py b/je_auto_control/gui/main_widget.py index 7843d4d..fe5e440 100644 --- a/je_auto_control/gui/main_widget.py +++ b/je_auto_control/gui/main_widget.py @@ -1,22 +1,19 @@ import json -import sys -from threading import Thread from PySide6.QtCore import QTimer, Signal, QObject from PySide6.QtGui import QIntValidator, QDoubleValidator, QKeyEvent, Qt from PySide6.QtWidgets import ( QWidget, QLineEdit, QComboBox, QPushButton, QVBoxLayout, QLabel, QGridLayout, QHBoxLayout, QRadioButton, QButtonGroup, QMessageBox, - QTabWidget, QTextEdit, QFileDialog, QCheckBox, QGroupBox, QSplitter, - QListWidget + QTabWidget, QTextEdit, QFileDialog, QCheckBox, QGroupBox ) from je_auto_control.gui.language_wrapper.multi_language_wrapper import language_wrapper from je_auto_control.wrapper.auto_control_keyboard import ( - type_keyboard, press_keyboard_key, release_keyboard_key, hotkey, write, check_key_is_press + type_keyboard, hotkey, write ) from je_auto_control.wrapper.auto_control_mouse import ( - click_mouse, get_mouse_position, set_mouse_position, press_mouse, release_mouse, mouse_scroll + click_mouse, get_mouse_position, mouse_scroll ) from je_auto_control.wrapper.auto_control_screen import screen_size, screenshot, get_pixel from je_auto_control.wrapper.auto_control_image import locate_all_image, locate_image_center, locate_and_click diff --git a/je_auto_control/gui/main_window.py b/je_auto_control/gui/main_window.py index 3d8751c..4774afc 100644 --- a/je_auto_control/gui/main_window.py +++ b/je_auto_control/gui/main_window.py @@ -1,7 +1,6 @@ import sys from PySide6.QtWidgets import QMainWindow, QApplication, QComboBox, QLabel, QHBoxLayout, QWidget -from PySide6.QtGui import QAction from qt_material import QtStyleTools from je_auto_control.gui.language_wrapper.multi_language_wrapper import language_wrapper diff --git a/je_auto_control/osx/screen/osx_screen.py b/je_auto_control/osx/screen/osx_screen.py index be82b17..85a2f99 100644 --- a/je_auto_control/osx/screen/osx_screen.py +++ b/je_auto_control/osx/screen/osx_screen.py @@ -1,6 +1,6 @@ import sys import ctypes -from ctypes import c_void_p, c_double, c_uint32 +from ctypes import c_void_p, c_uint32 from typing import Tuple from je_auto_control.utils.exception.exception_tags import osx_import_error_message diff --git a/je_auto_control/utils/executor/action_executor.py b/je_auto_control/utils/executor/action_executor.py index aca52d2..d20e4d7 100644 --- a/je_auto_control/utils/executor/action_executor.py +++ b/je_auto_control/utils/executor/action_executor.py @@ -1,6 +1,4 @@ -import builtins import types -from inspect import getmembers, isbuiltin from typing import Any, Dict, List, Union from je_auto_control.utils.exception.exception_tags import ( @@ -107,10 +105,6 @@ def __init__(self): "AC_execute_process": start_exe, } - # 加入所有 Python 內建函式 Add all Python builtins - for function in getmembers(builtins, isbuiltin): - self.event_dict[str(function[0])] = function[1] - def _execute_event(self, action: list) -> Any: """ 執行單一事件 diff --git a/je_auto_control/utils/file_process/get_dir_file_list.py b/je_auto_control/utils/file_process/get_dir_file_list.py index 3a6ce10..da8dfec 100644 --- a/je_auto_control/utils/file_process/get_dir_file_list.py +++ b/je_auto_control/utils/file_process/get_dir_file_list.py @@ -1,20 +1,22 @@ from os import getcwd, walk from os.path import abspath, join -from typing import List +from typing import List, Optional def get_dir_files_as_list( - dir_path: str = getcwd(), + dir_path: Optional[str] = None, default_search_file_extension: str = ".json" ) -> List[str]: """ Get all files in a directory that end with a specific extension. 遍歷指定目錄,取得所有符合副檔名的檔案清單 - :param dir_path: Directory path to search 要搜尋的目錄路徑 + :param dir_path: Directory path to search 要搜尋的目錄路徑 (預設為呼叫時的當前工作目錄) :param default_search_file_extension: File extension to filter 要搜尋的副檔名 (預設 ".json") :return: List of absolute file paths 符合條件的檔案絕對路徑清單 """ + if dir_path is None: + dir_path = getcwd() extension = default_search_file_extension.lower() return [ abspath(join(root, file)) diff --git a/je_auto_control/utils/project/create_project_structure.py b/je_auto_control/utils/project/create_project_structure.py index c2726ec..26f1474 100644 --- a/je_auto_control/utils/project/create_project_structure.py +++ b/je_auto_control/utils/project/create_project_structure.py @@ -11,6 +11,8 @@ template_keyword_1, template_keyword_2, bad_template_1 ) +_project_lock = Lock() + def create_dir(dir_name: str) -> None: """ @@ -47,17 +49,16 @@ def create_template(parent_name: str, project_path: str = None) -> None: keyword_dir_path = Path(project_path) / parent_name / "keyword" executor_dir_path = Path(project_path) / parent_name / "executor" - lock = Lock() - # 建立 keyword JSON 檔案 Create keyword JSON files - if keyword_dir_path.exists() and keyword_dir_path.is_dir(): - write_action_json(str(keyword_dir_path / "keyword1.json"), template_keyword_1) - write_action_json(str(keyword_dir_path / "keyword2.json"), template_keyword_2) - write_action_json(str(keyword_dir_path / "bad_keyword_1.json"), bad_template_1) + with _project_lock: + # 建立 keyword JSON 檔案 Create keyword JSON files + if keyword_dir_path.exists() and keyword_dir_path.is_dir(): + write_action_json(str(keyword_dir_path / "keyword1.json"), template_keyword_1) + write_action_json(str(keyword_dir_path / "keyword2.json"), template_keyword_2) + write_action_json(str(keyword_dir_path / "bad_keyword_1.json"), bad_template_1) - # 建立 executor Python 檔案 Create executor Python files - if executor_dir_path.exists() and executor_dir_path.is_dir(): - with lock: + # 建立 executor Python 檔案 Create executor Python files + if executor_dir_path.exists() and executor_dir_path.is_dir(): _write_file( executor_dir_path / "executor_one_file.py", executor_template_1.replace("{temp}", str(keyword_dir_path / "keyword1.json")) diff --git a/je_auto_control/utils/xml/change_xml_structure/change_xml_structure.py b/je_auto_control/utils/xml/change_xml_structure/change_xml_structure.py index 7dd4bf8..2f68de7 100644 --- a/je_auto_control/utils/xml/change_xml_structure/change_xml_structure.py +++ b/je_auto_control/utils/xml/change_xml_structure/change_xml_structure.py @@ -1,6 +1,6 @@ from collections import defaultdict from xml.etree import ElementTree -from typing import Union, Dict, Any +from typing import Dict, Any def elements_tree_to_dict(elements_tree: ElementTree.Element) -> Dict[str, Any]: diff --git a/je_auto_control/windows/window/windows_window_manage.py b/je_auto_control/windows/window/windows_window_manage.py index b99aee9..d7f9a84 100644 --- a/je_auto_control/windows/window/windows_window_manage.py +++ b/je_auto_control/windows/window/windows_window_manage.py @@ -1,5 +1,5 @@ from ctypes import WINFUNCTYPE, c_bool, c_int, POINTER, create_unicode_buffer -from typing import Union, List, Tuple, Optional +from typing import List, Tuple, Optional from je_auto_control.windows.core.utils.win32_ctype_input import user32 diff --git a/je_auto_control/wrapper/auto_control_image.py b/je_auto_control/wrapper/auto_control_image.py index c9f3baa..2d088cb 100644 --- a/je_auto_control/wrapper/auto_control_image.py +++ b/je_auto_control/wrapper/auto_control_image.py @@ -2,7 +2,7 @@ from je_auto_control.utils.cv2_utils import template_detection from je_auto_control.utils.cv2_utils.screenshot import pil_screenshot -from je_auto_control.utils.exception.exception_tags import cant_find_image_error_message, find_image_error_variable_error_message +from je_auto_control.utils.exception.exception_tags import cant_find_image_error_message from je_auto_control.utils.exception.exceptions import ImageNotFoundException from je_auto_control.utils.logging.logging_instance import autocontrol_logger from je_auto_control.utils.test_record.record_test_class import record_action_to_list diff --git a/pyproject.toml b/pyproject.toml index da4cab0..0b3be44 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,12 +14,12 @@ description = "GUI Automation Framework" requires-python = ">=3.10" license-files = ["LICENSE"] dependencies = [ - "je_open_cv", - "pillow", - "pyobjc-core;platform_system=='Darwin'", - "pyobjc;platform_system=='Darwin'", - "python-Xlib;platform_system=='Linux'", - "mss" + "je_open_cv==0.0.22", + "pillow==12.2.0", + "pyobjc-core==12.1;platform_system=='Darwin'", + "pyobjc==12.1;platform_system=='Darwin'", + "python-Xlib==0.33;platform_system=='Linux'", + "mss==10.1.0" ] classifiers = [ "Programming Language :: Python :: 3.10", @@ -43,4 +43,4 @@ content-type = "text/markdown" find = { namespaces = false } [project.optional-dependencies] -gui = ["PySide6==6.11.0", "qt-material"] +gui = ["PySide6==6.11.0", "qt-material==2.17"] diff --git a/requirements.txt b/requirements.txt index eb6212d..ecd31e7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ je_auto_control -qt-material -mss -Pyside6==6.10.1 +qt-material==2.17 +mss==10.1.0 +PySide6==6.11.0 From 11070b4ab6cbdb6633c7ae774d486284c5b84545 Mon Sep 17 00:00:00 2001 From: JeffreyChen Date: Sat, 18 Apr 2026 00:41:27 +0800 Subject: [PATCH 2/4] Update example jsons Update example jsons --- .idea/workspace.xml | 111 ++++++++++------- AutoControl/executor/executor_bad_file.py | 9 ++ AutoControl/executor/executor_folder.py | 7 ++ AutoControl/executor/executor_one_file.py | 7 ++ AutoControl/keyword/bad_keyword_1.json | 26 ++++ AutoControl/keyword/keyword1.json | 143 ++++++++++++++++++++++ AutoControl/keyword/keyword2.json | 133 ++++++++++++++++++++ 7 files changed, 391 insertions(+), 45 deletions(-) create mode 100644 AutoControl/executor/executor_bad_file.py create mode 100644 AutoControl/executor/executor_folder.py create mode 100644 AutoControl/executor/executor_one_file.py create mode 100644 AutoControl/keyword/bad_keyword_1.json create mode 100644 AutoControl/keyword/keyword1.json create mode 100644 AutoControl/keyword/keyword2.json diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 3d60252..0f6b65a 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -5,8 +5,27 @@ - + + + + + + + + + + + + + + + + + + + + - { + "keyToString": { + "DefaultHtmlFileTemplate": "HTML File", + "Python.auto_control_keyboard.executor": "Run", + "Python.auto_control_mouse.executor": "Run", + "Python.calculator.executor": "Run", + "Python.callback_test.executor": "Run", + "Python.create_project_test.executor": "Run", + "Python.critical_exit_test.executor": "Run", + "Python.executor_one_file.executor": "Run", + "Python.get_pixel_test.executor": "Run", + "Python.keyboard_is_press_test.executor": "Run", + "Python.keyboard_type_test.executor": "Run", + "Python.main_widget.executor": "Run", + "Python.main_window.executor": "Run", + "Python.mouse_test.executor": "Run", + "Python.record_test.executor": "Run", + "Python.screen_test.executor": "Run", + "Python.screenshot_test.executor": "Run", + "Python.test.executor": "Run", + "Python.video_recording.executor": "Run", + "Python.win32_screen.executor": "Run", + "RunOnceActivity.OpenProjectViewOnStart": "true", + "RunOnceActivity.ShowReadmeOnStart": "true", + "RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true", + "RunOnceActivity.git.unshallow": "true", + "RunOnceActivity.typescript.service.memoryLimit.init": "true", + "WebServerToolWindowFactoryState": "false", + "codeWithMe.voiceChat.enabledByDefault": "false", + "com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultAutoModeForALLUsers.v1": "true", + "com.intellij.ml.llm.matterhorn.ej.ui.settings.DefaultModelSelectionForGA.v1": "true", + "git-widget-placeholder": "dev", + "ignore.virus.scanning.warn.message": "true", + "junie.onboarding.icon.badge.shown": "true", + "last_opened_file_path": "D:/Codes/AutoControlGUI", + "node.js.detected.package.eslint": "true", + "node.js.detected.package.tslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "node.js.selected.package.tslint": "(autodetect)", + "nodejs_package_manager_path": "npm", + "settings.editor.selected.configurable": "discord-application", + "to.speed.mode.migration.done": "true", + "vue.rearranger.settings.migration": "true" } -}]]> +} @@ -638,6 +657,8 @@ + + diff --git a/AutoControl/executor/executor_bad_file.py b/AutoControl/executor/executor_bad_file.py new file mode 100644 index 0000000..669b1ab --- /dev/null +++ b/AutoControl/executor/executor_bad_file.py @@ -0,0 +1,9 @@ + +# This example is primarily intended to remind users of the importance of verifying input. +from je_auto_control import execute_action, read_action_json + +execute_action( + read_action_json( + r"D:\Codes\AutoControlGUI\AutoControl\keyword\bad_keyword_1.json" + ) +) diff --git a/AutoControl/executor/executor_folder.py b/AutoControl/executor/executor_folder.py new file mode 100644 index 0000000..dde81b1 --- /dev/null +++ b/AutoControl/executor/executor_folder.py @@ -0,0 +1,7 @@ +from je_auto_control import execute_files, get_dir_files_as_list + +execute_files( + get_dir_files_as_list( + r"D:\Codes\AutoControlGUI\AutoControl\keyword" + ) +) diff --git a/AutoControl/executor/executor_one_file.py b/AutoControl/executor/executor_one_file.py new file mode 100644 index 0000000..6c3d28c --- /dev/null +++ b/AutoControl/executor/executor_one_file.py @@ -0,0 +1,7 @@ +from je_auto_control import execute_action, read_action_json + +execute_action( + read_action_json( + r"D:\Codes\AutoControlGUI\AutoControl\keyword\keyword1.json" + ) +) diff --git a/AutoControl/keyword/bad_keyword_1.json b/AutoControl/keyword/bad_keyword_1.json new file mode 100644 index 0000000..80de85a --- /dev/null +++ b/AutoControl/keyword/bad_keyword_1.json @@ -0,0 +1,26 @@ +[ + [ + "AC_set_record_enable", + [ + true + ] + ], + [ + "AC_add_package_to_executor", + [ + "os" + ] + ], + [ + "os_system", + [ + "python --version" + ] + ], + [ + "os_system", + [ + "python -m pip --version" + ] + ] +] \ No newline at end of file diff --git a/AutoControl/keyword/keyword1.json b/AutoControl/keyword/keyword1.json new file mode 100644 index 0000000..d50d68d --- /dev/null +++ b/AutoControl/keyword/keyword1.json @@ -0,0 +1,143 @@ +[ + [ + "AC_set_record_enable", + [ + true + ] + ], + [ + "AC_write", + { + "write_string": "Hello World" + } + ], + [ + "AC_type_keyboard", + { + "keycode": "return" + } + ], + [ + "AC_write", + { + "write_string": "If you want Windows write upcase string" + } + ], + [ + "AC_type_keyboard", + { + "keycode": "return" + } + ], + [ + "AC_write", + { + "write_string": "you need to press shift first" + } + ], + [ + "AC_type_keyboard", + { + "keycode": "return" + } + ], + [ + "AC_press_keyboard_key", + { + "keycode": "shift" + } + ], + [ + "AC_write", + { + "write_string": "UPCASEE" + } + ], + [ + "AC_release_keyboard_key", + { + "keycode": "shift" + } + ], + [ + "AC_type_keyboard", + { + "keycode": "return" + } + ], + [ + "AC_write", + { + "write_string": "this is example how to use keyword" + } + ], + [ + "AC_write", + { + "write_string": " and add module to executor" + } + ], + [ + "AC_type_keyboard", + { + "keycode": "return" + } + ], + [ + "AC_write", + { + "write_string": "now i will add time module and sleep 3 sec" + } + ], + [ + "AC_add_package_to_executor", + [ + "time" + ] + ], + [ + "time_sleep", + [ + 3 + ] + ], + [ + "AC_type_keyboard", + { + "keycode": "return" + } + ], + [ + "AC_write", + { + "write_string": "also you can use builtin function on executor like print" + } + ], + [ + "print", + [ + "Google Bye World" + ] + ], + [ + "AC_type_keyboard", + { + "keycode": "return" + } + ], + [ + "AC_write", + { + "write_string": "and i will create an html report for you" + } + ], + [ + "AC_generate_html_report" + ], + [ + "AC_type_keyboard", + { + "keycode": "return" + } + ] +] \ No newline at end of file diff --git a/AutoControl/keyword/keyword2.json b/AutoControl/keyword/keyword2.json new file mode 100644 index 0000000..a87dc44 --- /dev/null +++ b/AutoControl/keyword/keyword2.json @@ -0,0 +1,133 @@ +[ + [ + "AC_set_record_enable", + [ + true + ] + ], + [ + "AC_write", + { + "write_string": "in this keyword file we will change the mouse position" + } + ], + [ + "AC_type_keyboard", + { + "keycode": "return" + } + ], + [ + "AC_set_mouse_position", + [ + 500, + 500 + ] + ], + [ + "AC_set_mouse_position", + { + "x": 100, + "y": 100 + } + ], + [ + "AC_set_mouse_position", + [ + 600, + 600 + ] + ], + [ + "AC_set_mouse_position", + { + "x": 100, + "y": 100 + } + ], + [ + "AC_set_mouse_position", + [ + 400, + 400 + ] + ], + [ + "AC_set_mouse_position", + { + "x": 100, + "y": 100 + } + ], + [ + "AC_set_mouse_position", + [ + 300, + 300 + ] + ], + [ + "AC_set_mouse_position", + { + "x": 100, + "y": 100 + } + ], + [ + "AC_set_mouse_position", + [ + 200, + 200 + ] + ], + [ + "AC_set_mouse_position", + { + "x": 100, + "y": 100 + } + ], + [ + "AC_set_mouse_position", + [ + 700, + 700 + ] + ], + [ + "AC_set_mouse_position", + { + "x": 100, + "y": 100 + } + ], + [ + "AC_set_mouse_position", + [ + 800, + 800 + ] + ], + [ + "AC_set_mouse_position", + { + "x": 100, + "y": 100 + } + ], + [ + "AC_write", + { + "write_string": "now i will create an json report for you" + } + ], + [ + "AC_type_keyboard", + { + "keycode": "return" + } + ], + [ + "AC_generate_json_report" + ] +] \ No newline at end of file From 7b8e67063a51852d122b05fe56558b87f20823da Mon Sep 17 00:00:00 2001 From: JeffreyChen Date: Sat, 18 Apr 2026 14:01:07 +0800 Subject: [PATCH 3/4] Enforce SonarQube/Codacy rules; split platform_wrapper backends - CLAUDE.md: add Static Analysis Compliance section covering complexity, exception chaining, Bandit security, resource management, and naming. - Replace print() in library code with autocontrol_logger across utils, wrapper, osx, and linux backends to satisfy python:S4792. - Narrow bare `except Exception` to specific exception tuples and add `raise ... from error` for chain preservation (python:S5655). - Remove shell=True from ShellManager; normalize commands via shlex to argv list, eliminating Bandit B602. - Replace wildcard Cocoa/Foundation imports in osx_listener with explicit symbols (python:S2208). - Drop sys.argv side effects from start_autocontrol_socket_server; bind default host to 127.0.0.1 for least privilege. - Split platform_wrapper monolith into _platform_linux / _platform_osx / _platform_windows to satisfy the 750-line file limit. --- CLAUDE.md | 80 ++ je_auto_control/__main__.py | 8 +- je_auto_control/gui/_auto_click_tab.py | 263 ++++ je_auto_control/gui/main_widget.py | 119 +- .../listener/x11_linux_listener.py | 4 +- je_auto_control/osx/keyboard/osx_keyboard.py | 3 +- je_auto_control/osx/listener/osx_listener.py | 10 +- .../callback/callback_function_executor.py | 10 +- .../utils/critical_exit/critical_exit.py | 6 +- je_auto_control/utils/cv2_utils/screenshot.py | 6 +- .../utils/cv2_utils/video_recording.py | 4 +- .../utils/executor/action_executor.py | 7 +- .../generate_report/generate_html_report.py | 2 +- .../generate_report/generate_json_report.py | 2 +- .../generate_report/generate_xml_report.py | 2 +- je_auto_control/utils/json/json_file.py | 11 +- .../package_manager/package_manager_class.py | 11 +- .../utils/shell_process/shell_exec.py | 84 +- .../auto_control_socket_server.py | 28 +- .../utils/start_exe/start_another_process.py | 4 +- .../utils/xml/xml_file/xml_file.py | 12 +- je_auto_control/wrapper/_platform_linux.py | 225 ++++ je_auto_control/wrapper/_platform_osx.py | 149 +++ je_auto_control/wrapper/_platform_windows.py | 272 +++++ je_auto_control/wrapper/auto_control_image.py | 8 +- .../wrapper/auto_control_keyboard.py | 24 +- je_auto_control/wrapper/auto_control_mouse.py | 28 +- .../wrapper/auto_control_record.py | 4 +- .../wrapper/auto_control_screen.py | 12 +- je_auto_control/wrapper/platform_wrapper.py | 1080 +---------------- 30 files changed, 1215 insertions(+), 1263 deletions(-) create mode 100644 je_auto_control/gui/_auto_click_tab.py create mode 100644 je_auto_control/wrapper/_platform_linux.py create mode 100644 je_auto_control/wrapper/_platform_osx.py create mode 100644 je_auto_control/wrapper/_platform_windows.py diff --git a/CLAUDE.md b/CLAUDE.md index 23aec59..fe37703 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -133,3 +133,83 @@ python -m build - JSON action command names use `AC_` prefix (e.g., `AC_click_mouse`). - Platform backends follow naming: `{platform}_{function}.py` (e.g., `win32_ctype_mouse_control.py`). - Virtual key mappings are in `core/utils/*_vk.py` per platform. + +## Static Analysis Compliance (SonarQube / Codacy / Pylint / Bandit) + +All code must satisfy the following rules so automated scanners (SonarQube, Codacy, Pylint, Bandit, Radon, Prospector) report zero new issues. + +### Complexity & Size Limits + +- **Cyclomatic complexity** per function ≤ 10. Refactor with early returns, extracted helpers, or lookup dicts when exceeded. +- **Cognitive complexity** per function ≤ 15 (SonarQube `python:S3776`). +- **Function length** ≤ 75 lines. Long procedural flows must be split into named helpers. +- **Parameter count** ≤ 7 (`python:S107`). Group related parameters into a dataclass or config object when exceeded. +- **Nesting depth** ≤ 4 (`python:S134`). Flatten with guard clauses. +- **File length** ≤ 750 lines. Split large modules along responsibility lines. +- **Identical branches**: `if`/`elif`/`else` branches must not have identical bodies (`python:S3923`). +- **Duplicated code**: no duplicated blocks ≥ 10 lines across the project (Sonar default). Extract to a shared helper. + +### Bug & Correctness Rules + +- **No bare `except:`** — always catch a specific exception type (`python:S5754`, Bandit `B001`). +- **No empty `except` blocks** (`python:S2737`). At minimum log the error or re-raise. +- **Preserve exception chain**: inside `except`, raising a new exception must use `raise NewError(...) from exc` (`python:S5655`). +- **No mutable default arguments** (`python:S5727`): never use `def f(x=[])` or `{}`. Use `None` + lazy init. +- **No unused imports, variables, parameters, or assignments** (`python:S1481`, `S1854`, `S1172`). Remove them; do not rename to `_unused`. +- **No dead / unreachable code** (`python:S1763`). +- **No commented-out code blocks** (`python:S125`) — delete instead; git history preserves it. +- **No `TODO`/`FIXME`/`XXX`** without an issue-tracker reference in the same comment (`python:S1135`). +- **No `print()`** in library code (`je_auto_control/` outside `gui/` stdout tooling). Use the project logger. +- **No `assert` for runtime checks** in non-test code (Bandit `B101`) — `assert` is stripped with `-O`. Raise explicit exceptions. +- **String formatting**: prefer f-strings over `%` or `.format()` for readability; never interpolate untrusted data into shell/SQL. +- **Equality with `None`/`True`/`False`**: use `is` / `is not`, never `==` (`python:S2589`). +- **Boolean simplification**: no `if cond: return True else: return False` — return the expression directly (`python:S1126`). +- **Identical expressions on both sides** of `and`/`or`/`==`/`!=` are forbidden (`python:S1764`). + +### Security Rules (Bandit / Sonar Security Hotspots) + +- **No `eval`, `exec`, `compile`** on any runtime-sourced string (Bandit `B307`, `B102`). +- **No `pickle`, `marshal`, `shelve`, `dill`** on data from disk, network, or user input (Bandit `B301`, `B302`). Use JSON with schema validation. +- **No `subprocess` with `shell=True`** or string-built command lines (Bandit `B602`, `B605`). Pass argv lists and validate against allowlists. +- **No `os.system`, `os.popen`, `commands.*`** (Bandit `B605`, `B607`). +- **No insecure hash** (`md5`, `sha1`) for security purposes (Bandit `B303`, `B324`). Use `hashlib.sha256` or better. +- **No `tempfile.mktemp`** — use `NamedTemporaryFile` / `mkstemp` (Bandit `B306`). +- **No hardcoded passwords, tokens, or secrets** (Bandit `B105`–`B107`, `python:S2068`). +- **No `yaml.load`** without `SafeLoader` (Bandit `B506`). +- **`requests`/`urllib` calls** must set explicit `timeout=` (`python:S5332`, Bandit `B113`). +- **No `ssl._create_unverified_context` / `verify=False`** (Bandit `B501`). +- **Path traversal**: validate and `os.path.realpath` user-supplied paths before I/O. +- **Socket binds** must default to `127.0.0.1`; `0.0.0.0` requires an explicit, documented opt-in. + +### Resource & Concurrency + +- **Always use `with`** for files, sockets, locks, and OpenCV `VideoCapture`/`VideoWriter` (`python:S5720`). No manual `close()` in normal flow. +- **Release platform resources** (GDI handles, Quartz event sources, X display) in `finally` or `__exit__`. +- **Thread-safety**: shared mutable state between the socket server, recording thread, and callback executor must be guarded by `threading.Lock` / `queue.Queue`. + +### Style & Naming + +- **snake_case** for functions, methods, variables, modules; **PascalCase** for classes; **UPPER_SNAKE_CASE** for module-level constants (`python:S117`, Pylint `C0103`). +- **Max line length**: 120 chars (`python:S103`). +- **Docstrings** on every public module, class, and function (`python:S1720`, Pylint `C0114`–`C0116`) — one-line summary minimum; type hints replace parameter-type prose. +- **Import order**: stdlib → third-party → first-party, separated by blank lines; no wildcard imports except in `__init__.py` façade (`python:S2208`). +- **No `global`** statements outside module initialization (`python:S2208`). + +### Test Hygiene + +- Tests must avoid `assert` against object identity of mutable literals and must not depend on execution order (Pylint / Sonar `python:S5914`). +- No `time.sleep` > 1s in unit tests; use fakes / event signals. + +### Automated Verification + +Run before every commit; fix all new findings: + +```bash +pip install ruff pylint bandit radon +ruff check je_auto_control/ +pylint je_auto_control/ +bandit -r je_auto_control/ -x je_auto_control/test +radon cc je_auto_control/ -a -nc # flags functions with CC >= C (>10) +``` + +If a rule must be suppressed, add an inline justification: `# noqa: # reason: ` or `# nosec B404 # reason: `. Blanket suppressions at file/module level are forbidden. diff --git a/je_auto_control/__main__.py b/je_auto_control/__main__.py index 6cb24d7..0f6a97f 100644 --- a/je_auto_control/__main__.py +++ b/je_auto_control/__main__.py @@ -12,6 +12,7 @@ from je_auto_control.utils.file_process.get_dir_file_list import \ get_dir_files_as_list from je_auto_control.utils.json.json_file import read_action_json +from je_auto_control.utils.logging.logging_instance import autocontrol_logger from je_auto_control.utils.project.create_project_structure import create_project_dir if __name__ == "__main__": @@ -61,6 +62,9 @@ def preprocess_read_str_execute_action(execute_str: str): argparse_event_dict.get(key)(value) if all(value is None for value in args.values()): raise AutoControlArgparseException(argparse_get_wrong_data_error_message) - except Exception as error: - print(repr(error), file=sys.stderr) + except AutoControlArgparseException as error: + autocontrol_logger.error("argparse failure: %r", error) + sys.exit(1) + except (OSError, ValueError, RuntimeError) as error: + autocontrol_logger.error("cli execution failed: %r", error) sys.exit(1) diff --git a/je_auto_control/gui/_auto_click_tab.py b/je_auto_control/gui/_auto_click_tab.py new file mode 100644 index 0000000..650b389 --- /dev/null +++ b/je_auto_control/gui/_auto_click_tab.py @@ -0,0 +1,263 @@ +from PySide6.QtGui import QIntValidator +from PySide6.QtWidgets import ( + QWidget, QLineEdit, QComboBox, QPushButton, QVBoxLayout, QLabel, + QGridLayout, QHBoxLayout, QRadioButton, QButtonGroup, QMessageBox, + QGroupBox, +) + +from je_auto_control.gui.language_wrapper.multi_language_wrapper import language_wrapper +from je_auto_control.wrapper.auto_control_keyboard import ( + type_keyboard, hotkey, write, get_keyboard_keys_table, +) +from je_auto_control.wrapper.auto_control_mouse import ( + click_mouse, get_mouse_position, mouse_scroll, + mouse_keys_table, special_mouse_keys_table, +) + + +def _t(key: str) -> str: + return language_wrapper.language_word_dict.get(key, key) + + +class AutoClickTabMixin: + """ + Mixin that provides the auto-click tab UI and handlers. + Requires the host widget to expose `self.timer`, `self.repeat_count`, + `self.repeat_max` attributes set in its __init__. + """ + + def _build_auto_click_tab(self) -> QWidget: + tab = QWidget() + outer = QVBoxLayout() + + click_group = QGroupBox(_t("tab_auto_click")) + grid = QGridLayout() + row = 0 + + grid.addWidget(QLabel(_t("input_method")), row, 0) + self.mouse_radio = QRadioButton(_t("mouse_radio")) + self.keyboard_radio = QRadioButton(_t("keyboard_radio")) + self.mouse_radio.setChecked(True) + self._input_group = QButtonGroup() + self._input_group.addButton(self.mouse_radio) + self._input_group.addButton(self.keyboard_radio) + h = QHBoxLayout() + h.addWidget(self.mouse_radio) + h.addWidget(self.keyboard_radio) + grid.addLayout(h, row, 1) + + row += 1 + grid.addWidget(QLabel(_t("interval_time")), row, 0) + self.interval_input = QLineEdit("1000") + self.interval_input.setValidator(QIntValidator(1, 999999999)) + grid.addWidget(self.interval_input, row, 1) + + row += 1 + grid.addWidget(QLabel(_t("cursor_x")), row, 0) + self.cursor_x_input = QLineEdit() + self.cursor_x_input.setValidator(QIntValidator()) + grid.addWidget(self.cursor_x_input, row, 1) + + row += 1 + grid.addWidget(QLabel(_t("cursor_y")), row, 0) + self.cursor_y_input = QLineEdit() + self.cursor_y_input.setValidator(QIntValidator()) + grid.addWidget(self.cursor_y_input, row, 1) + + row += 1 + grid.addWidget(QLabel(_t("mouse_button")), row, 0) + self.mouse_button_combo = QComboBox() + self.mouse_button_combo.addItems( + list(mouse_keys_table.keys()) if isinstance(mouse_keys_table, dict) else list(mouse_keys_table) + ) + grid.addWidget(self.mouse_button_combo, row, 1) + + row += 1 + grid.addWidget(QLabel(_t("keyboard_button")), row, 0) + self.keyboard_button_combo = QComboBox() + self.keyboard_button_combo.addItems(list(get_keyboard_keys_table().keys())) + grid.addWidget(self.keyboard_button_combo, row, 1) + + row += 1 + grid.addWidget(QLabel(_t("click_type")), row, 0) + self.click_type_combo = QComboBox() + self.click_type_combo.addItems([_t("single_click"), _t("double_click")]) + grid.addWidget(self.click_type_combo, row, 1) + + row += 1 + self.repeat_until_stopped = QRadioButton(_t("repeat_until_stopped_radio")) + self.repeat_count_times = QRadioButton(_t("repeat_radio")) + self.repeat_count_input = QLineEdit() + self.repeat_count_input.setValidator(QIntValidator(1, 999999999)) + self.repeat_count_input.setPlaceholderText(_t("times")) + rg = QButtonGroup(tab) + rg.addButton(self.repeat_until_stopped) + rg.addButton(self.repeat_count_times) + self.repeat_until_stopped.setChecked(True) + rh = QHBoxLayout() + rh.addWidget(self.repeat_until_stopped) + rh.addWidget(self.repeat_count_times) + rh.addWidget(self.repeat_count_input) + grid.addLayout(rh, row, 0, 1, 2) + + row += 1 + btn_h = QHBoxLayout() + self.start_button = QPushButton(_t("start")) + self.start_button.clicked.connect(self._start_auto_click) + self.stop_button = QPushButton(_t("stop")) + self.stop_button.clicked.connect(self._stop_auto_click) + btn_h.addWidget(self.start_button) + btn_h.addWidget(self.stop_button) + grid.addLayout(btn_h, row, 0, 1, 2) + + click_group.setLayout(grid) + outer.addWidget(click_group) + + pos_group = QGroupBox(_t("get_position")) + pos_layout = QHBoxLayout() + self.pos_btn = QPushButton(_t("get_position")) + self.pos_btn.clicked.connect(self._get_mouse_pos) + self.pos_label = QLabel(_t("current_position") + " --") + pos_layout.addWidget(self.pos_btn) + pos_layout.addWidget(self.pos_label) + pos_group.setLayout(pos_layout) + outer.addWidget(pos_group) + + hotkey_group = QGroupBox(_t("hotkey_label")) + hk_layout = QHBoxLayout() + self.hotkey_input = QLineEdit() + self.hotkey_input.setPlaceholderText("ctrl,a") + self.hotkey_btn = QPushButton(_t("hotkey_send")) + self.hotkey_btn.clicked.connect(self._send_hotkey) + hk_layout.addWidget(self.hotkey_input) + hk_layout.addWidget(self.hotkey_btn) + hotkey_group.setLayout(hk_layout) + outer.addWidget(hotkey_group) + + write_group = QGroupBox(_t("write_label")) + wr_layout = QHBoxLayout() + self.write_input = QLineEdit() + self.write_btn = QPushButton(_t("write_send")) + self.write_btn.clicked.connect(self._send_write) + wr_layout.addWidget(self.write_input) + wr_layout.addWidget(self.write_btn) + write_group.setLayout(wr_layout) + outer.addWidget(write_group) + + scroll_group = QGroupBox(_t("mouse_scroll_label")) + sc_layout = QHBoxLayout() + self.scroll_value_input = QLineEdit("3") + self.scroll_value_input.setValidator(QIntValidator()) + sc_layout.addWidget(QLabel(_t("mouse_scroll_label"))) + sc_layout.addWidget(self.scroll_value_input) + if special_mouse_keys_table: + self.scroll_dir_combo = QComboBox() + self.scroll_dir_combo.addItems(list(special_mouse_keys_table.keys())) + sc_layout.addWidget(self.scroll_dir_combo) + else: + self.scroll_dir_combo = None + self.scroll_btn = QPushButton(_t("scroll_send")) + self.scroll_btn.clicked.connect(self._send_scroll) + sc_layout.addWidget(self.scroll_btn) + scroll_group.setLayout(sc_layout) + outer.addWidget(scroll_group) + + outer.addStretch() + + self.mouse_radio.toggled.connect(self._update_click_mode) + self._update_click_mode() + + tab.setLayout(outer) + return tab + + def _update_click_mode(self): + use_mouse = self.mouse_radio.isChecked() + self.cursor_x_input.setEnabled(use_mouse) + self.cursor_y_input.setEnabled(use_mouse) + self.mouse_button_combo.setEnabled(use_mouse) + self.keyboard_button_combo.setEnabled(not use_mouse) + + def _start_auto_click(self): + try: + interval = int(self.interval_input.text()) + except ValueError: + QMessageBox.warning(self, "Warning", "Interval must be a number") + return + self.repeat_count = 0 + try: + self.repeat_max = int(self.repeat_count_input.text()) + except ValueError: + self.repeat_max = 0 + self.timer.setInterval(interval) + try: + self.timer.timeout.disconnect(self._timer_tick) + except RuntimeError: + pass + self.timer.timeout.connect(self._timer_tick) + self.timer.start() + + def _stop_auto_click(self): + self.timer.stop() + + def _timer_tick(self): + if self.repeat_until_stopped.isChecked(): + self._do_click() + elif self.repeat_count_times.isChecked(): + self.repeat_count += 1 + if self.repeat_count <= self.repeat_max: + self._do_click() + else: + self.repeat_count = 0 + self.timer.stop() + + def _do_click(self): + try: + is_double = self.click_type_combo.currentIndex() == 1 + if self.mouse_radio.isChecked(): + btn = self.mouse_button_combo.currentText() + x = int(self.cursor_x_input.text() or "0") + y = int(self.cursor_y_input.text() or "0") + click_mouse(btn, x, y) + if is_double: + click_mouse(btn, x, y) + else: + key = self.keyboard_button_combo.currentText() + type_keyboard(key) + if is_double: + type_keyboard(key) + except (OSError, ValueError, TypeError, RuntimeError) as error: + self.timer.stop() + QMessageBox.warning(self, "Error", str(error)) + + def _get_mouse_pos(self): + try: + x, y = get_mouse_position() + self.pos_label.setText(_t("current_position") + f" ({x}, {y})") + self.cursor_x_input.setText(str(x)) + self.cursor_y_input.setText(str(y)) + except (OSError, ValueError, TypeError, RuntimeError) as error: + QMessageBox.warning(self, "Error", str(error)) + + def _send_hotkey(self): + try: + keys = [k.strip() for k in self.hotkey_input.text().split(",") if k.strip()] + if keys: + hotkey(keys) + except (OSError, ValueError, TypeError, RuntimeError) as error: + QMessageBox.warning(self, "Error", str(error)) + + def _send_write(self): + try: + text = self.write_input.text() + if text: + write(text) + except (OSError, ValueError, TypeError, RuntimeError) as error: + QMessageBox.warning(self, "Error", str(error)) + + def _send_scroll(self): + try: + val = int(self.scroll_value_input.text() or "3") + direction = self.scroll_dir_combo.currentText() if self.scroll_dir_combo else "scroll_down" + mouse_scroll(val, scroll_direction=direction) + except (OSError, ValueError, TypeError, RuntimeError) as error: + QMessageBox.warning(self, "Error", str(error)) diff --git a/je_auto_control/gui/main_widget.py b/je_auto_control/gui/main_widget.py index fe5e440..dc6a54f 100644 --- a/je_auto_control/gui/main_widget.py +++ b/je_auto_control/gui/main_widget.py @@ -8,18 +8,11 @@ QTabWidget, QTextEdit, QFileDialog, QCheckBox, QGroupBox ) +from je_auto_control.gui._auto_click_tab import AutoClickTabMixin from je_auto_control.gui.language_wrapper.multi_language_wrapper import language_wrapper -from je_auto_control.wrapper.auto_control_keyboard import ( - type_keyboard, hotkey, write -) -from je_auto_control.wrapper.auto_control_mouse import ( - click_mouse, get_mouse_position, mouse_scroll -) from je_auto_control.wrapper.auto_control_screen import screen_size, screenshot, get_pixel from je_auto_control.wrapper.auto_control_image import locate_all_image, locate_image_center, locate_and_click from je_auto_control.wrapper.auto_control_record import record, stop_record -from je_auto_control.wrapper.auto_control_keyboard import get_keyboard_keys_table -from je_auto_control.wrapper.auto_control_mouse import mouse_keys_table, special_mouse_keys_table from je_auto_control.utils.executor.action_executor import execute_action, execute_files from je_auto_control.utils.json.json_file import read_action_json, write_action_json from je_auto_control.utils.file_process.get_dir_file_list import get_dir_files_as_list @@ -45,7 +38,7 @@ class _WorkerSignals(QObject): # ============================================================================= # Main Widget # ============================================================================= -class AutoControlGUIWidget(QWidget): +class AutoControlGUIWidget(AutoClickTabMixin, QWidget): def __init__(self, parent=None): super().__init__(parent) @@ -277,9 +270,9 @@ def _do_click(self): type_keyboard(key) if is_double: type_keyboard(key) - except Exception as e: + except (OSError, ValueError, TypeError, RuntimeError) as error: self.timer.stop() - QMessageBox.warning(self, "Error", str(e)) + QMessageBox.warning(self, "Error", str(error)) def _get_mouse_pos(self): try: @@ -287,32 +280,32 @@ def _get_mouse_pos(self): self.pos_label.setText(_t("current_position") + f" ({x}, {y})") self.cursor_x_input.setText(str(x)) self.cursor_y_input.setText(str(y)) - except Exception as e: - QMessageBox.warning(self, "Error", str(e)) + except (OSError, ValueError, TypeError, RuntimeError) as error: + QMessageBox.warning(self, "Error", str(error)) def _send_hotkey(self): try: keys = [k.strip() for k in self.hotkey_input.text().split(",") if k.strip()] if keys: hotkey(keys) - except Exception as e: - QMessageBox.warning(self, "Error", str(e)) + except (OSError, ValueError, TypeError, RuntimeError) as error: + QMessageBox.warning(self, "Error", str(error)) def _send_write(self): try: text = self.write_input.text() if text: write(text) - except Exception as e: - QMessageBox.warning(self, "Error", str(e)) + except (OSError, ValueError, TypeError, RuntimeError) as error: + QMessageBox.warning(self, "Error", str(error)) def _send_scroll(self): try: val = int(self.scroll_value_input.text() or "3") direction = self.scroll_dir_combo.currentText() if self.scroll_dir_combo else "scroll_down" mouse_scroll(val, scroll_direction=direction) - except Exception as e: - QMessageBox.warning(self, "Error", str(e)) + except (OSError, ValueError, TypeError, RuntimeError) as error: + QMessageBox.warning(self, "Error", str(error)) # ========================================================================= # Tab 2: Screenshot @@ -386,8 +379,8 @@ def _get_screen_size(self): try: w, h = screen_size() self.screen_size_label.setText(f"{w} x {h}") - except Exception as e: - QMessageBox.warning(self, "Error", str(e)) + except (OSError, ValueError, TypeError, RuntimeError) as error: + QMessageBox.warning(self, "Error", str(error)) def _browse_ss_path(self): path, _ = QFileDialog.getSaveFileName(self, _t("save_screenshot"), "", "PNG (*.png);;All (*)") @@ -403,8 +396,8 @@ def _take_screenshot(self): region = [int(x.strip()) for x in region_text.split(",")] screenshot(file_path=path, screen_region=region) self.ss_result_text.setText(f"Screenshot saved: {path or '(not saved)'}") - except Exception as e: - self.ss_result_text.setText(f"Error: {e}") + except (OSError, ValueError, TypeError, RuntimeError) as error: + self.ss_result_text.setText(f"Error: {error}") def _get_pixel_color(self): try: @@ -412,8 +405,8 @@ def _get_pixel_color(self): y = int(self.pixel_y_input.text()) color = get_pixel(x, y) self.pixel_result_label.setText(_t("pixel_result") + f" {color}") - except Exception as e: - self.pixel_result_label.setText(f"Error: {e}") + except (OSError, ValueError, TypeError, RuntimeError) as error: + self.pixel_result_label.setText(f"Error: {error}") # ========================================================================= # Tab 3: Image Detection @@ -476,16 +469,16 @@ def _locate_image(self): path, th, draw = self._get_detect_params() result = locate_image_center(path, th, draw) self.detect_result_text.setText(f"Center: {result}") - except Exception as e: - self.detect_result_text.setText(f"Error: {e}") + except (OSError, ValueError, TypeError, RuntimeError) as error: + self.detect_result_text.setText(f"Error: {error}") def _locate_all(self): try: path, th, draw = self._get_detect_params() result = locate_all_image(path, th, draw) self.detect_result_text.setText(f"Found {len(result)} matches:\n{result}") - except Exception as e: - self.detect_result_text.setText(f"Error: {e}") + except (OSError, ValueError, TypeError, RuntimeError) as error: + self.detect_result_text.setText(f"Error: {error}") def _locate_click(self): try: @@ -493,8 +486,8 @@ def _locate_click(self): btn = self.mouse_button_combo.currentText() if hasattr(self, "mouse_button_combo") else "mouse_left" result = locate_and_click(path, btn, th, draw) self.detect_result_text.setText(f"Clicked at: {result}") - except Exception as e: - self.detect_result_text.setText(f"Error: {e}") + except (OSError, ValueError, TypeError, RuntimeError) as error: + self.detect_result_text.setText(f"Error: {error}") # ========================================================================= # Tab 4: Record / Playback @@ -538,16 +531,16 @@ def _start_record(self): try: record() self.record_status_label.setText(_t("record_status") + " " + _t("record_recording")) - except Exception as e: - QMessageBox.warning(self, "Error", str(e)) + except (OSError, ValueError, TypeError, RuntimeError) as error: + QMessageBox.warning(self, "Error", str(error)) def _stop_record(self): try: self._record_data = stop_record() or [] self.record_status_label.setText(_t("record_status") + " " + _t("record_idle")) self.record_list_text.setText(json.dumps(self._record_data, indent=2, ensure_ascii=False)) - except Exception as e: - QMessageBox.warning(self, "Error", str(e)) + except (OSError, ValueError, TypeError, RuntimeError) as error: + QMessageBox.warning(self, "Error", str(error)) def _playback_record(self): try: @@ -555,8 +548,8 @@ def _playback_record(self): QMessageBox.warning(self, "Warning", "No recorded data") return execute_action(self._record_data) - except Exception as e: - QMessageBox.warning(self, "Error", str(e)) + except (OSError, ValueError, TypeError, RuntimeError) as error: + QMessageBox.warning(self, "Error", str(error)) def _save_record(self): try: @@ -566,8 +559,8 @@ def _save_record(self): path, _ = QFileDialog.getSaveFileName(self, _t("save_record"), "", "JSON (*.json)") if path: write_action_json(path, self._record_data) - except Exception as e: - QMessageBox.warning(self, "Error", str(e)) + except (OSError, ValueError, TypeError, RuntimeError) as error: + QMessageBox.warning(self, "Error", str(error)) def _load_record(self): try: @@ -575,8 +568,8 @@ def _load_record(self): if path: self._record_data = read_action_json(path) self.record_list_text.setText(json.dumps(self._record_data, indent=2, ensure_ascii=False)) - except Exception as e: - QMessageBox.warning(self, "Error", str(e)) + except (OSError, ValueError, TypeError, RuntimeError) as error: + QMessageBox.warning(self, "Error", str(error)) # ========================================================================= # Tab 5: Script Executor @@ -633,8 +626,8 @@ def _browse_script(self): try: data = read_action_json(path) self.script_editor.setText(json.dumps(data, indent=2, ensure_ascii=False)) - except Exception as e: - self.script_result_text.setText(f"Error loading: {e}") + except (OSError, ValueError, TypeError, RuntimeError) as error: + self.script_result_text.setText(f"Error loading: {error}") def _execute_script(self): try: @@ -644,8 +637,8 @@ def _execute_script(self): data = read_action_json(path) result = execute_action(data) self.script_result_text.setText(json.dumps(result, indent=2, default=str, ensure_ascii=False)) - except Exception as e: - self.script_result_text.setText(f"Error: {e}") + except (OSError, ValueError, TypeError, RuntimeError) as error: + self.script_result_text.setText(f"Error: {error}") def _browse_script_dir(self): path = QFileDialog.getExistingDirectory(self, _t("execute_dir_label")) @@ -660,8 +653,8 @@ def _execute_dir(self): files = get_dir_files_as_list(path) result = execute_files(files) self.script_result_text.setText(json.dumps(result, indent=2, default=str, ensure_ascii=False)) - except Exception as e: - self.script_result_text.setText(f"Error: {e}") + except (OSError, ValueError, TypeError, RuntimeError) as error: + self.script_result_text.setText(f"Error: {error}") def _execute_manual_script(self): try: @@ -671,8 +664,8 @@ def _execute_manual_script(self): data = json.loads(text) result = execute_action(data) self.script_result_text.setText(json.dumps(result, indent=2, default=str, ensure_ascii=False)) - except Exception as e: - self.script_result_text.setText(f"Error: {e}") + except (OSError, ValueError, TypeError, RuntimeError) as error: + self.script_result_text.setText(f"Error: {error}") # ========================================================================= # Tab 6: Screen Recording @@ -746,16 +739,16 @@ def _start_screen_record(self): resolution = (int(w), int(h)) self.screen_recorder.start_new_record(name, output, codec, fps, resolution) self.sr_status_label.setText(_t("screen_record_status") + " " + _t("record_recording")) - except Exception as e: - QMessageBox.warning(self, "Error", str(e)) + except (OSError, ValueError, TypeError, RuntimeError) as error: + QMessageBox.warning(self, "Error", str(error)) def _stop_screen_record(self): try: name = self.sr_name_input.text() or "default" self.screen_recorder.stop_record(name) self.sr_status_label.setText(_t("screen_record_status") + " " + _t("record_idle")) - except Exception as e: - QMessageBox.warning(self, "Error", str(e)) + except (OSError, ValueError, TypeError, RuntimeError) as error: + QMessageBox.warning(self, "Error", str(error)) # ========================================================================= # Tab 7: Shell Command @@ -807,8 +800,8 @@ def _execute_shell(self): mgr = ShellManager() mgr.exec_shell(cmd) self.shell_output_text.setText(f"Executed: {cmd}\n(Check console for output)") - except Exception as e: - self.shell_output_text.setText(f"Error: {e}") + except (OSError, ValueError, TypeError, RuntimeError) as error: + self.shell_output_text.setText(f"Error: {error}") def _browse_exe(self): path, _ = QFileDialog.getOpenFileName(self, _t("start_exe_label"), "", "Executable (*.exe);;All (*)") @@ -822,8 +815,8 @@ def _start_exe(self): return start_exe(path) self.shell_output_text.setText(f"Started: {path}") - except Exception as e: - self.shell_output_text.setText(f"Error: {e}") + except (OSError, ValueError, TypeError, RuntimeError) as error: + self.shell_output_text.setText(f"Error: {error}") # ========================================================================= # Tab 8: Report @@ -883,24 +876,24 @@ def _gen_html(self): name = self.report_name_input.text() or "autocontrol_report" generate_html_report(name) self.report_result_text.setText(f"HTML report generated: {name}") - except Exception as e: - self.report_result_text.setText(f"Error: {e}") + except (OSError, ValueError, TypeError, RuntimeError) as error: + self.report_result_text.setText(f"Error: {error}") def _gen_json(self): try: name = self.report_name_input.text() or "autocontrol_report" generate_json_report(name) self.report_result_text.setText(f"JSON report generated: {name}") - except Exception as e: - self.report_result_text.setText(f"Error: {e}") + except (OSError, ValueError, TypeError, RuntimeError) as error: + self.report_result_text.setText(f"Error: {error}") def _gen_xml(self): try: name = self.report_name_input.text() or "autocontrol_report" generate_xml_report(name) self.report_result_text.setText(f"XML report generated: {name}") - except Exception as e: - self.report_result_text.setText(f"Error: {e}") + except (OSError, ValueError, TypeError, RuntimeError) as error: + self.report_result_text.setText(f"Error: {error}") # ========================================================================= # Global keyboard shortcut: Ctrl+4 to stop diff --git a/je_auto_control/linux_with_x11/listener/x11_linux_listener.py b/je_auto_control/linux_with_x11/listener/x11_linux_listener.py index 01c6027..c02f5fa 100644 --- a/je_auto_control/linux_with_x11/listener/x11_linux_listener.py +++ b/je_auto_control/linux_with_x11/listener/x11_linux_listener.py @@ -69,7 +69,7 @@ def run(self, reply) -> None: if self.record_flag and self.record_queue is not None: temp = (event.type, event.detail, event.root_x, event.root_y) self.record_queue.put(temp) - except Exception as error: + except (OSError, RuntimeError, AttributeError, TypeError, ValueError) as error: raise AutoControlException(f"{listener_error_message}: {error}") from error def record(self, record_queue: Queue) -> None: @@ -142,7 +142,7 @@ def run(self) -> None: # 持續等待事件 self.root.display.next_event() - except Exception as error: + except (OSError, RuntimeError, AttributeError, TypeError, ValueError) as error: raise AutoControlException(f"{listener_error_message}: {error}") from error finally: self.handler.still_listener = False diff --git a/je_auto_control/osx/keyboard/osx_keyboard.py b/je_auto_control/osx/keyboard/osx_keyboard.py index 281d5d0..3889323 100644 --- a/je_auto_control/osx/keyboard/osx_keyboard.py +++ b/je_auto_control/osx/keyboard/osx_keyboard.py @@ -2,6 +2,7 @@ from je_auto_control.utils.exception.exception_tags import osx_import_error_message from je_auto_control.utils.exception.exceptions import AutoControlException +from je_auto_control.utils.logging.logging_instance import autocontrol_logger # === 平台檢查 Platform Check === # 僅允許在 macOS (Darwin) 環境執行,否則拋出例外 @@ -70,7 +71,7 @@ def normal_key(keycode: int, is_shift: bool, is_down: bool) -> None: Quartz.CGEventPost(Quartz.kCGHIDEventTap, event) except ValueError as error: - print(repr(error), file=sys.stderr) + autocontrol_logger.error("normal_key failed: %r", error) def special_key(keycode: str, is_shift: bool) -> None: diff --git a/je_auto_control/osx/listener/osx_listener.py b/je_auto_control/osx/listener/osx_listener.py index dd40546..4ff3af9 100644 --- a/je_auto_control/osx/listener/osx_listener.py +++ b/je_auto_control/osx/listener/osx_listener.py @@ -9,8 +9,14 @@ if sys.platform not in ["darwin"]: raise AutoControlException(osx_import_error_message) -from Cocoa import * -from Foundation import * +from Cocoa import ( + NSApplication, + NSEvent, + NSEventMaskKeyDown, + NSEventMaskLeftMouseDown, + NSEventMaskRightMouseDown, + NSObject, +) from PyObjCTools import AppHelper # === 全域事件記錄 Queue Global event record queue === diff --git a/je_auto_control/utils/callback/callback_function_executor.py b/je_auto_control/utils/callback/callback_function_executor.py index 47b4002..0189c18 100644 --- a/je_auto_control/utils/callback/callback_function_executor.py +++ b/je_auto_control/utils/callback/callback_function_executor.py @@ -1,10 +1,10 @@ -from sys import stderr from typing import Callable, Any # utils cv2_utils from je_auto_control.utils.cv2_utils.screenshot import pil_screenshot from je_auto_control.utils.exception.exception_tags import get_bad_trigger_method_error_message, get_bad_trigger_function_error_message from je_auto_control.utils.exception.exceptions import CallbackExecutorException +from je_auto_control.utils.logging.logging_instance import autocontrol_logger # executor from je_auto_control.utils.executor.action_executor import execute_action, execute_files # file process @@ -174,8 +174,12 @@ def callback_function( return execute_return_value - except Exception as error: - print(repr(error), file=stderr) + except CallbackExecutorException as error: + autocontrol_logger.error("callback_function config error: %r", error) + return None + except (TypeError, ValueError, RuntimeError) as error: + autocontrol_logger.error("callback_function execution failed: %r", error) + return None # === 全域 Callback Executor 實例 Global Instance === diff --git a/je_auto_control/utils/critical_exit/critical_exit.py b/je_auto_control/utils/critical_exit/critical_exit.py index 86b52f2..89e1c92 100644 --- a/je_auto_control/utils/critical_exit/critical_exit.py +++ b/je_auto_control/utils/critical_exit/critical_exit.py @@ -1,7 +1,7 @@ import _thread -import sys from threading import Thread +from je_auto_control.utils.logging.logging_instance import autocontrol_logger from je_auto_control.wrapper.auto_control_keyboard import keyboard_keys_table from je_auto_control.wrapper.platform_wrapper import keyboard_check @@ -49,8 +49,8 @@ def run(self) -> None: while True: if keyboard_check.check_key_is_press(self._exit_check_key): _thread.interrupt_main() # 中斷主程式 Interrupt main thread - except Exception as error: - print(repr(error), file=sys.stderr) + except (OSError, RuntimeError) as error: + autocontrol_logger.error("critical exit listener failed: %r", error) def init_critical_exit(self) -> None: """ diff --git a/je_auto_control/utils/cv2_utils/screenshot.py b/je_auto_control/utils/cv2_utils/screenshot.py index 239e31b..c615809 100644 --- a/je_auto_control/utils/cv2_utils/screenshot.py +++ b/je_auto_control/utils/cv2_utils/screenshot.py @@ -1,6 +1,8 @@ from PIL import ImageGrab, Image from typing import List, Optional +from je_auto_control.utils.logging.logging_instance import autocontrol_logger + def pil_screenshot(file_path: Optional[str] = None, screen_region: Optional[List[int]] = None) -> Image.Image: """ @@ -23,7 +25,7 @@ def pil_screenshot(file_path: Optional[str] = None, screen_region: Optional[List if file_path: try: image.save(file_path) - except Exception as e: - print(f"Failed to save screenshot: {e}") + except (OSError, ValueError) as error: + autocontrol_logger.error("Failed to save screenshot: %r", error) return image \ No newline at end of file diff --git a/je_auto_control/utils/cv2_utils/video_recording.py b/je_auto_control/utils/cv2_utils/video_recording.py index 2aa4b15..b2efe91 100644 --- a/je_auto_control/utils/cv2_utils/video_recording.py +++ b/je_auto_control/utils/cv2_utils/video_recording.py @@ -66,8 +66,8 @@ def run(self): screen_image = sct.grab(resolution) image_rgb = cv2.cvtColor(np.array(screen_image), cv2.COLOR_BGRA2BGR) video_writer.write(image_rgb) - except Exception as e: - autocontrol_logger.error(f"RecordingThread error: {e}") + except (cv2.error, ValueError, RuntimeError) as error: + autocontrol_logger.error("RecordingThread error: %r", error) finally: video_writer.release() autocontrol_logger.info("RecordingThread stopped and video released") \ No newline at end of file diff --git a/je_auto_control/utils/executor/action_executor.py b/je_auto_control/utils/executor/action_executor.py index d20e4d7..59ba6e9 100644 --- a/je_auto_control/utils/executor/action_executor.py +++ b/je_auto_control/utils/executor/action_executor.py @@ -149,7 +149,7 @@ def execute_action(self, action_list: Union[list, dict]) -> Dict[str, str]: event_response = self._execute_event(action) execute_record = "execute: " + str(action) execute_record_dict[execute_record] = event_response - except Exception as error: + except (AutoControlActionException, OSError, RuntimeError, AttributeError, TypeError, ValueError) as error: autocontrol_logger.info( f"execute_action failed, action: {action}, error: {repr(error)}" ) @@ -157,10 +157,9 @@ def execute_action(self, action_list: Union[list, dict]) -> Dict[str, str]: execute_record = "execute: " + str(action) execute_record_dict[execute_record] = repr(error) - # 輸出執行結果 Print results + # 輸出執行結果 Log results for key, value in execute_record_dict.items(): - print(key, flush=True) - print(value, flush=True) + autocontrol_logger.info("%s -> %s", key, value) return execute_record_dict diff --git a/je_auto_control/utils/generate_report/generate_html_report.py b/je_auto_control/utils/generate_report/generate_html_report.py index 14608a2..04ab131 100644 --- a/je_auto_control/utils/generate_report/generate_html_report.py +++ b/je_auto_control/utils/generate_report/generate_html_report.py @@ -157,7 +157,7 @@ def generate_html_report(html_name: str = "default_name") -> None: try: with open(html_name + ".html", "w+", encoding="utf-8") as file_to_write: file_to_write.write(new_html_string) - except Exception as error: + except OSError as error: autocontrol_logger.error( f"generate_html_report failed, html_name: {html_name}, error: {repr(error)}" ) \ No newline at end of file diff --git a/je_auto_control/utils/generate_report/generate_json_report.py b/je_auto_control/utils/generate_report/generate_json_report.py index 1c37551..ff3cca5 100644 --- a/je_auto_control/utils/generate_report/generate_json_report.py +++ b/je_auto_control/utils/generate_report/generate_json_report.py @@ -54,7 +54,7 @@ def _write_json_file(file_name: str, data: Dict[str, Dict[str, str]], lock: Lock try: with open(file_name, "w+", encoding="utf-8") as file_to_write: json.dump(data, file_to_write, indent=4, ensure_ascii=False) - except Exception as error: + except (OSError, TypeError, ValueError) as error: autocontrol_logger.error(f"Failed to write {file_name}, error: {repr(error)}") diff --git a/je_auto_control/utils/generate_report/generate_xml_report.py b/je_auto_control/utils/generate_report/generate_xml_report.py index bb54973..c92afb2 100644 --- a/je_auto_control/utils/generate_report/generate_xml_report.py +++ b/je_auto_control/utils/generate_report/generate_xml_report.py @@ -39,7 +39,7 @@ def _write_xml_file(file_name: str, xml_content: str, lock: Lock) -> None: try: with open(file_name, "w+", encoding="utf-8") as file_to_write: file_to_write.write(xml_content) - except Exception as error: + except OSError as error: autocontrol_logger.error(f"Failed to write {file_name}, error: {repr(error)}") diff --git a/je_auto_control/utils/json/json_file.py b/je_auto_control/utils/json/json_file.py index d7cbbce..cd76288 100644 --- a/je_auto_control/utils/json/json_file.py +++ b/je_auto_control/utils/json/json_file.py @@ -23,10 +23,9 @@ def read_action_json(json_file_path: str) -> List[List[Dict[str, Dict[str, str]] if file_path.exists() and file_path.is_file(): with open(json_file_path, encoding="utf-8") as read_file: return json.load(read_file) - else: - raise AutoControlJsonActionException(cant_find_json_error_message) - except Exception as error: - raise AutoControlJsonActionException(f"{cant_find_json_error_message}: {repr(error)}") + raise AutoControlJsonActionException(cant_find_json_error_message) + except (OSError, json.JSONDecodeError) as error: + raise AutoControlJsonActionException(f"{cant_find_json_error_message}: {repr(error)}") from error def write_action_json(json_save_path: str, action_json: list) -> None: @@ -41,5 +40,5 @@ def write_action_json(json_save_path: str, action_json: list) -> None: try: with open(json_save_path, "w+", encoding="utf-8") as file_to_write: json.dump(action_json, file_to_write, indent=4, ensure_ascii=False) - except Exception as error: - raise AutoControlJsonActionException(f"{cant_save_json_error_message}: {repr(error)}") \ No newline at end of file + except (OSError, TypeError, ValueError) as error: + raise AutoControlJsonActionException(f"{cant_save_json_error_message}: {repr(error)}") from error \ No newline at end of file diff --git a/je_auto_control/utils/package_manager/package_manager_class.py b/je_auto_control/utils/package_manager/package_manager_class.py index 361c471..9e14538 100644 --- a/je_auto_control/utils/package_manager/package_manager_class.py +++ b/je_auto_control/utils/package_manager/package_manager_class.py @@ -2,7 +2,6 @@ from importlib.util import find_spec from inspect import getmembers, isfunction, isbuiltin, isclass from types import ModuleType -from sys import stderr from typing import Optional from je_auto_control.utils.logging.logging_instance import autocontrol_logger @@ -36,7 +35,7 @@ def check_package(self, package: str) -> Optional[ModuleType]: installed_package = importlib.import_module(found_spec.name) self.installed_package_dict[found_spec.name] = installed_package except ModuleNotFoundError as error: - print(repr(error), file=stderr) + autocontrol_logger.error("import %s failed: %r", package, error) return self.installed_package_dict.get(package) def add_package_to_executor(self, package: str) -> None: @@ -69,9 +68,9 @@ def get_member(self, package: str, predicate, target) -> None: for member in getmembers(installed_package, predicate): target.event_dict[f"{package}_{member[0]}"] = member[1] elif installed_package is None: - print(repr(ModuleNotFoundError(f"Can't find package {package}")), file=stderr) + autocontrol_logger.error("can't find package %s", package) else: - print(f"Executor error {self.executor}", file=stderr) + autocontrol_logger.error("Executor error %r", self.executor) def add_package_to_target(self, package: str, target) -> None: """ @@ -84,8 +83,8 @@ def add_package_to_target(self, package: str, target) -> None: try: for predicate in (isfunction, isbuiltin, isclass): self.get_member(package, predicate, target) - except Exception as error: - print(repr(error), file=stderr) + except (ImportError, AttributeError, TypeError) as error: + autocontrol_logger.error("add_package_to_target failed: %r", error) # 全域 PackageManager 實例 Global instance diff --git a/je_auto_control/utils/shell_process/shell_exec.py b/je_auto_control/utils/shell_process/shell_exec.py index 35531f9..67d236d 100644 --- a/je_auto_control/utils/shell_process/shell_exec.py +++ b/je_auto_control/utils/shell_process/shell_exec.py @@ -3,16 +3,27 @@ import subprocess import sys from threading import Thread -from typing import Union +from typing import List, Union from je_auto_control.utils.logging.logging_instance import autocontrol_logger +def _normalize_command(shell_command: Union[str, List[str]]) -> List[str]: + """ + Normalize shell command to an argv list with no shell interpretation. + 將 shell 指令正規化為 argv list,不經 shell 解譯,避免指令注入。 + """ + if isinstance(shell_command, list): + return [str(part) for part in shell_command] + posix_mode = sys.platform not in ("win32", "cygwin", "msys") + return shlex.split(shell_command, posix=posix_mode) + + class ShellManager: """ ShellManager Shell 指令管理器 - - 執行外部 shell 指令 + - 執行外部 shell 指令 (不使用 shell=True,避免注入) - 使用背景執行緒持續讀取 stdout / stderr - 將輸出放入 queue,供 pull_text() 取出 """ @@ -31,68 +42,58 @@ def __init__(self, shell_encoding: str = "utf-8", program_buffer: int = 10240000 self.program_encoding: str = shell_encoding self.program_buffer: int = program_buffer - def exec_shell(self, shell_command: Union[str, list]) -> None: + def exec_shell(self, shell_command: Union[str, List[str]]) -> None: """ - Execute shell command. - 執行 shell 指令 + Execute shell command with shell=False. + 執行 shell 指令 (shell=False,呼叫端需自備 argv 或可被 shlex 切分的字串) """ autocontrol_logger.info(f"exec_shell, shell_command: {shell_command}") try: self.exit_program() - - if sys.platform in ["win32", "cygwin", "msys"]: - args = shell_command if isinstance(shell_command, str) else " ".join(shell_command) - self.process = subprocess.Popen( - args, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - shell=True, - ) - else: - args = shlex.split(shell_command) if isinstance(shell_command, str) else shell_command - self.process = subprocess.Popen( - args, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - shell=False, - ) + args = _normalize_command(shell_command) + self.process = subprocess.Popen( # nosec B603 # reason: shell=False, argv list validated via _normalize_command + args, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=False, + ) self.still_run_shell = True - # stdout thread self.read_program_output_from_thread = Thread( target=self._read_stream, args=(self.process.stdout, self.run_output_queue), - daemon=True + daemon=True, ) self.read_program_output_from_thread.start() - # stderr thread self.read_program_error_output_from_thread = Thread( target=self._read_stream, args=(self.process.stderr, self.run_error_queue), - daemon=True + daemon=True, ) self.read_program_error_output_from_thread.start() - except Exception as error: - autocontrol_logger.error(f"exec_shell failed, shell_command: {shell_command}, error: {repr(error)}") + except (OSError, ValueError) as error: + autocontrol_logger.error( + f"exec_shell failed, shell_command: {shell_command}, error: {repr(error)}" + ) def pull_text(self) -> None: """ - Pull text from queues and print. - 從 queue 取出訊息並輸出 + Pull text from queues and log. + 從 queue 取出訊息並透過 logger 輸出 """ try: while not self.run_error_queue.empty(): error_message = self.run_error_queue.get_nowait().strip() if error_message: - print(error_message, file=sys.stderr) + autocontrol_logger.error(error_message) while not self.run_output_queue.empty(): output_message = self.run_output_queue.get_nowait().strip() if output_message: - print(output_message) + autocontrol_logger.info(output_message) except queue.Empty: pass @@ -109,21 +110,23 @@ def exit_program(self) -> None: if self.process is not None: self.process.terminate() - print(f"Shell command exit with code {self.process.returncode}") + autocontrol_logger.info( + f"Shell command exit with code {self.process.returncode}" + ) self.process = None - self.print_and_clear_queue() + self.log_and_clear_queue() - def print_and_clear_queue(self) -> None: + def log_and_clear_queue(self) -> None: """ - Print and clear queues. - 輸出並清空 queue + Log and clear queues. + 透過 logger 輸出並清空 queue """ while not self.run_output_queue.empty(): - print(self.run_output_queue.get_nowait().strip()) + autocontrol_logger.info(self.run_output_queue.get_nowait().strip()) while not self.run_error_queue.empty(): - print(self.run_error_queue.get_nowait().strip(), file=sys.stderr) + autocontrol_logger.error(self.run_error_queue.get_nowait().strip()) self.run_output_queue = queue.Queue() self.run_error_queue = queue.Queue() @@ -140,5 +143,4 @@ def _read_stream(self, stream, target_queue: queue.Queue) -> None: target_queue.put_nowait(line.decode(self.program_encoding, "replace")) -# 預設 ShellManager 實例 Default instance -default_shell_manager = ShellManager() \ No newline at end of file +default_shell_manager = ShellManager() diff --git a/je_auto_control/utils/socket_server/auto_control_socket_server.py b/je_auto_control/utils/socket_server/auto_control_socket_server.py index bb51227..6110680 100644 --- a/je_auto_control/utils/socket_server/auto_control_socket_server.py +++ b/je_auto_control/utils/socket_server/auto_control_socket_server.py @@ -1,9 +1,9 @@ import json import socketserver -import sys import threading from je_auto_control.utils.executor.action_executor import execute_action +from je_auto_control.utils.logging.logging_instance import autocontrol_logger class TCPServerHandler(socketserver.BaseRequestHandler): @@ -11,11 +11,11 @@ class TCPServerHandler(socketserver.BaseRequestHandler): def handle(self) -> None: command_string = str(self.request.recv(8192).strip(), encoding="utf-8") socket = self.request - print("command is: " + command_string, flush=True) + autocontrol_logger.info("command is: %s", command_string) if command_string == "quit_server": self.server.shutdown() self.server.close_flag = True - print("Now quit server", flush=True) + autocontrol_logger.info("Now quit server") else: try: execute_str = json.loads(command_string) @@ -24,15 +24,15 @@ def handle(self) -> None: socket.sendall("\n".encode("utf-8")) socket.sendall("Return_Data_Over_JE".encode("utf-8")) socket.sendall("\n".encode("utf-8")) - except Exception as error: - print(repr(error), file=sys.stderr) + except (json.JSONDecodeError, ValueError, RuntimeError) as error: + autocontrol_logger.error("socket command failed: %r", error) try: socket.sendall(str(error).encode("utf-8")) socket.sendall("\n".encode("utf-8")) socket.sendall("Return_Data_Over_JE".encode("utf-8")) socket.sendall("\n".encode("utf-8")) - except Exception as error: - print(repr(error)) + except OSError as send_error: + autocontrol_logger.error("send error reply failed: %r", send_error) class TCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): @@ -42,12 +42,14 @@ def __init__(self, server_address, request_handler_class): self.close_flag: bool = False -def start_autocontrol_socket_server(host: str = "localhost", port: int = 9938) -> TCPServer: - if len(sys.argv) == 2: - host = sys.argv[1] - elif len(sys.argv) == 3: - host = sys.argv[1] - port = int(sys.argv[2]) +def start_autocontrol_socket_server(host: str = "127.0.0.1", port: int = 9938) -> TCPServer: + """ + Start the AutoControl TCP command server. + 啟動 AutoControl TCP 指令伺服器。 + + :param host: bind address; defaults to localhost for least privilege. + :param port: TCP port to listen on. + """ server = TCPServer((host, port), TCPServerHandler) server_thread = threading.Thread(target=server.serve_forever) server_thread.daemon = True diff --git a/je_auto_control/utils/start_exe/start_another_process.py b/je_auto_control/utils/start_exe/start_another_process.py index a650958..f0ed77f 100644 --- a/je_auto_control/utils/start_exe/start_another_process.py +++ b/je_auto_control/utils/start_exe/start_another_process.py @@ -23,11 +23,11 @@ def start_exe(exe_path: str) -> None: process_manager = ShellManager() process_manager.exec_shell(str(exe_path_obj)) autocontrol_logger.info(f"Successfully started executable: {exe_path_obj}") - except Exception as error: + except (OSError, ValueError, RuntimeError) as error: autocontrol_logger.error( f"start_exe, exe_path: {exe_path_obj}, exec_shell failed: {repr(error)}" ) - raise AutoControlException(f"Failed to execute {exe_path_obj}: {repr(error)}") + raise AutoControlException(f"Failed to execute {exe_path_obj}: {repr(error)}") from error else: autocontrol_logger.error( f"start_exe, exe_path: {exe_path_obj}, failed: {can_not_find_file_error_message}" diff --git a/je_auto_control/utils/xml/xml_file/xml_file.py b/je_auto_control/utils/xml/xml_file/xml_file.py index c2a914f..6955246 100644 --- a/je_auto_control/utils/xml/xml_file/xml_file.py +++ b/je_auto_control/utils/xml/xml_file/xml_file.py @@ -57,8 +57,8 @@ def xml_parser_from_string(self, **kwargs) -> ElementTree.Element: """ try: self.xml_root = ElementTree.fromstring(self.xml_string, **kwargs) - except ParseError as e: - raise XMLException(f"{cant_read_xml_error_message}: {repr(e)}") + except ParseError as error: + raise XMLException(f"{cant_read_xml_error_message}: {repr(error)}") from error return self.xml_root def xml_parser_from_file(self, **kwargs) -> ElementTree.Element: @@ -70,8 +70,8 @@ def xml_parser_from_file(self, **kwargs) -> ElementTree.Element: """ try: self.tree = ElementTree.parse(self.xml_string, **kwargs) - except (OSError, ParseError) as e: - raise XMLException(f"{cant_read_xml_error_message}: {repr(e)}") + except (OSError, ParseError) as error: + raise XMLException(f"{cant_read_xml_error_message}: {repr(error)}") from error self.xml_root = self.tree.getroot() self.xml_from_type = "file" return self.xml_root @@ -88,5 +88,5 @@ def write_xml(self, write_xml_filename: str, write_content: str) -> None: content = ElementTree.fromstring(write_content.strip()) tree = ElementTree.ElementTree(content) tree.write(write_xml_filename, encoding="utf-8", xml_declaration=True) - except ParseError as e: - raise XMLException(f"{cant_read_xml_error_message}: {repr(e)}") \ No newline at end of file + except ParseError as error: + raise XMLException(f"{cant_read_xml_error_message}: {repr(error)}") from error \ No newline at end of file diff --git a/je_auto_control/wrapper/_platform_linux.py b/je_auto_control/wrapper/_platform_linux.py new file mode 100644 index 0000000..4e1f9fb --- /dev/null +++ b/je_auto_control/wrapper/_platform_linux.py @@ -0,0 +1,225 @@ +from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import ( + x11_linux_key_backspace, x11_linux_key_slash_b, x11_linux_key_tab, + x11_linux_key_enter, x11_linux_key_return, x11_linux_key_shift, + x11_linux_key_ctrl, x11_linux_key_alt, x11_linux_key_pause, + x11_linux_key_capslock, x11_linux_key_esc, x11_linux_key_pgup, + x11_linux_key_pgdn, x11_linux_key_pageup, x11_linux_key_pagedown, + x11_linux_key_end, x11_linux_key_home, x11_linux_key_left, + x11_linux_key_up, x11_linux_key_right, x11_linux_key_down, + x11_linux_key_select, x11_linux_key_print, x11_linux_key_execute, + x11_linux_key_prtsc, x11_linux_key_prtscr, x11_linux_key_prntscrn, + x11_linux_key_insert, x11_linux_key_del, x11_linux_key_delete, + x11_linux_key_help, x11_linux_key_win, x11_linux_key_winleft, + x11_linux_key_winright, x11_linux_key_apps, + x11_linux_key_num0, x11_linux_key_num1, x11_linux_key_num2, + x11_linux_key_num3, x11_linux_key_num4, x11_linux_key_num5, + x11_linux_key_num6, x11_linux_key_num7, x11_linux_key_num8, + x11_linux_key_num9, x11_linux_key_multiply, x11_linux_key_add, + x11_linux_key_separator, x11_linux_key_subtract, + x11_linux_key_decimal, x11_linux_key_divide, + x11_linux_key_f1, x11_linux_key_f2, x11_linux_key_f3, x11_linux_key_f4, + x11_linux_key_f5, x11_linux_key_f6, x11_linux_key_f7, x11_linux_key_f8, + x11_linux_key_f9, x11_linux_key_f10, x11_linux_key_f11, x11_linux_key_f12, + x11_linux_key_f13, x11_linux_key_f14, x11_linux_key_f15, x11_linux_key_f16, + x11_linux_key_f17, x11_linux_key_f18, x11_linux_key_f19, x11_linux_key_f20, + x11_linux_key_f21, x11_linux_key_f22, x11_linux_key_f23, x11_linux_key_f24, + x11_linux_key_numlock, x11_linux_key_scrolllock, + x11_linux_key_shiftleft, x11_linux_key_shiftright, + x11_linux_key_ctrlleft, x11_linux_key_ctrlright, + x11_linux_key_altleft, x11_linux_key_altright, + x11_linux_key_space, x11_linux_key_newline_n, x11_linux_key_newline_r, + x11_linux_key_newline_t, x11_linux_key_exclam, x11_linux_key_numbersign, + x11_linux_key_percent, x11_linux_key_dollar, x11_linux_key_ampersand, + x11_linux_key_quotedbl, x11_linux_key_apostrophe, + x11_linux_key_parenleft, x11_linux_key_parenright, + x11_linux_key_asterisk, x11_linux_key_equal, x11_linux_key_plus, + x11_linux_key_comma, x11_linux_key_minus, x11_linux_key_period, + x11_linux_key_slash, x11_linux_key_colon, x11_linux_key_semicolon, + x11_linux_key_less, x11_linux_key_greater, x11_linux_key_question, + x11_linux_key_at, x11_linux_key_bracketleft, x11_linux_key_bracketright, + x11_linux_key_backslash, x11_linux_key_asciicircum, + x11_linux_key_underscore, x11_linux_key_grave, + x11_linux_key_braceleft, x11_linux_key_bar, x11_linux_key_braceright, + x11_linux_key_asciitilde, + x11_linux_key_a, x11_linux_key_b, x11_linux_key_c, x11_linux_key_d, + x11_linux_key_e, x11_linux_key_f, x11_linux_key_g, x11_linux_key_h, + x11_linux_key_i, x11_linux_key_j, x11_linux_key_k, x11_linux_key_l, + x11_linux_key_m, x11_linux_key_n, x11_linux_key_o, x11_linux_key_p, + x11_linux_key_q, x11_linux_key_r, x11_linux_key_s, x11_linux_key_t, + x11_linux_key_u, x11_linux_key_v, x11_linux_key_w, x11_linux_key_x, + x11_linux_key_y, x11_linux_key_z, + x11_linux_key_A, x11_linux_key_B, x11_linux_key_C, x11_linux_key_D, + x11_linux_key_E, x11_linux_key_F, x11_linux_key_G, x11_linux_key_H, + x11_linux_key_I, x11_linux_key_J, x11_linux_key_K, x11_linux_key_L, + x11_linux_key_M, x11_linux_key_N, x11_linux_key_O, x11_linux_key_P, + x11_linux_key_Q, x11_linux_key_R, x11_linux_key_S, x11_linux_key_T, + x11_linux_key_U, x11_linux_key_V, x11_linux_key_W, x11_linux_key_X, + x11_linux_key_Y, x11_linux_key_Z, + x11_linux_key_1, x11_linux_key_2, x11_linux_key_3, x11_linux_key_4, + x11_linux_key_5, x11_linux_key_6, x11_linux_key_7, x11_linux_key_8, + x11_linux_key_9, x11_linux_key_0, +) +from je_auto_control.linux_with_x11.keyboard import x11_linux_keyboard_control +from je_auto_control.linux_with_x11.listener import x11_linux_listener +from je_auto_control.linux_with_x11.mouse import x11_linux_mouse_control +from je_auto_control.linux_with_x11.mouse.x11_linux_mouse_control import ( + x11_linux_mouse_left, x11_linux_mouse_middle, x11_linux_mouse_right, + x11_linux_scroll_direction_up, x11_linux_scroll_direction_down, + x11_linux_scroll_direction_left, x11_linux_scroll_direction_right, +) +from je_auto_control.linux_with_x11.record.x11_linux_record import x11_linux_recoder +from je_auto_control.linux_with_x11.screen import x11_linux_screen +from je_auto_control.utils.exception.exceptions import AutoControlException +from je_auto_control.utils.logging.logging_instance import autocontrol_logger + +autocontrol_logger.info("Load Linux x11 Setting") + +keyboard_keys_table = { + "backspace": x11_linux_key_backspace, + "\b": x11_linux_key_slash_b, + "tab": x11_linux_key_tab, + "enter": x11_linux_key_enter, + "return": x11_linux_key_return, + "shift": x11_linux_key_shift, + "ctrl": x11_linux_key_ctrl, + "alt": x11_linux_key_alt, + "pause": x11_linux_key_pause, + "capslock": x11_linux_key_capslock, + "esc": x11_linux_key_esc, + "pgup": x11_linux_key_pgup, + "pgdn": x11_linux_key_pgdn, + "pageup": x11_linux_key_pageup, + "pagedown": x11_linux_key_pagedown, + "end": x11_linux_key_end, + "home": x11_linux_key_home, + "left": x11_linux_key_left, + "up": x11_linux_key_up, + "right": x11_linux_key_right, + "down": x11_linux_key_down, + "select": x11_linux_key_select, + "print": x11_linux_key_print, + "execute": x11_linux_key_execute, + "prtsc": x11_linux_key_prtsc, + "prtscr": x11_linux_key_prtscr, + "prntscrn": x11_linux_key_prntscrn, + "insert": x11_linux_key_insert, + "del": x11_linux_key_del, + "delete": x11_linux_key_delete, + "help": x11_linux_key_help, + "win": x11_linux_key_win, + "winleft": x11_linux_key_winleft, + "winright": x11_linux_key_winright, + "apps": x11_linux_key_apps, + "num0": x11_linux_key_num0, + "num1": x11_linux_key_num1, + "num2": x11_linux_key_num2, + "num3": x11_linux_key_num3, + "num4": x11_linux_key_num4, + "num5": x11_linux_key_num5, + "num6": x11_linux_key_num6, + "num7": x11_linux_key_num7, + "num8": x11_linux_key_num8, + "num9": x11_linux_key_num9, + "multiply": x11_linux_key_multiply, + "add": x11_linux_key_add, + "separator": x11_linux_key_separator, + "subtract": x11_linux_key_subtract, + "decimal": x11_linux_key_decimal, + "divide": x11_linux_key_divide, + "f1": x11_linux_key_f1, "f2": x11_linux_key_f2, "f3": x11_linux_key_f3, + "f4": x11_linux_key_f4, "f5": x11_linux_key_f5, "f6": x11_linux_key_f6, + "f7": x11_linux_key_f7, "f8": x11_linux_key_f8, "f9": x11_linux_key_f9, + "f10": x11_linux_key_f10, "f11": x11_linux_key_f11, "f12": x11_linux_key_f12, + "f13": x11_linux_key_f13, "f14": x11_linux_key_f14, "f15": x11_linux_key_f15, + "f16": x11_linux_key_f16, "f17": x11_linux_key_f17, "f18": x11_linux_key_f18, + "f19": x11_linux_key_f19, "f20": x11_linux_key_f20, "f21": x11_linux_key_f21, + "f22": x11_linux_key_f22, "f23": x11_linux_key_f23, "f24": x11_linux_key_f24, + "numlock": x11_linux_key_numlock, + "scrolllock": x11_linux_key_scrolllock, + "shiftleft": x11_linux_key_shiftleft, + "shiftright": x11_linux_key_shiftright, + "ctrlleft": x11_linux_key_ctrlleft, + "ctrlright": x11_linux_key_ctrlright, + "altleft": x11_linux_key_altleft, + "altright": x11_linux_key_altright, + "space": x11_linux_key_space, + "\n": x11_linux_key_newline_n, + "\r": x11_linux_key_newline_r, + "\t": x11_linux_key_newline_t, + "!": x11_linux_key_exclam, + "#": x11_linux_key_numbersign, + "%": x11_linux_key_percent, + "$": x11_linux_key_dollar, + "&": x11_linux_key_ampersand, + '"': x11_linux_key_quotedbl, + "'": x11_linux_key_apostrophe, + "(": x11_linux_key_parenleft, + ")": x11_linux_key_parenright, + "*": x11_linux_key_asterisk, + "=": x11_linux_key_equal, + "+": x11_linux_key_plus, + ",": x11_linux_key_comma, + "-": x11_linux_key_minus, + ".": x11_linux_key_period, + "/": x11_linux_key_slash, + ":": x11_linux_key_colon, + ";": x11_linux_key_semicolon, + "<": x11_linux_key_less, + ">": x11_linux_key_greater, + "?": x11_linux_key_question, + "@": x11_linux_key_at, + "[": x11_linux_key_bracketleft, + "]": x11_linux_key_bracketright, + "\\": x11_linux_key_backslash, + "^": x11_linux_key_asciicircum, + "_": x11_linux_key_underscore, + "`": x11_linux_key_grave, + "{": x11_linux_key_braceleft, + "|": x11_linux_key_bar, + "}": x11_linux_key_braceright, + "~": x11_linux_key_asciitilde, + "a": x11_linux_key_a, "b": x11_linux_key_b, "c": x11_linux_key_c, + "d": x11_linux_key_d, "e": x11_linux_key_e, "f": x11_linux_key_f, + "g": x11_linux_key_g, "h": x11_linux_key_h, "i": x11_linux_key_i, + "j": x11_linux_key_j, "k": x11_linux_key_k, "l": x11_linux_key_l, + "m": x11_linux_key_m, "n": x11_linux_key_n, "o": x11_linux_key_o, + "p": x11_linux_key_p, "q": x11_linux_key_q, "r": x11_linux_key_r, + "s": x11_linux_key_s, "t": x11_linux_key_t, "u": x11_linux_key_u, + "v": x11_linux_key_v, "w": x11_linux_key_w, "x": x11_linux_key_x, + "y": x11_linux_key_y, "z": x11_linux_key_z, + "A": x11_linux_key_A, "B": x11_linux_key_B, "C": x11_linux_key_C, + "D": x11_linux_key_D, "E": x11_linux_key_E, "F": x11_linux_key_F, + "G": x11_linux_key_G, "H": x11_linux_key_H, "I": x11_linux_key_I, + "J": x11_linux_key_J, "K": x11_linux_key_K, "L": x11_linux_key_L, + "M": x11_linux_key_M, "N": x11_linux_key_N, "O": x11_linux_key_O, + "P": x11_linux_key_P, "Q": x11_linux_key_Q, "R": x11_linux_key_R, + "S": x11_linux_key_S, "T": x11_linux_key_T, "U": x11_linux_key_U, + "V": x11_linux_key_V, "W": x11_linux_key_W, "X": x11_linux_key_X, + "Y": x11_linux_key_Y, "Z": x11_linux_key_Z, + "1": x11_linux_key_1, "2": x11_linux_key_2, "3": x11_linux_key_3, + "4": x11_linux_key_4, "5": x11_linux_key_5, "6": x11_linux_key_6, + "7": x11_linux_key_7, "8": x11_linux_key_8, "9": x11_linux_key_9, + "0": x11_linux_key_0, +} + +mouse_keys_table = { + "mouse_left": x11_linux_mouse_left, + "mouse_middle": x11_linux_mouse_middle, + "mouse_right": x11_linux_mouse_right, +} + +special_mouse_keys_table = { + "scroll_up": x11_linux_scroll_direction_up, + "scroll_down": x11_linux_scroll_direction_down, + "scroll_left": x11_linux_scroll_direction_left, + "scroll_right": x11_linux_scroll_direction_right, +} + +keyboard = x11_linux_keyboard_control +keyboard_check = x11_linux_listener +mouse = x11_linux_mouse_control +screen = x11_linux_screen +recorder = x11_linux_recoder + +if None in [keyboard_keys_table, mouse_keys_table, special_mouse_keys_table, keyboard, mouse, screen, recorder]: + raise AutoControlException("Can't init auto control") diff --git a/je_auto_control/wrapper/_platform_osx.py b/je_auto_control/wrapper/_platform_osx.py new file mode 100644 index 0000000..9714a88 --- /dev/null +++ b/je_auto_control/wrapper/_platform_osx.py @@ -0,0 +1,149 @@ +from je_auto_control.osx.core.utils.osx_vk import ( + osx_key_a, osx_key_A, osx_key_b, osx_key_B, osx_key_c, osx_key_C, + osx_key_d, osx_key_D, osx_key_e, osx_key_E, osx_key_f, osx_key_F, + osx_key_g, osx_key_G, osx_key_h, osx_key_H, osx_key_i, osx_key_I, + osx_key_j, osx_key_J, osx_key_k, osx_key_K, osx_key_l, osx_key_L, + osx_key_m, osx_key_M, osx_key_n, osx_key_N, osx_key_o, osx_key_O, + osx_key_p, osx_key_P, osx_key_q, osx_key_Q, osx_key_r, osx_key_R, + osx_key_s, osx_key_S, osx_key_t, osx_key_T, osx_key_u, osx_key_U, + osx_key_v, osx_key_V, osx_key_w, osx_key_W, osx_key_x, osx_key_X, + osx_key_y, osx_key_Y, osx_key_z, osx_key_Z, + osx_key_1, osx_key_exclam, osx_key_2, osx_key_at, + osx_key_3, osx_key_numbersign, osx_key_4, osx_key_money, + osx_key_5, osx_key_percent, osx_key_6, osx_key_asciicircum, + osx_key_7, osx_key_ampersand, osx_key_8, osx_key_asterisk, + osx_key_9, osx_key_parenleft, osx_key_0, osx_key_parenright, + osx_key_equal, osx_key_plus, osx_key_minus, osx_key_underscore, + osx_key_bracketright, osx_key_braceright, + osx_key_bracketleft, osx_key_braceleft, + osx_key_apostrophe, osx_key_quotedbl, + osx_key_semicolon, osx_key_colon, osx_key_backslash, osx_key_bar, + osx_key_comma, osx_key_less, osx_key_slash, osx_key_question, + osx_key_period, osx_key_greater, osx_key_grave, osx_key_asciitilde, + osx_key_space, osx_key_return, osx_key_newline, osx_key_enter, + osx_key_tab, osx_key_backspace, osx_key_esc, osx_key_command, + osx_key_shift, osx_key_caps_lock, osx_key_option, osx_key_alt, + osx_key_ctrl, osx_key_shift_right, osx_key_option_right, + osx_key_control_right, osx_key_fn, + osx_key_volume_up, osx_key_volume_down, osx_key_volume_mute, + osx_key_f1, osx_key_f2, osx_key_f3, osx_key_f4, osx_key_f5, + osx_key_f6, osx_key_f7, osx_key_f8, osx_key_f9, osx_key_f10, + osx_key_f11, osx_key_f12, osx_key_f13, osx_key_f14, osx_key_f15, + osx_key_f16, osx_key_f17, osx_key_f18, osx_key_f19, osx_key_f20, + osx_key_help, osx_key_home, osx_key_pageup, osx_key_end, + osx_key_pagedown, osx_key_left, osx_key_right, osx_key_down, osx_key_up, + osx_key_yen, osx_key_eisu, osx_key_kana, + osx_mouse_left, osx_mouse_middle, osx_mouse_right, +) +from je_auto_control.osx.keyboard import osx_keyboard, osx_keyboard_check +from je_auto_control.osx.mouse import osx_mouse +from je_auto_control.osx.screen import osx_screen +from je_auto_control.utils.exception.exceptions import AutoControlException +from je_auto_control.utils.logging.logging_instance import autocontrol_logger + +autocontrol_logger.info("Load MacOS Setting") + +keyboard_keys_table = { + "a": osx_key_a, "A": osx_key_A, + "b": osx_key_b, "B": osx_key_B, + "c": osx_key_c, "C": osx_key_C, + "d": osx_key_d, "D": osx_key_D, + "e": osx_key_e, "E": osx_key_E, + "f": osx_key_f, "F": osx_key_F, + "g": osx_key_g, "G": osx_key_G, + "h": osx_key_h, "H": osx_key_H, + "i": osx_key_i, "I": osx_key_I, + "j": osx_key_j, "J": osx_key_J, + "k": osx_key_k, "K": osx_key_K, + "l": osx_key_l, "L": osx_key_L, + "m": osx_key_m, "M": osx_key_M, + "n": osx_key_n, "N": osx_key_N, + "o": osx_key_o, "O": osx_key_O, + "p": osx_key_p, "P": osx_key_P, + "q": osx_key_q, "Q": osx_key_Q, + "r": osx_key_r, "R": osx_key_R, + "s": osx_key_s, "S": osx_key_S, + "t": osx_key_t, "T": osx_key_T, + "u": osx_key_u, "U": osx_key_U, + "v": osx_key_v, "V": osx_key_V, + "w": osx_key_w, "W": osx_key_W, + "x": osx_key_x, "X": osx_key_X, + "y": osx_key_y, "Y": osx_key_Y, + "z": osx_key_z, "Z": osx_key_Z, + "1": osx_key_1, "!": osx_key_exclam, + "2": osx_key_2, "@": osx_key_at, + "3": osx_key_3, "#": osx_key_numbersign, + "4": osx_key_4, "$": osx_key_money, + "5": osx_key_5, "%": osx_key_percent, + "6": osx_key_6, "^": osx_key_asciicircum, + "7": osx_key_7, "&": osx_key_ampersand, + "8": osx_key_8, "*": osx_key_asterisk, + "9": osx_key_9, "(": osx_key_parenleft, + "0": osx_key_0, ")": osx_key_parenright, + "=": osx_key_equal, "+": osx_key_plus, + "-": osx_key_minus, "_": osx_key_underscore, + "]": osx_key_bracketright, "}": osx_key_braceright, + "[": osx_key_bracketleft, "{": osx_key_braceleft, + "'": osx_key_apostrophe, '"': osx_key_quotedbl, + ";": osx_key_semicolon, ":": osx_key_colon, + "\\": osx_key_backslash, "|": osx_key_bar, + ",": osx_key_comma, "<": osx_key_less, + "/": osx_key_slash, "?": osx_key_question, + ".": osx_key_period, ">": osx_key_greater, + "`": osx_key_grave, "~": osx_key_asciitilde, + "space": osx_key_space, + "return": osx_key_return, + "newline": osx_key_newline, + "enter": osx_key_enter, + "tab": osx_key_tab, + "backspace": osx_key_backspace, + "esc": osx_key_esc, + "command": osx_key_command, + "shift": osx_key_shift, + "caps_lock": osx_key_caps_lock, + "option": osx_key_option, + "alt": osx_key_alt, + "ctrl": osx_key_ctrl, + "shift_right": osx_key_shift_right, + "option_right": osx_key_option_right, + "control_right": osx_key_control_right, + "fn": osx_key_fn, + "volume_up": osx_key_volume_up, + "volume_down": osx_key_volume_down, + "volume_mute": osx_key_volume_mute, + "f1": osx_key_f1, "f2": osx_key_f2, "f3": osx_key_f3, + "f4": osx_key_f4, "f5": osx_key_f5, "f6": osx_key_f6, + "f7": osx_key_f7, "f8": osx_key_f8, "f9": osx_key_f9, + "f10": osx_key_f10, "f11": osx_key_f11, "f12": osx_key_f12, + "f13": osx_key_f13, "f14": osx_key_f14, "f15": osx_key_f15, + "f16": osx_key_f16, "f17": osx_key_f17, "f18": osx_key_f18, + "f19": osx_key_f19, "f20": osx_key_f20, + "help": osx_key_help, + "home": osx_key_home, + "pageup": osx_key_pageup, + "end": osx_key_end, + "pagedown": osx_key_pagedown, + "left": osx_key_left, + "right": osx_key_right, + "down": osx_key_down, + "up": osx_key_up, + "yen": osx_key_yen, + "eisu": osx_key_eisu, + "kana": osx_key_kana, +} + +mouse_keys_table = { + "mouse_left": osx_mouse_left, + "mouse_middle": osx_mouse_middle, + "mouse_right": osx_mouse_right, +} + +special_mouse_keys_table = None +keyboard = osx_keyboard +keyboard_check = osx_keyboard_check +mouse = osx_mouse +screen = osx_screen +recorder = None + +if None in [keyboard_keys_table, mouse_keys_table, keyboard_check, keyboard, mouse, screen]: + raise AutoControlException("Can't init auto control") diff --git a/je_auto_control/wrapper/_platform_windows.py b/je_auto_control/wrapper/_platform_windows.py new file mode 100644 index 0000000..55541f7 --- /dev/null +++ b/je_auto_control/wrapper/_platform_windows.py @@ -0,0 +1,272 @@ +from je_auto_control.utils.exception.exceptions import AutoControlException +from je_auto_control.utils.logging.logging_instance import autocontrol_logger +from je_auto_control.windows.core.utils import win32_keypress_check +from je_auto_control.windows.core.utils.win32_vk import ( + WIN32_ABSOLUTE, WIN32_EventF_EXTENDEDKEY, WIN32_EventF_KEYUP, + WIN32_EventF_SCANCODE, WIN32_EventF_UNICODE, WIN32_HWHEEL, + WIN32_LEFTDOWN, WIN32_LEFTUP, WIN32_MIDDLEDOWN, WIN32_MIDDLEUP, + WIN32_MOVE, WIN32_RIGHTDOWN, WIN32_RIGHTUP, + WIN32_VK_ACCEPT, WIN32_VK_ADD, WIN32_VK_APPS, WIN32_VK_BACK, + WIN32_VK_BROWSER_BACK, WIN32_VK_BROWSER_FAVORITES, + WIN32_VK_BROWSER_FORWARD, WIN32_VK_BROWSER_REFRESH, + WIN32_VK_BROWSER_SEARCH, WIN32_VK_BROWSER_STOP, WIN32_VK_CANCEL, + WIN32_VK_CAPITAL, WIN32_VK_CLEAR, WIN32_VK_CONTROL, WIN32_VK_CONVERT, + WIN32_VK_DECIMAL, WIN32_VK_DELETE, WIN32_VK_DIVIDE, WIN32_VK_DOWN, + WIN32_VK_END, WIN32_VK_ESCAPE, WIN32_VK_EXECUTE, + WIN32_VK_F1, WIN32_VK_F2, WIN32_VK_F3, WIN32_VK_F4, WIN32_VK_F5, + WIN32_VK_F6, WIN32_VK_F7, WIN32_VK_F8, WIN32_VK_F9, WIN32_VK_F10, + WIN32_VK_F11, WIN32_VK_F12, WIN32_VK_F13, WIN32_VK_F14, WIN32_VK_F15, + WIN32_VK_F16, WIN32_VK_F17, WIN32_VK_F18, WIN32_VK_F19, WIN32_VK_F20, + WIN32_VK_F21, WIN32_VK_F22, WIN32_VK_F23, WIN32_VK_F24, + WIN32_VK_FINAL, WIN32_VK_HANJA, WIN32_VK_HELP, WIN32_VK_HOME, + WIN32_VK_IME_OFF, WIN32_VK_IME_ON, WIN32_VK_INSERT, WIN32_VK_JUNJA, + WIN32_VK_KANA, WIN32_VK_LAUNCH_APP1, WIN32_VK_LAUNCH_APP2, + WIN32_VK_LAUNCH_MAIL, WIN32_VK_LAUNCH_MEDIA_SELECT, + WIN32_VK_LBUTTON, WIN32_VK_LCONTROL, WIN32_VK_LEFT, WIN32_VK_LMENU, + WIN32_VK_LSHIFT, WIN32_VK_LWIN, WIN32_VK_MBUTTON, + WIN32_VK_MEDIA_NEXT_TRACK, WIN32_VK_MEDIA_PLAY_PAUSE, + WIN32_VK_MEDIA_PREV_TRACK, WIN32_VK_MEDIA_STOP, + WIN32_VK_MODECHANGE, WIN32_VK_MULTIPLY, WIN32_VK_Menu, + WIN32_VK_NEXT, WIN32_VK_NONCONVERT, WIN32_VK_NUMLOCK, + WIN32_VK_NUMPAD0, WIN32_VK_NUMPAD1, WIN32_VK_NUMPAD2, + WIN32_VK_NUMPAD3, WIN32_VK_NUMPAD4, WIN32_VK_NUMPAD5, + WIN32_VK_NUMPAD6, WIN32_VK_NUMPAD7, WIN32_VK_NUMPAD8, WIN32_VK_NUMPAD9, + WIN32_VK_PAUSE, WIN32_VK_PRINT, WIN32_VK_PRIOR, WIN32_VK_RBUTTON, + WIN32_VK_RCONTROL, WIN32_VK_RETURN, WIN32_VK_RIGHT, WIN32_VK_RMENU, + WIN32_VK_RSHIFT, WIN32_VK_RWIN, WIN32_VK_SCROLL, WIN32_VK_SELECT, + WIN32_VK_SEPARATOR, WIN32_VK_SHIFT, WIN32_VK_SLEEP, WIN32_VK_SNAPSHOT, + WIN32_VK_SPACE, WIN32_VK_SUBTRACT, WIN32_VK_TAB, WIN32_VK_UP, + WIN32_VK_VOLUME_DOWN, WIN32_VK_VOLUME_MUTE, WIN32_VK_VOLUME_UP, + WIN32_VK_XBUTTON1, WIN32_VK_XBUTTON2, WIN32_VkToVSC, + WIN32_WHEEL, WIN32_XBUTTON1, WIN32_XBUTTON2, WIN32_DOWN, WIN32_XUP, + WIN32_key0, WIN32_key1, WIN32_key2, WIN32_key3, WIN32_key4, + WIN32_key5, WIN32_key6, WIN32_key7, WIN32_key8, WIN32_key9, + WIN32_keyA, WIN32_keyB, WIN32_keyC, WIN32_keyD, WIN32_keyE, + WIN32_keyF, WIN32_keyG, WIN32_keyH, WIN32_keyI, WIN32_keyJ, + WIN32_keyK, WIN32_keyL, WIN32_keyM, WIN32_keyN, WIN32_keyO, + WIN32_keyP, WIN32_keyQ, WIN32_keyR, WIN32_keyS, WIN32_keyT, + WIN32_keyU, WIN32_keyV, WIN32_keyW, WIN32_keyX, WIN32_keyY, WIN32_keyZ, +) +from je_auto_control.windows.keyboard import win32_ctype_keyboard_control +from je_auto_control.windows.mouse import win32_ctype_mouse_control +from je_auto_control.windows.mouse.win32_ctype_mouse_control import ( + win32_mouse_left, win32_mouse_middle, win32_mouse_right, + win32_mouse_x1, win32_mouse_x2, +) +from je_auto_control.windows.record.win32_record import win32_recorder +from je_auto_control.windows.screen import win32_screen + +autocontrol_logger.info("Load Windows Setting") + +keyboard_keys_table = { + "absolute": WIN32_ABSOLUTE, + "eventf_extendedkey": WIN32_EventF_EXTENDEDKEY, + "eventf_keyup": WIN32_EventF_KEYUP, + "eventf_scancode": WIN32_EventF_SCANCODE, + "eventf_unicode": WIN32_EventF_UNICODE, + "hwheel": WIN32_HWHEEL, + "leftdown": WIN32_LEFTDOWN, + "leftup": WIN32_LEFTUP, + "middledown": WIN32_MIDDLEDOWN, + "middleup": WIN32_MIDDLEUP, + "move": WIN32_MOVE, + "rightdown": WIN32_RIGHTDOWN, + "rightup": WIN32_RIGHTUP, + "accept": WIN32_VK_ACCEPT, + "add": WIN32_VK_ADD, + "apps": WIN32_VK_APPS, + "back": WIN32_VK_BACK, + "browser_back": WIN32_VK_BROWSER_BACK, + "browser_favorites": WIN32_VK_BROWSER_FAVORITES, + "browser_forward": WIN32_VK_BROWSER_FORWARD, + "browser_refresh": WIN32_VK_BROWSER_REFRESH, + "browser_search": WIN32_VK_BROWSER_SEARCH, + "browser_stop": WIN32_VK_BROWSER_STOP, + "cancel": WIN32_VK_CANCEL, + "capital": WIN32_VK_CAPITAL, + "clear": WIN32_VK_CLEAR, + "control": WIN32_VK_CONTROL, + "convert": WIN32_VK_CONVERT, + "decimal": WIN32_VK_DECIMAL, + "delete": WIN32_VK_DELETE, + "divide": WIN32_VK_DIVIDE, + "vk_down": WIN32_VK_DOWN, + "end": WIN32_VK_END, + "escape": WIN32_VK_ESCAPE, + "execute": WIN32_VK_EXECUTE, + "f1": WIN32_VK_F1, + "f2": WIN32_VK_F2, + "f3": WIN32_VK_F3, + "f4": WIN32_VK_F4, + "f5": WIN32_VK_F5, + "f6": WIN32_VK_F6, + "f7": WIN32_VK_F7, + "f8": WIN32_VK_F8, + "f9": WIN32_VK_F9, + "f10": WIN32_VK_F10, + "f11": WIN32_VK_F11, + "f12": WIN32_VK_F12, + "f13": WIN32_VK_F13, + "f14": WIN32_VK_F14, + "f15": WIN32_VK_F15, + "f16": WIN32_VK_F16, + "f17": WIN32_VK_F17, + "f18": WIN32_VK_F18, + "f19": WIN32_VK_F19, + "f20": WIN32_VK_F20, + "f21": WIN32_VK_F21, + "f22": WIN32_VK_F22, + "f23": WIN32_VK_F23, + "f24": WIN32_VK_F24, + "final": WIN32_VK_FINAL, + "hanja": WIN32_VK_HANJA, + "help": WIN32_VK_HELP, + "home": WIN32_VK_HOME, + "ime_off": WIN32_VK_IME_OFF, + "ime_on": WIN32_VK_IME_ON, + "insert": WIN32_VK_INSERT, + "junja": WIN32_VK_JUNJA, + "kana": WIN32_VK_KANA, + "launch_app1": WIN32_VK_LAUNCH_APP1, + "LAUNCH_APP2": WIN32_VK_LAUNCH_APP2, + "launch_mail": WIN32_VK_LAUNCH_MAIL, + "launch_media_select": WIN32_VK_LAUNCH_MEDIA_SELECT, + "lbutton": WIN32_VK_LBUTTON, + "lcontrol": WIN32_VK_LCONTROL, + "left": WIN32_VK_LEFT, + "lmenu": WIN32_VK_LMENU, + "lshift": WIN32_VK_LSHIFT, + "lwin": WIN32_VK_LWIN, + "mbutton": WIN32_VK_MBUTTON, + "media_next_track": WIN32_VK_MEDIA_NEXT_TRACK, + "media_play_pause": WIN32_VK_MEDIA_PLAY_PAUSE, + "media_prev_track": WIN32_VK_MEDIA_PREV_TRACK, + "media_stop": WIN32_VK_MEDIA_STOP, + "modechange": WIN32_VK_MODECHANGE, + "multiply": WIN32_VK_MULTIPLY, + "menu": WIN32_VK_Menu, + "next": WIN32_VK_NEXT, + "nonconvert": WIN32_VK_NONCONVERT, + "numlock": WIN32_VK_NUMLOCK, + "num0": WIN32_VK_NUMPAD0, + "num1": WIN32_VK_NUMPAD1, + "num2": WIN32_VK_NUMPAD2, + "num3": WIN32_VK_NUMPAD3, + "num4": WIN32_VK_NUMPAD4, + "num5": WIN32_VK_NUMPAD5, + "num6": WIN32_VK_NUMPAD6, + "num7": WIN32_VK_NUMPAD7, + "num8": WIN32_VK_NUMPAD8, + "num9": WIN32_VK_NUMPAD9, + "pause": WIN32_VK_PAUSE, + "print": WIN32_VK_PRINT, + "prior": WIN32_VK_PRIOR, + "rbutton": WIN32_VK_RBUTTON, + "rcontrol": WIN32_VK_RCONTROL, + "return": WIN32_VK_RETURN, + "right": WIN32_VK_RIGHT, + "rmenu": WIN32_VK_RMENU, + "rshift": WIN32_VK_RSHIFT, + "rwin": WIN32_VK_RWIN, + "scroll": WIN32_VK_SCROLL, + "select": WIN32_VK_SELECT, + "separator": WIN32_VK_SEPARATOR, + "shift": WIN32_VK_SHIFT, + "sleep": WIN32_VK_SLEEP, + "snapshot": WIN32_VK_SNAPSHOT, + "space": WIN32_VK_SPACE, + "subtract": WIN32_VK_SUBTRACT, + "tab": WIN32_VK_TAB, + "up": WIN32_VK_UP, + "volume_down": WIN32_VK_VOLUME_DOWN, + "volume_mute": WIN32_VK_VOLUME_MUTE, + "volume_up": WIN32_VK_VOLUME_UP, + "vk_xbutton1": WIN32_VK_XBUTTON1, + "vk_xbutton2": WIN32_VK_XBUTTON2, + "xbutton1": WIN32_XBUTTON1, + "xbutton2": WIN32_XBUTTON2, + "vktovsc": WIN32_VkToVSC, + "wheel": WIN32_WHEEL, + "down": WIN32_DOWN, + "xup": WIN32_XUP, + "0": WIN32_key0, + "1": WIN32_key1, + "2": WIN32_key2, + "3": WIN32_key3, + "4": WIN32_key4, + "5": WIN32_key5, + "6": WIN32_key6, + "7": WIN32_key7, + "8": WIN32_key8, + "9": WIN32_key9, + "A": WIN32_keyA, + "a": WIN32_keyA, + "B": WIN32_keyB, + "b": WIN32_keyB, + "C": WIN32_keyC, + "c": WIN32_keyC, + "D": WIN32_keyD, + "d": WIN32_keyD, + "E": WIN32_keyE, + "e": WIN32_keyE, + "F": WIN32_keyF, + "f": WIN32_keyF, + "G": WIN32_keyG, + "g": WIN32_keyG, + "H": WIN32_keyH, + "h": WIN32_keyH, + "I": WIN32_keyI, + "i": WIN32_keyI, + "J": WIN32_keyJ, + "j": WIN32_keyJ, + "K": WIN32_keyK, + "k": WIN32_keyK, + "L": WIN32_keyL, + "l": WIN32_keyL, + "M": WIN32_keyM, + "m": WIN32_keyM, + "N": WIN32_keyN, + "n": WIN32_keyN, + "O": WIN32_keyO, + "o": WIN32_keyO, + "P": WIN32_keyP, + "p": WIN32_keyP, + "Q": WIN32_keyQ, + "q": WIN32_keyQ, + "R": WIN32_keyR, + "r": WIN32_keyR, + "S": WIN32_keyS, + "s": WIN32_keyS, + "T": WIN32_keyT, + "t": WIN32_keyT, + "U": WIN32_keyU, + "u": WIN32_keyU, + "V": WIN32_keyV, + "v": WIN32_keyV, + "W": WIN32_keyW, + "w": WIN32_keyW, + "X": WIN32_keyX, + "x": WIN32_keyX, + "Y": WIN32_keyY, + "y": WIN32_keyY, + "Z": WIN32_keyZ, + "z": WIN32_keyZ, +} + +mouse_keys_table = { + "mouse_left": win32_mouse_left, + "mouse_middle": win32_mouse_middle, + "mouse_right": win32_mouse_right, + "mouse_x1": win32_mouse_x1, + "mouse_x2": win32_mouse_x2, +} + +special_mouse_keys_table = None +keyboard = win32_ctype_keyboard_control +keyboard_check = win32_keypress_check +mouse = win32_ctype_mouse_control +screen = win32_screen +recorder = win32_recorder + +if None in [keyboard_keys_table, mouse_keys_table, keyboard_check, keyboard, mouse, screen, recorder]: + raise AutoControlException("Can't init auto control") diff --git a/je_auto_control/wrapper/auto_control_image.py b/je_auto_control/wrapper/auto_control_image.py index 2d088cb..d98b6c6 100644 --- a/je_auto_control/wrapper/auto_control_image.py +++ b/je_auto_control/wrapper/auto_control_image.py @@ -27,7 +27,7 @@ def locate_all_image(image, detect_threshold: float = 1.0, record_action_to_list("locate_all_image", {"image": image, "threshold": detect_threshold}) return image_data_array[1] raise ImageNotFoundException(f"{cant_find_image_error_message} / {image}") - except Exception as error: + except (OSError, RuntimeError, AttributeError, TypeError, ValueError, ImageNotFoundException) as error: record_action_to_list("locate_all_image", {"image": image}, repr(error)) autocontrol_logger.error(f"locate_all_image failed: {repr(error)}") raise @@ -51,7 +51,7 @@ def locate_image_center(image, detect_threshold: float = 1.0, record_action_to_list("locate_image_center", {"image": image, "threshold": detect_threshold}) return center_x, center_y raise ImageNotFoundException(f"{cant_find_image_error_message} / {image}") - except Exception as error: + except (OSError, RuntimeError, AttributeError, TypeError, ValueError, ImageNotFoundException) as error: record_action_to_list("locate_image_center", {"image": image}, repr(error)) autocontrol_logger.error(f"locate_image_center failed: {repr(error)}") raise @@ -78,7 +78,7 @@ def locate_and_click(image, mouse_keycode: Union[int, str], record_action_to_list("locate_and_click", {"image": image, "threshold": detect_threshold}) return center_x, center_y raise ImageNotFoundException(f"{cant_find_image_error_message} / {image}") - except Exception as error: + except (OSError, RuntimeError, AttributeError, TypeError, ValueError, ImageNotFoundException) as error: record_action_to_list("locate_and_click", {"image": image}, repr(error)) autocontrol_logger.error(f"locate_and_click failed: {repr(error)}") raise @@ -97,7 +97,7 @@ def screenshot(file_path: Optional[str] = None, region: Optional[List[int]] = No try: record_action_to_list("screenshot", {"file_path": file_path, "region": region}) return pil_screenshot(file_path, region) - except Exception as error: + except (OSError, RuntimeError, AttributeError, TypeError, ValueError, ImageNotFoundException) as error: record_action_to_list("screenshot", {"file_path": file_path, "region": region}, repr(error)) autocontrol_logger.error(f"screenshot failed: {repr(error)}") raise \ No newline at end of file diff --git a/je_auto_control/wrapper/auto_control_keyboard.py b/je_auto_control/wrapper/auto_control_keyboard.py index 171c5b5..89b11cd 100644 --- a/je_auto_control/wrapper/auto_control_keyboard.py +++ b/je_auto_control/wrapper/auto_control_keyboard.py @@ -56,11 +56,11 @@ def press_keyboard_key(keycode: Union[int, str], is_shift: bool = False, record_action_to_list("press_key", {"keycode": keycode, "is_shift": is_shift}) return str(keycode) - except Exception as error: + except (OSError, RuntimeError, AttributeError, TypeError, ValueError) as error: if not skip_record: record_action_to_list("press_key", {"keycode": keycode}, repr(error)) autocontrol_logger.error(f"press_keyboard_key failed: {repr(error)}") - raise AutoControlKeyboardException(f"{keyboard_press_key_error_message} {repr(error)}") + raise AutoControlKeyboardException(f"{keyboard_press_key_error_message} {repr(error)}") from error def release_keyboard_key(keycode: Union[int, str], is_shift: bool = False, @@ -81,11 +81,11 @@ def release_keyboard_key(keycode: Union[int, str], is_shift: bool = False, record_action_to_list("release_key", {"keycode": keycode, "is_shift": is_shift}) return str(keycode) - except Exception as error: + except (OSError, RuntimeError, AttributeError, TypeError, ValueError) as error: if not skip_record: record_action_to_list("release_key", {"keycode": keycode}, repr(error)) autocontrol_logger.error(f"release_keyboard_key failed: {repr(error)}") - raise AutoControlKeyboardException(f"{keyboard_release_key_error_message} {repr(error)}") + raise AutoControlKeyboardException(f"{keyboard_release_key_error_message} {repr(error)}") from error def type_keyboard(keycode: Union[int, str], is_shift: bool = False, @@ -103,11 +103,11 @@ def type_keyboard(keycode: Union[int, str], is_shift: bool = False, record_action_to_list("type_keyboard", {"keycode": keycode, "is_shift": is_shift}) return str(keycode) - except Exception as error: + except (OSError, RuntimeError, AttributeError, TypeError, ValueError) as error: if not skip_record: record_action_to_list("type_keyboard", {"keycode": keycode}, repr(error)) autocontrol_logger.error(f"type_keyboard failed: {repr(error)}") - raise AutoControlKeyboardException(f"{keyboard_type_key_error_message} {repr(error)}") + raise AutoControlKeyboardException(f"{keyboard_type_key_error_message} {repr(error)}") from error def check_key_is_press(keycode: Union[int, str]) -> Optional[bool]: """ @@ -122,7 +122,7 @@ def check_key_is_press(keycode: Union[int, str]) -> Optional[bool]: get_key_code = keycode if isinstance(keycode, int) else keyboard_keys_table.get(keycode) record_action_to_list("check_key_is_press", {"keycode": keycode}) return keyboard_check.check_key_is_press(keycode=get_key_code) - except Exception as error: + except (OSError, RuntimeError, AttributeError, TypeError, ValueError) as error: record_action_to_list("check_key_is_press", {"keycode": keycode}, repr(error)) autocontrol_logger.error(f"check_key_is_press failed: {repr(error)}") return None @@ -156,10 +156,10 @@ def write(write_string: str, is_shift: bool = False) -> Optional[str]: record_action_to_list("write", {"write_string": write_string, "is_shift": is_shift}) return result - except Exception as error: + except (OSError, RuntimeError, AttributeError, TypeError, ValueError) as error: record_action_to_list("write", {"write_string": write_string}, repr(error)) autocontrol_logger.error(f"write failed: {repr(error)}") - raise AutoControlKeyboardException(f"{keyboard_write_error_message} {repr(error)}") + raise AutoControlKeyboardException(f"{keyboard_write_error_message} {repr(error)}") from error def hotkey(key_code_list: list, is_shift: bool = False) -> Optional[Tuple[str, str]]: @@ -188,10 +188,10 @@ def hotkey(key_code_list: list, is_shift: bool = False) -> Optional[Tuple[str, s record_action_to_list("hotkey", {"keys": key_code_list, "is_shift": is_shift}) return press_str, release_str - except Exception as error: + except (OSError, RuntimeError, AttributeError, TypeError, ValueError) as error: record_action_to_list("hotkey", {"keys": key_code_list}, repr(error)) autocontrol_logger.error(f"hotkey failed: {repr(error)}") - raise AutoControlKeyboardException(f"{keyboard_hotkey_error_message} {repr(error)}") + raise AutoControlKeyboardException(f"{keyboard_hotkey_error_message} {repr(error)}") from error def send_key_event_to_window(window_title: str, keycode: Union[int, str]) -> None: """ @@ -221,7 +221,7 @@ def send_key_event_to_window(window_title: str, keycode: Union[int, str]) -> Non # 紀錄動作 Record action record_action_to_list("send_key_event_to_window", {"window_title": window_title, "keycode": get_key_code}) - except Exception as error: + except (OSError, RuntimeError, AttributeError, TypeError, ValueError) as error: record_action_to_list("send_key_event_to_window", {"window_title": window_title, "keycode": keycode}, repr(error)) autocontrol_logger.error( f"send_key_event_to_window failed, window={window_title}, keycode={keycode}, error={repr(error)}" diff --git a/je_auto_control/wrapper/auto_control_mouse.py b/je_auto_control/wrapper/auto_control_mouse.py index b859bf5..6a8016f 100644 --- a/je_auto_control/wrapper/auto_control_mouse.py +++ b/je_auto_control/wrapper/auto_control_mouse.py @@ -39,8 +39,8 @@ def mouse_preprocess(mouse_keycode: Union[int, str], x: int, y: int) -> Tuple[in mouse_keycode = mouse_keys_table.get(mouse_keycode) if mouse_keycode is None: raise AutoControlCantFindKeyException(table_cant_find_key_error_message) - except AutoControlCantFindKeyException: - raise AutoControlCantFindKeyException(table_cant_find_key_error_message) + except AutoControlCantFindKeyException as error: + raise AutoControlCantFindKeyException(table_cant_find_key_error_message) from error try: now_x, now_y = get_mouse_position() @@ -66,8 +66,8 @@ def get_mouse_position() -> tuple[int, int] | None: record_action_to_list("get_mouse_position", None) return mouse.position() except AutoControlMouseException as error: - raise AutoControlMouseException(mouse_get_position_error_message + " " + repr(error)) - except Exception as error: + raise AutoControlMouseException(mouse_get_position_error_message + " " + repr(error)) from error + except (OSError, RuntimeError, AttributeError, TypeError, ValueError) as error: record_action_to_list("get_mouse_position", None, repr(error)) autocontrol_logger.error(f"get_mouse_position failed: {repr(error)}") raise @@ -90,11 +90,11 @@ def set_mouse_position(x: int, y: int) -> tuple[int, int] | None: return x, y except AutoControlMouseException as error: autocontrol_logger.error(f"set_mouse_position failed: {repr(error)}") - raise AutoControlMouseException(mouse_set_position_error_message + " " + repr(error)) + raise AutoControlMouseException(mouse_set_position_error_message + " " + repr(error)) from error except ctypes.ArgumentError as error: autocontrol_logger.error(f"set_mouse_position invalid args: {repr(error)}") - raise AutoControlMouseException(mouse_wrong_value_error_message + " " + repr(error)) - except Exception as error: + raise AutoControlMouseException(mouse_wrong_value_error_message + " " + repr(error)) from error + except (OSError, RuntimeError, AttributeError, TypeError, ValueError) as error: record_action_to_list("set_mouse_position", param, repr(error)) autocontrol_logger.error(f"set_mouse_position failed: {repr(error)}") raise @@ -119,8 +119,8 @@ def press_mouse(mouse_keycode: Union[int, str], x: int = None, y: int = None) -> return mouse_keycode, x, y except AutoControlMouseException as error: autocontrol_logger.error(f"press_mouse failed: {repr(error)}") - raise AutoControlMouseException(mouse_press_mouse_error_message + " " + repr(error)) - except Exception as error: + raise AutoControlMouseException(mouse_press_mouse_error_message + " " + repr(error)) from error + except (OSError, RuntimeError, AttributeError, TypeError, ValueError) as error: record_action_to_list("press_mouse", param, repr(error)) autocontrol_logger.error(f"press_mouse failed: {repr(error)}") raise @@ -145,8 +145,8 @@ def release_mouse(mouse_keycode: Union[int, str], x: int = None, y: int = None) return mouse_keycode, x, y except AutoControlMouseException as error: autocontrol_logger.error(f"release_mouse failed: {repr(error)}") - raise AutoControlMouseException(mouse_release_mouse_error_message + " " + repr(error)) - except Exception as error: + raise AutoControlMouseException(mouse_release_mouse_error_message + " " + repr(error)) from error + except (OSError, RuntimeError, AttributeError, TypeError, ValueError) as error: record_action_to_list("release_mouse", param, repr(error)) autocontrol_logger.error(f"release_mouse failed: {repr(error)}") raise @@ -172,7 +172,7 @@ def click_mouse(mouse_keycode: Union[int, str], x: int = None, y: int = None) -> except AutoControlMouseException as error: record_action_to_list("click_mouse", param, repr(error)) autocontrol_logger.error(f"click_mouse failed: {repr(error)}") - raise AutoControlMouseException(mouse_click_mouse_error_message + " " + repr(error)) + raise AutoControlMouseException(mouse_click_mouse_error_message + " " + repr(error)) from error def mouse_scroll(scroll_value: int, x: int = None, y: int = None, @@ -210,7 +210,7 @@ def mouse_scroll(scroll_value: int, x: int = None, y: int = None, except AutoControlMouseException as error: autocontrol_logger.error(f"mouse_scroll failed: {repr(error)}") - raise AutoControlMouseException(mouse_scroll_error_message + " " + repr(error)) + raise AutoControlMouseException(mouse_scroll_error_message + " " + repr(error)) from error def send_mouse_event_to_window(window, mouse_keycode: Union[int, str], @@ -235,6 +235,6 @@ def send_mouse_event_to_window(window, mouse_keycode: Union[int, str], mouse.send_mouse_event_to_window(window, mouse_keycode=mouse_keycode, x=x, y=y) record_action_to_list("send_mouse_event_to_window", param) - except Exception as error: + except (OSError, RuntimeError, AttributeError, TypeError, ValueError) as error: record_action_to_list("send_mouse_event_to_window", param, repr(error)) autocontrol_logger.error(f"send_mouse_event_to_window failed: {repr(error)}") diff --git a/je_auto_control/wrapper/auto_control_record.py b/je_auto_control/wrapper/auto_control_record.py index cc65716..13b0877 100644 --- a/je_auto_control/wrapper/auto_control_record.py +++ b/je_auto_control/wrapper/auto_control_record.py @@ -18,7 +18,7 @@ def record() -> None: raise AutoControlException(macos_record_error_message) record_action_to_list("record", None) recorder.record() - except Exception as error: + except (OSError, RuntimeError, AttributeError, TypeError, ValueError, AutoControlException, AutoControlJsonActionException) as error: record_action_to_list("record", None, repr(error)) autocontrol_logger.error(f"record, failed: {repr(error)}") @@ -43,6 +43,6 @@ def stop_record() -> list: new_list.append([action[0], {"mouse_keycode": action[0], "x": action[1], "y": action[2]}]) record_action_to_list("stop_record", None) return new_list - except Exception as error: + except (OSError, RuntimeError, AttributeError, TypeError, ValueError, AutoControlException, AutoControlJsonActionException) as error: record_action_to_list("stop_record", None, repr(error)) autocontrol_logger.error(f"stop_record, failed: {repr(error)}") diff --git a/je_auto_control/wrapper/auto_control_screen.py b/je_auto_control/wrapper/auto_control_screen.py index 31492cb..127af7f 100644 --- a/je_auto_control/wrapper/auto_control_screen.py +++ b/je_auto_control/wrapper/auto_control_screen.py @@ -21,10 +21,10 @@ def screen_size() -> Tuple[int, int]: try: record_action_to_list("size", None) return screen.size() - except AutoControlScreenException: + except AutoControlScreenException as error: autocontrol_logger.error(f"screen_size failed: {screen_get_size_error_message}") - raise AutoControlScreenException(screen_get_size_error_message) - except Exception as error: + raise AutoControlScreenException(screen_get_size_error_message) from error + except (OSError, RuntimeError, AttributeError, TypeError, ValueError) as error: record_action_to_list("size", None, repr(error)) autocontrol_logger.error(f"screen_size failed: {repr(error)}") raise @@ -48,8 +48,8 @@ def screenshot(file_path: str = None, screen_region: list = None) -> List[int]: autocontrol_logger.error( f"screenshot failed, file_path: {file_path}, screen_region: {screen_region}, " f"error: {repr(error)}") - raise AutoControlScreenException(screen_screenshot_error_message + " " + repr(error)) - except Exception as error: + raise AutoControlScreenException(screen_screenshot_error_message + " " + repr(error)) from error + except (OSError, RuntimeError, AttributeError, TypeError, ValueError) as error: record_action_to_list("AC_screenshot", None, repr(error)) autocontrol_logger.error( f"screenshot failed, file_path: {file_path}, screen_region: {screen_region}, " @@ -68,7 +68,7 @@ def get_pixel(x: int, y: int, hwnd=None): return screen.get_pixel(x, y) else: return screen.get_pixel(x, y, hwnd) - except Exception as error: + except (OSError, RuntimeError, AttributeError, TypeError, ValueError) as error: record_action_to_list("AC_get_pixel", None, repr(error)) autocontrol_logger.error( f"get_pixel failed, x: {x}, y: {y}, hwnd: {hwnd}, " diff --git a/je_auto_control/wrapper/platform_wrapper.py b/je_auto_control/wrapper/platform_wrapper.py index 756e11a..a8945fc 100644 --- a/je_auto_control/wrapper/platform_wrapper.py +++ b/je_auto_control/wrapper/platform_wrapper.py @@ -1,1075 +1,27 @@ import sys from je_auto_control.utils.exception.exceptions import AutoControlException -from je_auto_control.utils.logging.logging_instance import autocontrol_logger if sys.platform in ["win32", "cygwin", "msys"]: - from je_auto_control.windows.core.utils.win32_vk import WIN32_ABSOLUTE - from je_auto_control.windows.core.utils.win32_vk import WIN32_EventF_EXTENDEDKEY - from je_auto_control.windows.core.utils.win32_vk import WIN32_EventF_KEYUP - from je_auto_control.windows.core.utils.win32_vk import WIN32_EventF_SCANCODE - from je_auto_control.windows.core.utils.win32_vk import WIN32_EventF_UNICODE - from je_auto_control.windows.core.utils.win32_vk import WIN32_HWHEEL - from je_auto_control.windows.core.utils.win32_vk import WIN32_LEFTDOWN - from je_auto_control.windows.core.utils.win32_vk import WIN32_LEFTUP - from je_auto_control.windows.core.utils.win32_vk import WIN32_MIDDLEDOWN - from je_auto_control.windows.core.utils.win32_vk import WIN32_MIDDLEUP - from je_auto_control.windows.core.utils.win32_vk import WIN32_MOVE - from je_auto_control.windows.core.utils.win32_vk import WIN32_RIGHTDOWN - from je_auto_control.windows.core.utils.win32_vk import WIN32_RIGHTUP - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_ACCEPT - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_ADD - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_APPS - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_BACK - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_BROWSER_BACK - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_BROWSER_FAVORITES - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_BROWSER_FORWARD - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_BROWSER_REFRESH - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_BROWSER_SEARCH - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_BROWSER_STOP - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_CANCEL - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_CAPITAL - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_CLEAR - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_CONTROL - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_CONVERT - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_DECIMAL - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_DELETE - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_DIVIDE - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_DOWN - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_END - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_ESCAPE - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_EXECUTE - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F1 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F10 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F11 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F12 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F13 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F14 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F15 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F16 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F17 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F18 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F19 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F2 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F20 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F21 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F22 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F23 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F24 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F3 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F4 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F5 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F6 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F7 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F8 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_F9 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_FINAL - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_HANJA - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_HELP - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_HOME - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_IME_OFF - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_IME_ON - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_INSERT - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_JUNJA - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_KANA - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_LAUNCH_APP1 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_LAUNCH_APP2 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_LAUNCH_MAIL - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_LAUNCH_MEDIA_SELECT - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_LBUTTON - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_LCONTROL - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_LEFT - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_LMENU - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_LSHIFT - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_LWIN - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_MBUTTON - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_MEDIA_NEXT_TRACK - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_MEDIA_PLAY_PAUSE - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_MEDIA_PREV_TRACK - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_MEDIA_STOP - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_MODECHANGE - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_MULTIPLY - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_Menu - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_NEXT - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_NONCONVERT - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_NUMLOCK - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_NUMPAD0 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_NUMPAD1 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_NUMPAD2 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_NUMPAD3 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_NUMPAD4 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_NUMPAD5 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_NUMPAD6 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_NUMPAD7 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_NUMPAD8 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_NUMPAD9 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_PAUSE - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_PRINT - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_PRIOR - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_RBUTTON - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_RCONTROL - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_RETURN - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_RIGHT - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_RMENU - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_RSHIFT - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_RWIN - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_SCROLL - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_SELECT - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_SEPARATOR - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_SHIFT - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_SLEEP - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_SNAPSHOT - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_SPACE - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_SUBTRACT - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_TAB - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_UP - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_VOLUME_DOWN - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_VOLUME_MUTE - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_VOLUME_UP - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_XBUTTON1 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VK_XBUTTON2 - from je_auto_control.windows.core.utils.win32_vk import WIN32_VkToVSC - from je_auto_control.windows.core.utils.win32_vk import WIN32_WHEEL - from je_auto_control.windows.core.utils.win32_vk import WIN32_XBUTTON1 - from je_auto_control.windows.core.utils.win32_vk import WIN32_XBUTTON2 - from je_auto_control.windows.core.utils.win32_vk import WIN32_DOWN - from je_auto_control.windows.core.utils.win32_vk import WIN32_XUP - from je_auto_control.windows.core.utils.win32_vk import WIN32_key0 - from je_auto_control.windows.core.utils.win32_vk import WIN32_key1 - from je_auto_control.windows.core.utils.win32_vk import WIN32_key2 - from je_auto_control.windows.core.utils.win32_vk import WIN32_key3 - from je_auto_control.windows.core.utils.win32_vk import WIN32_key4 - from je_auto_control.windows.core.utils.win32_vk import WIN32_key5 - from je_auto_control.windows.core.utils.win32_vk import WIN32_key6 - from je_auto_control.windows.core.utils.win32_vk import WIN32_key7 - from je_auto_control.windows.core.utils.win32_vk import WIN32_key8 - from je_auto_control.windows.core.utils.win32_vk import WIN32_key9 - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyA - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyB - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyC - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyD - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyE - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyF - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyG - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyH - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyI - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyJ - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyK - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyL - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyM - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyN - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyO - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyP - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyQ - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyR - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyS - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyT - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyU - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyV - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyW - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyX - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyY - from je_auto_control.windows.core.utils.win32_vk import WIN32_keyZ - from je_auto_control.windows.keyboard import win32_ctype_keyboard_control - from je_auto_control.windows.mouse import win32_ctype_mouse_control - from je_auto_control.windows.mouse.win32_ctype_mouse_control import win32_mouse_left - from je_auto_control.windows.mouse.win32_ctype_mouse_control import win32_mouse_middle - from je_auto_control.windows.mouse.win32_ctype_mouse_control import win32_mouse_right - from je_auto_control.windows.mouse.win32_ctype_mouse_control import win32_mouse_x1 - from je_auto_control.windows.mouse.win32_ctype_mouse_control import win32_mouse_x2 - from je_auto_control.windows.screen import win32_screen - from je_auto_control.windows.record.win32_record import win32_recorder - from je_auto_control.windows.core.utils import win32_keypress_check - -elif sys.platform in ["darwin"]: - from je_auto_control.osx.core.utils.osx_vk import osx_key_a, osx_key_A - from je_auto_control.osx.core.utils.osx_vk import osx_key_b, osx_key_B - from je_auto_control.osx.core.utils.osx_vk import osx_key_c, osx_key_C - from je_auto_control.osx.core.utils.osx_vk import osx_key_d, osx_key_D - from je_auto_control.osx.core.utils.osx_vk import osx_key_e, osx_key_E - from je_auto_control.osx.core.utils.osx_vk import osx_key_f, osx_key_F - from je_auto_control.osx.core.utils.osx_vk import osx_key_g, osx_key_G - from je_auto_control.osx.core.utils.osx_vk import osx_key_h, osx_key_H - from je_auto_control.osx.core.utils.osx_vk import osx_key_i, osx_key_I - from je_auto_control.osx.core.utils.osx_vk import osx_key_j, osx_key_J - from je_auto_control.osx.core.utils.osx_vk import osx_key_k, osx_key_K - from je_auto_control.osx.core.utils.osx_vk import osx_key_l, osx_key_L - from je_auto_control.osx.core.utils.osx_vk import osx_key_m, osx_key_M - from je_auto_control.osx.core.utils.osx_vk import osx_key_n, osx_key_N - from je_auto_control.osx.core.utils.osx_vk import osx_key_o, osx_key_O - from je_auto_control.osx.core.utils.osx_vk import osx_key_p, osx_key_P - from je_auto_control.osx.core.utils.osx_vk import osx_key_q, osx_key_Q - from je_auto_control.osx.core.utils.osx_vk import osx_key_r, osx_key_R - from je_auto_control.osx.core.utils.osx_vk import osx_key_s, osx_key_S - from je_auto_control.osx.core.utils.osx_vk import osx_key_t, osx_key_T - from je_auto_control.osx.core.utils.osx_vk import osx_key_u, osx_key_U - from je_auto_control.osx.core.utils.osx_vk import osx_key_v, osx_key_V - from je_auto_control.osx.core.utils.osx_vk import osx_key_w, osx_key_W - from je_auto_control.osx.core.utils.osx_vk import osx_key_x, osx_key_X - from je_auto_control.osx.core.utils.osx_vk import osx_key_y, osx_key_Y - from je_auto_control.osx.core.utils.osx_vk import osx_key_z, osx_key_Z - from je_auto_control.osx.core.utils.osx_vk import osx_key_1, osx_key_exclam - from je_auto_control.osx.core.utils.osx_vk import osx_key_2, osx_key_at - from je_auto_control.osx.core.utils.osx_vk import osx_key_3, osx_key_numbersign - from je_auto_control.osx.core.utils.osx_vk import osx_key_4, osx_key_money - from je_auto_control.osx.core.utils.osx_vk import osx_key_5, osx_key_percent - from je_auto_control.osx.core.utils.osx_vk import osx_key_6, osx_key_asciicircum - from je_auto_control.osx.core.utils.osx_vk import osx_key_7, osx_key_ampersand - from je_auto_control.osx.core.utils.osx_vk import osx_key_8, osx_key_asterisk - from je_auto_control.osx.core.utils.osx_vk import osx_key_9, osx_key_parenleft - from je_auto_control.osx.core.utils.osx_vk import osx_key_0, osx_key_parenright - from je_auto_control.osx.core.utils.osx_vk import osx_key_equal, osx_key_plus - from je_auto_control.osx.core.utils.osx_vk import osx_key_minus, osx_key_underscore - from je_auto_control.osx.core.utils.osx_vk import osx_key_bracketright, osx_key_braceright - from je_auto_control.osx.core.utils.osx_vk import osx_key_bracketleft, osx_key_braceleft - from je_auto_control.osx.core.utils.osx_vk import osx_key_apostrophe, osx_key_quotedbl - from je_auto_control.osx.core.utils.osx_vk import osx_key_semicolon, osx_key_colon - from je_auto_control.osx.core.utils.osx_vk import osx_key_backslash, osx_key_bar - from je_auto_control.osx.core.utils.osx_vk import osx_key_comma, osx_key_less - from je_auto_control.osx.core.utils.osx_vk import osx_key_slash, osx_key_question - from je_auto_control.osx.core.utils.osx_vk import osx_key_period, osx_key_greater - from je_auto_control.osx.core.utils.osx_vk import osx_key_grave, osx_key_asciitilde - from je_auto_control.osx.core.utils.osx_vk import osx_key_space - from je_auto_control.osx.core.utils.osx_vk import osx_key_return, osx_key_newline, osx_key_enter - from je_auto_control.osx.core.utils.osx_vk import osx_key_tab - from je_auto_control.osx.core.utils.osx_vk import osx_key_backspace - from je_auto_control.osx.core.utils.osx_vk import osx_key_esc - from je_auto_control.osx.core.utils.osx_vk import osx_key_command - from je_auto_control.osx.core.utils.osx_vk import osx_key_shift - from je_auto_control.osx.core.utils.osx_vk import osx_key_caps_lock - from je_auto_control.osx.core.utils.osx_vk import osx_key_option, osx_key_alt - from je_auto_control.osx.core.utils.osx_vk import osx_key_ctrl - from je_auto_control.osx.core.utils.osx_vk import osx_key_shift_right - from je_auto_control.osx.core.utils.osx_vk import osx_key_option_right - from je_auto_control.osx.core.utils.osx_vk import osx_key_control_right - from je_auto_control.osx.core.utils.osx_vk import osx_key_fn - from je_auto_control.osx.core.utils.osx_vk import osx_key_volume_up - from je_auto_control.osx.core.utils.osx_vk import osx_key_volume_down - from je_auto_control.osx.core.utils.osx_vk import osx_key_volume_mute - from je_auto_control.osx.core.utils.osx_vk import osx_key_f1 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f2 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f3 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f4 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f5 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f6 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f7 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f8 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f9 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f10 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f11 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f12 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f13 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f14 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f15 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f16 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f17 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f18 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f19 - from je_auto_control.osx.core.utils.osx_vk import osx_key_f20 - from je_auto_control.osx.core.utils.osx_vk import osx_key_help - from je_auto_control.osx.core.utils.osx_vk import osx_key_home - from je_auto_control.osx.core.utils.osx_vk import osx_key_pageup - from je_auto_control.osx.core.utils.osx_vk import osx_key_end - from je_auto_control.osx.core.utils.osx_vk import osx_key_pagedown - from je_auto_control.osx.core.utils.osx_vk import osx_key_left - from je_auto_control.osx.core.utils.osx_vk import osx_key_right - from je_auto_control.osx.core.utils.osx_vk import osx_key_down - from je_auto_control.osx.core.utils.osx_vk import osx_key_up - from je_auto_control.osx.core.utils.osx_vk import osx_key_yen - from je_auto_control.osx.core.utils.osx_vk import osx_key_eisu - from je_auto_control.osx.core.utils.osx_vk import osx_key_kana - from je_auto_control.osx.core.utils.osx_vk import osx_mouse_left - from je_auto_control.osx.core.utils.osx_vk import osx_mouse_middle - from je_auto_control.osx.core.utils.osx_vk import osx_mouse_right - from je_auto_control.osx.mouse import osx_mouse - from je_auto_control.osx.screen import osx_screen - from je_auto_control.osx.keyboard import osx_keyboard - from je_auto_control.osx.keyboard import osx_keyboard_check - + from je_auto_control.wrapper._platform_windows import ( + keyboard, keyboard_check, keyboard_keys_table, + mouse, mouse_keys_table, special_mouse_keys_table, + screen, recorder, + ) +elif sys.platform == "darwin": + from je_auto_control.wrapper._platform_osx import ( + keyboard, keyboard_check, keyboard_keys_table, + mouse, mouse_keys_table, special_mouse_keys_table, + screen, recorder, + ) elif sys.platform in ["linux", "linux2"]: - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_backspace - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_slash_b - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_tab - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_enter - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_return - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_shift - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_ctrl - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_alt - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_pause - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_capslock - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_esc - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_pgup - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_pgdn - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_pageup - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_pagedown - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_end - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_home - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_left - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_up - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_right - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_down - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_select - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_print - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_execute - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_prtsc - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_prtscr - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_prntscrn - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_insert - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_del - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_delete - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_help - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_win - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_winleft - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_winright - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_apps - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_num0 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_num1 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_num2 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_num3 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_num4 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_num5 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_num6 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_num7 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_num8 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_num9 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_multiply - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_add - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_separator - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_subtract - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_decimal - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_divide - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f1 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f2 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f3 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f4 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f5 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f6 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f7 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f8 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f9 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f10 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f11 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f12 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f13 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f14 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f15 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f16 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f17 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f18 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f19 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f20 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f21 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f22 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f23 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f24 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_numlock - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_scrolllock - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_shiftleft - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_shiftright - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_ctrlleft - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_ctrlright - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_altleft - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_altright - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_space - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_newline_n - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_newline_r - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_newline_t - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_exclam - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_numbersign - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_percent - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_dollar - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_ampersand - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_quotedbl - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_apostrophe - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_parenleft - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_parenright - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_asterisk - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_equal - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_plus - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_comma - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_minus - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_period - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_slash - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_colon - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_semicolon - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_less - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_greater - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_question - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_at - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_bracketleft - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_bracketright - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_backslash - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_asciicircum - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_underscore - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_grave - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_braceleft - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_bar - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_braceright - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_asciitilde - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_a - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_b - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_c - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_d - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_e - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_f - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_g - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_h - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_i - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_j - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_k - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_l - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_m - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_n - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_o - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_p - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_q - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_r - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_s - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_t - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_u - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_v - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_w - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_x - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_y - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_z - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_A - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_B - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_C - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_D - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_E - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_F - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_G - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_H - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_I - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_J - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_K - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_L - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_M - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_N - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_O - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_P - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_Q - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_R - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_S - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_T - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_U - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_V - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_W - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_X - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_Y - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_Z - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_1 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_2 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_3 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_4 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_5 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_6 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_7 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_8 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_9 - from je_auto_control.linux_with_x11.core.utils.x11_linux_vk import x11_linux_key_0 - from je_auto_control.linux_with_x11.mouse.x11_linux_mouse_control import x11_linux_mouse_left - from je_auto_control.linux_with_x11.mouse.x11_linux_mouse_control import x11_linux_mouse_middle - from je_auto_control.linux_with_x11.mouse.x11_linux_mouse_control import x11_linux_mouse_right - from je_auto_control.linux_with_x11.mouse.x11_linux_mouse_control import x11_linux_scroll_direction_up - from je_auto_control.linux_with_x11.mouse.x11_linux_mouse_control import x11_linux_scroll_direction_down - from je_auto_control.linux_with_x11.mouse.x11_linux_mouse_control import x11_linux_scroll_direction_left - from je_auto_control.linux_with_x11.mouse.x11_linux_mouse_control import x11_linux_scroll_direction_right - from je_auto_control.linux_with_x11.keyboard import x11_linux_keyboard_control - from je_auto_control.linux_with_x11.listener import x11_linux_listener - from je_auto_control.linux_with_x11.mouse import x11_linux_mouse_control - from je_auto_control.linux_with_x11.screen import x11_linux_screen - from je_auto_control.linux_with_x11.record.x11_linux_record import x11_linux_recoder - + from je_auto_control.wrapper._platform_linux import ( + keyboard, keyboard_check, keyboard_keys_table, + mouse, mouse_keys_table, special_mouse_keys_table, + screen, recorder, + ) else: raise AutoControlException("unknown operating system") -keyboard_keys_table = None -mouse_keys_table = None -special_mouse_keys_table = None -keyboard = None -keyboard_check = None -mouse = None -screen = None -recorder = None - -if sys.platform in ["win32", "cygwin", "msys"]: - autocontrol_logger.info("Load Windows Setting") - keyboard_keys_table = { - "absolute": WIN32_ABSOLUTE, - "eventf_extendedkey": WIN32_EventF_EXTENDEDKEY, - "eventf_keyup": WIN32_EventF_KEYUP, - "eventf_scancode": WIN32_EventF_SCANCODE, - "eventf_unicode": WIN32_EventF_UNICODE, - "hwheel": WIN32_HWHEEL, - "leftdown": WIN32_LEFTDOWN, - "leftup": WIN32_LEFTUP, - "middledown": WIN32_MIDDLEDOWN, - "middleup": WIN32_MIDDLEUP, - "move": WIN32_MOVE, - "rightdown": WIN32_RIGHTDOWN, - "rightup": WIN32_RIGHTUP, - "accept": WIN32_VK_ACCEPT, - "add": WIN32_VK_ADD, - "apps": WIN32_VK_APPS, - "back": WIN32_VK_BACK, - "browser_back": WIN32_VK_BROWSER_BACK, - "browser_favorites": WIN32_VK_BROWSER_FAVORITES, - "browser_forward": WIN32_VK_BROWSER_FORWARD, - "browser_refresh": WIN32_VK_BROWSER_REFRESH, - "browser_search": WIN32_VK_BROWSER_SEARCH, - "browser_stop": WIN32_VK_BROWSER_STOP, - "cancel": WIN32_VK_CANCEL, - "capital": WIN32_VK_CAPITAL, - "clear": WIN32_VK_CLEAR, - "control": WIN32_VK_CONTROL, - "convert": WIN32_VK_CONVERT, - "decimal": WIN32_VK_DECIMAL, - "delete": WIN32_VK_DELETE, - "divide": WIN32_VK_DIVIDE, - "vk_down": WIN32_VK_DOWN, - "end": WIN32_VK_END, - "escape": WIN32_VK_ESCAPE, - "execute": WIN32_VK_EXECUTE, - "f1": WIN32_VK_F1, - "f2": WIN32_VK_F2, - "f3": WIN32_VK_F3, - "f4": WIN32_VK_F4, - "f5": WIN32_VK_F5, - "f6": WIN32_VK_F6, - "f7": WIN32_VK_F7, - "f8": WIN32_VK_F8, - "f9": WIN32_VK_F9, - "f10": WIN32_VK_F10, - "f11": WIN32_VK_F11, - "f12": WIN32_VK_F12, - "f13": WIN32_VK_F13, - "f14": WIN32_VK_F14, - "f15": WIN32_VK_F15, - "f16": WIN32_VK_F16, - "f17": WIN32_VK_F17, - "f18": WIN32_VK_F18, - "f19": WIN32_VK_F19, - "f20": WIN32_VK_F20, - "f21": WIN32_VK_F21, - "f22": WIN32_VK_F22, - "f23": WIN32_VK_F23, - "f24": WIN32_VK_F24, - "final": WIN32_VK_FINAL, - "hanja": WIN32_VK_HANJA, - "help": WIN32_VK_HELP, - "home": WIN32_VK_HOME, - "ime_off": WIN32_VK_IME_OFF, - "ime_on": WIN32_VK_IME_ON, - "insert": WIN32_VK_INSERT, - "junja": WIN32_VK_JUNJA, - "kana": WIN32_VK_KANA, - "launch_app1": WIN32_VK_LAUNCH_APP1, - "LAUNCH_APP2": WIN32_VK_LAUNCH_APP2, - "launch_mail": WIN32_VK_LAUNCH_MAIL, - "launch_media_select": WIN32_VK_LAUNCH_MEDIA_SELECT, - "lbutton": WIN32_VK_LBUTTON, - "lcontrol": WIN32_VK_LCONTROL, - "left": WIN32_VK_LEFT, - "lmenu": WIN32_VK_LMENU, - "lshift": WIN32_VK_LSHIFT, - "lwin": WIN32_VK_LWIN, - "mbutton": WIN32_VK_MBUTTON, - "media_next_track": WIN32_VK_MEDIA_NEXT_TRACK, - "media_play_pause": WIN32_VK_MEDIA_PLAY_PAUSE, - "media_prev_track": WIN32_VK_MEDIA_PREV_TRACK, - "media_stop": WIN32_VK_MEDIA_STOP, - "modechange": WIN32_VK_MODECHANGE, - "multiply": WIN32_VK_MULTIPLY, - "menu": WIN32_VK_Menu, - "next": WIN32_VK_NEXT, - "nonconvert": WIN32_VK_NONCONVERT, - "numlock": WIN32_VK_NUMLOCK, - "num0": WIN32_VK_NUMPAD0, - "num1": WIN32_VK_NUMPAD1, - "num2": WIN32_VK_NUMPAD2, - "num3": WIN32_VK_NUMPAD3, - "num4": WIN32_VK_NUMPAD4, - "num5": WIN32_VK_NUMPAD5, - "num6": WIN32_VK_NUMPAD6, - "num7": WIN32_VK_NUMPAD7, - "num8": WIN32_VK_NUMPAD8, - "num9": WIN32_VK_NUMPAD9, - "pause": WIN32_VK_PAUSE, - "print": WIN32_VK_PRINT, - "prior": WIN32_VK_PRIOR, - "rbutton": WIN32_VK_RBUTTON, - "rcontrol": WIN32_VK_RCONTROL, - "return": WIN32_VK_RETURN, - "right": WIN32_VK_RIGHT, - "rmenu": WIN32_VK_RMENU, - "rshift": WIN32_VK_RSHIFT, - "rwin": WIN32_VK_RWIN, - "scroll": WIN32_VK_SCROLL, - "select": WIN32_VK_SELECT, - "separator": WIN32_VK_SEPARATOR, - "shift": WIN32_VK_SHIFT, - "sleep": WIN32_VK_SLEEP, - "snapshot": WIN32_VK_SNAPSHOT, - "space": WIN32_VK_SPACE, - "subtract": WIN32_VK_SUBTRACT, - "tab": WIN32_VK_TAB, - "up": WIN32_VK_UP, - "volume_down": WIN32_VK_VOLUME_DOWN, - "volume_mute": WIN32_VK_VOLUME_MUTE, - "volume_up": WIN32_VK_VOLUME_UP, - "vk_xbutton1": WIN32_VK_XBUTTON1, - "vk_xbutton2": WIN32_VK_XBUTTON2, - "xbutton1": WIN32_XBUTTON1, - "xbutton2": WIN32_XBUTTON2, - "vktovsc": WIN32_VkToVSC, - "wheel": WIN32_WHEEL, - "down": WIN32_DOWN, - "xup": WIN32_XUP, - "0": WIN32_key0, - "1": WIN32_key1, - "2": WIN32_key2, - "3": WIN32_key3, - "4": WIN32_key4, - "5": WIN32_key5, - "6": WIN32_key6, - "7": WIN32_key7, - "8": WIN32_key8, - "9": WIN32_key9, - "A": WIN32_keyA, - "a": WIN32_keyA, - "B": WIN32_keyB, - "b": WIN32_keyB, - "C": WIN32_keyC, - "c": WIN32_keyC, - "D": WIN32_keyD, - "d": WIN32_keyD, - "E": WIN32_keyE, - "e": WIN32_keyE, - "F": WIN32_keyF, - "f": WIN32_keyF, - "G": WIN32_keyG, - "g": WIN32_keyG, - "H": WIN32_keyH, - "h": WIN32_keyH, - "I": WIN32_keyI, - "i": WIN32_keyI, - "J": WIN32_keyJ, - "j": WIN32_keyJ, - "K": WIN32_keyK, - "k": WIN32_keyK, - "L": WIN32_keyL, - "l": WIN32_keyL, - "M": WIN32_keyM, - "m": WIN32_keyM, - "N": WIN32_keyN, - "n": WIN32_keyN, - "O": WIN32_keyO, - "o": WIN32_keyO, - "P": WIN32_keyP, - "p": WIN32_keyP, - "Q": WIN32_keyQ, - "q": WIN32_keyQ, - "R": WIN32_keyR, - "r": WIN32_keyR, - "S": WIN32_keyS, - "s": WIN32_keyS, - "T": WIN32_keyT, - "t": WIN32_keyT, - "U": WIN32_keyU, - "u": WIN32_keyU, - "V": WIN32_keyV, - "v": WIN32_keyV, - "W": WIN32_keyW, - "w": WIN32_keyW, - "X": WIN32_keyX, - "x": WIN32_keyX, - "Y": WIN32_keyY, - "y": WIN32_keyY, - "Z": WIN32_keyZ, - "z": WIN32_keyZ, - } - mouse_keys_table = { - "mouse_left": win32_mouse_left, - "mouse_middle": win32_mouse_middle, - "mouse_right": win32_mouse_right, - "mouse_x1": win32_mouse_x1, - "mouse_x2": win32_mouse_x2 - } - keyboard = win32_ctype_keyboard_control - keyboard_check = win32_keypress_check - mouse = win32_ctype_mouse_control - screen = win32_screen - recorder = win32_recorder - - if None in [keyboard_keys_table, mouse_keys_table, keyboard_check, keyboard, mouse, screen, recorder]: - raise AutoControlException("Can't init auto control") - -elif sys.platform in ["darwin"]: - autocontrol_logger.info("Load MacOS Setting") - keyboard_keys_table = { - "a": osx_key_a, - "A": osx_key_A, - "b": osx_key_b, - "B": osx_key_B, - "c": osx_key_c, - "C": osx_key_C, - "d": osx_key_d, - "D": osx_key_D, - "e": osx_key_e, - "E": osx_key_E, - "f": osx_key_f, - "F": osx_key_F, - "g": osx_key_g, - "G": osx_key_G, - "h": osx_key_h, - "H": osx_key_H, - "i": osx_key_i, - "I": osx_key_I, - "j": osx_key_j, - "J": osx_key_J, - "k": osx_key_k, - "K": osx_key_K, - "l": osx_key_l, - "L": osx_key_L, - "m": osx_key_m, - "M": osx_key_M, - "n": osx_key_n, - "N": osx_key_N, - "o": osx_key_o, - "O": osx_key_O, - "p": osx_key_p, - "P": osx_key_P, - "q": osx_key_q, - "Q": osx_key_Q, - "r": osx_key_r, - "R": osx_key_R, - "s": osx_key_s, - "S": osx_key_S, - "t": osx_key_t, - "T": osx_key_T, - "u": osx_key_u, - "U": osx_key_U, - "v": osx_key_v, - "V": osx_key_V, - "w": osx_key_w, - "W": osx_key_W, - "x": osx_key_x, - "X": osx_key_X, - "y": osx_key_y, - "Y": osx_key_Y, - "z": osx_key_z, - "Z": osx_key_Z, - "1": osx_key_1, - "!": osx_key_exclam, - "2": osx_key_2, - "@": osx_key_at, - "3": osx_key_3, - "#": osx_key_numbersign, - "4": osx_key_4, - "$": osx_key_money, - "5": osx_key_5, - "%": osx_key_percent, - "6": osx_key_6, - "^": osx_key_asciicircum, - "7": osx_key_7, - "&": osx_key_ampersand, - "8": osx_key_8, - "*": osx_key_asterisk, - "9": osx_key_9, - "(": osx_key_parenleft, - "0": osx_key_0, - ")": osx_key_parenright, - "=": osx_key_equal, - "+": osx_key_plus, - "-": osx_key_minus, - "_": osx_key_underscore, - "]": osx_key_bracketright, - "}": osx_key_braceright, - "[": osx_key_bracketleft, - "{": osx_key_braceleft, - "'": osx_key_apostrophe, - '"': osx_key_quotedbl, - ";": osx_key_semicolon, - ":": osx_key_colon, - "\\": osx_key_backslash, - "|": osx_key_bar, - ",": osx_key_comma, - "<": osx_key_less, - "/": osx_key_slash, - "?": osx_key_question, - ".": osx_key_period, - ">": osx_key_greater, - "`": osx_key_grave, - "~": osx_key_asciitilde, - "space": osx_key_space, - "return": osx_key_return, - "newline": osx_key_newline, - "enter": osx_key_enter, - "tab": osx_key_tab, - "backspace": osx_key_backspace, - "esc": osx_key_esc, - "command": osx_key_command, - "shift": osx_key_shift, - "caps_lock": osx_key_caps_lock, - "option": osx_key_option, - "alt": osx_key_alt, - "ctrl": osx_key_ctrl, - "shift_right": osx_key_shift_right, - "option_right": osx_key_option_right, - "control_right": osx_key_control_right, - "fn": osx_key_fn, - "volume_up": osx_key_volume_up, - "volume_down": osx_key_volume_down, - "volume_mute": osx_key_volume_mute, - "f1": osx_key_f1, - "f2": osx_key_f2, - "f3": osx_key_f3, - "f4": osx_key_f4, - "f5": osx_key_f5, - "f6": osx_key_f6, - "f7": osx_key_f7, - "f8": osx_key_f8, - "f9": osx_key_f9, - "f10": osx_key_f10, - "f11": osx_key_f11, - "f12": osx_key_f12, - "f13": osx_key_f13, - "f14": osx_key_f14, - "f15": osx_key_f15, - "f16": osx_key_f16, - "f17": osx_key_f17, - "f18": osx_key_f18, - "f19": osx_key_f19, - "f20": osx_key_f20, - "help": osx_key_help, - "home": osx_key_home, - "pageup": osx_key_pageup, - "end": osx_key_end, - "pagedown": osx_key_pagedown, - "left": osx_key_left, - "right": osx_key_right, - "down": osx_key_down, - "up": osx_key_up, - "yen": osx_key_yen, - "eisu": osx_key_eisu, - "kana": osx_key_kana, - } - mouse_keys_table = { - "mouse_left": osx_mouse_left, - "mouse_middle": osx_mouse_middle, - "mouse_right": osx_mouse_right, - } - keyboard = osx_keyboard - keyboard_check = osx_keyboard_check - mouse = osx_mouse - screen = osx_screen - if None in [keyboard_keys_table, mouse_keys_table, keyboard_check, keyboard, mouse, screen]: - raise AutoControlException("Can't init auto control") - -elif sys.platform in ["linux", "linux2"]: - autocontrol_logger.info("Load Linux x11 Setting") - keyboard_keys_table = { - "backspace": x11_linux_key_backspace, - "\b": x11_linux_key_slash_b, - "tab": x11_linux_key_tab, - "enter": x11_linux_key_enter, - "return": x11_linux_key_return, - "shift": x11_linux_key_shift, - "ctrl": x11_linux_key_ctrl, - "alt": x11_linux_key_alt, - "pause": x11_linux_key_pause, - "capslock": x11_linux_key_capslock, - "esc": x11_linux_key_esc, - "pgup": x11_linux_key_pgup, - "pgdn": x11_linux_key_pgdn, - "pageup": x11_linux_key_pageup, - "pagedown": x11_linux_key_pagedown, - "end": x11_linux_key_end, - "home": x11_linux_key_home, - "left": x11_linux_key_left, - "up": x11_linux_key_up, - "right": x11_linux_key_right, - "down": x11_linux_key_down, - "select": x11_linux_key_select, - "print": x11_linux_key_print, - "execute": x11_linux_key_execute, - "prtsc": x11_linux_key_prtsc, - "prtscr": x11_linux_key_prtscr, - "prntscrn": x11_linux_key_prntscrn, - "insert": x11_linux_key_insert, - "del": x11_linux_key_del, - "delete": x11_linux_key_delete, - "help": x11_linux_key_help, - "win": x11_linux_key_win, - "winleft": x11_linux_key_winleft, - "winright": x11_linux_key_winright, - "apps": x11_linux_key_apps, - "num0": x11_linux_key_num0, - "num1": x11_linux_key_num1, - "num2": x11_linux_key_num2, - "num3": x11_linux_key_num3, - "num4": x11_linux_key_num4, - "num5": x11_linux_key_num5, - "num6": x11_linux_key_num6, - "num7": x11_linux_key_num7, - "num8": x11_linux_key_num8, - "num9": x11_linux_key_num9, - "multiply": x11_linux_key_multiply, - "add": x11_linux_key_add, - "separator": x11_linux_key_separator, - "subtract": x11_linux_key_subtract, - "decimal": x11_linux_key_decimal, - "divide": x11_linux_key_divide, - "f1": x11_linux_key_f1, - "f2": x11_linux_key_f2, - "f3": x11_linux_key_f3, - "f4": x11_linux_key_f4, - "f5": x11_linux_key_f5, - "f6": x11_linux_key_f6, - "f7": x11_linux_key_f7, - "f8": x11_linux_key_f8, - "f9": x11_linux_key_f9, - "f10": x11_linux_key_f10, - "f11": x11_linux_key_f11, - "f12": x11_linux_key_f12, - "f13": x11_linux_key_f13, - "f14": x11_linux_key_f14, - "f15": x11_linux_key_f15, - "f16": x11_linux_key_f16, - "f17": x11_linux_key_f17, - "f18": x11_linux_key_f18, - "f19": x11_linux_key_f19, - "f20": x11_linux_key_f20, - "f21": x11_linux_key_f21, - "f22": x11_linux_key_f22, - "f23": x11_linux_key_f23, - "f24": x11_linux_key_f24, - "numlock": x11_linux_key_numlock, - "scrolllock": x11_linux_key_scrolllock, - "shiftleft": x11_linux_key_shiftleft, - "shiftright": x11_linux_key_shiftright, - "ctrlleft": x11_linux_key_ctrlleft, - "ctrlright": x11_linux_key_ctrlright, - "altleft": x11_linux_key_altleft, - "altright": x11_linux_key_altright, - "space": x11_linux_key_space, - "\n": x11_linux_key_newline_n, - "\r": x11_linux_key_newline_r, - "\t": x11_linux_key_newline_t, - "!": x11_linux_key_exclam, - "#": x11_linux_key_numbersign, - "%": x11_linux_key_percent, - "$": x11_linux_key_dollar, - "&": x11_linux_key_ampersand, - '"': x11_linux_key_quotedbl, - "'": x11_linux_key_apostrophe, - "(": x11_linux_key_parenleft, - ")": x11_linux_key_parenright, - "*": x11_linux_key_asterisk, - "=": x11_linux_key_equal, - "+": x11_linux_key_plus, - ",": x11_linux_key_comma, - "-": x11_linux_key_minus, - ".": x11_linux_key_period, - "/": x11_linux_key_slash, - ":": x11_linux_key_colon, - ";": x11_linux_key_semicolon, - "<": x11_linux_key_less, - ">": x11_linux_key_greater, - "?": x11_linux_key_question, - "@": x11_linux_key_at, - "[": x11_linux_key_bracketleft, - "]": x11_linux_key_bracketright, - "\\": x11_linux_key_backslash, - "^": x11_linux_key_asciicircum, - "_": x11_linux_key_underscore, - "`": x11_linux_key_grave, - "{": x11_linux_key_braceleft, - "|": x11_linux_key_bar, - "}": x11_linux_key_braceright, - "~": x11_linux_key_asciitilde, - "a": x11_linux_key_a, - "b": x11_linux_key_b, - "c": x11_linux_key_c, - "d": x11_linux_key_d, - "e": x11_linux_key_e, - "f": x11_linux_key_f, - "g": x11_linux_key_g, - "h": x11_linux_key_h, - "i": x11_linux_key_i, - "j": x11_linux_key_j, - "k": x11_linux_key_k, - "l": x11_linux_key_l, - "m": x11_linux_key_m, - "n": x11_linux_key_n, - "o": x11_linux_key_o, - "p": x11_linux_key_p, - "q": x11_linux_key_q, - "r": x11_linux_key_r, - "s": x11_linux_key_s, - "t": x11_linux_key_t, - "u": x11_linux_key_u, - "v": x11_linux_key_v, - "w": x11_linux_key_w, - "x": x11_linux_key_x, - "y": x11_linux_key_y, - "z": x11_linux_key_z, - "A": x11_linux_key_A, - "B": x11_linux_key_B, - "C": x11_linux_key_C, - "D": x11_linux_key_D, - "E": x11_linux_key_E, - "F": x11_linux_key_F, - "G": x11_linux_key_G, - "H": x11_linux_key_H, - "I": x11_linux_key_I, - "J": x11_linux_key_J, - "K": x11_linux_key_K, - "L": x11_linux_key_L, - "M": x11_linux_key_M, - "N": x11_linux_key_N, - "O": x11_linux_key_O, - "P": x11_linux_key_P, - "Q": x11_linux_key_Q, - "R": x11_linux_key_R, - "S": x11_linux_key_S, - "T": x11_linux_key_T, - "U": x11_linux_key_U, - "V": x11_linux_key_V, - "W": x11_linux_key_W, - "X": x11_linux_key_X, - "Y": x11_linux_key_Y, - "Z": x11_linux_key_Z, - "1": x11_linux_key_1, - "2": x11_linux_key_2, - "3": x11_linux_key_3, - "4": x11_linux_key_4, - "5": x11_linux_key_5, - "6": x11_linux_key_6, - "7": x11_linux_key_7, - "8": x11_linux_key_8, - "9": x11_linux_key_9, - "0": x11_linux_key_0, - } - mouse_keys_table = { - "mouse_left": x11_linux_mouse_left, - "mouse_middle": x11_linux_mouse_middle, - "mouse_right": x11_linux_mouse_right - } - special_mouse_keys_table = { - "scroll_up": x11_linux_scroll_direction_up, - "scroll_down": x11_linux_scroll_direction_down, - "scroll_left": x11_linux_scroll_direction_left, - "scroll_right": x11_linux_scroll_direction_right - } - keyboard = x11_linux_keyboard_control - keyboard_check = x11_linux_listener - mouse = x11_linux_mouse_control - screen = x11_linux_screen - recorder = x11_linux_recoder - if None in [keyboard_keys_table, mouse_keys_table, special_mouse_keys_table, keyboard, mouse, screen, recorder]: - raise AutoControlException("Can't init auto control") - if None in [keyboard_keys_table, mouse_keys_table, keyboard, mouse, screen]: raise AutoControlException("Can't init auto control") From e435a6f9e164cef1fb37d92b1e563d1b7994c746 Mon Sep 17 00:00:00 2001 From: JeffreyChen Date: Sat, 18 Apr 2026 14:01:40 +0800 Subject: [PATCH 4/4] Drop duplicate Auto Click tab code from AutoControlGUIWidget AutoClickTabMixin owns the _build_auto_click_tab / _do_click / _send_* methods; the copies in main_widget were dead duplicates. --- je_auto_control/gui/main_widget.py | 245 +---------------------------- 1 file changed, 1 insertion(+), 244 deletions(-) diff --git a/je_auto_control/gui/main_widget.py b/je_auto_control/gui/main_widget.py index dc6a54f..4527d2f 100644 --- a/je_auto_control/gui/main_widget.py +++ b/je_auto_control/gui/main_widget.py @@ -4,7 +4,7 @@ from PySide6.QtGui import QIntValidator, QDoubleValidator, QKeyEvent, Qt from PySide6.QtWidgets import ( QWidget, QLineEdit, QComboBox, QPushButton, QVBoxLayout, QLabel, - QGridLayout, QHBoxLayout, QRadioButton, QButtonGroup, QMessageBox, + QGridLayout, QHBoxLayout, QMessageBox, QTabWidget, QTextEdit, QFileDialog, QCheckBox, QGroupBox ) @@ -64,249 +64,6 @@ def __init__(self, parent=None): self.screen_recorder = ScreenRecorder() self._record_data = [] - # ========================================================================= - # Tab 1: Auto Click - # ========================================================================= - def _build_auto_click_tab(self) -> QWidget: - tab = QWidget() - outer = QVBoxLayout() - - # --- Mouse / Keyboard click group --- - click_group = QGroupBox(_t("tab_auto_click")) - grid = QGridLayout() - row = 0 - - grid.addWidget(QLabel(_t("input_method")), row, 0) - self.mouse_radio = QRadioButton(_t("mouse_radio")) - self.keyboard_radio = QRadioButton(_t("keyboard_radio")) - self.mouse_radio.setChecked(True) - self._input_group = QButtonGroup() - self._input_group.addButton(self.mouse_radio) - self._input_group.addButton(self.keyboard_radio) - h = QHBoxLayout() - h.addWidget(self.mouse_radio) - h.addWidget(self.keyboard_radio) - grid.addLayout(h, row, 1) - - row += 1 - grid.addWidget(QLabel(_t("interval_time")), row, 0) - self.interval_input = QLineEdit("1000") - self.interval_input.setValidator(QIntValidator(1, 999999999)) - grid.addWidget(self.interval_input, row, 1) - - row += 1 - grid.addWidget(QLabel(_t("cursor_x")), row, 0) - self.cursor_x_input = QLineEdit() - self.cursor_x_input.setValidator(QIntValidator()) - grid.addWidget(self.cursor_x_input, row, 1) - - row += 1 - grid.addWidget(QLabel(_t("cursor_y")), row, 0) - self.cursor_y_input = QLineEdit() - self.cursor_y_input.setValidator(QIntValidator()) - grid.addWidget(self.cursor_y_input, row, 1) - - row += 1 - grid.addWidget(QLabel(_t("mouse_button")), row, 0) - self.mouse_button_combo = QComboBox() - self.mouse_button_combo.addItems(list(mouse_keys_table.keys()) if isinstance(mouse_keys_table, dict) else list(mouse_keys_table)) - grid.addWidget(self.mouse_button_combo, row, 1) - - row += 1 - grid.addWidget(QLabel(_t("keyboard_button")), row, 0) - self.keyboard_button_combo = QComboBox() - self.keyboard_button_combo.addItems(list(get_keyboard_keys_table().keys())) - grid.addWidget(self.keyboard_button_combo, row, 1) - - row += 1 - grid.addWidget(QLabel(_t("click_type")), row, 0) - self.click_type_combo = QComboBox() - self.click_type_combo.addItems([_t("single_click"), _t("double_click")]) - grid.addWidget(self.click_type_combo, row, 1) - - row += 1 - self.repeat_until_stopped = QRadioButton(_t("repeat_until_stopped_radio")) - self.repeat_count_times = QRadioButton(_t("repeat_radio")) - self.repeat_count_input = QLineEdit() - self.repeat_count_input.setValidator(QIntValidator(1, 999999999)) - self.repeat_count_input.setPlaceholderText(_t("times")) - rg = QButtonGroup(tab) - rg.addButton(self.repeat_until_stopped) - rg.addButton(self.repeat_count_times) - self.repeat_until_stopped.setChecked(True) - rh = QHBoxLayout() - rh.addWidget(self.repeat_until_stopped) - rh.addWidget(self.repeat_count_times) - rh.addWidget(self.repeat_count_input) - grid.addLayout(rh, row, 0, 1, 2) - - row += 1 - btn_h = QHBoxLayout() - self.start_button = QPushButton(_t("start")) - self.start_button.clicked.connect(self._start_auto_click) - self.stop_button = QPushButton(_t("stop")) - self.stop_button.clicked.connect(self._stop_auto_click) - btn_h.addWidget(self.start_button) - btn_h.addWidget(self.stop_button) - grid.addLayout(btn_h, row, 0, 1, 2) - - click_group.setLayout(grid) - outer.addWidget(click_group) - - # --- Mouse position --- - pos_group = QGroupBox(_t("get_position")) - pos_layout = QHBoxLayout() - self.pos_btn = QPushButton(_t("get_position")) - self.pos_btn.clicked.connect(self._get_mouse_pos) - self.pos_label = QLabel(_t("current_position") + " --") - pos_layout.addWidget(self.pos_btn) - pos_layout.addWidget(self.pos_label) - pos_group.setLayout(pos_layout) - outer.addWidget(pos_group) - - # --- Hotkey --- - hotkey_group = QGroupBox(_t("hotkey_label")) - hk_layout = QHBoxLayout() - self.hotkey_input = QLineEdit() - self.hotkey_input.setPlaceholderText("ctrl,a") - self.hotkey_btn = QPushButton(_t("hotkey_send")) - self.hotkey_btn.clicked.connect(self._send_hotkey) - hk_layout.addWidget(self.hotkey_input) - hk_layout.addWidget(self.hotkey_btn) - hotkey_group.setLayout(hk_layout) - outer.addWidget(hotkey_group) - - # --- Write text --- - write_group = QGroupBox(_t("write_label")) - wr_layout = QHBoxLayout() - self.write_input = QLineEdit() - self.write_btn = QPushButton(_t("write_send")) - self.write_btn.clicked.connect(self._send_write) - wr_layout.addWidget(self.write_input) - wr_layout.addWidget(self.write_btn) - write_group.setLayout(wr_layout) - outer.addWidget(write_group) - - # --- Scroll --- - scroll_group = QGroupBox(_t("mouse_scroll_label")) - sc_layout = QHBoxLayout() - self.scroll_value_input = QLineEdit("3") - self.scroll_value_input.setValidator(QIntValidator()) - sc_layout.addWidget(QLabel(_t("mouse_scroll_label"))) - sc_layout.addWidget(self.scroll_value_input) - if special_mouse_keys_table: - self.scroll_dir_combo = QComboBox() - self.scroll_dir_combo.addItems(list(special_mouse_keys_table.keys())) - sc_layout.addWidget(self.scroll_dir_combo) - else: - self.scroll_dir_combo = None - self.scroll_btn = QPushButton(_t("scroll_send")) - self.scroll_btn.clicked.connect(self._send_scroll) - sc_layout.addWidget(self.scroll_btn) - scroll_group.setLayout(sc_layout) - outer.addWidget(scroll_group) - - outer.addStretch() - - # toggle handler - self.mouse_radio.toggled.connect(self._update_click_mode) - self._update_click_mode() - - tab.setLayout(outer) - return tab - - def _update_click_mode(self): - use_mouse = self.mouse_radio.isChecked() - self.cursor_x_input.setEnabled(use_mouse) - self.cursor_y_input.setEnabled(use_mouse) - self.mouse_button_combo.setEnabled(use_mouse) - self.keyboard_button_combo.setEnabled(not use_mouse) - - def _start_auto_click(self): - try: - interval = int(self.interval_input.text()) - except ValueError: - QMessageBox.warning(self, "Warning", "Interval must be a number") - return - self.repeat_count = 0 - try: - self.repeat_max = int(self.repeat_count_input.text()) - except ValueError: - self.repeat_max = 0 - self.timer.setInterval(interval) - try: - self.timer.timeout.disconnect(self._timer_tick) - except RuntimeError: - pass - self.timer.timeout.connect(self._timer_tick) - self.timer.start() - - def _stop_auto_click(self): - self.timer.stop() - - def _timer_tick(self): - if self.repeat_until_stopped.isChecked(): - self._do_click() - elif self.repeat_count_times.isChecked(): - self.repeat_count += 1 - if self.repeat_count <= self.repeat_max: - self._do_click() - else: - self.repeat_count = 0 - self.timer.stop() - - def _do_click(self): - try: - is_double = self.click_type_combo.currentIndex() == 1 - if self.mouse_radio.isChecked(): - btn = self.mouse_button_combo.currentText() - x = int(self.cursor_x_input.text() or "0") - y = int(self.cursor_y_input.text() or "0") - click_mouse(btn, x, y) - if is_double: - click_mouse(btn, x, y) - else: - key = self.keyboard_button_combo.currentText() - type_keyboard(key) - if is_double: - type_keyboard(key) - except (OSError, ValueError, TypeError, RuntimeError) as error: - self.timer.stop() - QMessageBox.warning(self, "Error", str(error)) - - def _get_mouse_pos(self): - try: - x, y = get_mouse_position() - self.pos_label.setText(_t("current_position") + f" ({x}, {y})") - self.cursor_x_input.setText(str(x)) - self.cursor_y_input.setText(str(y)) - except (OSError, ValueError, TypeError, RuntimeError) as error: - QMessageBox.warning(self, "Error", str(error)) - - def _send_hotkey(self): - try: - keys = [k.strip() for k in self.hotkey_input.text().split(",") if k.strip()] - if keys: - hotkey(keys) - except (OSError, ValueError, TypeError, RuntimeError) as error: - QMessageBox.warning(self, "Error", str(error)) - - def _send_write(self): - try: - text = self.write_input.text() - if text: - write(text) - except (OSError, ValueError, TypeError, RuntimeError) as error: - QMessageBox.warning(self, "Error", str(error)) - - def _send_scroll(self): - try: - val = int(self.scroll_value_input.text() or "3") - direction = self.scroll_dir_combo.currentText() if self.scroll_dir_combo else "scroll_down" - mouse_scroll(val, scroll_direction=direction) - except (OSError, ValueError, TypeError, RuntimeError) as error: - QMessageBox.warning(self, "Error", str(error)) - # ========================================================================= # Tab 2: Screenshot # =========================================================================