diff --git a/.idea/AutoControl.iml b/.idea/AutoControl.iml
index 0365335..d8b726a 100644
--- a/.idea/AutoControl.iml
+++ b/.idea/AutoControl.iml
@@ -4,8 +4,9 @@
+
-
+
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 6744968..3d60252 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,10 +5,7 @@
-
-
-
-
+
@@ -105,9 +102,10 @@
"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": "#165 on dev",
+ "git-widget-placeholder": "dev",
"ignore.virus.scanning.warn.message": "true",
"junie.onboarding.icon.badge.shown": "true",
"last_opened_file_path": "C:/CodeWorkspace/Python/AutoControlGUI/.github/workflows",
@@ -151,6 +149,7 @@
+
@@ -175,6 +174,7 @@
+
@@ -199,6 +199,7 @@
+
@@ -223,6 +224,7 @@
+
@@ -247,6 +249,7 @@
+
@@ -271,8 +274,8 @@
-
-
+
+
@@ -634,6 +637,7 @@
+
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index 25cb707..d65bbef 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -9,7 +9,7 @@ version: 2
build:
os: ubuntu-22.04
tools:
- python: "3.11"
+ python: "3.12"
# Build documentation in the "docs/" directory with Sphinx
sphinx:
diff --git a/README.md b/README.md
index 5c678c9..3f84e90 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,7 @@
[](https://pypi.org/project/je_auto_control/)
[](https://pypi.org/project/je_auto_control/)
[](LICENSE)
+[](https://autocontrol.readthedocs.io/en/latest/?badge=latest)
**AutoControl** is a cross-platform Python GUI automation framework providing mouse control, keyboard input, image recognition, screen capture, action scripting, and report generation — all through a unified API that works on Windows, macOS, and Linux (X11).
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 4170c03..3884022 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1 +1,2 @@
-sphinx-rtd-theme
\ No newline at end of file
+sphinx-rtd-theme
+sphinx>=7.0
diff --git a/docs/source/API/api_index.rst b/docs/source/API/api_index.rst
index ae4a946..042a5ff 100644
--- a/docs/source/API/api_index.rst
+++ b/docs/source/API/api_index.rst
@@ -1,21 +1,47 @@
-AutoControl API Documentation
-----
+=================
+API Reference
+=================
+
+Complete API documentation for all AutoControl modules.
+
+Wrapper API
+===========
+
+Platform-agnostic high-level functions.
+
+.. toctree::
+ :maxdepth: 2
+
+ wrapper/mouse
+ wrapper/keyboard
+ wrapper/image
+ wrapper/screen
+ wrapper/record
+
+Utils API
+=========
+
+Utility modules for scripting, reporting, and more.
.. toctree::
- :maxdepth: 4
-
- wrapper/image.rst
- wrapper/keyboard.rst
- wrapper/mouse.rst
- wrapper/record.rst
- wrapper/screen.rst
- utils/callback.rst
- utils/critical_exit.rst
- utils/executor.rst
- utils/scheduler.rst
- utils/file.rst
- utils/generate_report.rst
- utils/package_manager.rst
- utils/socket_server.rst
- special/keyboard_keys.rst
- special/mouse_keys.rst
+ :maxdepth: 2
+
+ utils/executor
+ utils/callback
+ utils/generate_report
+ utils/scheduler
+ utils/file
+ utils/package_manager
+ utils/socket_server
+ utils/critical_exit
+
+Key Reference
+=============
+
+Platform-specific key code tables.
+
+.. toctree::
+ :maxdepth: 2
+
+ special/keyboard_keys
+ special/mouse_keys
diff --git a/docs/source/API/special/keyboard_keys.rst b/docs/source/API/special/keyboard_keys.rst
index cb1d6e4..dd7cc67 100644
--- a/docs/source/API/special/keyboard_keys.rst
+++ b/docs/source/API/special/keyboard_keys.rst
@@ -1,542 +1,184 @@
-Keyboard keys API
-----
+=============
+Keyboard Keys
+=============
-* Windows
+Keyboard key names available per platform. Use these names as the ``keycode`` parameter
+in keyboard functions.
-.. code-block:: python
+.. note::
- 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,
- }
+ Key names are **platform-specific**. Always check the table for your target platform.
+ Use ``keys_table`` and ``get_special_table()`` at runtime to get the exact keys
+ available on the current system.
-* Linux
+Windows
+=======
-.. code-block:: python
+Common keys:
- 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,
- }
+.. list-table::
+ :header-rows: 1
+ :widths: 30 70
-* MacOS
+ * - Key Name
+ - Description
+ * - ``a`` - ``z``
+ - Letter keys
+ * - ``0`` - ``9``
+ - Number keys
+ * - ``f1`` - ``f24``
+ - Function keys
+ * - ``enter``, ``return``
+ - Enter / Return
+ * - ``tab``
+ - Tab
+ * - ``space``
+ - Space bar
+ * - ``back``
+ - Backspace
+ * - ``escape``
+ - Escape
+ * - ``lcontrol``, ``rcontrol``
+ - Left / Right Control
+ * - ``lshift``, ``rshift``
+ - Left / Right Shift
+ * - ``lalt``, ``ralt``
+ - Left / Right Alt
+ * - ``lwin``, ``rwin``
+ - Left / Right Windows key
+ * - ``up``, ``down``, ``left``, ``right``
+ - Arrow keys
+ * - ``insert``, ``delete``
+ - Insert / Delete
+ * - ``home``, ``end``
+ - Home / End
+ * - ``pageup``, ``pagedown``
+ - Page Up / Page Down
+ * - ``capslock``
+ - Caps Lock
+ * - ``numlock``
+ - Num Lock
+ * - ``print_screen``
+ - Print Screen
+ * - ``numpad0`` - ``numpad9``
+ - Numpad keys
+ * - ``add``, ``subtract``, ``multiply``, ``divide``
+ - Numpad operators
+ * - ``apps``
+ - Application / Menu key
+ * - ``browser_back``, ``browser_forward``
+ - Browser navigation keys
+ * - ``volume_mute``, ``volume_up``, ``volume_down``
+ - Volume control keys
-.. code-block:: python
+.. tip::
- 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,
- }
\ No newline at end of file
+ For the complete list of 200+ Windows keys, use ``keys_table`` at runtime:
+
+ .. code-block:: python
+
+ from je_auto_control import keys_table
+ for key_name in sorted(keys_table.keys()):
+ print(key_name)
+
+Linux (X11)
+===========
+
+Common keys:
+
+.. list-table::
+ :header-rows: 1
+ :widths: 30 70
+
+ * - Key Name
+ - Description
+ * - ``a`` - ``z``
+ - Letter keys
+ * - ``0`` - ``9``
+ - Number keys
+ * - ``f1`` - ``f12``
+ - Function keys
+ * - ``return``
+ - Enter / Return
+ * - ``tab``
+ - Tab
+ * - ``space``
+ - Space bar
+ * - ``backspace``
+ - Backspace
+ * - ``escape``
+ - Escape
+ * - ``ctrl``, ``ctrl_r``
+ - Left / Right Control
+ * - ``shift``, ``shift_r``
+ - Left / Right Shift
+ * - ``alt``, ``alt_r``
+ - Left / Right Alt
+ * - ``super``, ``super_r``
+ - Left / Right Super (Windows) key
+ * - ``up``, ``down``, ``left``, ``right``
+ - Arrow keys
+ * - ``insert``, ``delete``
+ - Insert / Delete
+ * - ``home``, ``end``
+ - Home / End
+ * - ``page_up``, ``page_down``
+ - Page Up / Page Down
+ * - ``caps_lock``
+ - Caps Lock
+ * - ``num_lock``
+ - Num Lock
+
+.. tip::
+
+ Linux supports 380+ key codes. Use ``keys_table`` at runtime for the complete list.
+
+macOS
+=====
+
+Common keys:
+
+.. list-table::
+ :header-rows: 1
+ :widths: 30 70
+
+ * - Key Name
+ - Description
+ * - ``a`` - ``z``
+ - Letter keys (mapped to macOS virtual key codes)
+ * - ``0`` - ``9``
+ - Number keys
+ * - ``f1`` - ``f20``
+ - Function keys
+ * - ``return``
+ - Enter / Return
+ * - ``tab``
+ - Tab
+ * - ``space``
+ - Space bar
+ * - ``delete``
+ - Backspace / Delete
+ * - ``escape``
+ - Escape
+ * - ``command``
+ - Command key
+ * - ``shift``, ``shift_r``
+ - Left / Right Shift
+ * - ``option``, ``option_r``
+ - Left / Right Option (Alt)
+ * - ``control``
+ - Control
+ * - ``up``, ``down``, ``left``, ``right``
+ - Arrow keys
+ * - ``home``, ``end``
+ - Home / End
+ * - ``page_up``, ``page_down``
+ - Page Up / Page Down
+ * - ``caps_lock``
+ - Caps Lock
+ * - ``volume_up``, ``volume_down``, ``mute``
+ - Volume control keys
+
+.. tip::
+
+ macOS supports 170+ key codes. Use ``keys_table`` at runtime for the complete list.
diff --git a/docs/source/API/special/mouse_keys.rst b/docs/source/API/special/mouse_keys.rst
index 76bbaaf..fe6fde5 100644
--- a/docs/source/API/special/mouse_keys.rst
+++ b/docs/source/API/special/mouse_keys.rst
@@ -1,40 +1,76 @@
-Mouse keys API
-----
-
-* Windows
-
-.. code-block:: python
-
- 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
- }
-
-* Linux
-
-.. code-block:: python
-
- 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
- }
-
-* MacOS
-
-.. code-block:: python
-
- mouse_keys_table = {
- "mouse_left": osx_mouse_left,
- "mouse_middle": osx_mouse_middle,
- "mouse_right": osx_mouse_right,
- }
\ No newline at end of file
+==========
+Mouse Keys
+==========
+
+Mouse button key names available per platform.
+
+Windows
+=======
+
+.. list-table::
+ :header-rows: 1
+ :widths: 40 60
+
+ * - Key Name
+ - Description
+ * - ``mouse_left``
+ - Left mouse button
+ * - ``mouse_middle``
+ - Middle mouse button (scroll wheel click)
+ * - ``mouse_right``
+ - Right mouse button
+ * - ``mouse_x1``
+ - Extra button 1 (back)
+ * - ``mouse_x2``
+ - Extra button 2 (forward)
+
+Linux (X11)
+===========
+
+**Standard buttons:**
+
+.. list-table::
+ :header-rows: 1
+ :widths: 40 60
+
+ * - Key Name
+ - Description
+ * - ``mouse_left``
+ - Left mouse button
+ * - ``mouse_middle``
+ - Middle mouse button
+ * - ``mouse_right``
+ - Right mouse button
+
+**Scroll directions (special keys):**
+
+.. list-table::
+ :header-rows: 1
+ :widths: 40 60
+
+ * - Key Name
+ - Description
+ * - ``scroll_up``
+ - Scroll up
+ * - ``scroll_down``
+ - Scroll down
+ * - ``scroll_left``
+ - Scroll left
+ * - ``scroll_right``
+ - Scroll right
+
+macOS
+=====
+
+.. list-table::
+ :header-rows: 1
+ :widths: 40 60
+
+ * - Key Name
+ - Description
+ * - ``mouse_left``
+ - Left mouse button
+ * - ``mouse_middle``
+ - Middle mouse button
+ * - ``mouse_right``
+ - Right mouse button
diff --git a/docs/source/API/utils/callback.rst b/docs/source/API/utils/callback.rst
index 4b69dce..23999d6 100644
--- a/docs/source/API/utils/callback.rst
+++ b/docs/source/API/utils/callback.rst
@@ -1,21 +1,40 @@
+=====================
Callback Function API
+=====================
+
+The Callback Executor runs a trigger function and then invokes a callback.
+
----
-.. code-block:: python
-
- def callback_function(
- self,
- trigger_function_name: str,
- callback_function: typing.Callable,
- callback_function_param: [dict, None] = None,
- callback_param_method: str = "kwargs",
- **kwargs
- ):
- """
- :param trigger_function_name: what function we want to trigger only accept function in event_dict
- :param callback_function: what function we want to callback
- :param callback_function_param: callback function's param only accept dict
- :param callback_param_method: what type param will use on callback function only accept kwargs and args
- :param kwargs: trigger_function's param
- :return: trigger_function_name return value
- """
\ No newline at end of file
+callback_function
+=================
+
+.. function:: callback_executor.callback_function(trigger_function_name, callback_function, callback_function_param=None, callback_param_method="kwargs", **kwargs)
+
+ Executes a trigger function from the event dictionary, then calls a callback function.
+
+ :param str trigger_function_name: Name of the function to trigger (must exist in ``event_dict``).
+ :param callable callback_function: Function to call after the trigger completes.
+ :param dict callback_function_param: Parameters for the callback function. Pass ``None`` for no parameters.
+ :param str callback_param_method: How to pass parameters to the callback:
+
+ - ``"args"`` -- unpack as positional arguments
+ - ``"kwargs"`` -- unpack as keyword arguments
+
+ :param kwargs: Keyword arguments passed to the trigger function.
+ :returns: Return value of the trigger function.
+
+ **Example:**
+
+ .. code-block:: python
+
+ from je_auto_control import callback_executor
+
+ def on_complete(width, height):
+ print(f"Screen size: {width}x{height}")
+
+ result = callback_executor.callback_function(
+ trigger_function_name="screen_size",
+ callback_function=on_complete,
+ callback_param_method="args"
+ )
diff --git a/docs/source/API/utils/critical_exit.rst b/docs/source/API/utils/critical_exit.rst
index b61621a..54ebdb3 100644
--- a/docs/source/API/utils/critical_exit.rst
+++ b/docs/source/API/utils/critical_exit.rst
@@ -1,47 +1,53 @@
+=================
Critical Exit API
+=================
+
+Safety mechanism to forcibly terminate automation scripts via a hotkey.
+
----
-.. code-block:: python
-
- class CriticalExit(Thread):
- """
- use to make program interrupt
- """
-
- def __init__(self, default_daemon: bool = True):
- """
- default interrupt is keyboard F7 key
- :param default_daemon bool thread setDaemon
- """
- super().__init__()
- self.daemon = default_daemon
- self._exit_check_key: int = keyboard_keys_table.get("f7")
-
- def set_critical_key(self, keycode: [int, str] = None) -> None:
- """
- set interrupt key
- :param keycode interrupt key
- """
- if isinstance(keycode, int):
- self._exit_check_key = keycode
- else:
- self._exit_check_key = keyboard_keys_table.get(keycode)
-
- def run(self) -> None:
- """
- listener keycode _exit_check_key to interrupt
- """
- try:
- while True:
- if keyboard_check.check_key_is_press(self._exit_check_key):
- _thread.interrupt_main()
- except Exception as error:
- print(repr(error), file=sys.stderr)
-
- def init_critical_exit(self) -> None:
- """
- should only use this to start critical exit
- may this function will add more
- """
- critical_thread = self
- critical_thread.start()
\ No newline at end of file
+CriticalExit
+============
+
+.. class:: CriticalExit(default_daemon=True)
+
+ A daemon thread that monitors a keyboard key and interrupts the main thread when pressed.
+ Inherits from ``threading.Thread``.
+
+ :param bool default_daemon: Whether the thread runs as a daemon. Defaults to ``True``.
+
+ The default interrupt key is **F7**.
+
+ .. method:: set_critical_key(keycode=None)
+
+ Changes the hotkey used to trigger the critical exit.
+
+ :param keycode: New key name or key code. If ``None``, no change is made.
+ :type keycode: int or str
+
+ **Example:**
+
+ .. code-block:: python
+
+ critical = CriticalExit()
+ critical.set_critical_key("escape")
+
+ .. method:: run()
+
+ The thread's main loop. Continuously checks if the exit key is pressed and
+ calls ``_thread.interrupt_main()`` when detected.
+
+ .. warning:: Do not call ``run()`` directly. Use :meth:`init_critical_exit` instead.
+
+ .. method:: init_critical_exit()
+
+ Starts the critical exit monitoring thread. This is the recommended way to
+ enable critical exit.
+
+ **Example:**
+
+ .. code-block:: python
+
+ from je_auto_control import CriticalExit
+
+ CriticalExit().init_critical_exit()
diff --git a/docs/source/API/utils/executor.rst b/docs/source/API/utils/executor.rst
index 48522f1..b64e744 100644
--- a/docs/source/API/utils/executor.rst
+++ b/docs/source/API/utils/executor.rst
@@ -1,26 +1,74 @@
+============
Executor API
+============
+
+The executor is the JSON action interpreter that parses and executes automation scripts.
+
----
-.. code-block:: python
+execute_action
+==============
+
+.. function:: execute_action(action_list)
+
+ Executes all actions in the given action list.
+
+ :param action_list: A list of actions to execute. Each action is a list of
+ ``[function_name, {params}]``.
+ :type action_list: list or dict
+ :returns: Dictionary mapping each action to its return value.
+ :rtype: dict
+
+ **Example:**
+
+ .. code-block:: python
+
+ from je_auto_control import execute_action
+
+ result = execute_action([
+ ["AC_set_mouse_position", {"x": 100, "y": 200}],
+ ["AC_click_mouse", {"mouse_keycode": "mouse_left"}]
+ ])
+
+----
+
+execute_files
+=============
+
+.. function:: execute_files(execute_files_list)
+
+ Executes all JSON action files in the given list.
+
+ :param list execute_files_list: List of file paths to execute.
+ :returns: List of execution results for each file.
+ :rtype: list
+
+ **Example:**
+
+ .. code-block:: python
+
+ from je_auto_control import execute_files, get_dir_files_as_list
+
+ execute_files(get_dir_files_as_list("./actions/"))
+
+----
+
+add_command_to_executor
+=======================
+
+.. function:: add_command_to_executor(command_dict)
+
+ Adds custom commands to the executor's event dictionary.
+
+ :param dict command_dict: Dictionary of ``{"command_name": callable}`` to add.
- def execute_action(self, action_list: [list, dict]) -> dict:
- """
- use to execute all action on action list(action file or program list)
- :param action_list the list include action
- for loop the list and execute action
- """
+ **Example:**
-.. code-block:: python
+ .. code-block:: python
- def execute_files(self, execute_files_list: list) -> list:
- """
- :param execute_files_list: list include execute files path
- :return: every execute detail as list
- """
+ from je_auto_control import executor
-.. code-block:: python
+ def my_custom_function(message):
+ print(f"Custom: {message}")
- def add_command_to_executor(command_dict: dict):
- """
- :param command_dict: dict include command we want to add to event_dict
- """
\ No newline at end of file
+ executor.event_dict["my_func"] = my_custom_function
diff --git a/docs/source/API/utils/file.rst b/docs/source/API/utils/file.rst
index 1b1614a..ec6275a 100644
--- a/docs/source/API/utils/file.rst
+++ b/docs/source/API/utils/file.rst
@@ -1,14 +1,32 @@
-File process API
+====================
+File Processing API
+====================
+
+Utility functions for working with action files.
+
----
-.. code-block:: python
-
- def get_dir_files_as_list(
- dir_path: str = getcwd(),
- default_search_file_extension: str = ".json") -> List[str]:
- """
- get dir file when end with default_search_file_extension
- :param dir_path: which dir we want to walk and get file list
- :param default_search_file_extension: which extension we want to search
- :return: [] if nothing searched or [file1, file2.... files] file was searched
- """
\ No newline at end of file
+get_dir_files_as_list
+=====================
+
+.. function:: get_dir_files_as_list(dir_path=os.getcwd(), default_search_file_extension=".json")
+
+ Walks a directory and returns all files matching the given extension.
+
+ :param str dir_path: Directory path to search. Defaults to the current working directory.
+ :param str default_search_file_extension: File extension to filter by (e.g., ``".json"``).
+ :returns: List of matching file paths. Empty list if no files found.
+ :rtype: list[str]
+
+ **Example:**
+
+ .. code-block:: python
+
+ from je_auto_control import get_dir_files_as_list
+
+ # Get all JSON files in a directory
+ files = get_dir_files_as_list("./actions/")
+ print(files) # ['./actions/step1.json', './actions/step2.json']
+
+ # Search for Python files instead
+ py_files = get_dir_files_as_list("./scripts/", ".py")
diff --git a/docs/source/API/utils/generate_report.rst b/docs/source/API/utils/generate_report.rst
index b534d80..1e65520 100644
--- a/docs/source/API/utils/generate_report.rst
+++ b/docs/source/API/utils/generate_report.rst
@@ -1,47 +1,74 @@
-Generate Report API
+=====================
+Report Generation API
+=====================
+
+Functions for generating test reports from recorded automation actions.
+
+----
+
+generate_html
+=============
+
+.. function:: generate_html()
+
+ Creates an HTML string from recorded test actions.
+
+ :returns: HTML report content.
+ :rtype: str
+
+----
+
+generate_html_report
+====================
+
+.. function:: generate_html_report(html_name="default_name")
+
+ Saves an HTML report file.
+
+ :param str html_name: Output file name (without extension).
+
+----
+
+generate_json
+=============
+
+.. function:: generate_json()
+
+ Creates JSON data from recorded test actions.
+
+ :returns: Tuple of ``(success_dict, failure_dict)``.
+ :rtype: tuple[dict, dict]
+
----
-.. code-block:: python
+generate_json_report
+====================
+
+.. function:: generate_json_report(json_file_name="default_name")
- def generate_html() -> str:
- """
- this function will create html string
- :return: html_string
- """
+ Saves a JSON report file.
-.. code-block:: python
+ :param str json_file_name: Output file name (without extension).
- def generate_html_report(html_name: str = "default_name"):
- """
- Output html report file
- :param html_name: save html file name
- """
+----
+
+generate_xml
+============
-.. code-block:: python
+.. function:: generate_xml()
- def generate_json():
- """
- :return: two dict {success_dict}, {failure_dict}
- """
+ Creates XML data from recorded test actions.
-.. code-block:: python
+ :returns: Tuple of ``(success_dict, failure_dict)``.
+ :rtype: tuple[dict, dict]
- def generate_json_report(json_file_name: str = "default_name"):
- """
- Output json report file
- :param json_file_name: save json file's name
- """
+----
-.. code-block:: python
+generate_xml_report
+===================
- def generate_xml():
- """
- :return: two dict {success_dict}, {failure_dict}
- """
+.. function:: generate_xml_report(xml_file_name="default_name")
-.. code-block:: python
+ Saves an XML report file.
- def generate_xml_report(xml_file_name: str = "default_name"):
- """
- :param xml_file_name: save xml file name
- """
\ No newline at end of file
+ :param str xml_file_name: Output file name (without extension).
diff --git a/docs/source/API/utils/package_manager.rst b/docs/source/API/utils/package_manager.rst
index d3276d1..f3fa093 100644
--- a/docs/source/API/utils/package_manager.rst
+++ b/docs/source/API/utils/package_manager.rst
@@ -1,101 +1,66 @@
+====================
Package Manager API
+====================
+
+The ``PackageManager`` class dynamically loads external Python packages into the
+executor and callback executor at runtime.
+
----
+PackageManager
+==============
+
+.. class:: PackageManager
+
+ .. method:: check_package(package)
+
+ Checks if a package is installed and importable.
+
+ :param str package: Package name to check.
+ :returns: The imported module if found, ``None`` otherwise.
+
+ .. method:: add_package_to_executor(package)
+
+ Loads all functions, built-ins, and classes from a package into the main executor's
+ ``event_dict``.
+
+ :param str package: Package name to load.
+
+ Functions are added with the naming convention ``package_function``.
+ For example, ``time.sleep`` becomes ``time_sleep``.
+
+ .. method:: add_package_to_callback_executor(package)
+
+ Loads all functions, built-ins, and classes from a package into the callback executor's
+ ``event_dict``.
+
+ :param str package: Package name to load.
+
+ .. method:: get_member(package, predicate, target)
+
+ Retrieves members from a package matching the given predicate and adds them to the
+ target executor.
+
+ :param str package: Package name.
+ :param predicate: Inspection predicate (e.g., ``isfunction``, ``isclass``).
+ :param target: Target executor whose ``event_dict`` will be updated.
+
+ .. method:: add_package_to_target(package, target)
+
+ Loads functions, built-ins, and classes from a package into the specified target executor.
+
+ :param str package: Package name.
+ :param target: Target executor.
+
+**Example:**
+
.. code-block:: python
- from importlib import import_module
- from importlib.util import find_spec
- from inspect import getmembers, isfunction, isbuiltin, isclass
- from sys import stderr
-
-
- class PackageManager(object):
-
- def __init__(self):
- self.installed_package_dict = {
- }
- self.executor = None
- self.callback_executor = None
-
- def check_package(self, package: str):
- """
- :param package: package to check exists or not
- :return: package if find else None
- """
- if self.installed_package_dict.get(package, None) is None:
- found_spec = find_spec(package)
- if found_spec is not None:
- try:
- installed_package = import_module(found_spec.name)
- self.installed_package_dict.update(
- {found_spec.name: installed_package})
- except ModuleNotFoundError as error:
- print(repr(error), file=stderr)
- return self.installed_package_dict.get(package, None)
-
- def add_package_to_executor(self, package):
- """
- :param package: package's function will add to executor
- """
- self.add_package_to_target(
- package=package,
- target=self.executor
- )
-
- def add_package_to_callback_executor(self, package):
- """
- :param package: package's function will add to callback_executor
- """
- self.add_package_to_target(
- package=package,
- target=self.callback_executor
- )
-
- def get_member(self, package, predicate, target):
- """
- :param package: package we want to get member
- :param predicate: predicate
- :param target: which event_dict will be added
- """
- installed_package = self.check_package(package)
- if installed_package is not None and target is not None:
- for member in getmembers(installed_package, predicate):
- target.event_dict.update(
- {str(package) + "_" + str(member[0]): member[1]})
- elif installed_package is None:
- print(repr(ModuleNotFoundError(f"Can't find package {package}")),
- file=stderr)
- else:
- print(f"Executor error {self.executor}", file=stderr)
-
- def add_package_to_target(self, package, target):
- """
- :param package: package we want to get member
- :param target: which event_dict will be added
- """
- try:
- self.get_member(
- package=package,
- predicate=isfunction,
- target=target
- )
- self.get_member(
- package=package,
- predicate=isbuiltin,
- target=target
- )
- self.get_member(
- package=package,
- predicate=isfunction,
- target=target
- )
- self.get_member(
- package=package,
- predicate=isclass,
- target=target
- )
- except Exception as error:
- print(repr(error), file=stderr)
-
-
- package_manager = PackageManager()
\ No newline at end of file
+ from je_auto_control import package_manager
+
+ # Add 'os' module to the executor
+ package_manager.add_package_to_executor("os")
+
+ # Now you can use os functions in JSON actions:
+ # ["os_getcwd", {}]
+ # ["os_listdir", {"path": "."}]
diff --git a/docs/source/API/utils/scheduler.rst b/docs/source/API/utils/scheduler.rst
index 7ee025f..9578e3f 100644
--- a/docs/source/API/utils/scheduler.rst
+++ b/docs/source/API/utils/scheduler.rst
@@ -1,192 +1,117 @@
+=============
Scheduler API
+=============
+
+The ``SchedulerManager`` class wraps APScheduler for scheduling automation tasks.
+
----
-.. code-block:: python
-
- def add_blocking_job(
- self, func: Callable, trigger: str = None, args: Union[list, tuple] = None,
- kwargs: dict = None, id: str = None, name: str = None,
- misfire_grace_time: int = undefined, coalesce: bool = undefined, max_instances: int = undefined,
- next_run_time: datetime = undefined, jobstore: str = 'default', executor: str = 'default',
- replace_existing: bool = False, **trigger_args: Any) -> Job:
- """
- Just an apscheduler add job wrapper.
- :param func: callable (or a textual reference to one) to run at the given time
- :param str|apscheduler.triggers.base.BaseTrigger trigger: trigger that determines when
- ``func`` is called
- :param list|tuple args: list of positional arguments to call func with
- :param dict kwargs: dict of keyword arguments to call func with
- :param str|unicode id: explicit identifier for the job (for modifying it later)
- :param str|unicode name: textual description of the job
- :param int misfire_grace_time: seconds after the designated runtime that the job is still
- allowed to be run (or ``None`` to allow the job to run no matter how late it is)
- :param bool coalesce: run once instead of many times if the scheduler determines that the
- job should be run more than once in succession
- :param int max_instances: maximum number of concurrently running instances allowed for this
- job
- :param datetime next_run_time: when to first run the job, regardless of the trigger (pass
- ``None`` to add the job as paused)
- :param str|unicode jobstore: alias of the job store to store the job in
- :param str|unicode executor: alias of the executor to run the job with
- :param bool replace_existing: ``True`` to replace an existing job with the same ``id``
- (but retain the number of runs from the existing one)
- :return: Job
- """
-
-.. code-block:: python
-
- def add_nonblocking_job(
- self, func: Callable, trigger: str = None, args: Union[list, tuple] = None,
- kwargs: dict = None, id: str = None, name: str = None,
- misfire_grace_time: int = undefined, coalesce: bool = undefined, max_instances: int = undefined,
- next_run_time: datetime = undefined, jobstore: str = 'default', executor: str = 'default',
- replace_existing: bool = False, **trigger_args: Any) -> Job:
- """
- Just an apscheduler add job wrapper.
- :param func: callable (or a textual reference to one) to run at the given time
- :param str|apscheduler.triggers.base.BaseTrigger trigger: trigger that determines when
- ``func`` is called
- :param list|tuple args: list of positional arguments to call func with
- :param dict kwargs: dict of keyword arguments to call func with
- :param str|unicode id: explicit identifier for the job (for modifying it later)
- :param str|unicode name: textual description of the job
- :param int misfire_grace_time: seconds after the designated runtime that the job is still
- allowed to be run (or ``None`` to allow the job to run no matter how late it is)
- :param bool coalesce: run once instead of many times if the scheduler determines that the
- job should be run more than once in succession
- :param int max_instances: maximum number of concurrently running instances allowed for this
- job
- :param datetime next_run_time: when to first run the job, regardless of the trigger (pass
- ``None`` to add the job as paused)
- :param str|unicode jobstore: alias of the job store to store the job in
- :param str|unicode executor: alias of the executor to run the job with
- :param bool replace_existing: ``True`` to replace an existing job with the same ``id``
- (but retain the number of runs from the existing one)
- :return: Job
- """
-
-.. code-block:: python
-
- def get_blocking_scheduler(self) -> BlockingScheduler:
- """
- Return self blocking scheduler
- :return: BlockingScheduler
- """
-
-.. code-block:: python
-
- def get_nonblocking_scheduler(self) -> BackgroundScheduler:
- """
- Return self background scheduler
- :return: BackgroundScheduler
- """
-
-.. code-block:: python
-
- def start_block_scheduler(self, *args: Any, **kwargs: Any) -> None:
- """
- Start blocking scheduler
- :return: None
- """
-
-.. code-block:: python
-
- def start_nonblocking_scheduler(self, *args: Any, **kwargs: Any) -> None:
- """
- Start background scheduler
- :return: None
- """
-
-.. code-block:: python
-
- def start_all_scheduler(self, *args: Any, **kwargs: Any) -> None:
- """
- Start background and blocking scheduler
- :return: None
- """
-
-.. code-block:: python
-
- def add_interval_blocking_secondly(
- self, function: Callable, id: str = None, args: Union[list, tuple] = None,
- kwargs: dict = None, seconds: int = 1, **trigger_args: Any) -> Job:
-
-.. code-block:: python
+SchedulerManager
+================
+
+.. class:: SchedulerManager
+
+ Manages blocking and non-blocking schedulers.
+
+ Adding Jobs
+ -----------
+
+ .. method:: add_blocking_job(func, trigger=None, args=None, kwargs=None, id=None, name=None, misfire_grace_time=undefined, coalesce=undefined, max_instances=undefined, next_run_time=undefined, jobstore='default', executor='default', replace_existing=False, **trigger_args)
+
+ Adds a job to the blocking scheduler. Wraps APScheduler's ``add_job()``.
+
+ :param callable func: Function to run.
+ :param str trigger: Trigger type (e.g., ``"interval"``, ``"cron"``).
+ :param str id: Unique job identifier.
+ :param str name: Human-readable job name.
+ :param bool replace_existing: If ``True``, replaces a job with the same ``id``.
+ :returns: The created Job instance.
+ :rtype: Job
+
+ .. method:: add_nonblocking_job(func, trigger=None, args=None, kwargs=None, id=None, name=None, **trigger_args)
+
+ Adds a job to the non-blocking (background) scheduler. Same parameters as ``add_blocking_job()``.
+
+ Interval Scheduling
+ -------------------
+
+ Convenience methods for interval-based scheduling. All accept ``function``, ``id``, ``args``, ``kwargs``, and the interval parameter.
+
+ **Blocking:**
+
+ .. method:: add_interval_blocking_secondly(function, id=None, seconds=1, **trigger_args)
+ .. method:: add_interval_blocking_minutely(function, id=None, minutes=1, **trigger_args)
+ .. method:: add_interval_blocking_hourly(function, id=None, hours=1, **trigger_args)
+ .. method:: add_interval_blocking_daily(function, id=None, days=1, **trigger_args)
+ .. method:: add_interval_blocking_weekly(function, id=None, weeks=1, **trigger_args)
+
+ **Non-blocking:**
+
+ .. method:: add_interval_nonblocking_secondly(function, id=None, seconds=1, **trigger_args)
+ .. method:: add_interval_nonblocking_minutely(function, id=None, minutes=1, **trigger_args)
+ .. method:: add_interval_nonblocking_hourly(function, id=None, hours=1, **trigger_args)
+ .. method:: add_interval_nonblocking_daily(function, id=None, days=1, **trigger_args)
+ .. method:: add_interval_nonblocking_weekly(function, id=None, weeks=1, **trigger_args)
- def add_interval_blocking_minutely(
- self, function: Callable, id: str = None, args: Union[list, tuple] = None,
- kwargs: dict = None, minutes: int = 1, **trigger_args: Any) -> Job:
+ Cron Scheduling
+ ---------------
-.. code-block:: python
+ .. method:: add_cron_blocking(function, id=None, **trigger_args)
- def add_interval_blocking_hourly(
- self, function: Callable, id: str = None, args: Union[list, tuple] = None,
- kwargs: dict = None, hours: int = 1, **trigger_args: Any) -> Job:
+ Adds a cron-triggered job to the blocking scheduler.
-.. code-block:: python
+ .. method:: add_cron_nonblocking(function, id=None, **trigger_args)
- def add_interval_blocking_daily(
- self, function: Callable, id: str = None, args: Union[list, tuple] = None,
- kwargs: dict = None, days: int = 1, **trigger_args: Any) -> Job:
+ Adds a cron-triggered job to the non-blocking scheduler.
-.. code-block:: python
+ Scheduler Control
+ -----------------
- def add_interval_blocking_weekly(
- self, function: Callable, id: str = None, args: Union[list, tuple] = None,
- kwargs: dict = None, weeks: int = 1, **trigger_args: Any) -> Job:
+ .. method:: get_blocking_scheduler()
-.. code-block:: python
+ :returns: The blocking scheduler instance.
+ :rtype: BlockingScheduler
- def add_interval_nonblocking_secondly(
- self, function: Callable, id: str = None, args: list = None,
- kwargs: dict = None, seconds: int = 1, **trigger_args: Any) -> Job:
+ .. method:: get_nonblocking_scheduler()
-.. code-block:: python
+ :returns: The background scheduler instance.
+ :rtype: BackgroundScheduler
- def add_interval_nonblocking_minutely(
- self, function: Callable, id: str = None, args: list = None,
- kwargs: dict = None, minutes: int = 1, **trigger_args: Any) -> Job:
+ .. method:: start_block_scheduler(*args, **kwargs)
-.. code-block:: python
+ Starts the blocking scheduler (blocks the current thread).
- def add_interval_nonblocking_hourly(
- self, function: Callable, id: str = None, args: Union[list, tuple] = None,
- kwargs: dict = None, hours: int = 1, **trigger_args: Any) -> Job:
+ .. method:: start_nonblocking_scheduler(*args, **kwargs)
-.. code-block:: python
+ Starts the non-blocking scheduler in a background thread.
- def add_interval_nonblocking_daily(
- self, function: Callable, id: str = None, args: Union[list, tuple] = None,
- kwargs: dict = None, days: int = 1, **trigger_args: Any) -> Job:
+ .. method:: start_all_scheduler(*args, **kwargs)
-.. code-block:: python
+ Starts both blocking and non-blocking schedulers.
- def add_interval_nonblocking_weekly(
- self, function: Callable, id: str = None, args: Union[list, tuple] = None,
- kwargs: dict = None, weeks: int = 1, **trigger_args: Any) -> Job:
+ Job Management
+ --------------
-.. code-block:: python
+ .. method:: remove_blocking_job(id, jobstore='default')
- def add_cron_blocking(
- self, function: Callable, id: str = None, **trigger_args: Any) -> Job:
+ Removes a job from the blocking scheduler.
-.. code-block:: python
+ :param str id: Job identifier.
- def add_cron_nonblocking(
- self, function: Callable, id: str = None, **trigger_args: Any) -> Job:
+ .. method:: remove_nonblocking_job(id, jobstore='default')
-.. code-block:: python
+ Removes a job from the non-blocking scheduler.
- def remove_blocking_job(self, id: str, jobstore: str = 'default') -> Any:
+ :param str id: Job identifier.
-.. code-block:: python
+ .. method:: shutdown_blocking_scheduler(wait=False)
- def remove_nonblocking_job(self, id: str, jobstore: str = 'default') -> Any:
+ Shuts down the blocking scheduler.
-.. code-block:: python
+ :param bool wait: If ``True``, waits for running jobs to finish.
- def shutdown_blocking_scheduler(self, wait: bool = False) -> None:
+ .. method:: shutdown_nonblocking_scheduler(wait=False)
-.. code-block:: python
+ Shuts down the non-blocking scheduler.
- def shutdown_nonblocking_scheduler(self, wait: bool = False) -> None:
+ :param bool wait: If ``True``, waits for running jobs to finish.
diff --git a/docs/source/API/utils/socket_server.rst b/docs/source/API/utils/socket_server.rst
index 2bae132..034ece8 100644
--- a/docs/source/API/utils/socket_server.rst
+++ b/docs/source/API/utils/socket_server.rst
@@ -1,60 +1,51 @@
+=================
Socket Server API
+=================
+
+TCP server for receiving and executing JSON automation commands remotely.
+
+----
+
+start_autocontrol_socket_server
+===============================
+
+.. function:: start_autocontrol_socket_server(host="localhost", port=9938)
+
+ Starts a threaded TCP server that accepts JSON automation commands.
+
+ :param str host: Server hostname. Defaults to ``"localhost"``.
+ :param int port: Server port. Defaults to ``9938``.
+ :returns: The server instance. Check ``server.close_flag`` to detect shutdown.
+ :rtype: TCPServer
+
+ The server can also read ``host`` and ``port`` from command-line arguments
+ (``sys.argv[1]`` and ``sys.argv[2]``).
+
+----
+
+TCPServer
+=========
+
+.. class:: TCPServer(server_address, RequestHandlerClass)
+
+ Threaded TCP server (extends ``socketserver.ThreadingMixIn`` and ``socketserver.TCPServer``).
+
+ .. attribute:: close_flag
+ :type: bool
+
+ Set to ``True`` when the server receives a ``"quit_server"`` command.
+
----
-.. code-block:: python
-
- import json
- import socketserver
- import sys
- import threading
-
- from je_auto_control.utils.executor.action_executor import execute_action
-
-
- class TCPServerHandler(socketserver.BaseRequestHandler):
-
- def handle(self):
- command_string = str(self.request.recv(8192).strip(), encoding="utf-8")
- socket = self.request
- print("command is: " + command_string, flush=True)
- if command_string == "quit_server":
- self.server.shutdown()
- self.server.close_flag = True
- print("Now quit server", flush=True)
- else:
- try:
- execute_str = json.loads(command_string)
- for execute_function, execute_return in execute_action(execute_str).items():
- socket.sendto(str(execute_return).encode("utf-8"), self.client_address)
- socket.sendto("\n".encode("utf-8"), self.client_address)
- socket.sendto("Return_Data_Over_JE".encode("utf-8"), self.client_address)
- socket.sendto("\n".encode("utf-8"), self.client_address)
- except Exception as error:
- print(repr(error), file=sys.stderr)
- try:
- socket.sendto(str(error).encode("utf-8"), self.client_address)
- socket.sendto("\n".encode("utf-8"), self.client_address)
- socket.sendto("Return_Data_Over_JE".encode("utf-8"), self.client_address)
- socket.sendto("\n".encode("utf-8"), self.client_address)
- except Exception as error:
- print(repr(error))
-
-
- class TCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
-
- def __init__(self, server_address, RequestHandlerClass):
- super().__init__(server_address, RequestHandlerClass)
- self.close_flag: bool = False
-
-
- def start_autocontrol_socket_server(host: str = "localhost", port: int = 9938):
- if len(sys.argv) == 2:
- host = sys.argv[1]
- elif len(sys.argv) == 3:
- host = sys.argv[1]
- port = int(sys.argv[2])
- server = TCPServer((host, port), TCPServerHandler)
- server_thread = threading.Thread(target=server.serve_forever)
- server_thread.daemon = True
- server_thread.start()
- return server
\ No newline at end of file
+TCPServerHandler
+================
+
+.. class:: TCPServerHandler
+
+ Request handler for the TCP server.
+
+ Receives up to 8192 bytes per request, decodes as UTF-8, and processes:
+
+ - ``"quit_server"`` -- shuts down the server.
+ - Any other string -- parsed as JSON and passed to ``execute_action()``.
+ Results are sent back to the client, terminated by ``"Return_Data_Over_JE"``.
diff --git a/docs/source/API/wrapper/image.rst b/docs/source/API/wrapper/image.rst
index 3175a54..86a81c0 100644
--- a/docs/source/API/wrapper/image.rst
+++ b/docs/source/API/wrapper/image.rst
@@ -1,47 +1,73 @@
+=========
Image API
+=========
+
+.. module:: je_auto_control
+
+Functions for image recognition using OpenCV template matching.
+
+----
+
+locate_all_image
+================
+
+.. function:: locate_all_image(image, detect_threshold=1, draw_image=False)
+
+ Locates all occurrences of a template image on the screen.
+
+ :param image: Template image to search for (file path or PIL image).
+ :type image: str or PIL.Image
+ :param float detect_threshold: Detection precision from ``0.0`` to ``1.0``.
+ ``1.0`` requires an exact match.
+ :param bool draw_image: If ``True``, marks detected areas on the returned image.
+ :returns: List of bounding boxes ``[[x1, y1, x2, y2], ...]``.
+ :rtype: list[list[int]]
+
+----
+
+locate_image_center
+===================
+
+.. function:: locate_image_center(image, detect_threshold=1, draw_image=False)
+
+ Locates a template image and returns its center position.
+
+ :param image: Template image to search for (file path or PIL image).
+ :type image: str or PIL.Image
+ :param float detect_threshold: Detection precision from ``0.0`` to ``1.0``.
+ :param bool draw_image: If ``True``, marks detected areas on the returned image.
+ :returns: Center coordinates ``(x, y)``.
+ :rtype: list[int, int]
+
+----
+
+locate_and_click
+================
+
+.. function:: locate_and_click(image, mouse_keycode, detect_threshold=1, draw_image=False)
+
+ Locates a template image and clicks on its center position.
+
+ :param image: Template image to search for (file path or PIL image).
+ :type image: str or PIL.Image
+ :param mouse_keycode: Mouse button to click (e.g., ``"mouse_left"``).
+ :type mouse_keycode: int or str
+ :param float detect_threshold: Detection precision from ``0.0`` to ``1.0``.
+ :param bool draw_image: If ``True``, marks detected areas on the returned image.
+ :returns: Center coordinates ``(x, y)`` of the clicked image.
+ :rtype: list[int, int]
+
----
-.. code-block:: python
-
- def locate_all_image(image, detect_threshold: [float, int] = 1,
- draw_image: bool = False) -> List[int]:
- """
- use to locate all image that detected and then return detected images list
- :param image which image we want to find on screen (png or PIL ImageGrab.grab())
- :param detect_threshold detect precision 0.0 ~ 1.0; 1 is absolute equal (float or int)
- :param draw_image draw detect tag on return image (bool)
- """
-
-
-.. code-block:: python
-
- def locate_image_center(image, detect_threshold: [float, int] = 1, draw_image: bool = False) -> List[Union[int, int]]:
- """
- use to locate image and return image center position
- :param image which image we want to find on screen (png or PIL ImageGrab.grab())
- :param detect_threshold detect precision 0.0 ~ 1.0; 1 is absolute equal (float or int)
- :param draw_image draw detect tag on return image (bool)
- """
-
-.. code-block:: python
-
- def locate_and_click(
- image, mouse_keycode: [int, str],
- detect_threshold: [float, int] = 1,
- draw_image: bool = False) -> List[Union[int, int]]:
- """
- use to locate image and click image center position and the return image center position
- :param image which image we want to find on screen (png or PIL ImageGrab.grab())
- :param mouse_keycode which mouse keycode we want to click
- :param detect_threshold detect precision 0.0 ~ 1.0; 1 is absolute equal (float or int)
- :param draw_image draw detect tag on return image (bool)
- """
-
-.. code-block:: python
-
- def screenshot(file_path: str = None, region: list = None) -> List[Union[int, int]]:
- """
- use to get now screen image return image
- :param file_path save screenshot path (None is no save)
- :param region screenshot screen_region (screenshot screen_region on screen)
- """
\ No newline at end of file
+screenshot
+==========
+
+.. function:: screenshot(file_path=None, region=None)
+
+ Captures the current screen.
+
+ :param str file_path: Path to save the screenshot. If ``None``, the image is not saved to disk.
+ :param list region: Screen region to capture as ``[x1, y1, x2, y2]``.
+ If ``None``, captures the full screen.
+ :returns: The captured screen image.
+ :rtype: PIL.Image
diff --git a/docs/source/API/wrapper/keyboard.rst b/docs/source/API/wrapper/keyboard.rst
index eca67f8..8850ca4 100644
--- a/docs/source/API/wrapper/keyboard.rst
+++ b/docs/source/API/wrapper/keyboard.rst
@@ -1,52 +1,93 @@
+============
Keyboard API
+============
+
+Functions for simulating keyboard input.
+
----
-.. code-block:: python
+get_special_table
+=================
- def get_special_table():
- return special_mouse_keys_table
+.. function:: get_special_table()
-.. code-block:: python
+ Returns the special keyboard keys table for the current platform.
- def get_keyboard_keys_table():
- return keyboard_keys_table
+ :returns: Dictionary of special key names to key codes.
+ :rtype: dict
-.. code-block:: python
+ .. note:: Not every platform has special keys.
+
+----
- def press_keyboard_key(keycode: [int, str], is_shift: bool = False, skip_record: bool = False) -> str:
- """
- use to press a key still press to use release key
- or use critical exit
- return keycode
- :param keycode which keycode we want to press
- :param is_shift press shift True or False
- :param skip_record skip record on record total list True or False
- """
+get_keyboard_keys_table
+=======================
-.. code-block:: python
+.. function:: get_keyboard_keys_table()
- def release_keyboard_key(keycode: [int, str], is_shift: bool = False, skip_record: bool = False) -> str:
- """
- use to release pressed key return keycode
- :param keycode which keycode we want to release
- :param is_shift press shift True or False
- :param skip_record skip record on record total list True or False
- """
+ Returns the full keyboard keys table for the current platform.
+
+ :returns: Dictionary of key names to key codes.
+ :rtype: dict
+
+----
+
+press_keyboard_key
+==================
+
+.. function:: press_keyboard_key(keycode, is_shift=False, skip_record=False)
+
+ Presses and holds a keyboard key. Use :func:`release_keyboard_key` to release it.
+
+ :param keycode: Key name or key code to press.
+ :type keycode: int or str
+ :param bool is_shift: Whether to press Shift simultaneously.
+ :param bool skip_record: If ``True``, this action will not be recorded.
+ :returns: The key code that was pressed.
+ :rtype: str
+
+----
+
+release_keyboard_key
+====================
+
+.. function:: release_keyboard_key(keycode, is_shift=False, skip_record=False)
+
+ Releases a previously pressed keyboard key.
+
+ :param keycode: Key name or key code to release.
+ :type keycode: int or str
+ :param bool is_shift: Whether Shift was pressed.
+ :param bool skip_record: If ``True``, this action will not be recorded.
+ :returns: The key code that was released.
+ :rtype: str
+
+----
+
+type_keyboard
+=============
+
+.. function:: type_keyboard(keycode, is_shift=False, skip_record=False)
+
+ Presses and immediately releases a keyboard key.
+
+ :param keycode: Key name or key code to type.
+ :type keycode: int or str
+ :param bool is_shift: Whether to press Shift simultaneously.
+ :param bool skip_record: If ``True``, this action will not be recorded.
+ :returns: The key code that was typed.
+ :rtype: str
+
+----
-.. code-block:: python
+check_key_is_press
+==================
- def type_keyboard(keycode: [int, str], is_shift: bool = False, skip_record: bool = False) -> str:
- """
- press and release key return keycode
- :param keycode which keycode we want to type
- :param is_shift press shift True or False
- :param skip_record skip record on record total list True or False
- """
+.. function:: check_key_is_press(keycode)
-.. code-block:: python
+ Checks whether a specific key is currently pressed.
- def check_key_is_press(keycode: [int, str]) -> bool:
- """
- use to check key is press return True or False
- :param keycode check key is press or not
- """
\ No newline at end of file
+ :param keycode: Key name or key code to check.
+ :type keycode: int or str
+ :returns: ``True`` if the key is pressed, ``False`` otherwise.
+ :rtype: bool
diff --git a/docs/source/API/wrapper/mouse.rst b/docs/source/API/wrapper/mouse.rst
index 5cda31e..2ec151d 100644
--- a/docs/source/API/wrapper/mouse.rst
+++ b/docs/source/API/wrapper/mouse.rst
@@ -1,84 +1,127 @@
+=========
Mouse API
+=========
+
+Functions for controlling the mouse cursor.
+
+----
+
+get_mouse_table
+===============
+
+.. function:: get_mouse_table()
+
+ Returns the mouse key table for the current platform.
+
+ :returns: Dictionary mapping mouse button names to platform-specific key codes.
+ :rtype: dict
+
+----
+
+mouse_preprocess
+================
+
+.. function:: mouse_preprocess(mouse_keycode, x, y)
+
+ Validates the mouse key code and resolves the cursor position.
+ If ``x`` or ``y`` is ``None``, the current mouse position is used.
+
+ :param mouse_keycode: Mouse button name or key code.
+ :type mouse_keycode: int or str
+ :param x: X coordinate. If ``None``, uses current position.
+ :type x: int
+ :param y: Y coordinate. If ``None``, uses current position.
+ :type y: int
+ :returns: Tuple of ``(keycode, x, y)``.
+ :rtype: tuple
+
+----
+
+get_mouse_position
+==================
+
+.. function:: get_mouse_position()
+
+ Returns the current mouse cursor position.
+
+ :returns: Tuple of ``(x, y)``.
+ :rtype: tuple[int, int]
+
+----
+
+set_mouse_position
+==================
+
+.. function:: set_mouse_position(x, y)
+
+ Moves the mouse cursor to the specified coordinates.
+
+ :param int x: Target X position.
+ :param int y: Target Y position.
+ :returns: Tuple of ``(x, y)``.
+ :rtype: tuple[int, int]
+
+----
+
+press_mouse
+===========
+
+.. function:: press_mouse(mouse_keycode, x=None, y=None)
+
+ Presses and holds a mouse button at the specified position.
+
+ :param mouse_keycode: Mouse button name (e.g., ``"mouse_left"``).
+ :type mouse_keycode: int or str
+ :param int x: X position (default: current position).
+ :param int y: Y position (default: current position).
+ :returns: Tuple of ``(keycode, x, y)``.
+ :rtype: tuple
+
----
-.. code-block:: python
-
- def get_mouse_table():
- return mouse_keys_table
-
-.. code-block:: python
-
- def mouse_preprocess(mouse_keycode: [int, str], x: int, y: int) -> Tuple[Union[int, str], int, int]:
- """
- check mouse keycode is verified or not
- and then check current mouse position
- if x or y is None set x, y is current position
- :param mouse_keycode which mouse keycode we want to click
- :param x mouse click x position
- :param y mouse click y position
- """
-
-.. code-block:: python
-
- def get_mouse_position() -> Tuple[int, int]:
- """
- get mouse current position
- return mouse_x, mouse_y
- """
-
-.. code-block:: python
-
- def set_mouse_position(x: int, y: int) -> Tuple[int, int]:
- """
- :param x set mouse position x
- :param y set mouse position y
- return x, y
- """
-
-.. code-block:: python
-
- def press_mouse(mouse_keycode: [int, str], x: int = None, y: int = None) -> Tuple[Union[int, str], int, int]:
- """
- press mouse keycode on x, y
- return keycode, x, y
- :param mouse_keycode which mouse keycode we want to press
- :param x mouse click x position
- :param y mouse click y position
- """
-
-.. code-block:: python
-
- def release_mouse(mouse_keycode: [int, str], x: int = None, y: int = None) -> Tuple[Union[int, str], int, int]:
- """
- release mouse keycode on x, y
- return keycode, x, y
- :param mouse_keycode which mouse keycode we want to release
- :param x mouse click x position
- :param y mouse click y position
- """
-
-.. code-block:: python
-
- def click_mouse(mouse_keycode: [int, str], x: int = None, y: int = None) -> Tuple[Union[int, str], int, int]:
- """
- press and release mouse keycode on x, y
- return keycode, x, y
- :param mouse_keycode which mouse keycode we want to click
- :param x mouse click x position
- :param y mouse click y position
- """
-
-.. code-block:: python
-
- def mouse_scroll(scroll_value: int, x: int = None, y: int = None, scroll_direction: str = "scroll_down") -> Tuple[int, str]:
- """"
- :param scroll_value scroll count
- :param x mouse click x position
- :param y mouse click y position
- :param scroll_direction which direction we want to scroll (only linux)
- scroll_direction = scroll_up : direction up
- scroll_direction = scroll_down : direction down
- scroll_direction = scroll_left : direction left
- scroll_direction = scroll_right : direction right
- """
+release_mouse
+=============
+
+.. function:: release_mouse(mouse_keycode, x=None, y=None)
+
+ Releases a previously pressed mouse button.
+
+ :param mouse_keycode: Mouse button name (e.g., ``"mouse_left"``).
+ :type mouse_keycode: int or str
+ :param int x: X position (default: current position).
+ :param int y: Y position (default: current position).
+ :returns: Tuple of ``(keycode, x, y)``.
+ :rtype: tuple
+
+----
+
+click_mouse
+===========
+
+.. function:: click_mouse(mouse_keycode, x=None, y=None)
+
+ Presses and releases a mouse button at the specified position.
+
+ :param mouse_keycode: Mouse button name (e.g., ``"mouse_left"``).
+ :type mouse_keycode: int or str
+ :param int x: X position (default: current position).
+ :param int y: Y position (default: current position).
+ :returns: Tuple of ``(keycode, x, y)``.
+ :rtype: tuple
+
+----
+
+mouse_scroll
+============
+
+.. function:: mouse_scroll(scroll_value, x=None, y=None, scroll_direction="scroll_down")
+
+ Scrolls the mouse wheel.
+ :param int scroll_value: Number of scroll units.
+ :param int x: X position (default: current position).
+ :param int y: Y position (default: current position).
+ :param str scroll_direction: Scroll direction (Linux only). One of:
+ ``"scroll_up"``, ``"scroll_down"``, ``"scroll_left"``, ``"scroll_right"``.
+ :returns: Tuple of ``(scroll_value, direction)``.
+ :rtype: tuple
diff --git a/docs/source/API/wrapper/record.rst b/docs/source/API/wrapper/record.rst
index 684ed79..29f0c57 100644
--- a/docs/source/API/wrapper/record.rst
+++ b/docs/source/API/wrapper/record.rst
@@ -1,16 +1,32 @@
+==========
Record API
+==========
+
+Functions for recording and replaying mouse/keyboard events.
+
----
-.. code-block:: python
+record
+======
+
+.. function:: record()
+
+ Starts recording all keyboard and mouse events in the background.
+ Recording continues until :func:`stop_record` is called.
+
+ :returns: None
+
+----
+
+stop_record
+===========
+
+.. function:: stop_record()
- def record() -> None:
- """
- start record keyboard and mouse event until stop_record
- """
+ Stops the current recording session and returns the captured events.
-.. code-block:: python
+ :returns: List of recorded actions in executor-compatible format.
+ :rtype: list
- def stop_record() -> list:
- """
- stop current record
- """
\ No newline at end of file
+ The returned list can be passed directly to ``execute_action()`` for playback,
+ or saved to a JSON file for later use.
diff --git a/docs/source/API/wrapper/screen.rst b/docs/source/API/wrapper/screen.rst
index dd959a5..6d5ccd2 100644
--- a/docs/source/API/wrapper/screen.rst
+++ b/docs/source/API/wrapper/screen.rst
@@ -1,18 +1,32 @@
+==========
Screen API
+==========
+
+Functions for screen information and capture.
+
+----
+
+screen_size
+===========
+
+.. function:: screen_size()
+
+ Returns the current screen resolution.
+
+ :returns: Screen dimensions as ``(width, height)``.
+ :rtype: tuple[int, int]
+
----
-.. code-block:: python
+screenshot
+==========
- def screen_size() -> Tuple[int, int]:
- """
- get screen size
- """
+.. function:: screenshot(file_path=None, screen_region=None)
-.. code-block:: python
+ Captures the current screen image.
- def screenshot(file_path: str = None, screen_region: list = None) -> List[int]:
- """
- use to capture current screen image
- :param file_path screenshot file save path
- :param screen_region screenshot screen_region
- """
\ No newline at end of file
+ :param str file_path: File path to save the screenshot. If ``None``, the image is not saved.
+ :param list screen_region: Region to capture as ``[x1, y1, x2, y2]``.
+ If ``None``, captures the full screen.
+ :returns: The captured screen image.
+ :rtype: list[int]
diff --git a/docs/source/Eng/doc/callback_function/callback_function_doc.rst b/docs/source/Eng/doc/callback_function/callback_function_doc.rst
index 1bca1c3..8572d95 100644
--- a/docs/source/Eng/doc/callback_function/callback_function_doc.rst
+++ b/docs/source/Eng/doc/callback_function/callback_function_doc.rst
@@ -1,56 +1,73 @@
-Callback Function
-----
+=================
+Callback Executor
+=================
-In AutoControl, callback functions are supported by the Callback Executor.
-Below is a simple example of using the Callback Executor:
+The Callback Executor allows you to execute an automation function and trigger a callback
+function upon completion.
+
+Basic Usage
+===========
.. code-block:: python
- from je_auto_control import callback_executor
- # trigger_function will first to execute, but return value need to wait everything done
- # so this test will first print("test") then print(size_function_return_value)
- print(
- callback_executor.callback_function(
- trigger_function_name="size",
- callback_function=print,
- callback_param_method="args",
- callback_function_param={"": "test"}
- )
- )
-
-* Note that if the "name: function" pair in the callback_executor event_dict is different from the executor, it is a bug.
-* Of course, like the executor, it can be expanded by adding external functions. Please see the example below.
-
-In this example, we use callback_executor to execute the "size" function defined in AutoControl.
-After executing the "size" function, the function passed to callback_function will be executed.
-The delivery method can be determined by the callback_param_method parameter.
-If it is "args", please pass in {"value1", "value2", ...}.
-Here, the ellipsis (...) represents multiple inputs.
- If it is "kwargs", please pass in {"actually_param_name": value, ...}.
-Here, the ellipsis (...) again represents multiple inputs.
- If you want to use the return value,
-since the return value will only be returned after all functions are executed,
-you will actually see the "print" statement
-before the "print(size_function_return_value)" statement in this example,
-even though the order of size -> print is correct.
-This is because the "size" function only returns the value itself without printing it.
-
-This code will load all built-in functions, methods, and classes of the time module into the callback executor.
-To use the loaded functions, we need to use the package_function name,
-for example, time.sleep will become time_sleep.
-
-If we want to add functions in the callback_executor, we can use the following code:
-
-This code will add all the functions of the time module to the executor (interpreter).
+ from je_auto_control import callback_executor
+
+ result = callback_executor.callback_function(
+ trigger_function_name="screen_size",
+ callback_function=print,
+ callback_param_method="args",
+ callback_function_param={"": "Callback triggered!"}
+ )
+ print(f"Return value: {result}")
+
+How It Works
+============
+
+1. The ``trigger_function_name`` function executes first.
+2. After it completes, the ``callback_function`` is called.
+3. The return value of the trigger function is returned after all callbacks finish.
+
+Parameters
+==========
+
+.. list-table::
+ :header-rows: 1
+ :widths: 30 70
+
+ * - Parameter
+ - Description
+ * - ``trigger_function_name``
+ - Name of the function to execute (must exist in ``event_dict``)
+ * - ``callback_function``
+ - The function to call after the trigger function completes
+ * - ``callback_function_param``
+ - Parameters to pass to the callback function (dict)
+ * - ``callback_param_method``
+ - ``"args"`` for positional or ``"kwargs"`` for keyword arguments
+ * - ``**kwargs``
+ - Additional keyword arguments passed to the trigger function
+
+Extending the Callback Executor
+================================
+
+Load external package functions into the callback executor:
.. code-block:: python
- from je_auto_control import package_manager
- package_manager.add_package_to_callback_executor("time")
+ from je_auto_control import package_manager
+
+ # Add all functions from the 'time' module
+ package_manager.add_package_to_callback_executor("time")
-If you need to check the updated event_dict, you can use:
+To inspect the current event dictionary:
.. code-block:: python
- from je_auto_control import callback_executor
- print(callback_executor.event_dict)
\ No newline at end of file
+ from je_auto_control import callback_executor
+
+ print(callback_executor.event_dict)
+
+.. note::
+
+ The callback executor's ``event_dict`` should contain the same function mappings as the
+ main executor. If they differ, it is a bug.
diff --git a/docs/source/Eng/doc/cli/cli_doc.rst b/docs/source/Eng/doc/cli/cli_doc.rst
index 8c2dbc9..a2a709e 100644
--- a/docs/source/Eng/doc/cli/cli_doc.rst
+++ b/docs/source/Eng/doc/cli/cli_doc.rst
@@ -1,19 +1,54 @@
-CLI
-----
+=======================
+Command-Line Interface
+=======================
-We can use the CLI mode to execute the keyword.
-json file or execute the folder containing the Keyword.json files.
+AutoControl can be used directly from the command line to execute automation scripts.
-The following example is to execute the specified path of the keyword JSON file.
+Execute a Single Action File
+=============================
-.. code-block::
+.. code-block:: bash
- python je_auto_control --execute_file "your_file_path"
+ python -m je_auto_control --execute_file "path/to/actions.json"
+ # Short form
+ python -m je_auto_control -e "path/to/actions.json"
+Execute All Files in a Directory
+================================
-The following example is to run all keyword JSON files in a specified folder:
+.. code-block:: bash
-.. code-block::
+ python -m je_auto_control --execute_dir "path/to/action_files/"
- python je_auto_control --execute_dir "your_dir_path"
\ No newline at end of file
+ # Short form
+ python -m je_auto_control -d "path/to/action_files/"
+
+Execute a JSON String Directly
+==============================
+
+.. code-block:: bash
+
+ python -m je_auto_control --execute_str '[["AC_screenshot", {"file_path": "test.png"}]]'
+
+Create a Project Template
+=========================
+
+.. code-block:: bash
+
+ python -m je_auto_control --create_project "path/to/my_project"
+
+ # Short form
+ python -m je_auto_control -c "path/to/my_project"
+
+Launch the GUI
+==============
+
+.. code-block:: bash
+
+ python -m je_auto_control
+
+.. note::
+
+ Launching the GUI requires the ``[gui]`` extra to be installed:
+ ``pip install je_auto_control[gui]``
diff --git a/docs/source/Eng/doc/create_project/create_project_doc.rst b/docs/source/Eng/doc/create_project/create_project_doc.rst
index 431815f..e911a42 100644
--- a/docs/source/Eng/doc/create_project/create_project_doc.rst
+++ b/docs/source/Eng/doc/create_project/create_project_doc.rst
@@ -1,23 +1,48 @@
-Create Project
-----
+==================
+Project Management
+==================
-In AutoControl, you can create a project which will automatically generate sample files once the project is created.
-These sample files include a Python executor file and a keyword.json file.
+AutoControl can scaffold a project directory with template files to help you get started quickly.
-To create a project, you can use the following method:
+Creating a Project
+==================
+
+Using Python:
.. code-block:: python
- from je_auto_control import create_project_dir
- # create on current workdir
- create_project_dir()
- # create project on project_path
- create_project_dir("project_path")
- # create project on project_path and dir name is My First Project
- create_project_dir("project_path", "My First Project")
+ from je_auto_control import create_project_dir
+
+ # Create in current working directory
+ create_project_dir()
+
+ # Create at a specific path
+ create_project_dir("path/to/project")
+
+ # Create with a custom directory name
+ create_project_dir("path/to/project", "My First Project")
+
+Using the CLI:
+
+.. code-block:: bash
+
+ python -m je_auto_control --create_project "path/to/project"
+
+Generated Structure
+===================
-Or using CLI, this will generate a project at the project_path location.
+.. code-block:: text
-.. code-block:: console
+ my_project/
+ └── AutoControl/
+ ├── keyword/
+ │ ├── keyword1.json # Template action file
+ │ ├── keyword2.json # Template action file
+ │ └── bad_keyword_1.json # Error handling template
+ └── executor/
+ ├── executor_one_file.py # Execute single file example
+ ├── executor_folder.py # Execute folder example
+ └── executor_bad_file.py # Error handling example
- python -m je_auto_control --create_project project_path
\ No newline at end of file
+The ``keyword/`` directory contains JSON action files, and the ``executor/`` directory
+contains Python scripts that demonstrate how to run them.
diff --git a/docs/source/Eng/doc/critical_exit/critical_exit_doc.rst b/docs/source/Eng/doc/critical_exit/critical_exit_doc.rst
index ba9c4f2..e5691d2 100644
--- a/docs/source/Eng/doc/critical_exit/critical_exit_doc.rst
+++ b/docs/source/Eng/doc/critical_exit/critical_exit_doc.rst
@@ -1,42 +1,62 @@
+=============
Critical Exit
-----
+=============
-* Critical Exit is a mechanism that provides fault protection.
-* Critical Exit is disabled by default.
-* If enabled, the default hotkey is F7.
-* To enable Critical Exit, call CriticalExit().init_critical_exit()
-* (enabling it will consume additional system resources).
+Critical Exit is a safety mechanism that allows you to forcibly stop an automation script
+by pressing a hotkey (default: **F7**).
-The following example is to make the mouse move uncontrollably and throw an exception.
-When the exception is caught, initialize the Critical Exit and automatically press F7.
-(Note! If you modify this example, you must be extremely careful.
-You may lose control of your computer, such as the mouse being out of control.)
+.. warning::
+
+ Critical Exit is **disabled by default**. Enabling it consumes additional system resources
+ as it runs a background thread that continuously monitors the keyboard.
+
+Enabling Critical Exit
+======================
+
+.. code-block:: python
+
+ from je_auto_control import CriticalExit
+
+ CriticalExit().init_critical_exit()
+
+After calling ``init_critical_exit()``, pressing **F7** will interrupt the main thread
+and terminate the program.
+
+Changing the Hotkey
+===================
.. code-block:: python
- import sys
+ from je_auto_control import CriticalExit
+
+ critical = CriticalExit()
+ critical.set_critical_key("escape") # Use Escape instead of F7
+ critical.init_critical_exit()
+
+Example: Recovering from Runaway Mouse
+=======================================
+
+.. code-block:: python
- from je_auto_control import AutoControlMouseException
- from je_auto_control import CriticalExit
- from je_auto_control import press_key
- from je_auto_control import set_position
- from je_auto_control import size
+ import sys
+ from je_auto_control import (
+ CriticalExit, AutoControlMouseException,
+ set_mouse_position, screen_size, press_keyboard_key
+ )
- # print your screen width and height
+ print(screen_size())
- print(size())
+ try:
+ while True:
+ set_mouse_position(200, 400)
+ set_mouse_position(400, 600)
+ raise AutoControlMouseException
+ except Exception as error:
+ print(repr(error), file=sys.stderr)
+ CriticalExit().init_critical_exit()
+ press_keyboard_key("f7")
- # simulate you can't use your mouse because you use while true to set mouse position
+.. danger::
- try:
- from time import sleep
- # Or no sleep
- sleep(3)
- while True:
- set_mouse_position(200, 400)
- set_mouse_position(400, 600)
- raise AutoControlMouseException
- except Exception as error:
- print(repr(error), file=sys.stderr)
- CriticalExit().init_critical_exit()
- press_key("f7")
\ No newline at end of file
+ Be extremely careful when testing automation loops that move the mouse continuously.
+ Always have Critical Exit enabled or another way to regain control.
diff --git a/docs/source/Eng/doc/generate_report/generate_report_doc.rst b/docs/source/Eng/doc/generate_report/generate_report_doc.rst
index d4d8cb9..9ed362d 100644
--- a/docs/source/Eng/doc/generate_report/generate_report_doc.rst
+++ b/docs/source/Eng/doc/generate_report/generate_report_doc.rst
@@ -1,156 +1,84 @@
-Generate Report
-----
+=================
+Report Generation
+=================
-* Generate Report can generate reports in the following formats:
- * HTML
- * JSON
- * XML
+AutoControl can generate test reports in HTML, JSON, and XML formats. Reports record
+which automation steps were executed and whether they succeeded or failed.
-* Generate Report is mainly used to record and confirm which steps were executed and whether they were successful or not.
-* If you want to use Generate Report, you need to set the recording to True by using test_record_instance.init_record = True.
-* The following example is used with keywords and an executor. If you don't understand, please first take a look at the executor.
+Setup
+=====
-Here's an example of generating an HTML report.
+Before generating reports, enable test recording:
.. code-block:: python
- import sys
-
- from je_auto_control import execute_action
- from je_auto_control import test_record_instance
-
- test_list = None
- test_record_instance.init_record = True
- if sys.platform in ["win32", "cygwin", "msys"]:
- test_list = [
- ["set_record_enable", {"set_enable": True}],
- ["type_keyboard", {"keycode": 65}],
- ["mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["get_mouse_position"],
- ["press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}],
- ["generate_html_report"],
- ]
-
- elif sys.platform in ["linux", "linux2"]:
- test_list = [
- ["set_record_enable", {"set_enable": True}],
- ["type_keyboard", {"keycode": 38}],
- ["mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["get_mouse_position"],
- ["press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}],
- ["generate_html_report"],
- ]
- elif sys.platform in ["darwin"]:
- test_list = [
- ["set_record_enable", {"set_enable": True}],
- ["type_keyboard", {"keycode": 0x00}],
- ["mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["get_mouse_position"],
- ["press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}],
- ["generate_html_report"],
- ]
- print("\n\n")
- execute_action(test_list)
-
-
-Here's an example of generating an JSON report.
+ from je_auto_control import test_record_instance
+
+ test_record_instance.init_record = True
+
+.. important::
+
+ Recording must be enabled **before** executing actions, otherwise no data will be captured.
+
+Generating Reports
+==================
+
+HTML Report
+-----------
+
+.. code-block:: python
+
+ from je_auto_control import execute_action, generate_html_report, test_record_instance
+
+ test_record_instance.init_record = True
+
+ actions = [
+ ["set_record_enable", {"set_enable": True}],
+ ["AC_set_mouse_position", {"x": 500, "y": 500}],
+ ["AC_click_mouse", {"mouse_keycode": "mouse_left"}],
+ ["generate_html_report"],
+ ]
+ execute_action(actions)
+
+This produces an HTML file where successful actions appear in **cyan** and failed actions in **red**.
+
+JSON Report
+-----------
.. code-block:: python
- import sys
-
- from je_auto_control import execute_action
- from je_auto_control import test_record_instance
-
- test_list = None
- test_record_instance.init_record = True
- if sys.platform in ["win32", "cygwin", "msys"]:
- test_list = [
- ["set_record_enable", {"set_enable": True}],
- ["type_keyboard", {"keycode": 65}],
- ["mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["get_mouse_position"],
- ["press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}],
- ["generate_json_report"],
- ]
-
- elif sys.platform in ["linux", "linux2"]:
- test_list = [
- ["set_record_enable", {"set_enable": True}],
- ["type_keyboard", {"keycode": 38}],
- ["mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["get_mouse_position"],
- ["press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}],
- ["generate_json_report"],
- ]
- elif sys.platform in ["darwin"]:
- test_list = [
- ["set_record_enable", {"set_enable": True}],
- ["type_keyboard", {"keycode": 0x00}],
- ["mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["get_mouse_position"],
- ["press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}],
- ["generate_json_report"],
- ]
- print("\n\n")
- execute_action(test_list)
-
-Here's an example of generating an XML report.
+ from je_auto_control import generate_json_report
+
+ generate_json_report("test_report") # -> test_report.json
+
+XML Report
+----------
+
+.. code-block:: python
+
+ from je_auto_control import generate_xml_report
+
+ generate_xml_report("test_report") # -> test_report.xml
+
+Getting Report Content as String
+================================
+
+If you need the report content without saving to a file:
.. code-block:: python
- import sys
-
- from je_auto_control import execute_action
- from je_auto_control import test_record_instance
-
- test_list = None
- test_record_instance.init_record = True
- if sys.platform in ["win32", "cygwin", "msys"]:
- test_list = [
- ["set_record_enable", {"set_enable": True}],
- ["type_keyboard", {"keycode": 65}],
- ["mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["get_mouse_position"],
- ["press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}],
- ["generate_xml_report"]
- ]
-
- elif sys.platform in ["linux", "linux2"]:
- test_list = [
- ["set_record_enable", {"set_enable": True}],
- ["type_keyboard", {"keycode": 38}],
- ["mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["get_mouse_position"],
- ["press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}],
- ["generate_xml_report"]
- ]
- elif sys.platform in ["darwin"]:
- test_list = [
- ["set_record_enable", {"set_enable": True}],
- ["type_keyboard", {"keycode": 0x00}],
- ["mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["get_mouse_position"],
- ["press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}],
- ["generate_xml_report"]
- ]
- print("\n\n")
- execute_action(test_list)
+ from je_auto_control import generate_html, generate_json, generate_xml
+
+ html_string = generate_html()
+ json_data = generate_json()
+ xml_data = generate_xml()
+
+Report Contents
+===============
+
+Each report entry includes:
+
+* **Function name** -- the automation function that was called
+* **Parameters** -- the arguments passed to the function
+* **Timestamp** -- when the action was executed
+* **Exception info** -- error details if the action failed
diff --git a/docs/source/Eng/doc/image/image_doc.rst b/docs/source/Eng/doc/image/image_doc.rst
index cdfd02f..9c04a1e 100644
--- a/docs/source/Eng/doc/image/image_doc.rst
+++ b/docs/source/Eng/doc/image/image_doc.rst
@@ -1,60 +1,85 @@
-Image detect
-----
+=================
+Image Recognition
+=================
-* Image detect provides functionalities related to image recognition.
-* Locating the position of a single image on the screen.
-* Locating the position of multiple images on the screen.
-* Locating the position of an image on the screen and clicking on it.
+AutoControl uses OpenCV template matching to locate UI elements on the screen.
+This is useful for finding buttons, icons, or other visual elements and interacting with them.
-This is mainly used to recognize images on the screen and perform clicks or determine if the image exists on the screen.
+Locate All Matches
+==================
-The following example is to locate all images.
+Find all occurrences of a template image on the screen:
.. code-block:: python
- import time
+ import time
+ from je_auto_control import locate_all_image, screenshot
- from je_auto_control import locate_all_image
- from je_auto_control import screenshot
+ time.sleep(2)
- time.sleep(2)
+ # detect_threshold: 0.0 ~ 1.0 (1.0 = exact match)
+ image_data = locate_all_image(
+ screenshot(),
+ detect_threshold=0.9,
+ draw_image=False
+ )
+ print(image_data) # [[x1, y1, x2, y2], ...]
- # detect_threshold 0~1 , 1 is absolute equal
- # draw_image, mark the find target
+Locate Image Center
+===================
- image_data = locate_all_image(screenshot(), detect_threshold=0.9, draw_image=False)
- print(image_data)
-
-The following example is used to locate and click on an image.
+Find a template image and return its center coordinates:
.. code-block:: python
- import time
+ import time
+ from je_auto_control import locate_image_center, screenshot
- from je_auto_control import locate_and_click
- from je_auto_control import screenshot
+ time.sleep(2)
- time.sleep(2)
+ cx, cy = locate_image_center(
+ screenshot(),
+ detect_threshold=0.9,
+ draw_image=False
+ )
+ print(f"Found at center: ({cx}, {cy})")
- # detect_threshold 0~1 , 1 is absolute equal
- # draw_image, mark the find target
- image_data = locate_and_click(screenshot(), "mouse_left", detect_threshold=0.9, draw_image=False)
- print(image_data)
+Locate and Click
+================
-The following example locates an image.
+Find a template image and automatically click on its center:
.. code-block:: python
- import time
-
- from je_auto_control import locate_image_center
- from je_auto_control import screenshot
-
- time.sleep(2)
-
- # detect_threshold 0~1 , 1 is absolute equal
- # draw_image, mark the find target
-
- image_data = locate_image_center(screenshot(), detect_threshold=0.9, draw_image=False)
- print(image_data)
-
+ import time
+ from je_auto_control import locate_and_click, screenshot
+
+ time.sleep(2)
+
+ image_data = locate_and_click(
+ screenshot(),
+ "mouse_left",
+ detect_threshold=0.9,
+ draw_image=False
+ )
+ print(image_data)
+
+Parameters
+==========
+
+.. list-table::
+ :header-rows: 1
+ :widths: 25 15 60
+
+ * - Parameter
+ - Type
+ - Description
+ * - ``image``
+ - str / PIL Image
+ - The template image to search for (file path or PIL ``ImageGrab.grab()`` result)
+ * - ``detect_threshold``
+ - float
+ - Detection precision from ``0.0`` to ``1.0``. ``1.0`` requires an exact match.
+ * - ``draw_image``
+ - bool
+ - If ``True``, marks the detected area on the returned image.
diff --git a/docs/source/Eng/doc/installation/installation_doc.rst b/docs/source/Eng/doc/installation/installation_doc.rst
index 719caf7..dc27cc1 100644
--- a/docs/source/Eng/doc/installation/installation_doc.rst
+++ b/docs/source/Eng/doc/installation/installation_doc.rst
@@ -1,31 +1,60 @@
+============
Installation
-----
+============
-.. code-block:: python
+Install from PyPI
+=================
- pip install je_auto_control
+.. code-block:: bash
-* Python & pip require version
- * Python 3.7 & up
- * pip 19.3 & up
+ pip install je_auto_control
-* Dev env
- * windows 11
- * osx 11 big sur
- * ubuntu 20.0.4
+Requirements
+============
-| If you want install on raspberry pi
+* Python 3.10 or higher
+* pip 19.3 or higher
-.. code-block:: python
+With GUI Support
+================
- sudo apt-get install python3
- pip3 install je_auto_control
- sudo apt-get install libcblas-dev
- sudo apt-get install libhdf5-dev
- sudo apt-get install libhdf5-serial-dev
- sudo apt-get install libatlas-base-dev
- sudo apt-get install libjasper-dev
- sudo apt-get install libqtgui4
- sudo apt-get install libqt4-test
- pip3 install -U pillow
- pip3 install -U numpy
\ No newline at end of file
+.. code-block:: bash
+
+ pip install je_auto_control[gui]
+
+Linux Prerequisites
+===================
+
+.. code-block:: bash
+
+ sudo apt-get install cmake libssl-dev
+
+Raspberry Pi
+============
+
+.. code-block:: bash
+
+ sudo apt-get install python3
+ pip3 install je_auto_control
+ sudo apt-get install libcblas-dev libhdf5-dev libhdf5-serial-dev
+ sudo apt-get install libatlas-base-dev libjasper-dev
+ sudo apt-get install libqtgui4 libqt4-test
+ pip3 install -U pillow numpy
+
+Development Environment
+=======================
+
+.. list-table::
+ :header-rows: 1
+ :widths: 30 70
+
+ * - Platform
+ - Tested Version
+ * - Windows
+ - Windows 11
+ * - macOS
+ - macOS Big Sur (11)
+ * - Linux
+ - Ubuntu 20.04
+ * - Raspberry Pi
+ - 3B / 4B
diff --git a/docs/source/Eng/doc/keyboard/keyboard_doc.rst b/docs/source/Eng/doc/keyboard/keyboard_doc.rst
index 7e6f4cc..3f2afb1 100644
--- a/docs/source/Eng/doc/keyboard/keyboard_doc.rst
+++ b/docs/source/Eng/doc/keyboard/keyboard_doc.rst
@@ -1,69 +1,96 @@
-Keyboard
-----
+================
+Keyboard Control
+================
-* Used to simulate keyboard control.
-* Provides functions such as hotkeys, checking keyboard key status (whether pressed), and simulating keyboard control.
-* The following example is to obtain information about the keyboard.
+AutoControl provides functions for simulating keyboard input including key press/release,
+typing strings, hotkey combinations, and key state detection.
-* special_table is a table of special keyboard keys (Note! Not every platform has them).
-* keys_table is a table of all available keys.
+Getting Key Tables
+==================
+
+Retrieve available key names:
.. code-block:: python
- from je_auto_control import keys_table, get_special_table
+ from je_auto_control import keys_table, get_special_table
+
+ # All available keys for your platform
+ print(keys_table)
+
+ # Special keys (platform-specific)
+ print(get_special_table())
- print(keys_table)
- print(get_special_table())
+.. tip::
+ See :doc:`/API/special/keyboard_keys` for the full list of available keyboard keys per platform.
-The following example presses a certain key on the keyboard and releases it after one second.
+Press and Release
+=================
+
+Hold a key down and release it after a delay:
.. code-block:: python
- from time import sleep
- from je_auto_control import press_keyboard_key, release_keyboard_key
+ from time import sleep
+ from je_auto_control import press_keyboard_key, release_keyboard_key
+
+ press_keyboard_key("a")
+ sleep(1)
+ release_keyboard_key("a")
- press_key("a")
- sleep(1)
- release_key("a")
+Type a Single Key
+=================
-The following example presses and releases a key.
+Press and immediately release a key:
.. code-block:: python
- from je_auto_control import type_keyboard
+ from je_auto_control import type_keyboard
- type_keyboard("a")
+ type_keyboard("a")
-The following example checks whether the 'a' key on the keyboard is being pressed.
+Check Key State
+===============
+
+Check whether a specific key is currently pressed:
.. code-block:: python
- from je_auto_control import check_key_is_press
+ from je_auto_control import check_key_is_press
+
+ is_pressed = check_key_is_press("a")
+ print(f"Key 'a' is pressed: {is_pressed}")
- check_key_is_press("a")
+Type a String
+=============
-The following example presses and releases a series of keys.
+Type a sequence of characters one by one:
.. code-block:: python
- from je_auto_control import write
+ from je_auto_control import write
- write("abcdefg")
+ write("Hello World")
-The following example uses a hotkey to press and then release the passed-in key in reverse.
+Hotkey Combinations
+===================
+
+Press multiple keys in sequence, then release them in reverse order:
.. code-block:: python
- import sys
+ import sys
+ from je_auto_control import hotkey
+
+ if sys.platform in ["win32", "cygwin", "msys"]:
+ hotkey(["lcontrol", "a", "lcontrol", "c", "lcontrol", "v"])
- from je_auto_control import hotkey
+ elif sys.platform == "darwin":
+ hotkey(["command", "a", "command", "c", "command", "v"])
- if sys.platform in ["win32", "cygwin", "msys"]:
- hotkey(["lcontrol", "a", "lcontrol", "c", "lcontrol", "v", "lcontrol", "v"])
+ elif sys.platform in ["linux", "linux2"]:
+ hotkey(["ctrl", "a", "ctrl", "c", "ctrl", "v"])
- elif sys.platform in ["darwin"]:
- hotkey(["command", "a", "command", "c", "command", "v", "command", "v"])
+.. warning::
- elif sys.platform in ["linux", "linux2"]:
- hotkey(["ctrl", "a", "ctrl", "c", "ctrl", "v", "ctrl", "v"])
\ No newline at end of file
+ Key names differ across platforms. Always check the key table for your target platform.
diff --git a/docs/source/Eng/doc/keyword_and_executor/keyword_and_executor_doc.rst b/docs/source/Eng/doc/keyword_and_executor/keyword_and_executor_doc.rst
index 34c8c82..05386f1 100644
--- a/docs/source/Eng/doc/keyword_and_executor/keyword_and_executor_doc.rst
+++ b/docs/source/Eng/doc/keyword_and_executor/keyword_and_executor_doc.rst
@@ -1,53 +1,103 @@
-Keyword & Executor
-----
-
-Keyword is a JSON file that contains many custom keywords and parameters.
-Keywords are used in conjunction with the Executor.
-The format of a keyword is as shown in the following example, and the same format is used in the JSON file.
+====================
+Keywords & Executor
+====================
+
+The Keyword/Executor system is AutoControl's JSON-based scripting engine. You define automation
+steps as JSON arrays (keywords), and the executor interprets and runs them.
+
+Keyword Format
+==============
+
+Keywords are JSON arrays where each element is an action:
+
+.. code-block:: json
+
+ [
+ ["function_name", {"param_name": "param_value"}],
+ ["function_name", {"param_name": "param_value"}]
+ ]
+
+For example:
+
+.. code-block:: json
+
+ [
+ ["AC_set_mouse_position", {"x": 500, "y": 300}],
+ ["AC_click_mouse", {"mouse_keycode": "mouse_left"}],
+ ["AC_write", {"write_string": "Hello"}]
+ ]
+
+Available Action Commands
+=========================
+
+.. list-table::
+ :header-rows: 1
+ :widths: 20 80
+
+ * - Category
+ - Commands
+ * - Mouse
+ - ``AC_click_mouse``, ``AC_set_mouse_position``, ``AC_get_mouse_position``, ``AC_press_mouse``, ``AC_release_mouse``, ``AC_mouse_scroll``
+ * - Keyboard
+ - ``AC_type_keyboard``, ``AC_press_keyboard_key``, ``AC_release_keyboard_key``, ``AC_write``, ``AC_hotkey``, ``AC_check_key_is_press``
+ * - Image
+ - ``AC_locate_all_image``, ``AC_locate_image_center``, ``AC_locate_and_click``
+ * - Screen
+ - ``AC_screen_size``, ``AC_screenshot``
+ * - Record
+ - ``AC_record``, ``AC_stop_record``
+ * - Report
+ - ``AC_generate_html``, ``AC_generate_json``, ``AC_generate_xml``, ``AC_generate_html_report``, ``AC_generate_json_report``, ``AC_generate_xml_report``
+ * - Project
+ - ``AC_create_project``
+ * - Shell
+ - ``AC_shell_command``
+ * - Executor
+ - ``AC_execute_action``, ``AC_execute_files``
+
+Executing a JSON File
+=====================
.. code-block:: python
- [
- ["function_name_in_event_dict": {"param_name": param_value}],
- ["function_name_in_event_dict": {"param_name": param_value}],
- ["function_name_in_event_dict": {"param_name": param_value}],
- # many....
- # If you are using position param
- ["function_name_in_event_dict": {param_value1, param_value2....}]
- ]
+ from je_auto_control import execute_action, read_action_json
-The executor is an interpreter that can parse JSON files and execute automation scripts.
-It can be easily transferred over the network to a remote server or computer,
-which can then execute the automation scripts using the executor.
+ execute_action(read_action_json("actions.json"))
-If we want to add a function to the executor, we can use the following code snippet.
-This code will load all the built-in functions, methods, and classes of the time module into the executor.
-To use the loaded functions, we need to use the package_function name, for example, time.sleep will become time_sleep.
+Executing All JSON Files in a Directory
+=======================================
.. code-block:: python
- from je_auto_control import package_manager
- package_manager.add_package_to_executor("time")
+ from je_auto_control import execute_files, get_dir_files_as_list
+ execute_files(get_dir_files_as_list("./action_files/"))
+Extending the Executor
+======================
-If you need to check the updated event_dict, you can use:
+You can dynamically load external Python packages into the executor:
.. code-block:: python
- from je_auto_control import executor
- print(executor.event_dict)
+ from je_auto_control import package_manager
-If we want to execute a JSON file
+ # Load all functions from the 'time' module
+ package_manager.add_package_to_executor("time")
-.. code-block:: python
+After loading, functions are available with the ``package_function`` naming convention.
+For example, ``time.sleep`` becomes ``time_sleep``:
- from je_auto_control import execute_action, read_action_json
- execute_action(read_action_json(file_path))
+.. code-block:: json
-If we want to execute all JSON files in a folder, we can use the following code snippet:
+ [
+ ["time_sleep", {"secs": 2}]
+ ]
+
+To inspect the current executor command dictionary:
.. code-block:: python
- from je_auto_control import execute_files, get_dir_files_as_list
- execute_files(get_dir_files_as_list(dir_path))
\ No newline at end of file
+ from je_auto_control import executor
+
+ print(executor.event_dict)
diff --git a/docs/source/Eng/doc/mouse/mouse_doc.rst b/docs/source/Eng/doc/mouse/mouse_doc.rst
index e26f62f..6f16543 100644
--- a/docs/source/Eng/doc/mouse/mouse_doc.rst
+++ b/docs/source/Eng/doc/mouse/mouse_doc.rst
@@ -1,54 +1,83 @@
-Mouse
-----
+=============
+Mouse Control
+=============
-* This module is used for simulating mouse control.
-* It provides functions for simulating clicks, setting positions, etc.
+AutoControl provides functions for simulating mouse actions including clicking,
+positioning, scrolling, and drag operations.
-The following example is to obtain information about mouse clicks:
-mouse_table contains all the available mouse buttons.
+Getting Mouse Button Table
+==========================
+
+Retrieve all available mouse button key names:
.. code-block:: python
- from je_auto_control import mouse_table
+ from je_auto_control import mouse_table
+
+ print(mouse_table)
+
+.. tip::
- print(mouse_table)
+ See :doc:`/API/special/mouse_keys` for the full list of available mouse keys per platform.
-The following example is holding down the mouse button and releasing it after one second.
+Press and Release
+=================
+
+Hold down a mouse button and release it after a delay:
.. code-block:: python
- from time import sleep
+ from time import sleep
+ from je_auto_control import press_mouse, release_mouse
- from je_auto_control import press_mouse, release_mouse
+ press_mouse("mouse_right")
+ sleep(1)
+ release_mouse("mouse_right")
- press_mouse("mouse_right")
- sleep(1)
- release_mouse("mouse_right")
+Click
+=====
-The following example is clicking and releasing the mouse.
+Press and immediately release a mouse button:
.. code-block:: python
- from je_auto_control import click_mouse
+ from je_auto_control import click_mouse
+
+ # Right click at current position
+ click_mouse("mouse_right")
- click_mouse("mouse_right")
+ # Left click at specific coordinates
+ click_mouse("mouse_left", x=500, y=300)
-The following example is to check the mouse position and change the mouse position.
+Position
+========
+
+Get and set the mouse cursor position:
.. code-block:: python
- from je_auto_control import get_mouse_position, set_mouse_position
+ from je_auto_control import get_mouse_position, set_mouse_position
+
+ # Get current position
+ x, y = get_mouse_position()
+ print(f"Mouse at: ({x}, {y})")
- print(get_mouse_position())
- set_mouse_position(100, 100)
+ # Move mouse to (100, 100)
+ set_mouse_position(100, 100)
-Here's an example where the mouse will scroll up after 3 seconds:
+Scroll
+======
+
+Scroll the mouse wheel:
.. code-block:: python
- from time import sleep
- from je_auto_control import scroll
+ from je_auto_control import mouse_scroll
+
+ # Scroll down by 5 units
+ mouse_scroll(scroll_value=5)
- sleep(3)
+.. note::
- scroll(100)
\ No newline at end of file
+ On Linux, you can specify the scroll direction using the ``scroll_direction`` parameter:
+ ``"scroll_up"``, ``"scroll_down"``, ``"scroll_left"``, ``"scroll_right"``.
diff --git a/docs/source/Eng/doc/record/record_doc.rst b/docs/source/Eng/doc/record/record_doc.rst
index bcd3f35..8c379be 100644
--- a/docs/source/Eng/doc/record/record_doc.rst
+++ b/docs/source/Eng/doc/record/record_doc.rst
@@ -1,30 +1,38 @@
-Record
-----
+=====================
+Recording & Playback
+=====================
-* Record is mainly used to record keyboard and mouse actions.
-* It can be used with an executor to replay keyboard and mouse actions.
-* The following example shows how to use it.
+AutoControl can record mouse and keyboard events and replay them using the executor.
+
+Record and Replay
+=================
.. code-block:: python
- from time import sleep
-
- from je_auto_control import execute_action
- from je_auto_control import record
- from je_auto_control import stop_record
- from je_auto_control import type_keyboard
-
- # this program will type test two time
- # one time is type key one time is test_record
-
- record()
- sleep(1)
- print(type_keyboard("t"))
- print(type_keyboard("e"))
- print(type_keyboard("s"))
- print(type_keyboard("t"))
- sleep(2)
- record_result = stop_record()
- print(record_result)
- execute_action(record_result)
- sleep(5)
\ No newline at end of file
+ from time import sleep
+ from je_auto_control import record, stop_record, execute_action
+
+ # Start recording all mouse and keyboard events
+ record()
+
+ sleep(5) # Record for 5 seconds
+
+ # Stop and get the recorded action list
+ actions = stop_record()
+ print(actions)
+
+ # Replay the recorded actions
+ execute_action(actions)
+
+.. note::
+
+ Action recording is **not available on macOS**. See :doc:`/getting_started/installation` for platform support details.
+
+How It Works
+============
+
+1. ``record()`` starts a background listener that captures all mouse and keyboard events.
+2. ``stop_record()`` stops the listener and returns a list of actions in the executor-compatible format.
+3. ``execute_action(actions)`` replays the captured actions through the built-in executor.
+
+The recorded actions are in the same JSON format used by the :doc:`/Eng/doc/keyword_and_executor/keyword_and_executor_doc`, so you can save them to a file and replay later.
diff --git a/docs/source/Eng/doc/scheduler/scheduler_doc.rst b/docs/source/Eng/doc/scheduler/scheduler_doc.rst
index 7f5d68b..2ef3337 100644
--- a/docs/source/Eng/doc/scheduler/scheduler_doc.rst
+++ b/docs/source/Eng/doc/scheduler/scheduler_doc.rst
@@ -1,19 +1,87 @@
+=========
Scheduler
-----
+=========
-You can use scheduling to perform repetitive tasks, either by using a simple wrapper for APScheduler or by consulting the API documentation to use it yourself.
+AutoControl provides a wrapper around `APScheduler `_ for
+scheduling repetitive automation tasks.
+
+Basic Example
+=============
+
+.. code-block:: python
+
+ from je_auto_control import SchedulerManager
+
+ def my_task():
+ print("Task executed!")
+ scheduler.remove_blocking_job(id="my_job")
+ scheduler.shutdown_blocking_scheduler()
+
+ scheduler = SchedulerManager()
+ scheduler.add_interval_blocking_secondly(function=my_task, id="my_job")
+ scheduler.start_block_scheduler()
+
+Blocking vs Non-Blocking
+=========================
+
+.. list-table::
+ :header-rows: 1
+ :widths: 30 70
+
+ * - Mode
+ - Description
+ * - Blocking
+ - ``start_block_scheduler()`` blocks the current thread. Use for standalone scheduler scripts.
+ * - Non-blocking
+ - ``start_nonblocking_scheduler()`` runs in a background thread. Use when you need the main thread for other work.
+
+Interval Scheduling
+===================
+
+Schedule a function to run at fixed intervals:
+
+.. code-block:: python
+
+ # Every second
+ scheduler.add_interval_blocking_secondly(function=my_task, id="job1")
+
+ # Every minute
+ scheduler.add_interval_blocking_minutely(function=my_task, id="job2")
+
+ # Every hour
+ scheduler.add_interval_blocking_hourly(function=my_task, id="job3")
+
+ # Every day
+ scheduler.add_interval_blocking_daily(function=my_task, id="job4")
+
+ # Every week
+ scheduler.add_interval_blocking_weekly(function=my_task, id="job5")
+
+Non-blocking equivalents are available with ``add_interval_nonblocking_*`` methods.
+
+Cron Scheduling
+===============
.. code-block:: python
- from je_auto_control import SchedulerManager
+ scheduler.add_cron_blocking(function=my_task, id="cron_job", hour=9, minute=30)
+Removing Jobs
+=============
+
+.. code-block:: python
+
+ scheduler.remove_blocking_job(id="job1")
+ scheduler.remove_nonblocking_job(id="job2")
+
+Shutting Down
+=============
+
+.. code-block:: python
- def test_scheduler():
- print("Test Scheduler")
- scheduler.remove_blocking_job(id="test")
- scheduler.shutdown_blocking_scheduler()
+ scheduler.shutdown_blocking_scheduler()
+ scheduler.shutdown_nonblocking_scheduler()
+.. tip::
- scheduler = SchedulerManager()
- scheduler.add_interval_blocking_secondly(function=test_scheduler, id="test")
- scheduler.start_block_scheduler()
+ See the :doc:`/API/utils/scheduler` for the complete API reference.
diff --git a/docs/source/Eng/doc/screen/screen_doc.rst b/docs/source/Eng/doc/screen/screen_doc.rst
index c37814f..8a2f995 100644
--- a/docs/source/Eng/doc/screen/screen_doc.rst
+++ b/docs/source/Eng/doc/screen/screen_doc.rst
@@ -1,20 +1,44 @@
-Screen
-----
+=================
+Screen Operations
+=================
-* Screen is used to get the screen size and take screenshots.
+AutoControl provides functions for capturing screenshots and retrieving screen dimensions.
-The following example shows how to take a screenshot.
+Screenshot
+==========
+
+Capture the current screen and save to a file:
.. code-block:: python
- from je_auto_control import screenshot
+ from je_auto_control import screenshot
+
+ # Save a full-screen screenshot
+ screenshot("my_screenshot.png")
+
+ # Capture a specific region [x1, y1, x2, y2]
+ screenshot("region.png", screen_region=[100, 100, 500, 400])
+
+Screen Size
+===========
+
+Get the current screen resolution:
+
+.. code-block:: python
+
+ from je_auto_control import screen_size
+
+ width, height = screen_size()
+ print(f"Screen resolution: {width} x {height}")
- screenshot()
+Get Pixel Color
+===============
-The following example shows how to get a screen size.
+Retrieve the color of a pixel at specific coordinates:
.. code-block:: python
- from je_auto_control import size
+ from je_auto_control import get_pixel
- print(size())
\ No newline at end of file
+ color = get_pixel(500, 300)
+ print(f"Pixel color at (500, 300): {color}")
diff --git a/docs/source/Eng/doc/socket_driver/socket_driver_doc.rst b/docs/source/Eng/doc/socket_driver/socket_driver_doc.rst
index 5aef2d8..7e731d5 100644
--- a/docs/source/Eng/doc/socket_driver/socket_driver_doc.rst
+++ b/docs/source/Eng/doc/socket_driver/socket_driver_doc.rst
@@ -1,25 +1,67 @@
-Socket Driver
-----
-
-* This is an experimental feature.
-* The Socket Server is mainly used to allow other programming languages to use AutoControl.
-* It processes received strings and performs actions through the underlying executor.
-* Tests can be performed remotely through this feature.
-* Currently, Java and C# support are experimental.
-* Return_Data_Over_JE should be transmitted at the end of each paragraph.
-* UTF-8 encoding is used.
-* Sending quit_server will shut down the server.
+==========================
+Socket Server (Remote API)
+==========================
+
+.. warning::
+
+ This is an **experimental** feature.
+
+The Socket Server allows other programming languages (or remote machines) to use AutoControl
+by sending JSON commands over TCP.
+
+Starting the Server
+===================
+
+.. code-block:: python
+
+ import sys
+ from je_auto_control import start_autocontrol_socket_server
+
+ try:
+ server = start_autocontrol_socket_server(host="localhost", port=9938)
+ while not server.close_flag:
+ pass
+ sys.exit(0)
+ except Exception as error:
+ print(repr(error))
+
+The server runs in a background thread and listens for JSON action commands.
+
+Sending Commands (Client)
+=========================
.. code-block:: python
- import sys
+ import socket
+ import json
+
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.connect(("localhost", 9938))
+
+ command = json.dumps([
+ ["AC_set_mouse_position", {"x": 500, "y": 300}],
+ ["AC_click_mouse", {"mouse_keycode": "mouse_left"}]
+ ])
+ sock.sendall(command.encode("utf-8"))
+
+ response = sock.recv(8192).decode("utf-8")
+ print(response)
+ sock.close()
+
+Protocol Details
+================
- from je_auto_control import start_autocontrol_socket_server
+.. list-table::
+ :header-rows: 1
+ :widths: 30 70
- try:
- server = start_autocontrol_socket_server()
- while not server.close_flag:
- pass
- sys.exit(0)
- except Exception as error:
- print(repr(error))
\ No newline at end of file
+ * - Property
+ - Value
+ * - Encoding
+ - UTF-8
+ * - End-of-response marker
+ - ``Return_Data_Over_JE``
+ * - Shutdown command
+ - Send ``"quit_server"`` to stop the server
+ * - Default port
+ - 9938
diff --git a/docs/source/Eng/eng_index.rst b/docs/source/Eng/eng_index.rst
index b8c1d01..6e3b5b4 100644
--- a/docs/source/Eng/eng_index.rst
+++ b/docs/source/Eng/eng_index.rst
@@ -1,20 +1,24 @@
-AutoControl English Documentation
-----
+==============================
+English Documentation
+==============================
+
+Comprehensive guides for all AutoControl features.
.. toctree::
- :maxdepth: 4
+ :maxdepth: 2
+ :caption: User Guide
- doc/installation/installation_doc.rst
- doc/create_project/create_project_doc.rst
- doc/keyboard/keyboard_doc.rst
- doc/mouse/mouse_doc.rst
- doc/screen/screen_doc.rst
- doc/image/image_doc.rst
- doc/record/record_doc.rst
- doc/generate_report/generate_report_doc.rst
- doc/callback_function/callback_function_doc.rst
- doc/keyword_and_executor/keyword_and_executor_doc.rst
- doc/critical_exit/critical_exit_doc.rst
- doc/cli/cli_doc.rst
- doc/scheduler/scheduler_doc.rst
- doc/socket_driver/socket_driver_doc.rst
\ No newline at end of file
+ doc/installation/installation_doc
+ doc/mouse/mouse_doc
+ doc/keyboard/keyboard_doc
+ doc/screen/screen_doc
+ doc/image/image_doc
+ doc/record/record_doc
+ doc/keyword_and_executor/keyword_and_executor_doc
+ doc/generate_report/generate_report_doc
+ doc/callback_function/callback_function_doc
+ doc/scheduler/scheduler_doc
+ doc/socket_driver/socket_driver_doc
+ doc/critical_exit/critical_exit_doc
+ doc/cli/cli_doc
+ doc/create_project/create_project_doc
diff --git a/docs/source/Zh/doc/callback_function/callback_function_doc.rst b/docs/source/Zh/doc/callback_function/callback_function_doc.rst
index b58ca20..9470157 100644
--- a/docs/source/Zh/doc/callback_function/callback_function_doc.rst
+++ b/docs/source/Zh/doc/callback_function/callback_function_doc.rst
@@ -1,50 +1,72 @@
-回調函數
-----
+================
+回調函數執行器
+================
-在 AutoControl 裡,Callback function 是由 Callback Executor 提供支援,
-以下是簡易的使用 Callback Executor 的範例,
+回調函數執行器允許你執行一個自動化函式,並在完成後觸發回調函式。
+
+基本用法
+========
.. code-block:: python
- from je_auto_control import callback_executor
- # trigger_function will first to execute, but return value need to wait everything done
- # so this test will first print("test") then print(size_function_return_value)
- print(
- callback_executor.callback_function(
- trigger_function_name="size",
- callback_function=print,
- callback_param_method="args",
- callback_function_param={"": "test"}
- )
- )
-
-* ( 注意!,如果 callback_executor event_dict 裡面包含的 name: function 需與 executor 一樣,不一樣則是 Bug)
-* (當然跟 executor 一樣可以藉由添加外部 function 來擴充,請看下面例子)
-
-在這個範例裡,我們使用 callback_executor 執行定義在 AutoControl 的 size function,
-然後執行完 size function 後,會去執行傳遞給 callback_function 的 function,
-可以由 callback_param_method 參數來決定要使用的傳遞方法,
-如果是 "args" 請傳入 {"value1", "value2", ...} 這裡 ... 代表可以複數傳入,
-如果是 "kwargs" 請傳入 {"actually_param_name": value, ...} 這裡 ... 代表可以複數傳入,
-然後如果要使用回傳值的話,由於回傳值會在所有 function 執行完後才回傳,
-實際上 size -> print 順序沒錯,但此例會先看到 print 之後才是 print(size_function_return_value),
-因為 size function 只有回傳值本身沒有 print 的動作。
-
-如果我們想要在 callback_executor 裡面添加 function,可以使用如下:
-這段程式碼會把所有 time module 的 builtin, function, method, class
-載入到 callback executor,然後要使用被載入的 function 需要使用 package_function 名稱,
-例如 time.sleep 會變成 time_sleep
-
-這段程式碼會把 time 所有的 function 加入 executor(直譯器裡)。
+ from je_auto_control import callback_executor
+
+ result = callback_executor.callback_function(
+ trigger_function_name="screen_size",
+ callback_function=print,
+ callback_param_method="args",
+ callback_function_param={"": "回調已觸發!"}
+ )
+ print(f"回傳值: {result}")
+
+運作方式
+========
+
+1. ``trigger_function_name`` 指定的函式首先執行。
+2. 完成後,呼叫 ``callback_function``。
+3. 觸發函式的回傳值在所有回調完成後回傳。
+
+參數說明
+========
+
+.. list-table::
+ :header-rows: 1
+ :widths: 30 70
+
+ * - 參數
+ - 說明
+ * - ``trigger_function_name``
+ - 要執行的函式名稱(必須存在於 ``event_dict`` 中)
+ * - ``callback_function``
+ - 觸發函式完成後要呼叫的函式
+ * - ``callback_function_param``
+ - 傳遞給回調函式的參數(dict)
+ * - ``callback_param_method``
+ - ``"args"`` 表示位置引數,``"kwargs"`` 表示關鍵字引數
+ * - ``**kwargs``
+ - 傳遞給觸發函式的額外關鍵字引數
+
+擴充回調執行器
+==============
+
+載入外部套件函式到回調執行器:
.. code-block:: python
- from je_auto_control import package_manager
- package_manager.add_package_to_callback_executor("time")
+ from je_auto_control import package_manager
+
+ # 載入 time 模組的所有函式
+ package_manager.add_package_to_callback_executor("time")
-如果你需要查看被更新的 event_dict 可以使用
+查看目前的事件字典:
.. code-block:: python
- from je_auto_control import callback_executor
- print(callback_executor.event_dict)
\ No newline at end of file
+ from je_auto_control import callback_executor
+
+ print(callback_executor.event_dict)
+
+.. note::
+
+ 回調執行器的 ``event_dict`` 應該包含與主執行器相同的函式對應。
+ 若不一致,則為 Bug。
diff --git a/docs/source/Zh/doc/cli/cli_doc.rst b/docs/source/Zh/doc/cli/cli_doc.rst
index 10503aa..96135ed 100644
--- a/docs/source/Zh/doc/cli/cli_doc.rst
+++ b/docs/source/Zh/doc/cli/cli_doc.rst
@@ -1,17 +1,54 @@
+============
命令列介面
-----
+============
-我們可以使用 CLI 模式去執行 keyword.json 檔案或執行包含 Keyword.json files 的資料夾,
-以下這個範例是去執行指定路徑的關鍵字 json 檔
+AutoControl 可以直接從命令列執行自動化腳本。
-.. code-block::
+執行單一動作檔案
+================
- python je_auto_control --execute_file "your_file_path"
+.. code-block:: bash
+ python -m je_auto_control --execute_file "path/to/actions.json"
+ # 簡寫
+ python -m je_auto_control -e "path/to/actions.json"
-以下這個範例是去執行指定路徑資料夾下所有的 keyword json 檔
+執行資料夾內所有檔案
+====================
-.. code-block::
+.. code-block:: bash
- python je_auto_control --execute_dir "your_dir_path"
\ No newline at end of file
+ python -m je_auto_control --execute_dir "path/to/action_files/"
+
+ # 簡寫
+ python -m je_auto_control -d "path/to/action_files/"
+
+直接執行 JSON 字串
+==================
+
+.. code-block:: bash
+
+ python -m je_auto_control --execute_str '[["AC_screenshot", {"file_path": "test.png"}]]'
+
+建立專案範本
+============
+
+.. code-block:: bash
+
+ python -m je_auto_control --create_project "path/to/my_project"
+
+ # 簡寫
+ python -m je_auto_control -c "path/to/my_project"
+
+啟動 GUI
+========
+
+.. code-block:: bash
+
+ python -m je_auto_control
+
+.. note::
+
+ 啟動 GUI 需要安裝 ``[gui]`` 額外套件:
+ ``pip install je_auto_control[gui]``
diff --git a/docs/source/Zh/doc/create_project/create_project_doc.rst b/docs/source/Zh/doc/create_project/create_project_doc.rst
index 29aebfc..449a3c6 100644
--- a/docs/source/Zh/doc/create_project/create_project_doc.rst
+++ b/docs/source/Zh/doc/create_project/create_project_doc.rst
@@ -1,23 +1,47 @@
-創建專案
-----
+========
+專案管理
+========
-在 AutoControl 裡可以創建專案,創建專案後將會自動生成範例文件,
-範例文件包含 python executor 檔案以及 keyword.json 檔案。
+AutoControl 可以建立專案目錄架構與範本檔案,幫助你快速開始。
-要創建專案可以用以下方式:
+建立專案
+========
+
+使用 Python:
.. code-block:: python
- from je_auto_control import create_project_dir
- # create on current workdir
- create_project_dir()
- # create project on project_path
- create_project_dir("project_path")
- # create project on project_path and dir name is My First Project
- create_project_dir("project_path", "My First Project")
+ from je_auto_control import create_project_dir
+
+ # 在目前工作目錄建立
+ create_project_dir()
+
+ # 在指定路徑建立
+ create_project_dir("path/to/project")
+
+ # 在指定路徑建立,並自訂目錄名稱
+ create_project_dir("path/to/project", "My First Project")
+
+使用 CLI:
+
+.. code-block:: bash
+
+ python -m je_auto_control --create_project "path/to/project"
+
+產生的目錄結構
+==============
-或是這個方式將會在 project_path 路徑產生專案
+.. code-block:: text
-.. code-block:: console
+ my_project/
+ └── AutoControl/
+ ├── keyword/
+ │ ├── keyword1.json # 動作範本檔案
+ │ ├── keyword2.json # 動作範本檔案
+ │ └── bad_keyword_1.json # 錯誤處理範本
+ └── executor/
+ ├── executor_one_file.py # 執行單一檔案範例
+ ├── executor_folder.py # 執行資料夾範例
+ └── executor_bad_file.py # 錯誤處理範例
- python -m je_auto_control --create_project project_path
\ No newline at end of file
+``keyword/`` 目錄包含 JSON 動作檔案,``executor/`` 目錄包含示範如何執行的 Python 腳本。
diff --git a/docs/source/Zh/doc/critical_exit/critical_exit_doc.rst b/docs/source/Zh/doc/critical_exit/critical_exit_doc.rst
index 250131b..5b0ff96 100644
--- a/docs/source/Zh/doc/critical_exit/critical_exit_doc.rst
+++ b/docs/source/Zh/doc/critical_exit/critical_exit_doc.rst
@@ -1,41 +1,60 @@
+========
緊急退出
-----
+========
-* Critical Exit 是提供故障保護的機制。
-* Critical Exit 預設是關閉的。
-* 如果開啟,預設按鍵是 F7。
-* 開啟的方法是 CriticalExit().init_critical_exit() (開啟後會額外消耗系統資源)
+緊急退出是一種安全機制,允許你透過按下熱鍵(預設:**F7**)來強制停止自動化腳本。
-以下這個範例是讓滑鼠不受控制的移動並拋出例外,
-當接收到例外,初始化 Critical Exit 並自動按下 F7,
-( 注意! 如果修改這個範例必須極度小心。 )
-(你可能會失去對你電腦的控制,例如滑鼠不受控制)
+.. warning::
+
+ 緊急退出 **預設為關閉**。啟用後會額外消耗系統資源,
+ 因為會在背景執行緒中持續監控鍵盤。
+
+啟用緊急退出
+============
+
+.. code-block:: python
+
+ from je_auto_control import CriticalExit
+
+ CriticalExit().init_critical_exit()
+
+呼叫 ``init_critical_exit()`` 後,按下 **F7** 會中斷主執行緒並終止程式。
+
+更改熱鍵
+========
.. code-block:: python
- import sys
+ from je_auto_control import CriticalExit
+
+ critical = CriticalExit()
+ critical.set_critical_key("escape") # 使用 Escape 取代 F7
+ critical.init_critical_exit()
+
+範例:從失控的滑鼠恢復
+======================
+
+.. code-block:: python
- from je_auto_control import AutoControlMouseException
- from je_auto_control import CriticalExit
- from je_auto_control import press_key
- from je_auto_control import set_position
- from je_auto_control import size
+ import sys
+ from je_auto_control import (
+ CriticalExit, AutoControlMouseException,
+ set_mouse_position, screen_size, press_keyboard_key
+ )
- # print your screen width and height
+ print(screen_size())
- print(size())
+ try:
+ while True:
+ set_mouse_position(200, 400)
+ set_mouse_position(400, 600)
+ raise AutoControlMouseException
+ except Exception as error:
+ print(repr(error), file=sys.stderr)
+ CriticalExit().init_critical_exit()
+ press_keyboard_key("f7")
- # simulate you can't use your mouse because you use while true to set mouse position
+.. danger::
- try:
- from time import sleep
- # Or no sleep
- sleep(3)
- while True:
- set_mouse_position(200, 400)
- set_mouse_position(400, 600)
- raise AutoControlMouseException
- except Exception as error:
- print(repr(error), file=sys.stderr)
- CriticalExit().init_critical_exit()
- press_key("f7")
\ No newline at end of file
+ 測試持續移動滑鼠的自動化迴圈時請極度小心。
+ 務必啟用緊急退出或準備其他方式來重新取得控制。
diff --git a/docs/source/Zh/doc/generate_report/generate_report_doc.rst b/docs/source/Zh/doc/generate_report/generate_report_doc.rst
index d27d83d..7567799 100644
--- a/docs/source/Zh/doc/generate_report/generate_report_doc.rst
+++ b/docs/source/Zh/doc/generate_report/generate_report_doc.rst
@@ -1,156 +1,84 @@
+========
報告產生
-----
+========
-Generate Report 可以生成以下格式的報告
+AutoControl 可以產生 HTML、JSON 和 XML 格式的測試報告。報告會記錄哪些自動化步驟被執行,
+以及是否成功。
-* HTML
-* JSON
-* XML
-* Generate Report 主要用來記錄與確認有哪些步驟執行,執行是否成功,
-* 如果要使用 Generate Report 需要先設定紀錄為 True,使用 test_record_instance.init_record = True
-* 下面的範例有搭配 keyword and executor 如果看不懂可以先去看看 executor
+設定
+====
-以下是產生 HTML 的範例。
+在產生報告之前,需先啟用測試記錄:
.. code-block:: python
- import sys
-
- from je_auto_control import execute_action
- from je_auto_control import test_record_instance
-
- test_list = None
- test_record_instance.init_record = True
- if sys.platform in ["win32", "cygwin", "msys"]:
- test_list = [
- ["set_record_enable", {"set_enable": True}],
- ["type_keyboard", {"keycode": 65}],
- ["mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["get_mouse_position"],
- ["press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}],
- ["generate_html_report"],
- ]
-
- elif sys.platform in ["linux", "linux2"]:
- test_list = [
- ["set_record_enable", {"set_enable": True}],
- ["type_keyboard", {"keycode": 38}],
- ["mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["get_mouse_position"],
- ["press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}],
- ["generate_html_report"],
- ]
- elif sys.platform in ["darwin"]:
- test_list = [
- ["set_record_enable", {"set_enable": True}],
- ["type_keyboard", {"keycode": 0x00}],
- ["mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["get_mouse_position"],
- ["press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}],
- ["generate_html_report"],
- ]
- print("\n\n")
- execute_action(test_list)
-
-
-以下是產生 JSON 的範例。
+ from je_auto_control import test_record_instance
+
+ test_record_instance.init_record = True
+
+.. important::
+
+ 記錄必須在執行動作 **之前** 啟用,否則不會擷取到任何資料。
+
+產生報告
+========
+
+HTML 報告
+---------
+
+.. code-block:: python
+
+ from je_auto_control import execute_action, generate_html_report, test_record_instance
+
+ test_record_instance.init_record = True
+
+ actions = [
+ ["set_record_enable", {"set_enable": True}],
+ ["AC_set_mouse_position", {"x": 500, "y": 500}],
+ ["AC_click_mouse", {"mouse_keycode": "mouse_left"}],
+ ["generate_html_report"],
+ ]
+ execute_action(actions)
+
+產生的 HTML 報告中,成功的動作以 **青色** 顯示,失敗的動作以 **紅色** 顯示。
+
+JSON 報告
+---------
.. code-block:: python
- import sys
-
- from je_auto_control import execute_action
- from je_auto_control import test_record_instance
-
- test_list = None
- test_record_instance.init_record = True
- if sys.platform in ["win32", "cygwin", "msys"]:
- test_list = [
- ["set_record_enable", {"set_enable": True}],
- ["type_keyboard", {"keycode": 65}],
- ["mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["get_mouse_position"],
- ["press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}],
- ["generate_json_report"],
- ]
-
- elif sys.platform in ["linux", "linux2"]:
- test_list = [
- ["set_record_enable", {"set_enable": True}],
- ["type_keyboard", {"keycode": 38}],
- ["mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["get_mouse_position"],
- ["press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}],
- ["generate_json_report"],
- ]
- elif sys.platform in ["darwin"]:
- test_list = [
- ["set_record_enable", {"set_enable": True}],
- ["type_keyboard", {"keycode": 0x00}],
- ["mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["get_mouse_position"],
- ["press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}],
- ["generate_json_report"],
- ]
- print("\n\n")
- execute_action(test_list)
-
-以下是產生 XML 的範例。
+ from je_auto_control import generate_json_report
+
+ generate_json_report("test_report") # -> test_report.json
+
+XML 報告
+--------
+
+.. code-block:: python
+
+ from je_auto_control import generate_xml_report
+
+ generate_xml_report("test_report") # -> test_report.xml
+
+取得報告內容為字串
+==================
+
+如果需要報告內容而不儲存為檔案:
.. code-block:: python
- import sys
-
- from je_auto_control import execute_action
- from je_auto_control import test_record_instance
-
- test_list = None
- test_record_instance.init_record = True
- if sys.platform in ["win32", "cygwin", "msys"]:
- test_list = [
- ["set_record_enable", {"set_enable": True}],
- ["type_keyboard", {"keycode": 65}],
- ["mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["get_mouse_position"],
- ["press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}],
- ["generate_xml_report"]
- ]
-
- elif sys.platform in ["linux", "linux2"]:
- test_list = [
- ["set_record_enable", {"set_enable": True}],
- ["type_keyboard", {"keycode": 38}],
- ["mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["get_mouse_position"],
- ["press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}],
- ["generate_xml_report"]
- ]
- elif sys.platform in ["darwin"]:
- test_list = [
- ["set_record_enable", {"set_enable": True}],
- ["type_keyboard", {"keycode": 0x00}],
- ["mouse_left", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["get_mouse_position"],
- ["press_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["release_mouse", {"mouse_keycode": "mouse_left", "x": 500, "y": 500}],
- ["type_keyboard", {"mouse_keycode": "dwadwawda", "dwadwad": 500, "wdawddwawad": 500}],
- ["generate_xml_report"]
- ]
- print("\n\n")
- execute_action(test_list)
+ from je_auto_control import generate_html, generate_json, generate_xml
+
+ html_string = generate_html()
+ json_data = generate_json()
+ xml_data = generate_xml()
+
+報告內容
+========
+
+每筆報告記錄包含:
+
+* **函式名稱** -- 被呼叫的自動化函式
+* **參數** -- 傳遞給函式的引數
+* **時間戳記** -- 動作執行的時間
+* **例外資訊** -- 動作失敗時的錯誤詳情
diff --git a/docs/source/Zh/doc/image/image_doc.rst b/docs/source/Zh/doc/image/image_doc.rst
index ec57f14..aa41d4c 100644
--- a/docs/source/Zh/doc/image/image_doc.rst
+++ b/docs/source/Zh/doc/image/image_doc.rst
@@ -1,60 +1,85 @@
-圖片偵測
-----
+========
+圖片辨識
+========
-* Image 提供了關於圖像辨識的功能。
-* 定位一張圖片在螢幕中的位置。
-* 定位多張圖片在螢幕中的位置。
-* 定位圖片在螢幕中的位置並點擊。
+AutoControl 使用 OpenCV 模板匹配技術在螢幕上定位 UI 元素。
+可用於尋找按鈕、圖示或其他視覺元素並與之互動。
-主要用來在螢幕上辨識圖片並進行點擊,或是判斷圖片是否存在螢幕上。
+定位所有匹配
+============
-以下範例是定位所有圖片
+尋找螢幕上所有符合模板圖片的位置:
.. code-block:: python
- import time
+ import time
+ from je_auto_control import locate_all_image, screenshot
- from je_auto_control import locate_all_image
- from je_auto_control import screenshot
+ time.sleep(2)
- time.sleep(2)
+ # detect_threshold: 0.0 ~ 1.0(1.0 = 完全匹配)
+ image_data = locate_all_image(
+ screenshot(),
+ detect_threshold=0.9,
+ draw_image=False
+ )
+ print(image_data) # [[x1, y1, x2, y2], ...]
- # detect_threshold 0~1 , 1 is absolute equal
- # draw_image, mark the find target
+定位圖片中心
+============
- image_data = locate_all_image(screenshot(), detect_threshold=0.9, draw_image=False)
- print(image_data)
-
-以下範例是定位並點擊圖片
+尋找模板圖片並回傳其中心座標:
.. code-block:: python
- import time
+ import time
+ from je_auto_control import locate_image_center, screenshot
- from je_auto_control import locate_and_click
- from je_auto_control import screenshot
+ time.sleep(2)
- time.sleep(2)
+ cx, cy = locate_image_center(
+ screenshot(),
+ detect_threshold=0.9,
+ draw_image=False
+ )
+ print(f"找到位置: ({cx}, {cy})")
- # detect_threshold 0~1 , 1 is absolute equal
- # draw_image, mark the find target
- image_data = locate_and_click(screenshot(), "mouse_left", detect_threshold=0.9, draw_image=False)
- print(image_data)
+定位並點擊
+==========
-以下範例是定位圖片
+尋找模板圖片並自動點擊其中心:
.. code-block:: python
- import time
-
- from je_auto_control import locate_image_center
- from je_auto_control import screenshot
-
- time.sleep(2)
-
- # detect_threshold 0~1 , 1 is absolute equal
- # draw_image, mark the find target
-
- image_data = locate_image_center(screenshot(), detect_threshold=0.9, draw_image=False)
- print(image_data)
-
+ import time
+ from je_auto_control import locate_and_click, screenshot
+
+ time.sleep(2)
+
+ image_data = locate_and_click(
+ screenshot(),
+ "mouse_left",
+ detect_threshold=0.9,
+ draw_image=False
+ )
+ print(image_data)
+
+參數說明
+========
+
+.. list-table::
+ :header-rows: 1
+ :widths: 25 15 60
+
+ * - 參數
+ - 型別
+ - 說明
+ * - ``image``
+ - str / PIL Image
+ - 要搜尋的模板圖片(檔案路徑或 PIL ``ImageGrab.grab()`` 結果)
+ * - ``detect_threshold``
+ - float
+ - 偵測精確度,範圍 ``0.0`` 到 ``1.0``。``1.0`` 要求完全匹配。
+ * - ``draw_image``
+ - bool
+ - 若為 ``True``,會在回傳的圖片上標記偵測到的區域。
diff --git a/docs/source/Zh/doc/installation/installation_doc.rst b/docs/source/Zh/doc/installation/installation_doc.rst
index 06543f8..0d1fb50 100644
--- a/docs/source/Zh/doc/installation/installation_doc.rst
+++ b/docs/source/Zh/doc/installation/installation_doc.rst
@@ -1,31 +1,60 @@
+======
安裝
-----
+======
-.. code-block:: python
+從 PyPI 安裝
+============
- pip install je_auto_control
+.. code-block:: bash
-* Python & pip require version
- * Python 3.7 & up
- * pip 19.3 & up
+ pip install je_auto_control
-* Dev env
- * windows 11
- * osx 11 big sur
- * ubuntu 20.0.4
+系統需求
+========
-| 如果想要在樹莓派使用
+* Python 3.10 以上
+* pip 19.3 以上
-.. code-block:: python
+安裝 GUI 支援
+=============
- sudo apt-get install python3
- pip3 install je_auto_control
- sudo apt-get install libcblas-dev
- sudo apt-get install libhdf5-dev
- sudo apt-get install libhdf5-serial-dev
- sudo apt-get install libatlas-base-dev
- sudo apt-get install libjasper-dev
- sudo apt-get install libqtgui4
- sudo apt-get install libqt4-test
- pip3 install -U pillow
- pip3 install -U numpy
\ No newline at end of file
+.. code-block:: bash
+
+ pip install je_auto_control[gui]
+
+Linux 前置套件
+==============
+
+.. code-block:: bash
+
+ sudo apt-get install cmake libssl-dev
+
+樹莓派
+======
+
+.. code-block:: bash
+
+ sudo apt-get install python3
+ pip3 install je_auto_control
+ sudo apt-get install libcblas-dev libhdf5-dev libhdf5-serial-dev
+ sudo apt-get install libatlas-base-dev libjasper-dev
+ sudo apt-get install libqtgui4 libqt4-test
+ pip3 install -U pillow numpy
+
+開發環境
+========
+
+.. list-table::
+ :header-rows: 1
+ :widths: 30 70
+
+ * - 平台
+ - 測試版本
+ * - Windows
+ - Windows 11
+ * - macOS
+ - macOS Big Sur (11)
+ * - Linux
+ - Ubuntu 20.04
+ * - Raspberry Pi
+ - 3B / 4B
diff --git a/docs/source/Zh/doc/keyboard/keyboard_doc.rst b/docs/source/Zh/doc/keyboard/keyboard_doc.rst
index 05c5276..0c15091 100644
--- a/docs/source/Zh/doc/keyboard/keyboard_doc.rst
+++ b/docs/source/Zh/doc/keyboard/keyboard_doc.rst
@@ -1,69 +1,96 @@
-鍵盤
-----
+========
+鍵盤控制
+========
-* 用來模擬鍵盤的控制。
-* 提供熱鍵、檢盤鍵盤按鍵狀態(是否按下)、模擬鍵盤控制等功能。
+AutoControl 提供模擬鍵盤輸入的功能,包括按鍵按下/釋放、輸入字串、
+熱鍵組合及按鍵狀態偵測。
-以下範例是取得鍵盤的資訊,
-* special_table 是特定的鍵盤按鍵 ( 注意! 不是每個平台都有 )
-* keys_table 是所有可以使用的按鍵
+取得按鍵表
+==========
+
+取得可用的按鍵名稱:
.. code-block:: python
- from je_auto_control import keys_table, get_special_table
+ from je_auto_control import keys_table, get_special_table
+
+ # 取得所有可用按鍵
+ print(keys_table)
+
+ # 取得特殊按鍵(因平台而異)
+ print(get_special_table())
- print(keys_table)
- print(get_special_table())
+.. tip::
+ 完整的鍵盤按鍵列表請參考 :doc:`/API/special/keyboard_keys`。
-以下範例是按著鍵盤的傳入的按鍵,並在一秒後釋放
+按下與釋放
+==========
+
+按住按鍵,延遲後釋放:
.. code-block:: python
- from time import sleep
- from je_auto_control import press_keyboard_key, release_keyboard_key
+ from time import sleep
+ from je_auto_control import press_keyboard_key, release_keyboard_key
+
+ press_keyboard_key("a")
+ sleep(1)
+ release_keyboard_key("a")
- press_key("a")
- sleep(1)
- release_key("a")
+按下單一按鍵
+============
-以下範例會幫你完成按下與釋放傳入的按鍵
+按下並立即釋放一個按鍵:
.. code-block:: python
- from je_auto_control import type_keyboard
+ from je_auto_control import type_keyboard
- type_keyboard("a")
+ type_keyboard("a")
-以下範例是檢查鍵盤 a 鍵是否按著
+檢查按鍵狀態
+=============
+
+檢查某個按鍵是否正被按住:
.. code-block:: python
- from je_auto_control import check_key_is_press
+ from je_auto_control import check_key_is_press
+
+ is_pressed = check_key_is_press("a")
+ print(f"按鍵 'a' 被按住: {is_pressed}")
- check_key_is_press("a")
+輸入字串
+========
-以下範例是按下與放開一串按鍵
+逐字輸入一串字元:
.. code-block:: python
- from je_auto_control import write
+ from je_auto_control import write
- write("abcdefg")
+ write("Hello World")
-以下範例使用熱鍵,會按下傳入的按鍵並相反的放開
+熱鍵組合
+========
+
+依序按下多個按鍵,再反向釋放:
.. code-block:: python
- import sys
+ import sys
+ from je_auto_control import hotkey
+
+ if sys.platform in ["win32", "cygwin", "msys"]:
+ hotkey(["lcontrol", "a", "lcontrol", "c", "lcontrol", "v"])
- from je_auto_control import hotkey
+ elif sys.platform == "darwin":
+ hotkey(["command", "a", "command", "c", "command", "v"])
- if sys.platform in ["win32", "cygwin", "msys"]:
- hotkey(["lcontrol", "a", "lcontrol", "c", "lcontrol", "v", "lcontrol", "v"])
+ elif sys.platform in ["linux", "linux2"]:
+ hotkey(["ctrl", "a", "ctrl", "c", "ctrl", "v"])
- elif sys.platform in ["darwin"]:
- hotkey(["command", "a", "command", "c", "command", "v", "command", "v"])
+.. warning::
- elif sys.platform in ["linux", "linux2"]:
- hotkey(["ctrl", "a", "ctrl", "c", "ctrl", "v", "ctrl", "v"])
\ No newline at end of file
+ 按鍵名稱在不同平台上有所不同,請務必查閱目標平台的按鍵表。
diff --git a/docs/source/Zh/doc/keyword_and_executor/keyword_and_executor_doc.rst b/docs/source/Zh/doc/keyword_and_executor/keyword_and_executor_doc.rst
index f30b143..396807f 100644
--- a/docs/source/Zh/doc/keyword_and_executor/keyword_and_executor_doc.rst
+++ b/docs/source/Zh/doc/keyword_and_executor/keyword_and_executor_doc.rst
@@ -1,54 +1,103 @@
+================
關鍵字與執行者
-----
-
-* Keyword 是一個 JSON 檔案裏面包含許多自定義的關鍵字與參數。
-* Keyword 會與 Executor 搭配使用。
-* Keyword 的格式是以下範例,且在 JSON 檔案裡面使用一樣格式。
+================
+
+關鍵字/執行者系統是 AutoControl 的 JSON 腳本引擎。你可以將自動化步驟定義為
+JSON 陣列(關鍵字),由執行者解析並執行。
+
+關鍵字格式
+==========
+
+關鍵字是 JSON 陣列,每個元素代表一個動作:
+
+.. code-block:: json
+
+ [
+ ["function_name", {"param_name": "param_value"}],
+ ["function_name", {"param_name": "param_value"}]
+ ]
+
+範例:
+
+.. code-block:: json
+
+ [
+ ["AC_set_mouse_position", {"x": 500, "y": 300}],
+ ["AC_click_mouse", {"mouse_keycode": "mouse_left"}],
+ ["AC_write", {"write_string": "Hello"}]
+ ]
+
+可用的動作指令
+==============
+
+.. list-table::
+ :header-rows: 1
+ :widths: 20 80
+
+ * - 分類
+ - 指令
+ * - 滑鼠
+ - ``AC_click_mouse``, ``AC_set_mouse_position``, ``AC_get_mouse_position``, ``AC_press_mouse``, ``AC_release_mouse``, ``AC_mouse_scroll``
+ * - 鍵盤
+ - ``AC_type_keyboard``, ``AC_press_keyboard_key``, ``AC_release_keyboard_key``, ``AC_write``, ``AC_hotkey``, ``AC_check_key_is_press``
+ * - 圖片
+ - ``AC_locate_all_image``, ``AC_locate_image_center``, ``AC_locate_and_click``
+ * - 螢幕
+ - ``AC_screen_size``, ``AC_screenshot``
+ * - 錄製
+ - ``AC_record``, ``AC_stop_record``
+ * - 報告
+ - ``AC_generate_html``, ``AC_generate_json``, ``AC_generate_xml``, ``AC_generate_html_report``, ``AC_generate_json_report``, ``AC_generate_xml_report``
+ * - 專案
+ - ``AC_create_project``
+ * - Shell
+ - ``AC_shell_command``
+ * - 執行器
+ - ``AC_execute_action``, ``AC_execute_files``
+
+執行 JSON 檔案
+===============
.. code-block:: python
- [
- ["function_name_in_event_dict": {"param_name": param_value}],
- ["function_name_in_event_dict": {"param_name": param_value}],
- ["function_name_in_event_dict": {"param_name": param_value}],
- # many....
- # If you are using position param
- ["function_name_in_event_dict": {param_value1, param_value2....}]
- ]
+ from je_auto_control import execute_action, read_action_json
-executor 是一個會解析 JSON 檔案的直譯器,
-可以簡單地透過網路傳輸到遠端伺服器或電腦,
-再藉由遠端伺服器或電腦的 executor 執行自動化。
+ execute_action(read_action_json("actions.json"))
-如果我們想要在 executor 裡面添加 function,可以使用如下:
-這段程式碼會把所有 time module 的 builtin, function, method, class
-載入到 executor,然後要使用被載入的 function 需要使用 package_function 名稱,
-例如 time.sleep 會變成 time_sleep
+執行資料夾內所有 JSON 檔案
+===========================
.. code-block:: python
- from je_auto_control import package_manager
- package_manager.add_package_to_executor("time")
+ from je_auto_control import execute_files, get_dir_files_as_list
+ execute_files(get_dir_files_as_list("./action_files/"))
+擴充執行者
+==========
-如果你需要查看被更新的 event_dict 可以使用
+你可以動態載入外部 Python 套件到執行者中:
.. code-block:: python
- from je_auto_control import executor
- print(executor.event_dict)
+ from je_auto_control import package_manager
-如果我們想要執行 JSON 檔案
+ # 載入 time 模組的所有函式
+ package_manager.add_package_to_executor("time")
-.. code-block:: python
+載入後,函式可透過 ``套件_函式名`` 的命名方式使用。
+例如 ``time.sleep`` 會變成 ``time_sleep``:
- from je_auto_control import execute_action, read_action_json
- execute_action(read_action_json(file_path))
+.. code-block:: json
-如果我們想要執行資料夾裡所有 JSON 檔案
+ [
+ ["time_sleep", {"secs": 2}]
+ ]
+
+查看目前執行者的指令字典:
.. code-block:: python
- from je_auto_control import execute_files, get_dir_files_as_list
- execute_files(get_dir_files_as_list(dir_path))
\ No newline at end of file
+ from je_auto_control import executor
+
+ print(executor.event_dict)
diff --git a/docs/source/Zh/doc/mouse/mouse_doc.rst b/docs/source/Zh/doc/mouse/mouse_doc.rst
index d65f9e6..f4a680b 100644
--- a/docs/source/Zh/doc/mouse/mouse_doc.rst
+++ b/docs/source/Zh/doc/mouse/mouse_doc.rst
@@ -1,54 +1,82 @@
-滑鼠
-----
+========
+滑鼠控制
+========
-* 主要用來模擬滑鼠的控制。
-* 提供模擬點擊、設定位置等功能。
+AutoControl 提供模擬滑鼠操作的功能,包括點擊、定位、捲動及拖曳操作。
-以下範例是取得鍵盤的資訊,
-* mouse_table 是所有可以使用的按鍵
+取得滑鼠按鍵表
+==============
+
+取得所有可用的滑鼠按鍵名稱:
.. code-block:: python
- from je_auto_control import mouse_table
+ from je_auto_control import mouse_table
+
+ print(mouse_table)
+
+.. tip::
- print(mouse_table)
+ 完整的滑鼠按鍵列表請參考 :doc:`/API/special/mouse_keys`。
-以下範例是按著滑鼠,一秒後釋放滑鼠
+按下與釋放
+==========
+
+按住滑鼠按鍵,延遲後釋放:
.. code-block:: python
- from time import sleep
+ from time import sleep
+ from je_auto_control import press_mouse, release_mouse
- from je_auto_control import press_mouse, release_mouse
+ press_mouse("mouse_right")
+ sleep(1)
+ release_mouse("mouse_right")
- press_mouse("mouse_right")
- sleep(1)
- release_mouse("mouse_right")
+點擊
+====
-以下範例是點擊並放開滑鼠
+按下並立即釋放滑鼠按鍵:
.. code-block:: python
- from je_auto_control import click_mouse
+ from je_auto_control import click_mouse
+
+ # 在目前位置右鍵點擊
+ click_mouse("mouse_right")
- click_mouse("mouse_right")
+ # 在指定座標左鍵點擊
+ click_mouse("mouse_left", x=500, y=300)
-以下範例是檢查滑鼠位置並改變滑鼠位置
+游標位置
+========
+
+取得及設定滑鼠游標位置:
.. code-block:: python
- from je_auto_control import get_mouse_position, set_mouse_position
+ from je_auto_control import get_mouse_position, set_mouse_position
+
+ # 取得目前位置
+ x, y = get_mouse_position()
+ print(f"滑鼠位置: ({x}, {y})")
- print(get_mouse_position())
- set_mouse_position(100, 100)
+ # 移動滑鼠到 (100, 100)
+ set_mouse_position(100, 100)
-以下範例是3秒後滑鼠會往上 scroll
+捲動
+====
+
+捲動滑鼠滾輪:
.. code-block:: python
- from time import sleep
- from je_auto_control import scroll
+ from je_auto_control import mouse_scroll
+
+ # 向下捲動 5 個單位
+ mouse_scroll(scroll_value=5)
- sleep(3)
+.. note::
- scroll(100)
\ No newline at end of file
+ 在 Linux 上,可以使用 ``scroll_direction`` 參數指定捲動方向:
+ ``"scroll_up"``、``"scroll_down"``、``"scroll_left"``、``"scroll_right"``。
diff --git a/docs/source/Zh/doc/record/record_doc.rst b/docs/source/Zh/doc/record/record_doc.rst
index d56c1df..aa4ff0e 100644
--- a/docs/source/Zh/doc/record/record_doc.rst
+++ b/docs/source/Zh/doc/record/record_doc.rst
@@ -1,31 +1,39 @@
-記錄
-----
+============
+錄製與回放
+============
-* Record 主要用來錄製鍵盤跟滑鼠的動作。
-* 可以搭配 executor 使用來重播鍵盤跟滑鼠動作。
+AutoControl 可以錄製滑鼠與鍵盤事件,並透過執行器回放。
-以下是範例如何使用
+使用範例
+========
.. code-block:: python
- from time import sleep
-
- from je_auto_control import execute_action
- from je_auto_control import record
- from je_auto_control import stop_record
- from je_auto_control import type_keyboard
-
- # this program will type test two time
- # one time is type key one time is test_record
-
- record()
- sleep(1)
- print(type_keyboard("t"))
- print(type_keyboard("e"))
- print(type_keyboard("s"))
- print(type_keyboard("t"))
- sleep(2)
- record_result = stop_record()
- print(record_result)
- execute_action(record_result)
- sleep(5)
\ No newline at end of file
+ from time import sleep
+ from je_auto_control import record, stop_record, execute_action
+
+ # 開始錄製所有滑鼠與鍵盤事件
+ record()
+
+ sleep(5) # 錄製 5 秒
+
+ # 停止錄製並取得動作列表
+ actions = stop_record()
+ print(actions)
+
+ # 回放錄製的動作
+ execute_action(actions)
+
+.. note::
+
+ macOS **不支援** 動作錄製功能。請參考 :doc:`/getting_started/installation` 了解平台支援詳情。
+
+運作方式
+========
+
+1. ``record()`` 啟動背景監聽器,擷取所有滑鼠與鍵盤事件。
+2. ``stop_record()`` 停止監聯器並回傳與執行器相容的動作列表。
+3. ``execute_action(actions)`` 透過內建執行器回放擷取的動作。
+
+錄製的動作格式與 :doc:`/Zh/doc/keyword_and_executor/keyword_and_executor_doc` 使用的 JSON 格式相同,
+可以儲存為檔案供日後回放。
diff --git a/docs/source/Zh/doc/scheduler/scheduler_doc.rst b/docs/source/Zh/doc/scheduler/scheduler_doc.rst
index 9b66156..cb4d8ee 100644
--- a/docs/source/Zh/doc/scheduler/scheduler_doc.rst
+++ b/docs/source/Zh/doc/scheduler/scheduler_doc.rst
@@ -1,19 +1,87 @@
-Scheduler
-----
+======
+排程器
+======
-可以使用排程來執行重複的任務,可以使用對 APScheduler 的簡易包裝或是觀看 API 文件自行使用
+AutoControl 提供 `APScheduler `_ 的包裝,
+用於排程重複性的自動化任務。
+
+基本範例
+========
+
+.. code-block:: python
+
+ from je_auto_control import SchedulerManager
+
+ def my_task():
+ print("任務已執行!")
+ scheduler.remove_blocking_job(id="my_job")
+ scheduler.shutdown_blocking_scheduler()
+
+ scheduler = SchedulerManager()
+ scheduler.add_interval_blocking_secondly(function=my_task, id="my_job")
+ scheduler.start_block_scheduler()
+
+阻塞與非阻塞模式
+=================
+
+.. list-table::
+ :header-rows: 1
+ :widths: 30 70
+
+ * - 模式
+ - 說明
+ * - 阻塞 (Blocking)
+ - ``start_block_scheduler()`` 會阻塞目前的執行緒。適用於獨立的排程腳本。
+ * - 非阻塞 (Non-blocking)
+ - ``start_nonblocking_scheduler()`` 在背景執行緒中執行。適用於主執行緒需要處理其他工作的情況。
+
+間隔排程
+========
+
+以固定間隔執行函式:
+
+.. code-block:: python
+
+ # 每秒
+ scheduler.add_interval_blocking_secondly(function=my_task, id="job1")
+
+ # 每分鐘
+ scheduler.add_interval_blocking_minutely(function=my_task, id="job2")
+
+ # 每小時
+ scheduler.add_interval_blocking_hourly(function=my_task, id="job3")
+
+ # 每天
+ scheduler.add_interval_blocking_daily(function=my_task, id="job4")
+
+ # 每週
+ scheduler.add_interval_blocking_weekly(function=my_task, id="job5")
+
+非阻塞版本可使用 ``add_interval_nonblocking_*`` 系列方法。
+
+Cron 排程
+=========
.. code-block:: python
- from je_auto_control import SchedulerManager
+ scheduler.add_cron_blocking(function=my_task, id="cron_job", hour=9, minute=30)
+移除任務
+========
+
+.. code-block:: python
+
+ scheduler.remove_blocking_job(id="job1")
+ scheduler.remove_nonblocking_job(id="job2")
+
+關閉排程器
+==========
+
+.. code-block:: python
- def test_scheduler():
- print("Test Scheduler")
- scheduler.remove_blocking_job(id="test")
- scheduler.shutdown_blocking_scheduler()
+ scheduler.shutdown_blocking_scheduler()
+ scheduler.shutdown_nonblocking_scheduler()
+.. tip::
- scheduler = SchedulerManager()
- scheduler.add_interval_blocking_secondly(function=test_scheduler, id="test")
- scheduler.start_block_scheduler()
+ 完整 API 參考請見 :doc:`/API/utils/scheduler`。
diff --git a/docs/source/Zh/doc/screen/screen_doc.rst b/docs/source/Zh/doc/screen/screen_doc.rst
index fb92983..5b0ddff 100644
--- a/docs/source/Zh/doc/screen/screen_doc.rst
+++ b/docs/source/Zh/doc/screen/screen_doc.rst
@@ -1,20 +1,44 @@
-螢幕
-----
+========
+螢幕操作
+========
-* Screen 用來取得螢幕尺寸與截圖。
+AutoControl 提供截圖與取得螢幕資訊的功能。
-以下範例是截圖
+截圖
+====
+
+擷取目前螢幕畫面並儲存為檔案:
.. code-block:: python
- from je_auto_control import screenshot
+ from je_auto_control import screenshot
+
+ # 全螢幕截圖
+ screenshot("my_screenshot.png")
+
+ # 擷取特定區域 [x1, y1, x2, y2]
+ screenshot("region.png", screen_region=[100, 100, 500, 400])
+
+螢幕尺寸
+========
+
+取得目前螢幕解析度:
+
+.. code-block:: python
+
+ from je_auto_control import screen_size
+
+ width, height = screen_size()
+ print(f"螢幕解析度: {width} x {height}")
- screenshot()
+取得像素顏色
+============
-以下範例是取得螢幕尺寸
+取得指定座標的像素顏色:
.. code-block:: python
- from je_auto_control import size
+ from je_auto_control import get_pixel
- print(size())
\ No newline at end of file
+ color = get_pixel(500, 300)
+ print(f"(500, 300) 的像素顏色: {color}")
diff --git a/docs/source/Zh/doc/socket_driver/socket_driver_doc.rst b/docs/source/Zh/doc/socket_driver/socket_driver_doc.rst
index f0784a7..8c957b6 100644
--- a/docs/source/Zh/doc/socket_driver/socket_driver_doc.rst
+++ b/docs/source/Zh/doc/socket_driver/socket_driver_doc.rst
@@ -1,26 +1,66 @@
-Socket Driver
-----
+==============================
+Socket 伺服器(遠端 API)
+==============================
-* 實驗性的功能。
-* Socket Server 主要用來讓其他程式語言也可以使用 AutoControl。
-* 透過底層的 executor 處理接收到字串並進行執行動作。
-* 可以透過遠端來執行測試的動作。
+.. warning::
-* 目前有實驗性的 Java 與 C# 支援。
-* 每個段落結束都應該傳輸 Return_Data_Over_JE。
-* 使用 UTF-8 encoding。
-* 傳送 quit_server 將會關閉伺服器。
+ 這是 **實驗性** 功能。
+
+Socket 伺服器允許其他程式語言(或遠端機器)透過 TCP 傳送 JSON 指令來使用 AutoControl。
+
+啟動伺服器
+==========
+
+.. code-block:: python
+
+ import sys
+ from je_auto_control import start_autocontrol_socket_server
+
+ try:
+ server = start_autocontrol_socket_server(host="localhost", port=9938)
+ while not server.close_flag:
+ pass
+ sys.exit(0)
+ except Exception as error:
+ print(repr(error))
+
+伺服器在背景執行緒中執行,監聽 JSON 自動化指令。
+
+傳送指令(客戶端)
+==================
.. code-block:: python
- import sys
+ import socket
+ import json
+
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.connect(("localhost", 9938))
+
+ command = json.dumps([
+ ["AC_set_mouse_position", {"x": 500, "y": 300}],
+ ["AC_click_mouse", {"mouse_keycode": "mouse_left"}]
+ ])
+ sock.sendall(command.encode("utf-8"))
+
+ response = sock.recv(8192).decode("utf-8")
+ print(response)
+ sock.close()
+
+協定細節
+========
- from je_auto_control import start_autocontrol_socket_server
+.. list-table::
+ :header-rows: 1
+ :widths: 30 70
- try:
- server = start_autocontrol_socket_server()
- while not server.close_flag:
- pass
- sys.exit(0)
- except Exception as error:
- print(repr(error))
\ No newline at end of file
+ * - 屬性
+ - 值
+ * - 編碼
+ - UTF-8
+ * - 回應結束標記
+ - ``Return_Data_Over_JE``
+ * - 關閉伺服器指令
+ - 傳送 ``"quit_server"`` 以停止伺服器
+ * - 預設連接埠
+ - 9938
diff --git a/docs/source/Zh/zh_index.rst b/docs/source/Zh/zh_index.rst
index 4576cc3..4b5a22a 100644
--- a/docs/source/Zh/zh_index.rst
+++ b/docs/source/Zh/zh_index.rst
@@ -1,20 +1,24 @@
-AutoControl 繁體中文 文件
-----
+====================
+繁體中文文件
+====================
+
+AutoControl 所有功能的完整使用指南。
.. toctree::
- :maxdepth: 4
+ :maxdepth: 2
+ :caption: 使用者指南
- doc/installation/installation_doc.rst
- doc/create_project/create_project_doc.rst
- doc/keyboard/keyboard_doc.rst
- doc/mouse/mouse_doc.rst
- doc/screen/screen_doc.rst
- doc/image/image_doc.rst
- doc/record/record_doc.rst
- doc/generate_report/generate_report_doc.rst
- doc/callback_function/callback_function_doc.rst
- doc/keyword_and_executor/keyword_and_executor_doc.rst
- doc/critical_exit/critical_exit_doc.rst
- doc/cli/cli_doc.rst
- doc/scheduler/scheduler_doc.rst
- doc/socket_driver/socket_driver_doc.rst
+ doc/installation/installation_doc
+ doc/mouse/mouse_doc
+ doc/keyboard/keyboard_doc
+ doc/screen/screen_doc
+ doc/image/image_doc
+ doc/record/record_doc
+ doc/keyword_and_executor/keyword_and_executor_doc
+ doc/generate_report/generate_report_doc
+ doc/callback_function/callback_function_doc
+ doc/scheduler/scheduler_doc
+ doc/socket_driver/socket_driver_doc
+ doc/critical_exit/critical_exit_doc
+ doc/cli/cli_doc
+ doc/create_project/create_project_doc
diff --git a/docs/source/conf.py b/docs/source/conf.py
index c1b47ff..b5e1f29 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -1,51 +1,49 @@
# Configuration file for the Sphinx documentation builder.
#
-# This file only contains a selection of the most common options. For a full
-# list see the documentation:
+# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
-# -- Path setup --------------------------------------------------------------
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-#
import os
import sys
-sys.path.insert(0, os.path.abspath('.'))
+sys.path.insert(0, os.path.abspath('../..'))
# -- Project information -----------------------------------------------------
project = 'AutoControl'
copyright = '2020 ~ Now, JE-Chen'
author = 'JE-Chen'
+release = '0.0.179'
# -- General configuration ---------------------------------------------------
-# Add any Sphinx extension module names here, as strings. They can be
-# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
-# ones.
extensions = [
- "sphinx.ext.autosectionlabel"
+ 'sphinx.ext.autosectionlabel',
+ 'sphinx.ext.autodoc',
+ 'sphinx.ext.viewcode',
]
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
+autosectionlabel_prefix_document = True
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-# This pattern also affects html_static_path and html_extra_path.
+templates_path = ['_templates']
exclude_patterns = []
# -- Options for HTML output -------------------------------------------------
-# The theme to use for HTML and HTML Help pages. See the documentation for
-# a list of builtin themes.
-#
html_theme = 'sphinx_rtd_theme'
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
+html_theme_options = {
+ 'navigation_depth': 4,
+ 'collapse_navigation': False,
+ 'sticky_navigation': True,
+ 'includehidden': True,
+ 'titles_only': False,
+}
+
html_static_path = ['_static']
+
+# -- Options for language ----------------------------------------------------
+
+language = 'en'
+locale_dirs = ['locale/']
+gettext_compact = False
diff --git a/docs/source/getting_started/installation.rst b/docs/source/getting_started/installation.rst
new file mode 100644
index 0000000..0bfb61d
--- /dev/null
+++ b/docs/source/getting_started/installation.rst
@@ -0,0 +1,106 @@
+============
+Installation
+============
+
+Requirements
+============
+
+* **Python** >= 3.10
+* **pip** >= 19.3
+
+Basic Installation
+==================
+
+Install AutoControl from PyPI:
+
+.. code-block:: bash
+
+ pip install je_auto_control
+
+With GUI Support
+================
+
+To use the built-in PySide6 graphical interface:
+
+.. code-block:: bash
+
+ pip install je_auto_control[gui]
+
+Linux Prerequisites
+===================
+
+On Linux, install the following system packages **before** installing AutoControl:
+
+.. code-block:: bash
+
+ sudo apt-get install cmake libssl-dev
+
+Raspberry Pi
+============
+
+On Raspberry Pi (3B / 4B), install the following:
+
+.. code-block:: bash
+
+ sudo apt-get install python3
+ pip3 install je_auto_control
+ sudo apt-get install libcblas-dev libhdf5-dev libhdf5-serial-dev
+ sudo apt-get install libatlas-base-dev libjasper-dev
+ sudo apt-get install libqtgui4 libqt4-test
+ pip3 install -U pillow numpy
+
+Dependencies
+============
+
+.. list-table::
+ :header-rows: 1
+ :widths: 25 75
+
+ * - Package
+ - Purpose
+ * - ``je_open_cv``
+ - Image recognition (OpenCV template matching)
+ * - ``pillow``
+ - Screenshot capture
+ * - ``mss``
+ - Fast multi-monitor screenshot
+ * - ``pyobjc``
+ - macOS backend (auto-installed on macOS)
+ * - ``python-Xlib``
+ - Linux X11 backend (auto-installed on Linux)
+ * - ``PySide6``
+ - GUI application (optional, install with ``[gui]``)
+ * - ``qt-material``
+ - GUI theme (optional, install with ``[gui]``)
+
+Platform Support
+================
+
+.. list-table::
+ :header-rows: 1
+ :widths: 20 15 25 40
+
+ * - Platform
+ - Status
+ - Backend
+ - Notes
+ * - Windows 10 / 11
+ - Supported
+ - Win32 API (ctypes)
+ - Full feature support
+ * - macOS 10.15+
+ - Supported
+ - pyobjc / Quartz
+ - Action recording not available; ``send_key_event_to_window`` / ``send_mouse_event_to_window`` not supported
+ * - Linux (X11)
+ - Supported
+ - python-Xlib
+ - Full feature support
+ * - Linux (Wayland)
+ - Not supported
+ - --
+ - May be added in a future release
+ * - Raspberry Pi 3B / 4B
+ - Supported
+ - python-Xlib
+ - Runs on X11
diff --git a/docs/source/getting_started/quickstart.rst b/docs/source/getting_started/quickstart.rst
new file mode 100644
index 0000000..eb86f41
--- /dev/null
+++ b/docs/source/getting_started/quickstart.rst
@@ -0,0 +1,124 @@
+===========
+Quick Start
+===========
+
+This guide walks you through the most common AutoControl features with minimal examples.
+
+Mouse Control
+=============
+
+.. code-block:: python
+
+ import je_auto_control
+
+ # Get current mouse position
+ x, y = je_auto_control.get_mouse_position()
+ print(f"Mouse at: ({x}, {y})")
+
+ # Move mouse to coordinates
+ je_auto_control.set_mouse_position(500, 300)
+
+ # Left click at current position
+ je_auto_control.click_mouse("mouse_left")
+
+ # Right click at specific coordinates
+ je_auto_control.click_mouse("mouse_right", x=800, y=400)
+
+ # Scroll down
+ je_auto_control.mouse_scroll(scroll_value=5)
+
+Keyboard Control
+================
+
+.. code-block:: python
+
+ import je_auto_control
+
+ # Press and release a single key
+ je_auto_control.type_keyboard("a")
+
+ # Type a whole string character by character
+ je_auto_control.write("Hello World")
+
+ # Hotkey combination (e.g., Ctrl+C)
+ je_auto_control.hotkey(["ctrl_l", "c"])
+
+ # Check if a key is currently pressed
+ is_pressed = je_auto_control.check_key_is_press("shift_l")
+
+Image Recognition
+=================
+
+.. code-block:: python
+
+ import je_auto_control
+
+ # Find all occurrences of an image on screen
+ positions = je_auto_control.locate_all_image("button.png", detect_threshold=0.9)
+
+ # Find a single image and get its center coordinates
+ cx, cy = je_auto_control.locate_image_center("icon.png", detect_threshold=0.85)
+
+ # Find an image and automatically click it
+ je_auto_control.locate_and_click("submit_button.png", mouse_keycode="mouse_left")
+
+Screenshot
+==========
+
+.. code-block:: python
+
+ import je_auto_control
+
+ # Full-screen screenshot
+ je_auto_control.pil_screenshot("screenshot.png")
+
+ # Screenshot of a specific region [x1, y1, x2, y2]
+ je_auto_control.pil_screenshot("region.png", screen_region=[100, 100, 500, 400])
+
+ # Get screen resolution
+ width, height = je_auto_control.screen_size()
+
+Action Recording & Playback
+============================
+
+.. code-block:: python
+
+ import je_auto_control
+ import time
+
+ je_auto_control.record()
+ time.sleep(10) # Record for 10 seconds
+ actions = je_auto_control.stop_record()
+
+ # Replay the recorded actions
+ je_auto_control.execute_action(actions)
+
+JSON Action Scripting
+=====================
+
+Create a JSON action file (``actions.json``):
+
+.. code-block:: json
+
+ [
+ ["AC_set_mouse_position", {"x": 500, "y": 300}],
+ ["AC_click_mouse", {"mouse_keycode": "mouse_left"}],
+ ["AC_write", {"write_string": "Hello from AutoControl"}],
+ ["AC_hotkey", {"key_code_list": ["ctrl_l", "s"]}]
+ ]
+
+Execute it:
+
+.. code-block:: python
+
+ import je_auto_control
+
+ je_auto_control.execute_action(
+ je_auto_control.read_action_json("actions.json")
+ )
+
+What's Next?
+============
+
+* See the :doc:`../Eng/eng_index` for detailed guides on each feature.
+* See the :doc:`../API/api_index` for complete API reference.
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 5a74b08..1564138 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -1,29 +1,65 @@
+===========
AutoControl
+===========
+
+**AutoControl** is a cross-platform Python GUI automation framework providing mouse control,
+keyboard input, image recognition, screen capture, action scripting, and report generation
+-- all through a unified API that works on Windows, macOS, and Linux (X11).
+
+.. note::
+
+ AutoControl does not currently support Linux Wayland. This may be added in a future release.
+
----
+Getting Started
+===============
+
.. toctree::
- :maxdepth: 4
+ :maxdepth: 2
+ :caption: Getting Started
- Eng/eng_index.rst
- Zh/zh_index.rst
- API/api_index.rst
+ getting_started/installation
+ getting_started/quickstart
-----
+User Guide (English)
+====================
-RoadMap
+.. toctree::
+ :maxdepth: 2
+ :caption: User Guide (English)
-----
+ Eng/eng_index
-* Project Kanban
-* https://github.com/orgs/Integration-Automation/projects/2/views/1
+User Guide (繁體中文)
+=====================
-----
+.. toctree::
+ :maxdepth: 2
+ :caption: 使用者指南 (繁體中文)
-Notice
+ Zh/zh_index
-----
+API Reference
+=============
+
+.. toctree::
+ :maxdepth: 2
+ :caption: API Reference
-* We don't support Unix/Linux Wayland GUI Now \
-* May be future feature
+ API/api_index
----
+
+Links
+=====
+
+* `PyPI `_
+* `GitHub `_
+* `Project Kanban `_
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`search`