""" modules/ar_interaction.py — FRIDAY AR Interaction Controls Hand tracking + Mouse control for AR holograms. """ import os import time from typing import Optional, Tuple from config import DATA_DIR INTERACTION_FILE = os.path.join(DATA_DIR, "ar_interaction.json") def _load() -> dict: if not os.path.exists(INTERACTION_FILE): return {"hand_enabled": False, "mouse_enabled": True, "last_hand_pos": None, "last_click": 0} try: import json with open(INTERACTION_FILE, "r") as f: return json.load(f) except: return {"hand_enabled": False, "mouse_enabled": True, "last_hand_pos": None, "last_click": 0} def _save(data: dict) -> None: try: os.makedirs(DATA_DIR, exist_ok=True) import json with open(INTERACTION_FILE, "w") as f: json.dump(data, f) except: pass # === Hand Tracking === def enable_hand_tracking(enabled: bool = True) -> str: """Enable/disable hand tracking.""" data = _load() data["hand_enabled"] = enabled _save(data) return f"Hand tracking {'enabled' if enabled else 'disabled'}." def is_hand_tracking() -> bool: return _load().get("hand_enabled", False) def set_hand_position(x: float, y: float, z: float = 0.0) -> None: """Update hand position from tracking.""" data = _load() data["last_hand_pos"] = {"x": x, "y": y, "z": z, "time": time.time()} _save(data) def get_hand_position() -> Optional[dict]: """Get last hand position.""" data = _load() pos = data.get("last_hand_pos") if pos and time.time() - pos.get("time", 0) < 0.5: # Fresh within 500ms return pos return None # === Mouse Control === def enable_mouse_control(enabled: bool = True) -> str: """Enable/disable mouse control.""" data = _load() data["mouse_enabled"] = enabled _save(data) return f"Mouse control {'enabled' if enabled else 'disabled'}." def is_mouse_enabled() -> bool: return _load().get("mouse_enabled", True) def get_mouse_position() -> Tuple[int, int]: """Get current mouse position.""" try: import ctypes pt = ctypes.wintypes.POINT() ctypes.windll.user32.GetCursorPos(ctypes.byref(pt)) return (pt.x, pt.y) except: return (0, 0) def simulate_click() -> None: """Simulate a mouse click.""" try: import ctypes ctypes.windll.user32.mouse_event(0x0002, 0, 0, 0, 0) # MOUSEEVENTF_LEFTDOWN ctypes.windll.user32.mouse_event(0x0004, 0, 0, 0, 0) # MOUSEEVENTF_LEFTUP except: pass def simulate_right_click() -> None: """Simulate a right mouse click.""" try: import ctypes ctypes.windll.user32.mouse_event(0x0008, 0, 0, 0, 0) # MOUSEEVENTF_RIGHTDOWN ctypes.windll.user32.mouse32mouse_event(0x0010, 0, 0, 0, 0) # MOUSEEVENTF_RIGHTUP except: pass def drag_to(x: int, y: int) -> None: """Drag mouse to position.""" try: import ctypes ctypes.windll.user32.SetCursorPos(x, y) except: pass # === AR Interaction State === def get_interaction_state() -> dict: """Get current interaction state for AR.""" hand_pos = get_hand_position() mouse_pos = get_mouse_position() return { "hand_enabled": is_hand_tracking(), "mouse_enabled": is_mouse_enabled(), "hand_position": hand_pos, "mouse_position": mouse_pos, } def process_gesture(gesture: str) -> str: """Process hand gesture commands.""" gesture = gesture.lower() if "fist" in gesture or "grab" in gesture: simulate_click() return "Grab - Clicked!" elif "point" in gesture: return "Pointing..." elif "wave" in gesture: return "Waving..." elif "open" in gesture: return "Hand open..." else: return f"Gesture: {gesture}" # === Voice Commands === def handle_command(command: str, speak) -> bool: c = command.lower() if "hand track" in c: if "enable" in c or "on" in c: result = enable_hand_tracking(True) elif "disable" in c or "off" in c: result = enable_hand_tracking(False) else: result = "Hand tracking enabled." if enable_hand_tracking(True) else "" speak(result) return True if "mouse control" in c: if "enable" in c or "on" in c: result = enable_mouse_control(True) elif "disable" in c or "off" in c: result = enable_mouse_control(False) else: result = "Mouse control enabled." speak(result) return True return False