# -*- coding: utf-8 -*- """P1-04:桌面会话探测 + 截图/全局热键能力路由(纯 stdlib,可在任何平台导入)。 契约(REPAIR_BACKLOG P1-04): - Windows 保持现有行为(Win32 RegisterHotKey + Qt grabWindow 覆盖层)。 - Linux X11:原生全局快捷键(XGrabKey,见 x11_hotkey.py)+ 原生屏幕捕获(Qt grabWindow,X11 可用)。 - Linux Wayland:截图走 xdg-desktop-portal(用户授权,不绕过 compositor,见 portal_capture.py); 全局热键依赖 compositor 桌面协议(ext-global-shortcut 等),本版本无免依赖实现 → 明确告知不可用,仅保留应用内 Alt+S 快捷键,主程序其余功能不受影响。 - offscreen/无显示(unknown):能力不可用要有明确日志,主程序仍可聊天。 """ import os import sys def session_kind() -> str: """返回 "win32" / "x11" / "wayland" / "unknown"。 判定顺序(Linux,综合 Qt 平台名与 XDG_SESSION_TYPE,见 PLATFORM_PLAN): 1. QT_QPA_PLATFORM 以 offscreen 开头 → unknown(自动化离屏,无桌面能力) 2. QT_QPA_PLATFORM 以 wayland 开头,或 WAYLAND_DISPLAY 已设置, 或 XDG_SESSION_TYPE=wayland → wayland 3. DISPLAY 已设置,或 XDG_SESSION_TYPE=x11 → x11 4. 其余(headless/无显示)→ unknown """ if sys.platform == "win32": return "win32" if sys.platform != "linux": # 其他 POSIX(macOS 等)不在本任务支持矩阵内 return "unknown" qt_plat = os.environ.get("QT_QPA_PLATFORM", "").strip() if qt_plat.startswith("offscreen"): return "unknown" xdg_type = os.environ.get("XDG_SESSION_TYPE", "").strip().lower() if (qt_plat.startswith("wayland") or os.environ.get("WAYLAND_DISPLAY", "").strip() or xdg_type == "wayland"): return "wayland" if os.environ.get("DISPLAY", "").strip() or xdg_type == "x11": return "x11" return "unknown" def hotkey_plan(kind: str): """全局热键能力路由 → (thread_factory | None, message)。 thread_factory() 返回 QThread(带 triggered 信号);None 表示无全局热键能力 (调用方应保留应用内 QShortcut 兜底)。message 需要打印以明确当前能力。 """ if kind == "win32": from ui.views.system_tools.global_hotkey import GlobalHotkeyThread return GlobalHotkeyThread, "[GlobalHotkey] Windows:系统级全局热键 Alt+S(RegisterHotKey)" if kind == "x11": from ui.views.system_tools.x11_hotkey import X11HotkeyThread return X11HotkeyThread, "[GlobalHotkey] X11:原生全局热键 Alt+S(XGrabKey)" if kind == "wayland": return None, ("[GlobalHotkey] Wayland:全局热键需要 compositor 桌面协议" "(ext-global-shortcut 等),本版本未启用 → 仅提供应用内 Alt+S 快捷键" "(窗口获焦时生效)与截图按钮;其余功能不受影响") return None, ("[GlobalHotkey] 当前环境无显示服务(offscreen/无 DISPLAY)→ 全局热键不可用;" "应用内 Alt+S 快捷键同样不可用,可用截图按钮以外的全部功能") def capture_plan(kind: str): """截图能力路由 → (mode, message)。 mode: "overlay"(Qt grabWindow 覆盖层,win32/x11) "portal"(xdg-desktop-portal 交互截图,wayland) "unavailable"(unknown:明确告知,主程序其余功能不受影响) """ if kind in ("win32", "x11"): return "overlay", None if kind == "wayland": return "portal", None return "unavailable", ("[Screenshot] 当前环境无法获取屏幕画面(offscreen/无显示)→ " "截图功能不可用;聊天与其他功能不受影响")