C.W.K.
Stream
Lesson 04 of 05 · published

모두의 키보드에 톨게이트를 놓지 마

~11 min · hotkey, event-tap, permissions, flagschanged

Level 0불씨 없음
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"억제 이벤트 탭은 기계가 만드는 모든 키 입력의 톨게이트야. 그 일을 정말 원하는지 아주 확실히 해."

요구사항

Firekeeper 기본 활성화는 맨 Fn 홀드 — 코드 조합 없이, 안 쓰는 키를 누르고 말하기. 사랑스러운 인터랙션이고 진짜 어색한 구현이야, 맨 모디파이어는 평범한 단축키가 아니니까. 평범한 단축키 API 엔 'Fn 눌림' 이벤트가 없어; 모디파이어는 플래그 변화로 자기를 알리고, 거기서 누르고-유지를 재구성해야 해.

솔깃한 틀린 도구

뻔한 답은 CGEventTap: 시스템 전역 이벤트 스트림에 앉아, 모든 키를 보고, 주장하는 걸 삼켜. 돼 — 그리고 네 앱을 기계가 만드는 모든 키 입력의 톨게이트로 만들어. 탭이 잘못 굴면, 네 앱이 깨지는 게 아니라; 타이핑 이 깨져, 어디서나. 가정이 아냐: 경쟁자의 억제 탭이 정확히 유저들 스페이스바를 먹은 거야. 위험 위에, 탭은 Input Monitoring 권한이 필요해 — 삽입에 이미 필요한 접근성 허가 위에 두 번째 무서운 프롬프트.

CGEventTap (거부됨):          flagsChanged + keyState (선택됨):
  모든 키 입력에 앉음           모디파이어 플래그 변화만 관찰
  시스템 전역 억제 가능         아무 키도 못 삼킴
  Input Monitoring 필요         이미 가진 접근성 신뢰를 탐
  경쟁자 게 스페이스바 먹음     가로채지 않는 걸 못 먹음

선택된 경로

Firekeeper 는 대신 NSEvent flagsChanged 모니터를 보고, 플래그만으로 못 가리는 경우를 CGEventSource.keyState 로 구분해 — 특히 쌍둥이 모디파이어(다른 Command 키 같은)가 아직 눌려 있을 때 누름과 놓음을 구별하는 거. 앱이 삽입 위해 이미 쥔 접근성 신뢰로 작동하고, 새 권한 표면을 안 더하고, 구조적으로 키 입력을 못 삼켜, 애초에 스트림을 안 가로채니까. 같은 인터랙션, 폭발 반경의 일부.

가로채기보다 관찰을 선호해. 시스템 이벤트를 알아야 할 때, 보는 게 길목에 서는 것보다 극적으로 안전해. 잘못 구는 관찰자는 틀린 값을 로그하고; 잘못 구는 가로채기는 모든 앱한테 시스템을 깨. 이벤트를 진짜 소비해야 할 때만 가로채기를 집어 — 눌러서-말하기 키한텐, 안 그래.
Fn 은 🌐 키로 이중 발화해. 최신 macOS 에서 Fn 키는 Globe 키이기도 해, 그래서 맨 Fn 홀드가 받아쓰기 위에 시스템 이모지/입력 소스 피커를 띄울 수 있어. 코드 해법이 없어 — 유저가 시스템 설정에서 '🌐 키를 누를 때: 아무 동작 안 함' 을 정해. 그래서 모든 바인딩이 커스터마이즈 가능하고 Setup 패널이 힌트를 드러내: OS 설정에 의존하는 인터랙션은 그 설정을 유저한테 말해줘야 해.

Code

모디파이어 플래그를 관찰; 스트림을 절대 안 가로챔·swift
// 플래그 변화를 봄 — 관찰하지, 절대 소비 안 함.
NSEvent.addGlobalMonitorForEvents(matching: [.flagsChanged]) { event in
    let fnHeld = event.modifierFlags.contains(.function)

    // flagsChanged 만으론 쌍둥이 모디파이어가 아직 눌렸을 때
    // 누름과 놓음을 늘 구별 못 함 — keyState 가 구분해줌.
    let physicallyDown = CGEventSource.keyState(.combinedSessionState,
                                                key: CGKeyCode(kVK_Function))
    switch (fnHeld, physicallyDown) {
    case (true, true):   controller.start(mode: .dictate)
    case (false, false): Task { await controller.stop() }
    default: break
    }
}
// CGEventTap 없음. 가로채지 않는 키를 삼킬 수 없음.

External links

Exercise

앱이 뭔가에 시스템 전역 인식이 필요한 케이스를 찾아(키 입력, 클립보드, 창 변화). 관찰이 필요한지 가로채기가 필요한지 물어. 각 설계에서 버그의 폭발 반경이 뭐고, 가로채기가 어떤 추가 권한을 치르게 해?
Hint
관찰의 최악 버그는 네 앱이 이벤트를 놓치거나 잘못 읽는 것 — 피해가 너한테 갇혀. 가로채기의 최악 버그는 OS 전체가 이벤트를 잃는 것 — 피해가 남들 타이핑이야. 가로채기는 보통 더 넓고 무서운 권한도 요구해, 그러니 두 번 내: 더 큰 위험과 설치 때 더 큰 마찰.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.