EU-Utility/premium/eu_integration/window_tracker.py

121 lines
3.6 KiB
Python

"""
Window tracker for monitoring Entropia Universe window state.
"""
import time
import logging
import threading
from typing import Optional, Callable, List
class WindowTracker:
"""Tracks the EU game window state.
Monitors window focus, visibility, and position without
interfering with the game.
"""
def __init__(self, poll_interval: float = 0.5):
"""Initialize window tracker.
Args:
poll_interval: Seconds between window checks
"""
self.poll_interval = poll_interval
self._running = False
self._thread: Optional[threading.Thread] = None
self._callbacks: List[Callable] = []
self._logger = logging.getLogger("WindowTracker")
self._is_focused = False
self._window_handle: Optional[int] = None
self._process_id: Optional[int] = None
def start(self, process_id: Optional[int] = None) -> bool:
"""Start tracking window."""
if self._running:
return True
self._process_id = process_id
self._running = True
self._thread = threading.Thread(target=self._track_loop, daemon=True)
self._thread.start()
return True
def stop(self) -> None:
"""Stop tracking window."""
self._running = False
if self._thread:
self._thread.join(timeout=1.0)
def on_change(self, callback: Callable[[bool], None]) -> Callable:
"""Register focus change callback."""
self._callbacks.append(callback)
return callback
def is_focused(self) -> bool:
"""Check if game window is focused."""
return self._is_focused
def _track_loop(self) -> None:
"""Main tracking loop."""
while self._running:
try:
focused = self._check_focus()
if focused != self._is_focused:
self._is_focused = focused
self._notify_change(focused)
time.sleep(self.poll_interval)
except Exception as e:
self._logger.error(f"Tracking error: {e}")
time.sleep(self.poll_interval)
def _check_focus(self) -> bool:
"""Check if game window is focused."""
try:
import win32gui
import win32process
hwnd = win32gui.GetForegroundWindow()
if self._process_id:
_, pid = win32process.GetWindowThreadProcessId(hwnd)
if pid == self._process_id:
return True
# Check window title - supports multiple patterns
title = win32gui.GetWindowText(hwnd)
title_lower = title.lower()
# Match various EU window titles:
# - "Entropia Universe Client (64 bit)"
# - "Entropia Universe Client (64 bit) - Planet Calypso"
# - "Entropia.exe"
patterns = [
'entropia universe client',
'entropia.exe',
'entropia universe'
]
return any(pattern in title_lower for pattern in patterns)
except ImportError:
pass
return False
def _notify_change(self, focused: bool) -> None:
"""Notify callbacks of focus change."""
for callback in self._callbacks:
try:
callback(focused)
except Exception as e:
self._logger.error(f"Callback error: {e}")