플랫폼 추상화¶
이 페이지는 CLAUDE.md의 구현 노트를 미러합니다. 서브시스템 변경 시
양쪽 다 업데이트하세요.
모든 플랫폼별 코드는 src/cue/platform/ 아래에 있습니다. 메인 앱은
cue.platform (facade)에서 import — cue.platform.macos나
cue.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()통해. rawos.chmod()호출 금지. - UI 폰트 크기: 플랫폼 모듈의
FONT_UI/FONT_MONO상수가 플랫폼 기본 폰트 추상화. 팝업 UI 변경은 두 플랫폼에서 테스트해야 함.
스트리밍 레코더 특수 케이스¶
스트리밍 레코더는 vendoring된 ocap-{platform} CLI를 서브프로세스로
실행. 새 CLI 옵션은 양쪽 ocap repo에서 지원해야 함. 서브모듈은
sync 유지 — pull 후 git submodule update --init --recursive.
서브모듈 / 벤더링 참고.
더 보기¶
cue.platform— facade 모듈 reference (deferred).- 크로스 플랫폼 규칙 — PR 체크리스트.
- 아키텍처 개요.