Skip to content
Merged

Dev #157

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 46 additions & 33 deletions .idea/workspace.xml

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions stable.toml → dev.toml
Original file line number Diff line number Diff line change
@@ -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" },
]
Expand Down Expand Up @@ -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"]
6 changes: 5 additions & 1 deletion je_auto_control/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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",
Expand All @@ -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"
]
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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()
22 changes: 21 additions & 1 deletion je_auto_control/linux_with_x11/mouse/x11_linux_mouse_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()



Empty file.
38 changes: 38 additions & 0 deletions je_auto_control/osx/pid/pid_control.py
Original file line number Diff line number Diff line change
@@ -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
17 changes: 9 additions & 8 deletions je_auto_control/utils/shell_process/shell_exec.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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)


Expand Down
5 changes: 3 additions & 2 deletions je_auto_control/windows/core/utils/win32_keypress_check.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
2 changes: 1 addition & 1 deletion je_auto_control/windows/message/window_message.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down
12 changes: 9 additions & 3 deletions je_auto_control/windows/mouse/win32_ctype_mouse_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
"""
Expand Down Expand Up @@ -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)
Original file line number Diff line number Diff line change
Expand Up @@ -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)
25 changes: 24 additions & 1 deletion je_auto_control/wrapper/auto_control_keyboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)}"
)
22 changes: 22 additions & 0 deletions je_auto_control/wrapper/auto_control_mouse.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)}"
)
12 changes: 6 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -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" },
]
Expand Down Expand Up @@ -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"]
2 changes: 1 addition & 1 deletion test/manual_test/windows_window.py
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
Loading