레퍼런스: gureum/gureum — macOS 한글 입력기 (BSD + LGPL) 핵심 의존: libhangul (C, 한글 조합 상태 머신), Apple InputMethodKit
macOS 전용 한글 입력기. 3가지 핵심 기능에 집중한다:
- 모아치기 — 초성/중성/종성 동시 타건, 순서 무관
- Vi 모드 — ESC/Ctrl+[ → 자동 영문 전환
- 내장 QWERTY — 입력기 내부 한영전환으로 씹힘 제로
참조:
OSXCore/InputController.swift,OSXCore/InputReceiver.swift,OSXCore/InputMethodServer.swift
macOS TSM → IMKServer (싱글턴)
→ InputController (IMKInputController)
→ InputReceiver (전처리, 커밋/업데이트 흐름)
→ Composer Chain
├─ HangulComposer (libhangul 래핑, 모아치기 포함)
└─ RomanComposer (내장 QWERTY, 패스스루)
3계층 분리: IMK 인터페이스 → 처리 로직 → 조합 로직
protocol Composer {
var delegate: Composer! { get set }
var composedString: String { get } // 조합 중 (밑줄)
var commitString: String { get } // 확정 대기
func dequeueCommitString() -> String // 소비 후 비움
func cancelComposition()
func input(text:key:modifiers:client:) -> InputResult
}- 기본 구현이 모든 호출을
delegate로 위임 - 이중 버퍼: composedString(밑줄) / commitString(확정) + dequeue 큐 패턴
GureumComposer가delegate를 HangulComposer ↔ RomanComposer로 동적 교체 (Strategy)
참조:
OSXCore/HangulComposer.swift,GureumTests/GureumTests.swift(모아치기 테스트 ~130줄)
초성/중성/종성을 동시에 눌러도 올바른 글자로 조합된다. 타건 순서에 무관.
"ㄱ"+"ㅏ" 동시 → "가" (순서 무관)
"ㄲ" 동시 타건 → "까"
"ㄱ"+"ㅏ"+"ㄴ" 동시 → "간"
libhangul의 hangulAutoReorder 옵션으로 활성화. HGInputContext가 입력 순서를 내부적으로 재정렬하여 조합.
// Configuration에서 설정
var hangulAutoReorder: Bool // true → 모아치기 활성화HangulComposer가 KVO로 이 설정을 감시하여 실시간 반영.
gureum 원본에서 검증하는 조합: 까, ㄺ, 괜, 뚫, 많, 삶, 얹 — 각각 역순 입력과 정순 입력의 결과가 동일한지 + 역순 삭제까지 검증.
참조:
OSXCore/GureumComposer.swift—filterCommand(),OSXCore/Configuration.swift
한글 입력 중 ESC 또는 Ctrl+[ 입력 시:
- 현재 조합 중인 한글을 확정(commit)
- 자동으로 영문(QWERTY) 모드로 전환
- Vim/Neovim에서 Normal 모드 진입 시 별도 한영전환 불필요
// GureumComposer.filterCommand() 내부
if config.romanModeByEscapeKey {
if key == .escape || (key == .ansiLeftBracket && modifiers.contains(.control)) {
return .changeLayout(.roman)
}
}전환 흐름:
filterCommand() → .changeLayout(.roman)
→ cancelAndCommit() (조합 확정)
→ delegate = romanComposer
→ selectMode() → macOS에 알림
var romanModeByEscapeKey: Bool // true → Vi 모드 활성화 (기본: true로 설정)참조:
OSXCore/RomanComposer.swift,OSXCore/GureumComposer.swift
macOS의 입력기 전환 시스템을 거치지 않고, 입력기 내부에서 한글↔영문을 전환한다. 전환 지연/씹힘이 없음.
GureumComposer가 두 Composer를 소유하고 delegate를 교체:
class GureumComposer: Composer {
let hangulComposer = HangulComposer() // 두벌식
let romanComposer = RomanComposer() // 내장 QWERTY
// delegate를 교체하여 모드 전환
func changeLayout(_ layout: ChangeLayout) {
cancelAndCommit() // 현재 조합 확정
if layout == .hangul {
delegate = hangulComposer
} else {
delegate = romanComposer
}
// macOS에 모드 변경 알림
selectMode(inputMode)
}
}RomanComposer는 composedString이 항상 빈 문자열 (조합 상태 없음, 즉시 커밋).
참조:
OSXCore/InputMethodServer.swift—IOKitty,OSXCore/InputController.swift
| 입력 | 동작 |
|---|---|
| CapsLock 짧게 (<0.5초) | 한영 전환 |
| CapsLock 길게 (≥0.5초) | 원래 CapsLock (대문자 잠금) |
macOS가 CapsLock을 입력기 전에 자체 처리하므로, IOHIDManager로 하드웨어 레벨 선점:
class IOKitty {
// IOHIDManager로 CapsLock 키 이벤트 감지
// 0.5초 타이머로 짧게/길게 구분
var capsLockTriggered: Bool
func handleCapsLock(pressed: Bool) {
if pressed {
startTimer(0.5)
} else {
if elapsed < 0.5 {
capsLockTriggered = true // → 한영전환
restoreLEDState() // CapsLock LED 복원
} else {
// 원래 CapsLock 동작 유지
}
}
}
}접근성 권한(IOHIDRequestAccess) 필요.
"r"(ㄱ) → process → preedit=[ㄱ] → 밑줄 "ㄱ"
"k"(ㅏ) → process → preedit=[가] → 밑줄 "가"
"s"(ㄴ) → process → commit=[가] preedit=[ㄴ] → "가" 확정, 밑줄 "ㄴ"
libhangul HGInputContext가 초성/중성/종성 상태 머신 관리. HangulComposer는 얇은 래퍼.
- libhangul 출력: 첫가끝(U+1100대) →
representableString()으로 호환 자모(U+3131대) 변환 - 초성/중성 필러(U+115F, U+1160) 제거
두벌식(han2)만 지원. setKeyboard(identifier: "2")로 고정.
UserDefaults 싱글턴. 루룸 키보드에 필요한 설정만:
| 설정 | 기본값 | 용도 |
|---|---|---|
romanModeByEscapeKey |
true | Vi 모드 |
hangulAutoReorder |
true | 모아치기 |
enableCapslockToToggleInputMode |
true | CapsLock 한영전환 |
- Composer Chain — 한글/영문 전환 = delegate 교체. 확장 시 새 Composer 추가만으로 가능. →
Composer.swift - 이중 버퍼 + dequeue — IMK 필수 패턴. 조합 중(밑줄)과 확정을 분리. →
InputReceiver.swift - IOHIDManager — CapsLock 짧게/길게 구분은 NSEvent 불가, 하드웨어 선점 필수. →
InputMethodServer.swift - libhangul — 한글 조합 복잡성을 캡슐화. 직접 구현하지 않는다. → libhangul
| 파일 | 원본 경로 | 역할 |
|---|---|---|
| Composer.swift | OSXCore/ |
Composer 프로토콜 |
| GureumComposer.swift | OSXCore/ |
라우터, Vi 모드, 한영전환 |
| HangulComposer.swift | OSXCore/ |
libhangul 래핑, 모아치기 |
| RomanComposer.swift | OSXCore/ |
내장 QWERTY |
| InputController.swift | OSXCore/ |
IMK 이벤트 핸들러 |
| InputReceiver.swift | OSXCore/ |
입력 처리 오케스트레이터 |
| InputMethodServer.swift | OSXCore/ |
IMKServer + IOKitty(CapsLock) |
| Configuration.swift | OSXCore/ |
설정 (3개만) |
| KeyCode.swift | OSXCore/ |
하드웨어 키 코드 |