콘텐츠로 이동

플랫폼 추상화

이 페이지는 CLAUDE.md의 구현 노트를 미러합니다. 서브시스템 변경 시 양쪽 다 업데이트하세요.

모든 플랫폼별 코드는 src/cue/platform/ 아래에 있습니다. 메인 앱은 cue.platform (facade)에서 import — cue.platform.macoscue.platform.windows에서 직접 import 금지 (플랫폼 가드된 블록 제외).

src/cue/platform/
├── __init__.py        # facade — 호출자는 이 모듈만 import
├── macos.py           # rumps tray, CGEventTap, AppleScript, Carbon, AX
├── windows.py         # pystray tray, pynput, UIA, SetWinEventHook
├── overlay_macos.py   # NSPanel per NSScreen, NSFloatingWindowLevel
└── overlay_windows.py # Tk Toplevel per monitor, WS_EX_LAYERED|TRANSPARENT

주요 플랫폼 차이

측면 macOS Windows
메뉴바 rumps.App (unicode title ) pystray.Icon (image from assets/icon.png)
글로벌 핫키 CGEventTap (Shift+Space) pynput.keyboard.GlobalHotKeys (Alt+`)
스크린샷 mss + Pillow (공유 capture.py) 동일
선택 텍스트 osascript Cmd+C + NSPasteboard win32clipboard Ctrl+C 시뮬레이션
팝업 서브프로세스 popup_window.py (customtkinter) 동일
다이얼로그 rumps.alert() ctypes.windll.user32.MessageBoxW
파일 권한 cue.fs.secure_dir() / secure_file() (POSIX chmod) no-op (Windows ACL 미설정)
빌드 PyInstaller / Nuitka → .app → DMG PyInstaller → .exe → Inno Setup
Frozen 감지 getattr(sys, 'frozen', False) 또는 __compiled__ (Nuitka) 동일
서브프로세스 콘솔 불필요 _CREATE_NO_WINDOW = 0x08000000
프라이버시 오버레이 pyobjc NSWindow per NSScreen, NSFloatingWindowLevel, CanJoinAllSpaces \| Stationary, main-thread via AppHelper.callAfter 전용 Tk 스레드, monitor별 Toplevel, click-through 위해 WS_EX_LAYERED \| WS_EX_TRANSPARENT \| WS_EX_NOACTIVATE \| WS_EX_TOOLWINDOW, import 시 monitor별 DPI awareness 설정
Secure-input 감지 Carbon IsSecureEventInputEnabled (시스템 차원 latch) UIA IsPasswordPropertyId on 포커스된 요소 + "Credential Dialog Xaml Host"용 윈도우 클래스 fallback. UIA 작업은 0.2초 timeout + cached last value 단일 ThreadPoolExecutor(max_workers=1)로 실행.
브라우저 URL 읽기 브라우저별 osascript AppleScript (Chrome / Safari / Arc / Brave / Vivaldi / Opera / Edge / Firefox / Orion / Zen) UIA address-bar traversal (Chrome / Edge / Brave / Vivaldi / Opera / Firefox / Librewolf)
일시정지 핫키 CGEventTap의 Cmd+Shift+Space (bare Shift+Space 제안 트리거 전에 체크 — double-fire 안 됨) pynput.GlobalHotKeys<cmd>+<shift>+<space> (Windows에서 <cmd>가 Win 키로 매핑)
Foreground 앱 watcher NSWorkspaceDidActivateApplicationNotification 자체 메시지 펌프 스레드의 SetWinEventHook(EVENT_SYSTEM_FOREGROUND, WINEVENT_OUTOFCONTEXT)

원칙 규칙

  • 한 플랫폼 모듈에 추가된 모든 기능은 다른 플랫폼에 카운터파트 필요. 크로스 플랫폼 규칙에 전체 PR 체크리스트.
  • 플랫폼별 import는 if sys.platform == "darwin": (또는 "win32") 가드 안 — 모듈 top-level에 unguarded 절대 금지. 이게 docs를 Linux runner에서 [macos] / [windows] extras 없이 빌드 가능하게 하는 이유.
  • 파일 권한 코드는 cue.fs.secure_dir() / secure_file() 통해. raw os.chmod() 호출 금지.
  • UI 폰트 크기: 플랫폼 모듈의 FONT_UI / FONT_MONO 상수가 플랫폼 기본 폰트 추상화. 팝업 UI 변경은 두 플랫폼에서 테스트해야 함.

스트리밍 레코더 특수 케이스

스트리밍 레코더는 vendoring된 ocap-{platform} CLI를 서브프로세스로 실행. 새 CLI 옵션은 양쪽 ocap repo에서 지원해야 함. 서브모듈은 sync 유지 — pull 후 git submodule update --init --recursive. 서브모듈 / 벤더링 참고.

더 보기