first commit
This commit is contained in:
130
core/window_manager.py
Normal file
130
core/window_manager.py
Normal file
@@ -0,0 +1,130 @@
|
||||
import subprocess
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional, Tuple
|
||||
from wechat_auto.utils.logger import logger
|
||||
from wechat_auto.config import settings
|
||||
|
||||
|
||||
@dataclass
|
||||
class WindowPosition:
|
||||
x: int
|
||||
y: int
|
||||
width: int
|
||||
height: int
|
||||
|
||||
@property
|
||||
def center(self) -> Tuple[int, int]:
|
||||
return (self.x + self.width // 2, self.y + self.height // 2)
|
||||
|
||||
def relative_to(self, rel_x: int, rel_y: int) -> Tuple[int, int]:
|
||||
return (self.x + rel_x, self.y + rel_y)
|
||||
|
||||
|
||||
class WindowManager:
|
||||
def __init__(self, window_name: str = None):
|
||||
self.window_name = window_name or settings.wechat_window_name
|
||||
|
||||
def find_window(self, timeout: float = 10.0) -> Optional[str]:
|
||||
start_time = time.time()
|
||||
|
||||
search_methods = [
|
||||
['xdotool', 'search', '--name', self.window_name],
|
||||
['xdotool', 'search', '--class', 'wechat'],
|
||||
['xdotool', 'search', '--classname', 'wechat'],
|
||||
]
|
||||
|
||||
while time.time() - start_time < timeout:
|
||||
for cmd in search_methods:
|
||||
try:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5
|
||||
)
|
||||
window_id = result.stdout.strip().split('\n')[0]
|
||||
if window_id:
|
||||
logger.info(f"找到窗口: {self.window_name}, ID: {window_id}")
|
||||
return window_id
|
||||
except Exception as e:
|
||||
logger.debug(f"搜索方式 {cmd} 失败: {e}")
|
||||
|
||||
time.sleep(0.5)
|
||||
|
||||
logger.error(f"未找到窗口: {self.window_name}")
|
||||
return None
|
||||
|
||||
def get_window_position(self, window_id: str = None) -> Optional[WindowPosition]:
|
||||
if not window_id:
|
||||
window_id = self.find_window()
|
||||
if not window_id:
|
||||
return None
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['xdotool', 'getwindowgeometry', window_id],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5
|
||||
)
|
||||
|
||||
output = result.stdout
|
||||
x = y = width = height = 0
|
||||
|
||||
for line in output.split('\n'):
|
||||
line = line.strip()
|
||||
if line.startswith('Position:'):
|
||||
parts = line.split(':')[1].strip().split(',')
|
||||
x = int(parts[0])
|
||||
y = int(parts[1])
|
||||
elif line.startswith('Geometry:'):
|
||||
parts = line.split(':')[1].strip().split('x')
|
||||
width = int(parts[0])
|
||||
height = int(parts[1])
|
||||
|
||||
if x or y or width or height:
|
||||
pos = WindowPosition(x=x, y=y, width=width, height=height)
|
||||
logger.info(f"窗口位置: {pos}")
|
||||
return pos
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取窗口位置失败: {e}")
|
||||
|
||||
return None
|
||||
|
||||
def activate_window(self, window_id: str = None) -> bool:
|
||||
if not window_id:
|
||||
window_id = self.find_window()
|
||||
if not window_id:
|
||||
return False
|
||||
|
||||
try:
|
||||
subprocess.run(
|
||||
['xdotool', 'windowactivate', window_id],
|
||||
capture_output=True,
|
||||
timeout=5
|
||||
)
|
||||
time.sleep(0.5)
|
||||
logger.info(f"窗口已激活: {window_id}")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"激活窗口失败: {e}")
|
||||
return False
|
||||
|
||||
def is_window_visible(self, window_id: str = None) -> bool:
|
||||
if not window_id:
|
||||
window_id = self.find_window()
|
||||
if not window_id:
|
||||
return False
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['xdotool', 'getwindowname', window_id],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5
|
||||
)
|
||||
return bool(result.stdout.strip())
|
||||
except Exception:
|
||||
return False
|
||||
Reference in New Issue
Block a user