131 lines
4.2 KiB
Python
131 lines
4.2 KiB
Python
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
|