Skip to content

IME·한글 구현 코드 예시

웹 composition 처리, libhangul 사용, 완성형 계산 코드

IME와 한글 입력을 실제로 다룰 때 참고할 코드 예시를 정리했다. 웹에서는 composition 이벤트만 처리하면 되고, 네이티브·임베디드에서는 libhangul 또는 직접 조합 로직을 쓸 수 있다.


1. 웹: composition 이벤트 처리 (JavaScript)

Section titled “1. 웹: composition 이벤트 처리 (JavaScript)”
const el = document.querySelector('input'); // 또는 contenteditable 요소
let isComposing = false;
let compositionStartOffset = 0; // 조합 구간 시작 위치 (에디터 모델 기준)
el.addEventListener('compositionstart', (e) => {
isComposing = true;
compositionStartOffset = getCurrentCursorOffset(); // 구현에 따라 커서 위치 저장
});
el.addEventListener('compositionupdate', (e) => {
const preedit = e.data;
// preedit을 화면에만 표시. 문서 모델에는 반영하지 않음.
updatePreeditDisplay(compositionStartOffset, preedit);
});
el.addEventListener('compositionend', (e) => {
const committed = e.data;
isComposing = false;
if (committed.length > 0) {
replaceRange(compositionStartOffset, getCurrentCursorOffset(), committed);
pushUndo();
}
clearPreeditDisplay();
});

1.2 단축키에서 조합 중 제외 (isComposing)

Section titled “1.2 단축키에서 조합 중 제외 (isComposing)”
el.addEventListener('keydown', (e) => {
if (e.isComposing) return; // IME 조합 중이면 단축키 무시
if (e.ctrlKey && e.key === 'b') {
e.preventDefault();
doBold();
}
});

1.3 composition 없이 insertText만 오는 경우

Section titled “1.3 composition 없이 insertText만 오는 경우”
el.addEventListener('input', (e) => {
if (isComposing) return; // compositionend에서 처리
if (e.inputType === 'insertText' && e.data) {
insertAtCursor(e.data);
pushUndo();
}
});

유니코드 한글 음절 공식: S = 0xAC00 + (L×588) + (V×28) + T. L=초성 인덱스(018), V=중성(020), T=종성(0~27, 0=없음).

const CHO = 19, JUNG = 21, JONG = 28;
const BASE = 0xac00;
function syllableToCodePoint(L, V, T) {
if (L < 0 || V < 0) return null;
const t = T >= 0 ? T : 0;
return BASE + L * (JUNG * JONG) + V * JONG + t;
}
function codePointToSyllable(S) {
if (S < BASE || S > 0xd7a3) return null;
const x = S - BASE;
const L = Math.floor(x / (JUNG * JONG));
const V = Math.floor((x % (JUNG * JONG)) / JONG);
const T = x % JONG;
return { L, V, T: T === 0 ? -1 : T };
}

초성·중성·종성 인덱스는 “한글 조합 원리” 문서의 자모 표와 동일하다. 2벌식 키 → (L,V,T) 매핑은 “한글 입력기 구현” 문서 참고.


libhangul은 HangulInputContext로 키 입력을 받아 preedit·commit 문자열을 돌려준다.

#include <hangul/hangul.h>
HangulInputContext* hic = hangul_ic_new("2"); /* "2" = 2벌식 키보드 ID */
/* 키 입력 시 (ascii = 키 코드 또는 문자) */
bool ret = hangul_ic_process(hic, ascii);
const ucschar* preedit = hangul_ic_get_preedit_string(hic);
const ucschar* commit = hangul_ic_get_commit_string(hic);
  • hangul_ic_process: 키 하나를 넣으면 내부 상태(L,V,T)를 갱신한다. 반환값은 “이번 입력으로 commit이 발생했는지” 등 구현에 따라 다름.
  • hangul_ic_get_preedit_string: 현재 조합 중인 문자열(완성형 한 글자 또는 자모).
  • hangul_ic_get_commit_string: 이번 process 호출로 확정된 문자열. 있으면 앱이 문서에 반영한 뒤, 다음 process 전에 hangul_ic_reset으로 commit 버퍼를 비우는 식으로 쓴다.
hangul_ic_backspace(hic); /* 조합 중 한 단계 취소 */
hangul_ic_reset(hic); /* 조합 상태·commit 버퍼 초기화 (포커스 잃음, Esc 등) */
HanjaTable* table = hanja_table_load("hanja.txt"); /* 한자 사전 파일 */
HanjaList* list = hanja_table_match_prefix(table, "한글"); /* 접두어 매칭 */
int n = hanja_list_get_size(list);
for (int i = 0; i < n; i++) {
const char* key = hanja_list_get_nth_key(list, i);
const char* value = hanja_list_get_nth_value(list, i);
/* key = 읽기, value = 한자 등 */
}
hanja_list_delete(list);
hanja_table_delete(table);

자세한 API는 한글: libhangul API 참고.