From 8d7296a93b8240d806fa31d2b04b124bf5ebd2c5 Mon Sep 17 00:00:00 2001 From: JeffreyChen Date: Sun, 26 Apr 2026 00:11:03 +0800 Subject: [PATCH 1/3] Hardcode AC_mouse_* aliases and sync executor command surface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AC_mouse_left/right/middle aliases all delegated to click_mouse and required mouse_keycode anyway, so the alias name was misleading. Worse, stop_record() recorded them as {"mouse_keycode": "AC_mouse_left", ...}, which is not a valid keycode in the mouse table — recorded JSON could not be replayed. Bind each alias to its hardcoded button and drop the keycode from the recorder output so record/replay round-trips cleanly. Other cleanups: - Use default_shell_manager singleton in both action and callback executors instead of constructing a fresh ShellManager per import. - Remove the duplicate screenshot() in auto_control_image.py — it was never imported and shadowed the canonical one in auto_control_screen. - Add the ~25 commands that were registered but missing from the README command tables (window, flow control, history, MCP, etc.). --- README.md | 12 +++++--- README/README_zh-CN.md | 12 +++++--- README/README_zh-TW.md | 12 +++++--- .../callback/callback_function_executor.py | 30 +++++++++++++++---- .../utils/executor/action_executor.py | 30 +++++++++++++++---- je_auto_control/wrapper/auto_control_image.py | 22 +------------- .../wrapper/auto_control_record.py | 2 +- test/unit_test/argparse/test1.json | 1 - test/unit_test/argparse/test2.json | 1 - .../execute_action/execute_action_test.py | 6 ++-- .../generate_report/html_report_test.py | 18 +++++------ test/unit_test/generate_report/json_report.py | 18 +++++------ .../generate_report/xml_report_test.py | 18 +++++------ test/unit_test/json/json_test.py | 6 ++-- 14 files changed, 107 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index 67c0fc0..d951d12 100644 --- a/README.md +++ b/README.md @@ -488,20 +488,24 @@ je_auto_control.execute_action([ | Category | Commands | |---|---| -| Mouse | `AC_click_mouse`, `AC_set_mouse_position`, `AC_get_mouse_position`, `AC_press_mouse`, `AC_release_mouse`, `AC_mouse_scroll`, `AC_mouse_left`, `AC_mouse_right`, `AC_mouse_middle` | -| Keyboard | `AC_type_keyboard`, `AC_press_keyboard_key`, `AC_release_keyboard_key`, `AC_write`, `AC_hotkey`, `AC_check_key_is_press` | +| Mouse | `AC_click_mouse`, `AC_set_mouse_position`, `AC_get_mouse_position`, `AC_get_mouse_table`, `AC_press_mouse`, `AC_release_mouse`, `AC_mouse_scroll`, `AC_mouse_left`, `AC_mouse_right`, `AC_mouse_middle` | +| Keyboard | `AC_type_keyboard`, `AC_press_keyboard_key`, `AC_release_keyboard_key`, `AC_write`, `AC_hotkey`, `AC_check_key_is_press`, `AC_get_keyboard_keys_table` | | Image | `AC_locate_all_image`, `AC_locate_image_center`, `AC_locate_and_click` | | Screen | `AC_screen_size`, `AC_screenshot` | | Accessibility | `AC_a11y_list`, `AC_a11y_find`, `AC_a11y_click` | | VLM (AI Locator) | `AC_vlm_locate`, `AC_vlm_click` | | OCR | `AC_locate_text`, `AC_click_text`, `AC_wait_text` | | Clipboard | `AC_clipboard_get`, `AC_clipboard_set` | -| Record | `AC_record`, `AC_stop_record` | +| Window | `AC_list_windows`, `AC_focus_window`, `AC_wait_window`, `AC_close_window` | +| Flow control | `AC_loop`, `AC_break`, `AC_continue`, `AC_if_image_found`, `AC_if_pixel`, `AC_while_image`, `AC_wait_image`, `AC_wait_pixel`, `AC_sleep`, `AC_retry` | +| Record | `AC_record`, `AC_stop_record`, `AC_set_record_enable` | | Report | `AC_generate_html`, `AC_generate_json`, `AC_generate_xml`, `AC_generate_html_report`, `AC_generate_json_report`, `AC_generate_xml_report` | +| Run history | `AC_history_list`, `AC_history_clear` | | Project | `AC_create_project` | | Shell | `AC_shell_command` | | Process | `AC_execute_process` | -| Executor | `AC_execute_action`, `AC_execute_files` | +| Executor | `AC_execute_action`, `AC_execute_files`, `AC_add_package_to_executor`, `AC_add_package_to_callback_executor` | +| MCP server | `AC_start_mcp_server`, `AC_start_mcp_http_server` | ### MCP Server (Use AutoControl from Claude) diff --git a/README/README_zh-CN.md b/README/README_zh-CN.md index 5ce0fc1..51eb59d 100644 --- a/README/README_zh-CN.md +++ b/README/README_zh-CN.md @@ -482,20 +482,24 @@ je_auto_control.execute_action([ | 类别 | 命令 | |---|---| -| 鼠标 | `AC_click_mouse`, `AC_set_mouse_position`, `AC_get_mouse_position`, `AC_press_mouse`, `AC_release_mouse`, `AC_mouse_scroll`, `AC_mouse_left`, `AC_mouse_right`, `AC_mouse_middle` | -| 键盘 | `AC_type_keyboard`, `AC_press_keyboard_key`, `AC_release_keyboard_key`, `AC_write`, `AC_hotkey`, `AC_check_key_is_press` | +| 鼠标 | `AC_click_mouse`, `AC_set_mouse_position`, `AC_get_mouse_position`, `AC_get_mouse_table`, `AC_press_mouse`, `AC_release_mouse`, `AC_mouse_scroll`, `AC_mouse_left`, `AC_mouse_right`, `AC_mouse_middle` | +| 键盘 | `AC_type_keyboard`, `AC_press_keyboard_key`, `AC_release_keyboard_key`, `AC_write`, `AC_hotkey`, `AC_check_key_is_press`, `AC_get_keyboard_keys_table` | | 图像 | `AC_locate_all_image`, `AC_locate_image_center`, `AC_locate_and_click` | | 屏幕 | `AC_screen_size`, `AC_screenshot` | | Accessibility | `AC_a11y_list`, `AC_a11y_find`, `AC_a11y_click` | | VLM(AI 定位) | `AC_vlm_locate`, `AC_vlm_click` | | OCR | `AC_locate_text`, `AC_click_text`, `AC_wait_text` | | 剪贴板 | `AC_clipboard_get`, `AC_clipboard_set` | -| 录制 | `AC_record`, `AC_stop_record` | +| 窗口 | `AC_list_windows`, `AC_focus_window`, `AC_wait_window`, `AC_close_window` | +| 流程控制 | `AC_loop`, `AC_break`, `AC_continue`, `AC_if_image_found`, `AC_if_pixel`, `AC_while_image`, `AC_wait_image`, `AC_wait_pixel`, `AC_sleep`, `AC_retry` | +| 录制 | `AC_record`, `AC_stop_record`, `AC_set_record_enable` | | 报告 | `AC_generate_html`, `AC_generate_json`, `AC_generate_xml`, `AC_generate_html_report`, `AC_generate_json_report`, `AC_generate_xml_report` | +| 执行记录 | `AC_history_list`, `AC_history_clear` | | 项目 | `AC_create_project` | | Shell | `AC_shell_command` | | 进程 | `AC_execute_process` | -| 执行器 | `AC_execute_action`, `AC_execute_files` | +| 执行器 | `AC_execute_action`, `AC_execute_files`, `AC_add_package_to_executor`, `AC_add_package_to_callback_executor` | +| MCP 服务器 | `AC_start_mcp_server`, `AC_start_mcp_http_server` | ### MCP 服务器(让 Claude 使用 AutoControl) diff --git a/README/README_zh-TW.md b/README/README_zh-TW.md index dbd8f73..01b8658 100644 --- a/README/README_zh-TW.md +++ b/README/README_zh-TW.md @@ -482,20 +482,24 @@ je_auto_control.execute_action([ | 類別 | 命令 | |---|---| -| 滑鼠 | `AC_click_mouse`, `AC_set_mouse_position`, `AC_get_mouse_position`, `AC_press_mouse`, `AC_release_mouse`, `AC_mouse_scroll`, `AC_mouse_left`, `AC_mouse_right`, `AC_mouse_middle` | -| 鍵盤 | `AC_type_keyboard`, `AC_press_keyboard_key`, `AC_release_keyboard_key`, `AC_write`, `AC_hotkey`, `AC_check_key_is_press` | +| 滑鼠 | `AC_click_mouse`, `AC_set_mouse_position`, `AC_get_mouse_position`, `AC_get_mouse_table`, `AC_press_mouse`, `AC_release_mouse`, `AC_mouse_scroll`, `AC_mouse_left`, `AC_mouse_right`, `AC_mouse_middle` | +| 鍵盤 | `AC_type_keyboard`, `AC_press_keyboard_key`, `AC_release_keyboard_key`, `AC_write`, `AC_hotkey`, `AC_check_key_is_press`, `AC_get_keyboard_keys_table` | | 圖像 | `AC_locate_all_image`, `AC_locate_image_center`, `AC_locate_and_click` | | 螢幕 | `AC_screen_size`, `AC_screenshot` | | Accessibility | `AC_a11y_list`, `AC_a11y_find`, `AC_a11y_click` | | VLM(AI 定位) | `AC_vlm_locate`, `AC_vlm_click` | | OCR | `AC_locate_text`, `AC_click_text`, `AC_wait_text` | | 剪貼簿 | `AC_clipboard_get`, `AC_clipboard_set` | -| 錄製 | `AC_record`, `AC_stop_record` | +| 視窗 | `AC_list_windows`, `AC_focus_window`, `AC_wait_window`, `AC_close_window` | +| 流程控制 | `AC_loop`, `AC_break`, `AC_continue`, `AC_if_image_found`, `AC_if_pixel`, `AC_while_image`, `AC_wait_image`, `AC_wait_pixel`, `AC_sleep`, `AC_retry` | +| 錄製 | `AC_record`, `AC_stop_record`, `AC_set_record_enable` | | 報告 | `AC_generate_html`, `AC_generate_json`, `AC_generate_xml`, `AC_generate_html_report`, `AC_generate_json_report`, `AC_generate_xml_report` | +| 執行紀錄 | `AC_history_list`, `AC_history_clear` | | 專案 | `AC_create_project` | | Shell | `AC_shell_command` | | 程序 | `AC_execute_process` | -| 執行器 | `AC_execute_action`, `AC_execute_files` | +| 執行器 | `AC_execute_action`, `AC_execute_files`, `AC_add_package_to_executor`, `AC_add_package_to_callback_executor` | +| MCP 伺服器 | `AC_start_mcp_server`, `AC_start_mcp_http_server` | ### MCP 伺服器(讓 Claude 使用 AutoControl) diff --git a/je_auto_control/utils/callback/callback_function_executor.py b/je_auto_control/utils/callback/callback_function_executor.py index 0189c18..934aef7 100644 --- a/je_auto_control/utils/callback/callback_function_executor.py +++ b/je_auto_control/utils/callback/callback_function_executor.py @@ -1,4 +1,4 @@ -from typing import Callable, Any +from typing import Any, Callable, Optional, Tuple # utils cv2_utils from je_auto_control.utils.cv2_utils.screenshot import pil_screenshot @@ -22,7 +22,7 @@ # project from je_auto_control.utils.project.create_project_structure import create_project_dir # shell -from je_auto_control.utils.shell_process.shell_exec import ShellManager +from je_auto_control.utils.shell_process.shell_exec import default_shell_manager # socket server from je_auto_control.utils.socket_server.auto_control_socket_server import start_autocontrol_socket_server # process @@ -48,6 +48,24 @@ from je_auto_control.wrapper.auto_control_screen import screen_size, screenshot +def _click_mouse_left(x: Optional[int] = None, + y: Optional[int] = None) -> Tuple[int, int, int]: + """Callback adapter: click left mouse button (button is hardcoded).""" + return click_mouse("mouse_left", x, y) + + +def _click_mouse_right(x: Optional[int] = None, + y: Optional[int] = None) -> Tuple[int, int, int]: + """Callback adapter: click right mouse button (button is hardcoded).""" + return click_mouse("mouse_right", x, y) + + +def _click_mouse_middle(x: Optional[int] = None, + y: Optional[int] = None) -> Tuple[int, int, int]: + """Callback adapter: click middle mouse button (button is hardcoded).""" + return click_mouse("mouse_middle", x, y) + + class CallbackFunctionExecutor: """ CallbackFunctionExecutor @@ -61,9 +79,9 @@ def __init__(self): # 事件字典,對應字串名稱到實際函式 self.event_dict: dict = { # mouse 滑鼠相關 - "AC_mouse_left": click_mouse, - "AC_mouse_right": click_mouse, - "AC_mouse_middle": click_mouse, + "AC_mouse_left": _click_mouse_left, + "AC_mouse_right": _click_mouse_right, + "AC_mouse_middle": _click_mouse_middle, "AC_click_mouse": click_mouse, "AC_get_mouse_table": get_mouse_table, "AC_get_mouse_position": get_mouse_position, @@ -129,7 +147,7 @@ def __init__(self): "AC_add_package_to_callback_executor": package_manager.add_package_to_callback_executor, # shell command - "AC_shell_command": ShellManager().exec_shell, + "AC_shell_command": default_shell_manager.exec_shell, # process "AC_execute_process": start_exe, diff --git a/je_auto_control/utils/executor/action_executor.py b/je_auto_control/utils/executor/action_executor.py index a4c2631..c4dfff0 100644 --- a/je_auto_control/utils/executor/action_executor.py +++ b/je_auto_control/utils/executor/action_executor.py @@ -1,5 +1,5 @@ import types -from typing import Any, Callable, Dict, List, Optional, Union +from typing import Any, Callable, Dict, List, Optional, Tuple, Union from je_auto_control.utils.exception.exception_tags import ( action_is_null_error_message, add_command_exception_error_message, @@ -38,7 +38,7 @@ from je_auto_control.utils.mcp_server.server import start_mcp_stdio_server from je_auto_control.utils.package_manager.package_manager_class import package_manager from je_auto_control.utils.project.create_project_structure import create_project_dir -from je_auto_control.utils.shell_process.shell_exec import ShellManager +from je_auto_control.utils.shell_process.shell_exec import default_shell_manager from je_auto_control.utils.start_exe.start_another_process import start_exe from je_auto_control.utils.test_record.record_test_class import record_action_to_list, test_record_instance from je_auto_control.wrapper.auto_control_image import locate_all_image, locate_and_click, locate_image_center @@ -91,6 +91,24 @@ def _vlm_locate_as_list(description: str, return None if coords is None else [coords[0], coords[1]] +def _click_mouse_left(x: Optional[int] = None, + y: Optional[int] = None) -> Tuple[int, int, int]: + """Executor adapter: click left mouse button (button is hardcoded).""" + return click_mouse("mouse_left", x, y) + + +def _click_mouse_right(x: Optional[int] = None, + y: Optional[int] = None) -> Tuple[int, int, int]: + """Executor adapter: click right mouse button (button is hardcoded).""" + return click_mouse("mouse_right", x, y) + + +def _click_mouse_middle(x: Optional[int] = None, + y: Optional[int] = None) -> Tuple[int, int, int]: + """Executor adapter: click middle mouse button (button is hardcoded).""" + return click_mouse("mouse_middle", x, y) + + def _history_list_as_dicts(limit: int = 100, source_type: Optional[str] = None) -> List[dict]: """Executor adapter: list run history as plain dicts (JSON-friendly).""" @@ -124,9 +142,9 @@ def __init__(self): # 事件字典,對應字串名稱到函式 self.event_dict: dict = { # Mouse 滑鼠相關 - "AC_mouse_left": click_mouse, - "AC_mouse_right": click_mouse, - "AC_mouse_middle": click_mouse, + "AC_mouse_left": _click_mouse_left, + "AC_mouse_right": _click_mouse_right, + "AC_mouse_middle": _click_mouse_middle, "AC_click_mouse": click_mouse, "AC_get_mouse_table": get_mouse_table, "AC_get_mouse_position": get_mouse_position, @@ -178,7 +196,7 @@ def __init__(self): "AC_create_project": create_project_dir, # Shell - "AC_shell_command": ShellManager().exec_shell, + "AC_shell_command": default_shell_manager.exec_shell, # Process "AC_execute_process": start_exe, diff --git a/je_auto_control/wrapper/auto_control_image.py b/je_auto_control/wrapper/auto_control_image.py index d98b6c6..612fc2b 100644 --- a/je_auto_control/wrapper/auto_control_image.py +++ b/je_auto_control/wrapper/auto_control_image.py @@ -1,7 +1,6 @@ -from typing import List, Tuple, Optional, Union +from typing import List, Tuple, Union 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 from je_auto_control.utils.exception.exceptions import ImageNotFoundException from je_auto_control.utils.logging.logging_instance import autocontrol_logger @@ -81,23 +80,4 @@ def locate_and_click(image, mouse_keycode: Union[int, str], 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 - - -def screenshot(file_path: Optional[str] = None, region: Optional[List[int]] = None): - """ - 擷取螢幕畫面 - Take a screenshot - - :param file_path: 儲存路徑 (None = 不儲存) - :param region: 擷取區域 [x1, y1, x2, y2] - :return: PIL Image - """ - autocontrol_logger.info(f"screenshot, file={file_path}, region={region}") - try: - record_action_to_list("screenshot", {"file_path": file_path, "region": region}) - return pil_screenshot(file_path, region) - 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_record.py b/je_auto_control/wrapper/auto_control_record.py index 964067e..acea3fb 100644 --- a/je_auto_control/wrapper/auto_control_record.py +++ b/je_auto_control/wrapper/auto_control_record.py @@ -40,7 +40,7 @@ def stop_record() -> list: if action[0] == "AC_type_keyboard": new_list.append([action[0], {"keycode": action[1]}]) else: - new_list.append([action[0], {"mouse_keycode": action[0], "x": action[1], "y": action[2]}]) + new_list.append([action[0], {"x": action[1], "y": action[2]}]) record_action_to_list("stop_record", None) return new_list except (OSError, RuntimeError, AttributeError, TypeError, ValueError, AutoControlException, AutoControlJsonActionException) as error: diff --git a/test/unit_test/argparse/test1.json b/test/unit_test/argparse/test1.json index 31fd018..5734a84 100644 --- a/test/unit_test/argparse/test1.json +++ b/test/unit_test/argparse/test1.json @@ -8,7 +8,6 @@ [ "AC_mouse_left", { - "mouse_keycode": "mouse_left", "x": 500, "y": 500 } diff --git a/test/unit_test/argparse/test2.json b/test/unit_test/argparse/test2.json index 31fd018..5734a84 100644 --- a/test/unit_test/argparse/test2.json +++ b/test/unit_test/argparse/test2.json @@ -8,7 +8,6 @@ [ "AC_mouse_left", { - "mouse_keycode": "mouse_left", "x": 500, "y": 500 } diff --git a/test/unit_test/execute_action/execute_action_test.py b/test/unit_test/execute_action/execute_action_test.py index bda00cf..5e6dd29 100644 --- a/test/unit_test/execute_action/execute_action_test.py +++ b/test/unit_test/execute_action/execute_action_test.py @@ -8,7 +8,7 @@ if sys.platform in ["win32", "cygwin", "msys"]: test_list = [ ["AC_type_keyboard", {"keycode": 65}], - ["AC_mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], + ["AC_mouse_left", {"x": 500, "y": 500}], ["AC_get_mouse_position"], ["AC_press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], ["AC_release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], @@ -18,7 +18,7 @@ elif sys.platform in ["linux", "linux2"]: test_list = [ ["AC_type_keyboard", {"keycode": 38}], - ["AC_mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], + ["AC_mouse_left", {"x": 500, "y": 500}], ["AC_get_mouse_position"], ["AC_press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], ["AC_release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], @@ -27,7 +27,7 @@ elif sys.platform in ["darwin"]: test_list = [ ["AC_type_keyboard", {"keycode": 0x00}], - ["AC_mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], + ["AC_mouse_left", {"x": 500, "y": 500}], ["AC_get_mouse_position"], ["AC_press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], ["AC_release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], diff --git a/test/unit_test/generate_report/html_report_test.py b/test/unit_test/generate_report/html_report_test.py index d13d5f3..68e6e75 100644 --- a/test/unit_test/generate_report/html_report_test.py +++ b/test/unit_test/generate_report/html_report_test.py @@ -9,10 +9,10 @@ test_list = [ ["AC_set_record_enable", {"set_enable": True}], ["AC_type_keyboard", {"keycode": 65}], - ["AC_mouse_left", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_mouse_left", {"x": 500, "y": 500}], ["AC_get_mouse_position"], - ["AC_press_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], - ["AC_release_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], + ["AC_release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], ["AC_type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}], ["AC_generate_html_report"], ] @@ -21,10 +21,10 @@ test_list = [ ["AC_set_record_enable", {"set_enable": True}], ["AC_type_keyboard", {"keycode": 38}], - ["AC_mouse_left", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_mouse_left", {"x": 500, "y": 500}], ["AC_get_mouse_position"], - ["AC_press_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], - ["AC_release_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], + ["AC_release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], ["AC_type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}], ["AC_generate_html_report"], ] @@ -32,10 +32,10 @@ test_list = [ ["AC_set_record_enable", {"set_enable": True}], ["AC_type_keyboard", {"keycode": 0x00}], - ["AC_mouse_left", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_mouse_left", {"x": 500, "y": 500}], ["AC_get_mouse_position"], - ["AC_press_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], - ["AC_release_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], + ["AC_release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], ["AC_type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}], ["AC_generate_html_report"], ] diff --git a/test/unit_test/generate_report/json_report.py b/test/unit_test/generate_report/json_report.py index a47d44a..b5cf6ca 100644 --- a/test/unit_test/generate_report/json_report.py +++ b/test/unit_test/generate_report/json_report.py @@ -9,10 +9,10 @@ test_list = [ ["AC_set_record_enable", {"set_enable": True}], ["AC_type_keyboard", {"keycode": 65}], - ["AC_mouse_left", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_mouse_left", {"x": 500, "y": 500}], ["AC_get_mouse_position"], - ["AC_press_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], - ["AC_release_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], + ["AC_release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], ["AC_type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}], ["AC_generate_json_report"], ] @@ -21,10 +21,10 @@ test_list = [ ["AC_set_record_enable", {"set_enable": True}], ["AC_type_keyboard", {"keycode": 38}], - ["AC_mouse_left", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_mouse_left", {"x": 500, "y": 500}], ["AC_get_mouse_position"], - ["AC_press_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], - ["AC_release_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], + ["AC_release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], ["AC_type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}], ["AC_generate_json_report"], ] @@ -32,10 +32,10 @@ test_list = [ ["AC_set_record_enable", {"set_enable": True}], ["AC_type_keyboard", {"keycode": 0x00}], - ["AC_mouse_left", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_mouse_left", {"x": 500, "y": 500}], ["AC_get_mouse_position"], - ["AC_press_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], - ["AC_release_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], + ["AC_release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], ["AC_type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}], ["AC_generate_json_report"], ] diff --git a/test/unit_test/generate_report/xml_report_test.py b/test/unit_test/generate_report/xml_report_test.py index f8bc90b..ff1fb74 100644 --- a/test/unit_test/generate_report/xml_report_test.py +++ b/test/unit_test/generate_report/xml_report_test.py @@ -9,10 +9,10 @@ test_list = [ ["AC_set_record_enable", {"set_enable": True}], ["AC_type_keyboard", {"keycode": 65}], - ["AC_mouse_left", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_mouse_left", {"x": 500, "y": 500}], ["AC_get_mouse_position"], - ["AC_press_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], - ["AC_release_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], + ["AC_release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], ["AC_type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}], ["AC_generate_xml_report"] ] @@ -21,10 +21,10 @@ test_list = [ ["AC_set_record_enable", {"set_enable": True}], ["AC_type_keyboard", {"keycode": 38}], - ["AC_mouse_left", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_mouse_left", {"x": 500, "y": 500}], ["AC_get_mouse_position"], - ["AC_press_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], - ["AC_release_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], + ["AC_release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], ["AC_type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}], ["AC_generate_xml_report"] ] @@ -32,10 +32,10 @@ test_list = [ ["AC_set_record_enable", {"set_enable": True}], ["AC_type_keyboard", {"keycode": 0x00}], - ["AC_mouse_left", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_mouse_left", {"x": 500, "y": 500}], ["AC_get_mouse_position"], - ["AC_press_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], - ["AC_release_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], + ["AC_release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], ["AC_type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}], ["AC_generate_xml_report"] ] diff --git a/test/unit_test/json/json_test.py b/test/unit_test/json/json_test.py index 70ebf02..9ad45cf 100644 --- a/test/unit_test/json/json_test.py +++ b/test/unit_test/json/json_test.py @@ -5,10 +5,10 @@ test_list = [ ["AC_type_keyboard", {"keycode": 0x00}], - ["AC_mouse_left", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_mouse_left", {"x": 500, "y": 500}], ["AC_get_mouse_position"], - ["AC_press_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], - ["AC_release_mouse", {"mouse_keycode": "AC_mouse_left", "x": 500, "y": 500}], + ["AC_press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], + ["AC_release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}], ] write_action_json(os.getcwd() + "/test1.json", test_list) From 62a7c32020235e8d8b1247b9a1eb280625dabb2b Mon Sep 17 00:00:00 2001 From: JeffreyChen Date: Sun, 26 Apr 2026 00:15:18 +0800 Subject: [PATCH 2/3] Move AC_mouse_* alias helpers into a shared module Sonar flagged 39.8% duplication on the previous commit because the three single-button click adapters were defined identically in both action_executor.py and callback_function_executor.py. Generate them once in utils/executor/mouse_aliases.py via a small factory and have both executors import the same callables. --- .../callback/callback_function_executor.py | 29 +++++------------- .../utils/executor/action_executor.py | 29 +++++------------- .../utils/executor/mouse_aliases.py | 30 +++++++++++++++++++ 3 files changed, 44 insertions(+), 44 deletions(-) create mode 100644 je_auto_control/utils/executor/mouse_aliases.py diff --git a/je_auto_control/utils/callback/callback_function_executor.py b/je_auto_control/utils/callback/callback_function_executor.py index 934aef7..5e63485 100644 --- a/je_auto_control/utils/callback/callback_function_executor.py +++ b/je_auto_control/utils/callback/callback_function_executor.py @@ -1,4 +1,4 @@ -from typing import Any, Callable, Optional, Tuple +from typing import Any, Callable # utils cv2_utils from je_auto_control.utils.cv2_utils.screenshot import pil_screenshot @@ -7,6 +7,9 @@ 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 +from je_auto_control.utils.executor.mouse_aliases import ( + click_mouse_left, click_mouse_middle, click_mouse_right, +) # file process from je_auto_control.utils.file_process.get_dir_file_list import get_dir_files_as_list # html report @@ -48,24 +51,6 @@ from je_auto_control.wrapper.auto_control_screen import screen_size, screenshot -def _click_mouse_left(x: Optional[int] = None, - y: Optional[int] = None) -> Tuple[int, int, int]: - """Callback adapter: click left mouse button (button is hardcoded).""" - return click_mouse("mouse_left", x, y) - - -def _click_mouse_right(x: Optional[int] = None, - y: Optional[int] = None) -> Tuple[int, int, int]: - """Callback adapter: click right mouse button (button is hardcoded).""" - return click_mouse("mouse_right", x, y) - - -def _click_mouse_middle(x: Optional[int] = None, - y: Optional[int] = None) -> Tuple[int, int, int]: - """Callback adapter: click middle mouse button (button is hardcoded).""" - return click_mouse("mouse_middle", x, y) - - class CallbackFunctionExecutor: """ CallbackFunctionExecutor @@ -79,9 +64,9 @@ def __init__(self): # 事件字典,對應字串名稱到實際函式 self.event_dict: dict = { # mouse 滑鼠相關 - "AC_mouse_left": _click_mouse_left, - "AC_mouse_right": _click_mouse_right, - "AC_mouse_middle": _click_mouse_middle, + "AC_mouse_left": click_mouse_left, + "AC_mouse_right": click_mouse_right, + "AC_mouse_middle": click_mouse_middle, "AC_click_mouse": click_mouse, "AC_get_mouse_table": get_mouse_table, "AC_get_mouse_position": get_mouse_position, diff --git a/je_auto_control/utils/executor/action_executor.py b/je_auto_control/utils/executor/action_executor.py index c4dfff0..18dccc5 100644 --- a/je_auto_control/utils/executor/action_executor.py +++ b/je_auto_control/utils/executor/action_executor.py @@ -1,5 +1,5 @@ import types -from typing import Any, Callable, Dict, List, Optional, Tuple, Union +from typing import Any, Callable, Dict, List, Optional, Union from je_auto_control.utils.exception.exception_tags import ( action_is_null_error_message, add_command_exception_error_message, @@ -22,6 +22,9 @@ from je_auto_control.utils.executor.flow_control import ( BLOCK_COMMANDS, LoopBreak, LoopContinue, ) +from je_auto_control.utils.executor.mouse_aliases import ( + click_mouse_left, click_mouse_middle, click_mouse_right, +) from je_auto_control.utils.ocr.ocr_engine import ( click_text as ocr_click_text, locate_text_center as ocr_locate_text_center, @@ -91,24 +94,6 @@ def _vlm_locate_as_list(description: str, return None if coords is None else [coords[0], coords[1]] -def _click_mouse_left(x: Optional[int] = None, - y: Optional[int] = None) -> Tuple[int, int, int]: - """Executor adapter: click left mouse button (button is hardcoded).""" - return click_mouse("mouse_left", x, y) - - -def _click_mouse_right(x: Optional[int] = None, - y: Optional[int] = None) -> Tuple[int, int, int]: - """Executor adapter: click right mouse button (button is hardcoded).""" - return click_mouse("mouse_right", x, y) - - -def _click_mouse_middle(x: Optional[int] = None, - y: Optional[int] = None) -> Tuple[int, int, int]: - """Executor adapter: click middle mouse button (button is hardcoded).""" - return click_mouse("mouse_middle", x, y) - - def _history_list_as_dicts(limit: int = 100, source_type: Optional[str] = None) -> List[dict]: """Executor adapter: list run history as plain dicts (JSON-friendly).""" @@ -142,9 +127,9 @@ def __init__(self): # 事件字典,對應字串名稱到函式 self.event_dict: dict = { # Mouse 滑鼠相關 - "AC_mouse_left": _click_mouse_left, - "AC_mouse_right": _click_mouse_right, - "AC_mouse_middle": _click_mouse_middle, + "AC_mouse_left": click_mouse_left, + "AC_mouse_right": click_mouse_right, + "AC_mouse_middle": click_mouse_middle, "AC_click_mouse": click_mouse, "AC_get_mouse_table": get_mouse_table, "AC_get_mouse_position": get_mouse_position, diff --git a/je_auto_control/utils/executor/mouse_aliases.py b/je_auto_control/utils/executor/mouse_aliases.py new file mode 100644 index 0000000..47131ab --- /dev/null +++ b/je_auto_control/utils/executor/mouse_aliases.py @@ -0,0 +1,30 @@ +"""Single-button mouse-click aliases shared by the action and callback executors. + +Each ``AC_mouse_