diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 92fe69f..1ab5cff 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,8 +5,6 @@
-
-
@@ -77,6 +75,8 @@
{
"keyToString": {
"DefaultHtmlFileTemplate": "HTML File",
+ "Python.auto_control_keyboard.executor": "Run",
+ "Python.auto_control_mouse.executor": "Run",
"Python.calculator.executor": "Run",
"Python.callback_test.executor": "Run",
"Python.create_project_test.executor": "Run",
@@ -87,9 +87,11 @@
"Python.record_test.executor": "Run",
"Python.screen_test.executor": "Run",
"Python.screenshot_test.executor": "Run",
+ "Python.test.executor": "Run",
"Python.video_recording.executor": "Run",
"RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
+ "RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
"RunOnceActivity.git.unshallow": "true",
"WebServerToolWindowFactoryState": "false",
"git-widget-placeholder": "dev",
@@ -102,6 +104,7 @@
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"settings.editor.selected.configurable": "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable",
+ "to.speed.mode.migration.done": "true",
"vue.rearranger.settings.migration": "true"
}
}
@@ -121,8 +124,8 @@
-
-
+
+
@@ -131,12 +134,12 @@
-
+
-
+
@@ -145,7 +148,7 @@
-
+
@@ -154,12 +157,12 @@
-
+
-
+
@@ -168,7 +171,7 @@
-
+
@@ -177,12 +180,12 @@
-
+
-
+
@@ -191,7 +194,7 @@
-
+
@@ -200,12 +203,12 @@
-
+
-
+
@@ -214,7 +217,7 @@
-
+
@@ -223,12 +226,12 @@
-
+
-
+
@@ -239,19 +242,19 @@
+
+
+
-
-
-
-
-
+
+
@@ -588,6 +591,13 @@
+
+
+
+
+
+
+
@@ -609,20 +619,23 @@
-
-
+
+
+
-
-
-
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/stable.toml b/dev.toml
similarity index 85%
rename from stable.toml
rename to dev.toml
index 0142098..2156464 100644
--- a/stable.toml
+++ b/dev.toml
@@ -1,12 +1,12 @@
-# Rename to build stable version
-# This is stable version
+# Rename to build dev version
+# This is dev version
[build-system]
-requires = ["setuptools>=61.0"]
+requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[project]
-name = "je_auto_control"
-version = "0.0.171"
+name = "je_auto_control_dev"
+version = "0.0.122"
authors = [
{ name = "JE-Chen", email = "jechenmailman@gmail.com" },
]
@@ -43,4 +43,4 @@ content-type = "text/markdown"
find = { namespaces = false }
[project.optional-dependencies]
-gui = ["PySide6==6.9.1", "qt-material"]
+gui = ["PySide6==6.9.2", "qt-material"]
diff --git a/je_auto_control/__init__.py b/je_auto_control/__init__.py
index 34b2d2b..df8515b 100644
--- a/je_auto_control/__init__.py
+++ b/je_auto_control/__init__.py
@@ -87,6 +87,7 @@
from je_auto_control.wrapper.auto_control_keyboard import release_keyboard_key
from je_auto_control.wrapper.auto_control_keyboard import type_keyboard
from je_auto_control.wrapper.auto_control_keyboard import write
+from je_auto_control.wrapper.auto_control_keyboard import send_key_event_to_window
# import mouse
from je_auto_control.wrapper.auto_control_mouse import click_mouse
from je_auto_control.wrapper.auto_control_mouse import get_mouse_position
@@ -96,6 +97,7 @@
from je_auto_control.wrapper.auto_control_mouse import release_mouse
from je_auto_control.wrapper.auto_control_mouse import set_mouse_position
from je_auto_control.wrapper.auto_control_mouse import special_mouse_keys_table
+from je_auto_control.wrapper.auto_control_mouse import send_mouse_event_to_window
# test_record
from je_auto_control.wrapper.auto_control_record import record
from je_auto_control.wrapper.auto_control_record import stop_record
@@ -104,6 +106,8 @@
from je_auto_control.wrapper.auto_control_screen import screenshot
# Recording
from je_auto_control.utils.cv2_utils.video_recording import RecordingThread
+# Windows
+from je_auto_control.windows.window import windows_window_manage
__all__ = [
"click_mouse", "mouse_keys_table", "get_mouse_position", "press_mouse", "release_mouse",
@@ -120,5 +124,5 @@
"generate_html", "generate_html_report", "generate_json", "generate_json_report", "generate_xml",
"generate_xml_report", "get_dir_files_as_list", "create_project_dir", "start_autocontrol_socket_server",
"callback_executor", "package_manager", "get_special_table", "ShellManager", "default_shell_manager",
- "RecordingThread"
+ "RecordingThread", "send_key_event_to_window", "send_mouse_event_to_window", "windows_window_manage"
]
diff --git a/je_auto_control/linux_with_x11/keyboard/x11_linux_keyboard_control.py b/je_auto_control/linux_with_x11/keyboard/x11_linux_keyboard_control.py
index c6524bf..fb2d4ae 100644
--- a/je_auto_control/linux_with_x11/keyboard/x11_linux_keyboard_control.py
+++ b/je_auto_control/linux_with_x11/keyboard/x11_linux_keyboard_control.py
@@ -9,7 +9,7 @@
from je_auto_control.linux_with_x11.core.utils.x11_linux_display import display
from Xlib.ext.xtest import fake_input
-from Xlib import X
+from Xlib import X, protocol
def press_key(keycode: int) -> None:
@@ -28,3 +28,20 @@ def release_key(keycode: int) -> None:
time.sleep(0.01)
fake_input(display, X.KeyRelease, keycode)
display.sync()
+
+def send_key_event_to_window(window_id, keycode: int):
+ window = display.create_resource_object('window', window_id)
+ event = protocol.event.KeyPress(
+ time=X.CurrentTime,
+ root=display.screen().root,
+ window=window,
+ same_screen=1,
+ child=X.NONE,
+ root_x=0, root_y=0, event_x=0, event_y=0,
+ state=0,
+ detail=keycode
+ )
+ window.send_event(event, propagate=True)
+ event.type = X.KeyRelease
+ window.send_event(event, propagate=True)
+ display.flush()
\ No newline at end of file
diff --git a/je_auto_control/linux_with_x11/mouse/x11_linux_mouse_control.py b/je_auto_control/linux_with_x11/mouse/x11_linux_mouse_control.py
index 9320b7d..0cd9f6e 100644
--- a/je_auto_control/linux_with_x11/mouse/x11_linux_mouse_control.py
+++ b/je_auto_control/linux_with_x11/mouse/x11_linux_mouse_control.py
@@ -8,7 +8,7 @@
if sys.platform not in ["linux", "linux2"]:
raise AutoControlException(linux_import_error)
-from Xlib import X
+from Xlib import X, protocol
from Xlib.ext.xtest import fake_input
from je_auto_control.linux_with_x11.core.utils.x11_linux_display import display
@@ -83,3 +83,23 @@ def scroll(scroll_value: int, scroll_direction: int) -> None:
for i in range(scroll_value):
click_mouse(scroll_direction)
total = total + i
+
+def send_mouse_event_to_window(window_id, mouse_keycode: int, x: int = None, y: int = None):
+ window = display.create_resource_object('window', window_id)
+ for ev_type in (X.ButtonPress, X.ButtonRelease):
+ ev = protocol.event.ButtonPress(
+ time=X.CurrentTime,
+ root=display.screen().root,
+ window=window,
+ same_screen=1,
+ child=X.NONE,
+ root_x=x, root_y=y, event_x=x, event_y=y,
+ state=0,
+ detail=mouse_keycode
+ )
+ ev.type = ev_type
+ window.send_event(ev, propagate=True)
+ display.flush()
+
+
+
diff --git a/je_auto_control/osx/pid/__init__.py b/je_auto_control/osx/pid/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/je_auto_control/osx/pid/pid_control.py b/je_auto_control/osx/pid/pid_control.py
new file mode 100644
index 0000000..1a07ccb
--- /dev/null
+++ b/je_auto_control/osx/pid/pid_control.py
@@ -0,0 +1,38 @@
+import objc
+from Quartz import CGEventCreateKeyboardEvent, kCGEventKeyDown, kCGEventKeyUp
+from ApplicationServices import ProcessSerialNumber, GetProcessForPID
+from ctypes import cdll, c_void_p
+import subprocess
+
+carbon = cdll.LoadLibrary('/System/Library/Frameworks/Carbon.framework/Carbon')
+
+
+def send_key_to_pid(pid, keycode):
+ psn = ProcessSerialNumber()
+ GetProcessForPID(pid, objc.byref(psn))
+ event_down = CGEventCreateKeyboardEvent(None, keycode, True)
+ event_up = CGEventCreateKeyboardEvent(None, keycode, False)
+ carbon.CGEventPostToPSN(c_void_p(id(psn)), event_down)
+ carbon.CGEventPostToPSN(c_void_p(id(psn)), event_up)
+
+def get_pid_by_window_title(title: str):
+ script = f'''
+ set targetWindowName to "{title}"
+ tell application "System Events"
+ repeat with proc in processes
+ repeat with win in windows of proc
+ if name of win contains targetWindowName then
+ return unix id of proc
+ end if
+ end repeat
+ end repeat
+ end tell
+ '''
+ try:
+ pid_str = subprocess.check_output(
+ ["osascript", "-e", script],
+ stderr=subprocess.DEVNULL
+ ).decode().strip()
+ return int(pid_str) if pid_str else None
+ except subprocess.CalledProcessError:
+ return None
diff --git a/je_auto_control/utils/shell_process/shell_exec.py b/je_auto_control/utils/shell_process/shell_exec.py
index 8044051..e7a130f 100644
--- a/je_auto_control/utils/shell_process/shell_exec.py
+++ b/je_auto_control/utils/shell_process/shell_exec.py
@@ -3,6 +3,7 @@
import subprocess
import sys
from threading import Thread
+from typing import Union
from je_auto_control.utils.logging.loggin_instance import autocontrol_logger
@@ -21,13 +22,13 @@ def __init__(
self.read_program_error_output_from_thread = None
self.read_program_output_from_thread = None
self.still_run_shell: bool = True
- self.process = None
- self.run_output_queue: queue = queue.Queue()
- self.run_error_queue: queue = queue.Queue()
+ self.process: Union[subprocess.Popen, None] = None
+ self.run_output_queue: queue.Queue = queue.Queue()
+ self.run_error_queue: queue.Queue = queue.Queue()
self.program_encoding: str = shell_encoding
self.program_buffer: int = program_buffer
- def exec_shell(self, shell_command: [str, list]) -> None:
+ def exec_shell(self, shell_command: Union[str, list]) -> None:
"""
:param shell_command: shell command will run
:return: if error return result and True else return result and False
@@ -115,16 +116,16 @@ def print_and_clear_queue(self) -> None:
def read_program_output_from_process(self) -> None:
while self.still_run_shell:
- program_output_data = self.process.stdout.raw.read(
+ program_output_data = self.process.stdout.readline(
self.program_buffer) \
- .decode(self.program_encoding)
+ .decode(self.program_encoding, "replace")
self.run_output_queue.put_nowait(program_output_data)
def read_program_error_output_from_process(self) -> None:
while self.still_run_shell:
- program_error_output_data = self.process.stderr.raw.read(
+ program_error_output_data = self.process.stderr.readline(
self.program_buffer) \
- .decode(self.program_encoding)
+ .decode(self.program_encoding, "replace")
self.run_error_queue.put_nowait(program_error_output_data)
diff --git a/je_auto_control/windows/core/utils/win32_keypress_check.py b/je_auto_control/windows/core/utils/win32_keypress_check.py
index 09ff2b1..bceb01e 100644
--- a/je_auto_control/windows/core/utils/win32_keypress_check.py
+++ b/je_auto_control/windows/core/utils/win32_keypress_check.py
@@ -1,4 +1,5 @@
import sys
+from typing import Union
from je_auto_control.utils.exception.exception_tags import windows_import_error
from je_auto_control.utils.exception.exceptions import AutoControlException
@@ -9,11 +10,11 @@
import ctypes
-def check_key_is_press(keycode: [int, str]) -> bool:
+def check_key_is_press(keycode: Union[int, str]) -> bool:
if isinstance(keycode, int):
temp: int = ctypes.windll.user32.GetAsyncKeyState(keycode)
else:
temp = ctypes.windll.user32.GetAsyncKeyState(ord(keycode))
- if temp > 1:
+ if temp != 0:
return True
return False
diff --git a/je_auto_control/windows/keyboard/win32_ctype_keyboard_control.py b/je_auto_control/windows/keyboard/win32_ctype_keyboard_control.py
index 1f833a3..4feb57f 100644
--- a/je_auto_control/windows/keyboard/win32_ctype_keyboard_control.py
+++ b/je_auto_control/windows/keyboard/win32_ctype_keyboard_control.py
@@ -6,7 +6,7 @@
if sys.platform not in ["win32", "cygwin", "msys"]:
raise AutoControlException(windows_import_error)
-from je_auto_control.windows.core.utils.win32_ctype_input import Input
+from je_auto_control.windows.core.utils.win32_ctype_input import Input, user32
from je_auto_control.windows.core.utils.win32_ctype_input import Keyboard
from je_auto_control.windows.core.utils.win32_ctype_input import KeyboardInput
from je_auto_control.windows.core.utils.win32_ctype_input import SendInput
@@ -28,3 +28,10 @@ def release_key(keycode: int) -> None:
"""
keyboard = Input(type=Keyboard, ki=KeyboardInput(wVk=keycode, dwFlags=win32_EventF_KEYUP))
SendInput(1, ctypes.byref(keyboard), ctypes.sizeof(keyboard))
+
+def send_key_event_to_window(window: str, keycode: int):
+ WM_KEYDOWN = 0x0100
+ WM_KEYUP = 0x0101
+ window = user32.FindWindowW(None, window)
+ user32.PostMessageW(window, WM_KEYDOWN, keycode, 0)
+ user32.PostMessageW(window, WM_KEYUP, keycode, 0)
diff --git a/je_auto_control/windows/message/window_message.py b/je_auto_control/windows/message/window_message.py
index cfbf533..526d569 100644
--- a/je_auto_control/windows/message/window_message.py
+++ b/je_auto_control/windows/message/window_message.py
@@ -1,5 +1,5 @@
from je_auto_control.windows.core.utils.win32_ctype_input import user32
-from je_auto_control.windows.window.window_hwnd import FindWindowW
+from je_auto_control.windows.window.windows_window_manage import FindWindowW
PostMessageW = user32.PostMessageW
SendMessageW = user32.SendMessageW
diff --git a/je_auto_control/windows/mouse/win32_ctype_mouse_control.py b/je_auto_control/windows/mouse/win32_ctype_mouse_control.py
index 89a0ef4..bda2873 100644
--- a/je_auto_control/windows/mouse/win32_ctype_mouse_control.py
+++ b/je_auto_control/windows/mouse/win32_ctype_mouse_control.py
@@ -7,7 +7,7 @@
if sys.platform not in ["win32", "cygwin", "msys"]:
raise AutoControlException(windows_import_error)
-from je_auto_control.windows.core.utils.win32_ctype_input import Input
+from je_auto_control.windows.core.utils.win32_ctype_input import Input, user32
from je_auto_control.windows.core.utils.win32_vk import win32_LEFTDOWN
from je_auto_control.windows.core.utils.win32_vk import win32_LEFTUP
from je_auto_control.windows.core.utils.win32_vk import win32_MIDDLEDOWN
@@ -50,7 +50,7 @@ def mouse_event(event, x: int, y: int, dwData: int = 0) -> None:
ctypes.windll.user32.mouse_event(event, ctypes.c_long(converted_x), ctypes.c_long(converted_y), dwData, 0)
-def position() -> [Tuple[int, int], None]:
+def position() -> tuple[int, int] | None:
"""
get mouse position
"""
@@ -102,10 +102,16 @@ def click_mouse(mouse_keycode: int, x: int = None, y: int = None) -> None:
release_mouse(mouse_keycode)
-def scroll(scroll_value: int, x: int = None, y: int = None) -> None:
+def scroll(scroll_value: int, x: int = None, y: int = None) -> None:
"""
:param scroll_value scroll count
:param x scroll x
:param y scroll y
"""
mouse_event(win32_WHEEL, x, y, dwData=scroll_value)
+
+
+def send_mouse_event_to_window(window, mouse_keycode: int, x: int = None, y: int = None):
+ lparam = (y << 16) | x
+ user32.PostMessageW(window, mouse_keycode, 1, lparam)
+ user32.PostMessageW(window, mouse_keycode, 0, lparam)
diff --git a/je_auto_control/windows/window/window_hwnd.py b/je_auto_control/windows/window/windows_window_manage.py
similarity index 82%
rename from je_auto_control/windows/window/window_hwnd.py
rename to je_auto_control/windows/window/windows_window_manage.py
index 1b7ae08..96815ce 100644
--- a/je_auto_control/windows/window/window_hwnd.py
+++ b/je_auto_control/windows/window/windows_window_manage.py
@@ -38,3 +38,12 @@ def close_window(hwnd) -> bool:
def destroy_window(hwnd) -> bool:
return DestroyWindow(hwnd)
+
+
+def set_foreground_window(hwnd) -> None:
+ user32.SetForegroundWindow(hwnd)
+
+def set_window_positon(hwnd, position: int) -> None:
+ swp_no_size = 0x0001
+ swp_no_move = 0x0002
+ user32.SetWindowPos(hwnd, position, 0, 0, 0, 0, swp_no_move | swp_no_size)
\ No newline at end of file
diff --git a/je_auto_control/wrapper/auto_control_keyboard.py b/je_auto_control/wrapper/auto_control_keyboard.py
index 954a6ff..b508d40 100644
--- a/je_auto_control/wrapper/auto_control_keyboard.py
+++ b/je_auto_control/wrapper/auto_control_keyboard.py
@@ -174,7 +174,7 @@ def type_keyboard(keycode: Union[int, str], is_shift: bool = False, skip_record:
)
-def check_key_is_press(keycode: [int, str]) -> bool | None:
+def check_key_is_press(keycode: Union[int, str]) -> bool | None:
"""
use to check key is press return True or False
:param keycode check key is press or not
@@ -302,3 +302,26 @@ def hotkey(key_code_list: list, is_shift: bool = False) -> tuple[str, str] | Non
f"hotkey, key_code_list: {key_code_list}, is_shift: {is_shift}, "
f"failed: {repr(error)}"
)
+
+def send_key_event_to_window(window_title, keycode: int):
+ autocontrol_logger.info(
+ f"send_key_event_to_window window:{window_title}, keycode:{keycode}"
+ )
+ param = locals()
+ try:
+ if sys.platform in ["darwin"]:
+ return
+ if isinstance(keycode, int):
+ get_key_code = keycode
+ else:
+ get_key_code = keyboard_keys_table.get(keycode)
+ keyboard.send_key_event_to_window(
+ window_title,
+ keycode=keycode
+ )
+ except Exception as error:
+ record_action_to_list("send_key_event_to_window", param, repr(error))
+ autocontrol_logger.error(
+ f"send_key_event_to_window window:{window_title}, keycode:{keycode}"
+ f"failed: {repr(error)}"
+ )
diff --git a/je_auto_control/wrapper/auto_control_mouse.py b/je_auto_control/wrapper/auto_control_mouse.py
index ce9a0c7..8966d6a 100644
--- a/je_auto_control/wrapper/auto_control_mouse.py
+++ b/je_auto_control/wrapper/auto_control_mouse.py
@@ -263,3 +263,25 @@ def mouse_scroll(
f"mouse_scroll, scroll_value: {scroll_value}, x: {x}, y: {y}, scroll_direction: {scroll_direction}, "
f"failed: {repr(error)}"
)
+
+def send_mouse_event_to_window(window, mouse_keycode: Union[int, str], x: int = None, y: int = None):
+ autocontrol_logger.info(
+ f"send_mouse_event_to_window window:{window} mouse_keycode:{mouse_keycode}, x: {x}, y: {y}"
+ )
+ param = locals()
+ try:
+ if sys.platform in ["darwin"]:
+ return
+ mouse_keycode, x, y = mouse_preprocess(mouse_keycode, x, y)
+ mouse.send_mouse_event_to_window(
+ window,
+ mouse_keycode=mouse_keycode,
+ x=x,
+ y=y,
+ )
+ except Exception as error:
+ record_action_to_list("send_mouse_event_to_window", param, repr(error))
+ autocontrol_logger.error(
+ f"send_mouse_event_to_window window:{window} mouse_keycode:{mouse_keycode}, x: {x}, y: {y}"
+ f"failed: {repr(error)}"
+ )
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index 13e70d7..f5f4034 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,12 +1,12 @@
-# Rename to build dev version
-# This is dev version
+# Rename to build stable version
+# This is stable version
[build-system]
-requires = ["setuptools"]
+requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[project]
-name = "je_auto_control_dev"
-version = "0.0.117"
+name = "je_auto_control"
+version = "0.0.174"
authors = [
{ name = "JE-Chen", email = "jechenmailman@gmail.com" },
]
@@ -43,4 +43,4 @@ content-type = "text/markdown"
find = { namespaces = false }
[project.optional-dependencies]
-gui = ["PySide6==6.9.1", "qt-material"]
+gui = ["PySide6==6.9.2", "qt-material"]
diff --git a/test/manual_test/windows_window.py b/test/manual_test/windows_window.py
index 49945ec..286f940 100644
--- a/test/manual_test/windows_window.py
+++ b/test/manual_test/windows_window.py
@@ -1,5 +1,5 @@
from je_auto_control.windows.message.window_message import post_message_to_window, messages
-from je_auto_control.windows.window.window_hwnd import get_all_window_hwnd
+from je_auto_control.windows.window.windows_window_manage import get_all_window_hwnd
hwnd_list = get_all_window_hwnd()
print(hwnd_list)