CrownyOS 한글 IME 배선 — crownyc_window.m 키 이벤트 → VM 키 큐
개요
CrownyOS 데스크톱 셸(하늘나라셸.한선)의 터미널 앱(crownyc/libs/앱_터미널.한선,
2026-07-11 실셸 승격)에 한글 내장 명령(도움/지우기/크라우니 <질문>)이 로직상
있었으나, 실제 맥 키보드로 한글을 입력할 경로가 막혀 있었다. 원인을 규명하고
Cocoa 키 이벤트 → VM 키 큐 → 앱 레이어까지 한글 코드포인트가 흐르도록 배선했다.
조사 결과 (핵심 — 예상과 다른 두 가지 발견)
1) 진짜 필터 위치는 libs/앱_터미널.한선의 터미널_키()
crownyc_window.m은 이미 NSTextInputClient 프로토콜(insertText:/setMarkedText: 등,
76~349행)을 구현해 macOS 시스템 IME(두벌식 등)의 조합 결과를 받고 있었다. 즉
한글 자모 조합 자체는 이미 OS가 처리하고, 완성된 커밋 문자열이 insertText:로
들어온다 — crowny-browser의 한글조합기.한선 같은 별도 두벌식 조합기를 새로 만들
필요가 없었다(과설계 방지, 지시사항 2-a와 일치).문제는 그 커밋 문자열이 ime_committed 전역 버퍼(opcode 901 텍스트큐)에만
쌓이고, 앱들이 실제로 읽는 채널인 key_queue(opcode 900 키큐)/key_pressed
(opcode 362 키입력)로는 전혀 전달되지 않았다는 것. 그 결과:
- 한글뿐 아니라 일반 ASCII 문자 입력도
insertText:경로로는key_queue에
doCommandBySelector: 특수키만
crowny_push_key()로 큐에 들어감). 앱_터미널.한선의 32~126 필터는 정확히
존재했지만, 애초에 그 코드가 도달할 방법이 charater 입력 경로에는 없었다.
- 즉 "한글만 막혀있다"는 원래 가정보다 범위가 넓은 실제 원인:
insertText:가
2) 하늘나라셸.한선의 이벤트 디스패치(이벤트확인/이벤트데이터, opcode
810~815)는 현재 죽은 코드 경로 — 금번 작업 범위 밖, 별도 이슈로 기록
crownyc.c의 evt_queue/crowny_evt_push()(주석: "Phase 6 — 브라우저 이벤트
루프")는 정의만 있고 crownyc.c/crownyc_window.m/compositor.c 어디에서도
crowny_evt_push()를 호출하는 곳이 없다(전수 grep, crownyc.c/crownyc_big.c/
crownyc_jitmain.c/pkg/crownyc.c/build/crownyc-next.c 전부 동일). 그런데
하늘나라셸.한선의 메인 루프는 이벤트확인()으로 이벤트 타입을 폴링하고
e==2일 때만 셸_앱키(현재앱, 이벤트데이터())를 호출한다. 이벤트확인()은
빈 큐이므로 항상 0을 반환 → 실제 GUI 실행에서는 셸_앱키가 전혀 호출되지
않는다(한글/ASCII 무관하게 키 입력이 앱까지 도달 못함). 이는 하늘나라셸.한선
수정이 금지된 이번 작업 범위 밖의 선행 버그이며, 향후 세션에서 다음 둘 중
하나로 해결해야 한다:
crownyc_window.m에서 crowny_evt_push()를 extern으로 노출해 키/클릭하늘나라셸.한선 메인 루프를 이벤트확인()/이벤트데이터() 대신키큐()(900)/키입력()(362) 직접 폴링으로 변경.구현
crownyc_window.m — insertText: (NSTextInputClient)
기존 ime_committed 적재 로직은 그대로 유지(회귀 없음, opcode 901 소비자가
생기면 계속 동작). 그 아래에 커밋 문자열의 각 UTF-16 코드유닛(한글 자모/음절은
전부 BMP라 1코드유닛=1글자, 서로게이트 페어 불필요)을 기존 crowny_push_key()
(원래 Cmd단축키·백스페이스 등에만 쓰이던 VM 키 큐 push 함수)로 그대로
push하도록 추가했다. 마킹텍스트(조합중) UI는 처리하지 않음 — 지시사항대로
"커밋 문자열만 큐잉"으로 최소 배선.objcNSUInteger slen = [s length];
for (NSUInteger i = 0; i < slen; i++) {
unichar uc = [s characterAtIndex:i];
if (uc > 0) crowny_push_key((int)uc);
}
이 한 변경으로 한글(자모 0x3131~0x318E, 음절 0xAC00~0xD7A3)뿐 아니라 그동안
누락돼 있던 일반 ASCII 문자 키 입력도 함께 key_queue에 도달하게 됐다
(둘 다 같은 채널을 공유하므로 회귀 아님 — 오히려 선행 버그를 같이 고침).
libs/앱_터미널.한선 — 터미널_키(코드)
기존 ASCII(32~126) 필터에 한글 호환 자모(12593~12686)와 완성형 음절
(44032~55203) 두 구간을 추가. 글자변환(코드)는 이미 U+10000 이상 4바이트
문자까지 지원(2026-06-21 수정)하므로 BMP 내의 한글 코드포인트는 문제없이
문자로 복원된다.VM 측(crownyc.c) 필터
crowny_push_key()(정수 큐잉)에는 애초에 ASCII 전용 필터가 없다 — 필터는
전적으로 앱 레이어(터미널_키)에만 있었으므로 crownyc.c 자체는 수정하지
않았다.검증
- `cc -O2 -DCROWNY_WINDOW -I. -framework Cocoa -framework Security -framework
→ exit 0 (Makefile의 crownyc_win` 타깃과
동일 링크 조합; 최초 시도에서 compositor.c theme.c ui.c 누락으로 링크
에러 발생 → Makefile 확인 후 정정).
- 기존
crownyc_win(7/7 09:22 빌드)을crownyc_win.bak-20260711로mv
mv 배치(제자리 cp 덮어쓰기 금지 규칙
준수).
./hanseonc_high libs/앱_터미널.한선→ exit 0 (7918 큐브)../hanseonc_high 하늘나라셸.한선→ exit 0 (24938 큐브, 전체 셸 임포트 체인
- 헤드리스 하네스(
한글IME하네스.한선,/tmp/claude-501/.../scratchpad/에
터미널_키()를 직접 호출해 6개 검증 전부 PASS:
1. 코드포인트 46020('도')+50880('움') 순차 주입 → 입력줄 "도움" 형성
2. Enter(13) → 내장 도움 명령 출력("Commands available" 라인) 확인
3. 자모 단독(12593='ㄱ') 주입 → 입력줄 "ㄱ" 형성
4. ASCII 회귀 없음("v"+"e"+"r" → "ver")
5. "ver" 명령 실행 확인("crownyc VM" 라인)
6. 범위 밖 코드(200) 주입 시 입력줄에 유입되지 않음(무시) 확인 ※ 작업지시서 예시 코드포인트(도=44536, 움=50780)는 실측과 달라(Python
ord('도')=46020, ord('움')=50880) 정정해 사용함 — 지시서의 오탈자로
판단.
관련 파일
/Users/ef/CrownyOS/crownyc/crownyc_window.m(76~360행,insertText:수정)/Users/ef/CrownyOS/crownyc/libs/앱_터미널.한선(터미널_키()함수, 필터 확장)/Users/ef/CrownyOS/crownyc/crownyc_win(재빌드된 바이너리, 신규)/Users/ef/CrownyOS/crownyc/crownyc_win.bak-20260711(구 바이너리 백업)/tmp/claude-501/-Users-ef/929a8ec9-1c47-4929-9008-6af6618baaf0/scratchpad/한글IME하네스.한선
하늘나라셸.한선(읽기 전용으로만 확인, 미수정)
잔여 이슈
- [미해결 — 별도 작업 필요]
하늘나라셸.한선이벤트 디스패치 자체가
이벤트확인()(810)이 폴링하는 evt_queue를
채우는 crowny_evt_push() 호출이 코드베이스 전체에 없음 → 실제 창을 띄워도
셸_앱키()가 호출되지 않아 이번에 배선한 한글 키 큐까지 도달하지 못할 수
있음. 이번 작업은 "코드가 터미널_키()에 도달했을 때" 정상 동작하는 것까지만
헤드리스로 검증했고, 이 상위 배선 문제는 하늘나라셸.한선 수정 금지 지시에
따라 손대지 않았다. 위 "조사 결과 2)" 참조.
- GUI 실측 미실시: 지시에 따라 실제 macOS 창을 띄우는 것은 하지 않았다.
crownyc_win(신규 바이너리)을 실행해 실제 두벌식 키보드로 "도움"을 입력해
보는 것은 사용자 몫으로 남긴다. 실행 명령: `./crownyc_win --window run
/tmp/하늘나라셸_test.toau` 또는 서비스매니페스트 경로 참조.
- 위 이슈 1이 해결되기 전까지는, 이번 배선이 실제 창에서 체감되려면
하늘나라셸.한선(또는 후속 세션)이 이벤트확인()/이벤트데이터() 대신
키큐()/키입력()을 폴링하도록 바뀌어야 한다.크라우니코드 보고
lookup HIT 0건 / MISS 2건(생성) / learn 추가 2건
(터미널키한글필터, cocoa_insertText_한글키큐배선)
2차 배선 (같은 날 후속 — 옵션 A 승인·완료): crowny_evt_push 공개 + 키/클릭 이벤트 evt_queue 배선
개요
1차 작업에서 발견·문서화한 선행 버그(잔여 이슈 1: crowny_evt_push() 호출부가
코드베이스 전체에 0곳 → 하늘나라셸.한선 메인 루프의 이벤트확인()(810)이
라이브 GUI에서 영원히 빈 큐만 폴링)를 옵션 A로 배선 완료. 오케스트레이터 승인.
이벤트 포맷 역추적 근거 (소비부 = SSOT)
crownyc.copcode 810(이벤트확인):crowny_evt_poll(&evt)성공 시evt.typepush, 빈 큐면 0.- opcode 812/813(
이벤트x/이벤트y): 직전 폴링된 이벤트(evt_queue[(evt_head-1+256)%256])의.x/.y. - opcode 815(
이벤트데이터): 같은 슬롯의.data1. - 타입 상수(crownyc.c 182~189행):
CROWNY_EVT_CLICK=1,CROWNY_EVT_KEY=2,CROWNY_EVT_QUIT=7. 하늘나라셸.한선소비 계약(132~155행, 읽기만):e==1→이벤트x()/이벤트y()로
e==2 → 셸_앱키(현재앱, 이벤트데이터()), e==7 → 종료.
- 따라서: 키 =
crowny_evt_push(2, 0, 0, 키코드, 0, NULL),
crowny_evt_push(1, fb좌표x, fb좌표y, 0, 0, NULL).수정 지점
/Users/ef/CrownyOS/crownyc/crownyc.c(약 200행):crowny_evt_push정의의
static 제거(공개 심볼화) + 사유 주석. 로직 무변경. (한선씨 동반 규칙은
1차와 동일하게 "하드웨어 이벤트 배선 예외" — 본 문서가 동반 문서.)
/Users/ef/CrownyOS/crownyc/crownyc_window.m:
crowny_push_key() (약 268행): 기존 key_queue/key_pressed push 유지 +
crowny_evt_push(2, 0, 0, code, 0, NULL) 병행 push. 이 함수가 세 경로
(Cmd 단축키, doCommandBySelector 특수키, insertText IME 커밋 문자)의
단일 합류점이므로 여기 한 곳 추가로 전 키 경로 커버.
- mouseDown: (약 227행): view_to_fb 변환 후
crowny_evt_push(1, mouse_x, mouse_y, 0, 0, NULL) — 프레임버퍼 좌표로
클릭 이벤트 전달. mouseDown에서만(1회) push, mouseUp은 미전달(셸 계약이
e==1=클릭 단발이므로 이중 발화 방지).
- 파일 상단(선언 순서상 mouseDown보다 뒤에 있는 공용 extern과 별개로,
mouseDown 내부 블록 로컬 extern 선언 사용).
- 기존 배선 회귀 없음: key_queue(키큐 900)/key_pressed(키입력 362)/
빌드·검증 증거
- 빌드: Makefile crownyc_win 타깃과 동일 조합(`cc -O2 -DCROWNY_WINDOW -I.
- 심볼:
nm -u crownyc_window.o→_crowny_evt_push(미해결 참조 존재 = 사용
nm crownyc.o → T _crowny_evt_push (전역 텍스트 심볼로 공개 확인).
이벤트폴링하네스.한선: 이벤트확인() 100회 폴링 전부 0(빈 큐)·크래시이벤트x/이벤트y/이벤트데이터 빈 큐 기본값 0 — PASS 2/2.
(GUI 없는 실행에서 evt_queue가 오염되지 않음 = 회귀 없음)
한글IME하네스.한선 재실행: 6/6 PASS (터미널_키 로직 회귀 없음).crownyc_win.bak-20260711-2로 mv 백업,crownyc_win으로 mv 배치. 원본(7/7) 백업
crownyc_win.bak-20260711 보존. (제자리 cp 금지 준수)사용자 실측 커맨드 및 기대 동작 (GUI는 헤드리스 검증 불가 — 사용자 몫)
bashcd /Users/ef/CrownyOS/crownyc
./hanseonc_high 하늘나라셸.한선 > /tmp/크라우니OS.toau
./crownyc_win --window run /tmp/크라우니OS.toau
기대: ①독에서 Terminal 클릭(이제 클릭이 evt_queue로 셸에 도달) → 터미널 열림 ②영문 타이핑(예: ver) + Enter → 명령 실행 ③맥 입력소스를 한글(두벌식)로 전환 후 "도움" 타이핑 + Enter → 내장 도움말 출력. 조합 중 글자는 화면에 안 보이고(마킹텍스트 UI 없음) 음절 확정 시점에 입력줄에 나타나는 것이 정상.
잔여 이슈 (2차 후 갱신)
- 1차 잔여 이슈 1(evt_queue 미배선)은 본 2차로 해결.
- GUI 실측은 여전히 사용자 몫(위 커맨드).
- 스크롤(EVT_SCROLL=3)/종료(EVT_QUIT=7)/우클릭은 이번에 배선하지 않음 —
- evt_queue는 Cocoa 메인스레드(생산)/VM 스레드(소비) 무락 공유 — 기존
크라우니코드 보고 (2차)
lookup HIT 0건 / MISS 1건(생성) / learn 추가 1건 (evt_queue_공개push_배선)