Skip to the content.

Nalgaeset Comprehensive-Setting (종합 설정 .set) XML — Specification

날개셋(Nalgaeset) 한글 입력기는 김용묵 님이 제작·배포하는 프리웨어이며, 그 설정을 계층적 XML 로 저장·불러올 수 있다. 이 문서는 그중 종합 설정(comprehensive setting) 파일 — 편집기 계층과 입력기 계층 전체를 한꺼번에 담는 최상위 형식(루트 <EditContextSetting>, 확장자 .set) — 의 요소·속성·값-식 문법·낱자 모델·조합 오토마타·편집기 계층·백스페이스 동작을 정리한 사양서다. 본 사양은 상호 운용(interoperability)을 위해 독립적으로 작성된 clean-room 문서이며, 모든 기술 내용은 역설계로 관찰한 동작과 공개 공식 페이지의 개념 설명을 근거로 새로 기술했다. 확정하지 못한 부분은 “(미확인)”으로 표기한다.

혼동 주의. 날개셋에는 같은 스키마의 하위 루트로 저장되는 유형(input type, .ist) 파일과 글쇠배열(.key) 파일이 따로 있다. 이 문서가 다루는 것은 그 둘을 포함하는 종합 설정(.set) 이다. 셋의 관계는 §0.1에서 명확히 한다.

라이선스 / clean-room / 네임스페이스 고지.


목차 (Table of Contents)


§0 개요 · 문서 구조 · 버전 · 네임스페이스

0.1 포맷 개요

날개셋의 설정 데이터는 계층 구조이며, 바이너리뿐 아니라 XML 형식으로도 저장·불러오기가 된다(텍스트 편집기로 확인·편집 가능). 그 계층의 세 단계가 각각 하나의 파일 종류에 대응하고, 안쪽일수록 바깥 파일의 부분(subset) 이다. 즉 세 파일은 서로 다른 포맷이 아니라 같은 스키마를 어느 요소에서 루트로 잘라 저장했는가의 차이다.

파일 종류 확장자 XML 루트 요소 담는 것
종합 설정 (comprehensive setting) .set <EditContextSetting> 편집기 계층 + 입력기 계층 전체(= 본 사양의 대상)
유형 (input type) .ist <InputEntry> 한 입력 항목 전체(인식부 + 생성부). 종합 설정의 일부
글쇠배열 (key layout) .key <KeyTable> 글쇠 1벌의 값-식 표만. 유형의 일부
EditContextSetting  (.set 종합 설정)   ← 본 사양
└─ InputLayer
   └─ InputEntry    (.ist 유형)         ← 단독 저장 시 이 요소가 루트
      └─ InputSchemeSetting
         └─ KeyTable (.key 글쇠배열)    ← 단독 저장 시 이 요소가 루트

혼동 주의. “유형(.ist)”과 “종합 설정(.set)”은 자주 헷갈린다. 본 사양은 종합 설정(.set, <EditContextSetting>) 을 규정한다. 유형 파일은 그 안의 <InputEntry> 하나를, 글쇠배열 파일은 그 안의 <KeyTable> 하나를 각각 루트로 단독 저장한 것이므로, 본 사양의 해당 요소 정의를 그대로 적용하면 된다(별도 포맷이 아님). 단, 단독 저장 시 루트 요소가 달라지는 점만 유의한다.

이 XML 의 값(글쇠가 만들어 내는 결과)은 고정 문자가 아니라 수식(expression) 이며, 그 문법은 C 언어 연산자 체계를 따른다. 수식 언어 자체는 §2 값-식 언어에서 다룬다.

0.2 레이어 모델

날개셋은 입력 처리를 두 개의 레이어로 나눈다. 이 모델은 공식 영문 안내(ngs survival guide)의 Editor Layer / input scheme + character generator 구분과, 실제 XML 의 object="…" 식별자 묶음이 정확히 일치한다.

레이어 (Layer) 역할 XML 위치 비고
Editor Layer (편집기 레이어) 전역 편집 동작, 입력 항목보다 먼저 인식되는 단축글쇠(한/영·한자·Caps 등)와 홑낱자 출력용 호환 자모 변환을 담당 <EditorLayer> (ShortcutTable, FinalConvTable) 모든 입력 항목에 공통 적용
Input Layer (입력 레이어) N개의 입력 항목(InputEntry) 을 담고, 어느 항목이 기본/현재 활성인지 지정 <InputLayer default=… current=…> 항목 = “자판/입력 항목”

InputEntry 는 다시 두 부품의 조합이다(per-entry).

두 부품은 각각 빈/기본/고급(Void/Basic/Advanced) 등급으로 구현되며, 이는 object 속성의 클래스 식별자 3종으로 나타난다.

부품 (component) 빈 (Void) 기본 (Basic) 고급 (Advanced)
input scheme (InputSchemeSetting) CInputScheme CBasicInputScheme CAdvancedScheme
character generator (GeneratorSetting) CIme CNgsIme CNgsImeEx

CInputScheme + CIme 조합은 어떤 변환도 하지 않는 패스스루(pass-through) 항목(예: 영문 QWERTY)이며, 이때 KeyTable 자체가 없다. 이 사양은 생성부 object"CNgsIme" 로 시작하고 KeyTable 이 있는 항목을 한글 조합 항목으로 규정한다.

문서 트리 전체 골격은 다음과 같다(대표 구현이 실제로 인식·파싱하는 요소만 표시; 세부 표/숫자는 §1 이하 참조).

EditContextSetting  @version=0x500
├─ EditorLayer  @flag=DEL_MOVE|ARROW_MOVE …
│  ├─ ShortcutTable
│  │  └─ Shortcut*  @key @modifier @usage @value      # 한/영·한자 등 전역 단축글쇠
│  └─ FinalConvTable
│     └─ FinalConv* @from @to                         # 조합용/옛 자모 → 호환 자모(홑낱자 출력)
└─ InputLayer  @default @current
   └─ InputEntry*                                     # 입력 항목 = scheme + generator
      ├─ InputSchemeSetting  @object(C…Scheme) [@flag]
      │  └─ KeyTable  @name @from @to
      │     └─ Key*   @at @value                       # ASCII 0x21..0x7E → 값-식
      └─ GeneratorSetting    @object(C…Ime) [@flag @flagex]
         ├─ UnitMixTable @predefined → UnitMix*  @unit @a @b @to   # 낱자 결합
         ├─ VirtualUnitTable → VirtualUnit* @unit @from @to  # 가상 단위
         ├─ JackolanternTable → …                            # 특수 도깨비불 규칙(미해석)
         ├─ AutomataTable    @default @predefined
         │  └─ Automata* @state @value @default @remark      # 조합 오토마타
         └─ Extra
            └─ Bksp* @key @value1 @value2 @condition1 @condition2  # 백스페이스 단위

주: KeyProgramTable, UnitAbbrTable, JackolanternTable, UserCompoTable / UserCandiTable / UserKeyTable, HanSubstTable / UnitSubstTable 등도 날개셋 파일에 나타날 수 있으나, 대표 구현이 현재 의미를 부여해 소비하는 것은 위 트리의 요소들이다(§1 “무시(미해석) 요소” 참조). 미소비 요소의 정확한 스키마는 (미확인).

0.3 루트 요소와 버전 속성

문서 루트는 항상 <EditContextSetting> 이며, 단일 속성 version 을 가진다. 분석 대상 파일과 테스트 픽스처 모두에서 값은 "0x500" 으로 관측된다(16진수 리터럴을 큰따옴표 문자열로 표기).

<?xml version="1.0" encoding="utf-8"?>
<EditContextSetting version="0x500"></EditContextSetting>

0.4 XML 네임스페이스 — 선택적 제안

중요한 명시. 실제 날개셋이 내보내는 XML 에는 xmlns 선언이 없다. 루트 <EditContextSetting> 와 모든 자식 요소는 네임스페이스가 없는(no-namespace) 이름이며, 적합한 파서도 로컬 태그 이름만으로 매칭한다(EditContextSetting, InputEntry 등). 따라서 네임스페이스를 요구하는 검증기는 실제 파일을 거부하게 된다.

상호 운용을 위해 본 사양은 도구(스키마·검증기·변환기) 식별 목적의 정규 식별자(canonical identifier) 로 다음 URI 를 제안한다. 이는 권고이자 선택 사항 이며, 적합한(conformant) 날개셋 파일에 이를 강제하지 않는다.

https://chaotic-ground.github.io/nalgaeset-reverse-spec/

권고 사용 방식:

맥락 권고
실제 날개셋 출력 호환 xmlns 없이 출력(no-namespace). 파서는 prefix 유무와 무관하게 로컬 이름으로 매칭해야 함.
도구 내부 식별/스키마 연결 위 URI 를 RELAX NG/XSD 의 targetNamespace 또는 문서 식별자로 사용 가능.
명시적 네임스페이스가 필요한 변환 결과 루트에 xmlns="https://chaotic-ground.github.io/nalgaeset-reverse-spec/" 를 선택적으로 부여하되, 날개셋으로 되돌릴 때는 제거.

즉, 읽기(reading)는 관용적(namespace-agnostic), 쓰기(writing)는 기본적으로 네임스페이스 없음을 원칙으로 한다.

날개셋에 줄 파일엔 절대 xmlns 를 넣지 말 것. elementFormDefault="qualified" 라서 루트에 기본 xmlns 하나만 붙여도 모든 자식 요소가 그 네임스페이스로 옮겨간다. 로컬 이름으로만 매칭하는 파서(예: presguel, 실측 확인)는 이를 무시하고 그대로 읽지만, namespaceURI 를 엄격히 따지는 파서에서는 문서 전체가 “모르는 요소”가 되어 에러도 없이 빈/기본 설정으로 폴백할 수 있다. 네임스페이스는 날개셋에 아무 이득이 없으므로(날개셋은 보지 않는다) 교환용 파일에는 직렬화하지 않는다.

0.5 XML 표기 제약

날개셋 XML 은 일반 XML 의 부분집합만 사용한다. 적합한 파일·도구는 다음 제약을 따른다.

  1. 속성은 반드시 태그 안에. 모든 값은 시작 태그의 속성으로만 주어진다(<A b="c"/> 형태). 자식 요소나 텍스트 노드로 값을 전달하는 형태(<A><B>c</B></A>)는 지원되지 않는다.
  2. 허용 엔티티. 사용할 수 있는 문자 엔티티는 &amp; &quot; &lt; &gt; 와 수치 문자 참조 &#nnn;(10진)·&#xnnn;(16진) 뿐이다. 그 밖의 명명 엔티티는 쓰지 않는다.
  3. 인코딩. 문서 인코딩은 UTF-8, UTF-16, 또는 운영체제 기본 문자셋 중 하나여야 한다.
  4. 주석. XML 주석 <!-- --> 은 중첩할 수 없다(<!-- 안에 또 다른 <!-- 를 둘 수 없음).

0.6 내정값(사용자 정의 기본값) 파일 — 범위 밖

본 사양의 범위 밖이지만, 날개셋에는 종합 설정과 별개로 내정값(사용자 정의 기본값) 파일 이 있다. 별도 scheme.xml(루트 <ConfigurationScheme>)에 FinalConvTable / BkspTable / UnitMixTable / VirtualUnitTable / JackolanternTable / UnitAbbrTable / AutomataTable 같은 표를 자유로운 순서로 추가해 두면, 종합 설정에서 명시하지 않은 항목의 내정값으로 쓰인다. 각 표의 문법(요소·속성·값-식)은 본 사양과 동일하다.

0.7 본 사양이 다루는 범위

이 문서 전체가 다루는 내용을 요약하면 다음과 같다(상세는 각 섹션).

  1. §0 개요 · 문서 구조 · 버전 · 네임스페이스 — (본 섹션) 포맷 정체성, 레이어 모델, 루트/버전, 네임스페이스 정책, XML 표기 제약, 내정값 파일.
  2. §1 XML 요소 및 속성 레퍼런스 — 적합한 파서가 읽는 요소·속성 전수, 컨테이너 트리, 무시되는 요소.
  3. §2 값-식 언어<Key @value> 의 C-스타일 수식 문법(EBNF), 태그 접두사(H3|, C0|), 컨텍스트 변수(T, P, AF, O).
  4. §3 한글 낱자 모델 · 니모닉 · 서열UnitMix(낱자 결합)·VirtualUnit(가상 단위)의 의미, 초/중/종성 CHO/JUNG/JONG 갈래와 서열(序列) 개념.
  5. §4 조합 오토마타<AutomataTable> / <Automata @state @value @default> 상태 전이 모델과 시작 상태(@default).
  6. §5 특수글쇠(C0) 및 Backspace 동작C0|N 명령 목록과 <Bksp> 의 삭제 단위(직전 한 타 / 최하위 낱자 직전 타 / 최하위 낱자 통째 / 음절 통째)와 BkspAttach 재조합 동작.
  7. §6 EditorLayer 테이블 및 낱자 결합Shortcut(전역 단축글쇠, 입력 항목 전환 !A 포함), FinalConv(조합용/옛 자모 → 호환 자모), UnitMix·VirtualUnit, flag 비트.

본 사양은 기능적 사실(동작·문법·코드값의 의미)을 기술하되, 모든 표현은 역설계로 관찰한 동작과 공개 공식 페이지(moogi.new21.org)의 개념 설명을 근거로 새로 작성했다. 확정하지 못한 부분은 “(미확인)”으로 표기한다.


§1 XML 요소 및 속성 레퍼런스

이 절은 적합한 파서가 실제로 읽어들이는 nalgaeset.xml(날개셋 “입력 설정”) 요소와 속성을 빠짐없이 정리한다. 표의 “필수/기본값” 은 대표 구현 기준이다(파서가 누락 시 어떤 폴백을 쓰는지). 날개셋 본가가 출력하지만 대표 구현이 아직 해석하지 않는 요소(예: KeyProgramTable, UnitAbbrTable, JackolanternTable, UserCompoTable, HanSubstTable 등)는 “무시(ignored)” 로 표시하며, 의미가 확정되지 않은 항목은 “(미확인)” 으로 표기한다.

표기 규약: 코드값(서열 번호, C0 명령 id, 자모 mnemonic→코드 대응 등) 구체 숫자는 본문에 덤프하지 않는다. 여기서는 요소·속성의 구조와 의미만 다룬다.

1.1 계층 트리

EditContextSetting              (root, @version)
├─ EditorLayer                  (@flag)              ── 전역 편집 계층
│  ├─ ShortcutTable                                  ── 컨테이너 (속성 없음)
│  │  └─ Shortcut*               (@key @modifier @usage @value)
│  └─ FinalConvTable                                 ── 컨테이너 (속성 없음)
│     └─ FinalConv*              (@from @to)
└─ InputLayer                    (@default @current) ── 입력 항목 모음
   └─ InputEntry*                                     ── 자판 1개 = [인식부] + [생성부] (.ist 단독 루트)
      ├─ InputSchemeSetting      (@object @flag …)   ── 글쇠 인식부 (생략 가능)
      │  ├─ KeyTable             (@name @flag @from @to)   ── (.key 단독 루트)
      │  │  └─ Key*              (@at @value)
      │  └─ KeyProgramTable                           ── 미해석/lax (§1.18)
      └─ GeneratorSetting        (@object @flag @flagex …) ── 낱자 조합/생성부 (생략 가능)
         ├─ UnitMixTable         (@predefined)
         │  └─ UnitMix*          (@unit @a @b @to)
         ├─ VirtualUnitTable                          ── 컨테이너
         │  └─ VirtualUnit*      (@unit @from @to)
         ├─ AutomataTable        (@default @predefined)
         │  └─ Automata*         (@value [@state @default @remark])
         ├─ Extra                                     ── 컨테이너
         │  └─ Bksp*             (@key @value1 @value2 @condition1 @condition2)
         └─ (UnitAbbrTable · UnitSubstTable · HanSubstTable@numeric · UserCandiTable ·
             UserCompoTable · UserKeyTable@doobeolchk · JackolanternTable)  ── 미해석/lax (§1.18)

* = 0개 이상 반복. 대괄호 [ ] 는 선택, · 로 나열한 표는 순서 무관(각 0..1)이다. 컨테이너(ShortcutTable, FinalConvTable, VirtualUnitTable, Extra)는 자체 속성 없이 자식만 묶지만, UnitMixTable(@predefinedAutomataTable(@default @predefined)처럼 속성을 갖는 표도 있다. 적합한 파서는 컨테이너를 트리 위치로 구분하지 않고 자식 태그명으로 처리하므로, InputSchemeSetting/GeneratorSetting 안의 표들은 출현 순서와 무관하며(스키마도 xs:all 사용), 각각 없거나 비어 있어도(<UnitMixTable/>) 파싱은 진행된다. InputEntry 의 인식부/생성부도 한쪽만 있을 수 있다. 위 트리의 순서는 예시일 뿐이며, 미해석/lax 표는 §1.18 참조.

EBNF 로 본 문서 골격(요소 단위, 속성 생략):

document     := EditContextSetting | InputEntry | KeyTable   (* .set / .ist / .key 단독 루트 *)
EditContextSetting := EditorLayer InputLayer
EditorLayer  := ShortcutTable? FinalConvTable?
ShortcutTable:= Shortcut*
FinalConvTable := FinalConv*
InputLayer   := InputEntry*
InputEntry   := InputSchemeSetting? GeneratorSetting?         (* 순서 무관 *)
InputSchemeSetting := (KeyTable | KeyProgramTable)*           (* 순서 무관, 각 0..1 *)
KeyTable     := Key*
GeneratorSetting := ( UnitMixTable | VirtualUnitTable | AutomataTable | Extra
                    | UnitAbbrTable | UnitSubstTable | HanSubstTable | UserCandiTable
                    | UserCompoTable | UserKeyTable | JackolanternTable )*
                                                              (* 순서 무관, 각 0..1 *)
UnitMixTable := UnitMix*
VirtualUnitTable := VirtualUnit*
AutomataTable:= Automata*
Extra        := Bksp*

1.2 EditContextSetting (루트)

전체 설정의 최상위. 직속 자식은 EditorLayer 1개와 InputLayer 1개.

속성 의미 필수 기본값
version 포맷 버전 문자열(관측값 0x500). 그대로 보관만 하고 분기에 쓰지 않는다(§0.3) 아니오 ""(빈 문자열)

1.3 EditorLayer (@flag)

전역 편집 계층. 입력 항목 전환 전에 동작하는 단축글쇠와, 홑낱자 출력용 호환 자모 변환표를 담는다.

속성 의미 필수 기본값
flag 편집 동작 플래그를 | 로 이어 붙인 집합(예 DEL_MOVE|ARROW_MOVE). | 로 분리해 문자열 리스트로 보관. 각 플래그의 구체 동작은 미해석(보관만; §6 flag 비트 참조) 아니오 없음(빈 리스트)

자식: ShortcutTable(→ Shortcut), FinalConvTable(→ FinalConv). 두 테이블의 상세 의미는 §6 참조.

1.4 Shortcut (@key, @modifier, @usage, @value)

ShortcutTable 아래의 전역 단축글쇠 1개. 이 항목들은 컴파일된 단축글쇠 표로 그대로 전달되고, 실제 해석(항목 전환/한자 변환 등)은 프런트엔드가 담당한다. (의미 상세는 §6.)

속성 의미 필수 기본값
key 대상 글쇠. Windows 가상키 이름 형식(예 VK_HANGUL=한/영, VK_HANJA=한자, VK_CAPITAL=Caps) 사실상 필수 ""
modifier 보조 상태/처리 플래그를 | 로 이은 집합(예 DONT_EAT|KEEP_LAMP). | 로 분리해 리스트로 보관 아니오 없음(빈 리스트)
usage value 의 해석 방식. 관측값 IME_SWITCH(항목 전환), KEYCHAR(문자/명령 주입). 문자열로 보관하며, 해석은 프런트엔드 아니오 ""
value 동작 값. IME_SWITCH 에서는 !A 형(항목 전환 명령), KEYCHAR 에서는 C0|0x82(한자 변환) 같은 명령/문자 식 아니오 ""

1.5 FinalConv (@from, @to)

FinalConvTable 아래 한 줄. 조합용/옛 자모 코드를 호환 자모(U+31xx)로 사상한다. 음절에 들어가지 못한 홑낱자(미완성 초/중/종성)를 출력할 때 적용된다. 코드포인트 쌍 맵(from → to)으로 적재되어 홑낱자 출력에 쓰인다(설정값 우선, 없으면 내장 기본 호환표). (의미 상세는 §6.)

속성 의미 필수 기본값
from 원본 자모 코드포인트(정수, 0x 16진/10진 모두 허용). 조합용 L/V/T, 옛한글 확장, PUA 등 (누락 시 해당 줄 파싱 오류)
to 목표 호환 자모 코드포인트(U+31xx 계열) (누락 시 파싱 오류)

from/to 가 정수로 파싱되지 않으면 정수 파싱 오류로 전체 파싱이 실패한다(다른 빈문자 폴백 속성과 달리 엄격).

1.6 InputLayer (@default, @current)

입력 항목(InputEntry)들의 모음. 어떤 항목이 부팅 기본이고 현재 어떤 항목이 선택돼 있는지를 지정.

속성 의미 필수 기본값
default 부팅 기본 항목의 0-기반 인덱스 아니오 0 (파싱 실패 시에도 0)
current 현재 활성 항목의 0-기반 인덱스 아니오 0

두 속성 모두 정수 파싱이 실패해도 0 으로 폴백한다(FinalConv 와 달리 관대).

1.7 InputEntry

입력 항목 1개 = “글쇠 인식부(InputSchemeSetting) + 낱자 생성부(GeneratorSetting)”. 자체 속성은 없다. 등장 순서대로 0,1,2… 인덱스가 매겨지며 InputLayer/@default·@current 가 이를 가리킨다. 이 사양은 생성부 objectCNgsIme… 로 시작하고 KeyTable 이 있는 첫 항목을 한글 조합 항목으로 규정한다.

1.8 InputSchemeSetting (@object, @flag, …)

글쇠 인식부. 물리 글쇠 입력을 값-식으로 바꾸는 KeyTable 을 담는다.

속성 의미 필수 기본값
object 인식부 구현 클래스명. 관측값 CInputScheme(빈/패스스루), CBasicInputScheme(기본), CAdvancedScheme(고급). 문자열로 보관 아니오 ""
flag 인식 옵션 플래그. 대표 구현 기준 현재 무시(읽지 않음)
기타(flagex 등) 본가가 출력할 수 있으나 대표 구현 기준 미해석(무시)

이 요소가 열리는 동안 파서는 내부 섹션을 인식부(Scheme)로 두어, 그 안의 Key 만 글쇠표 항목으로 받아들인다(§1.10 참조).

1.9 KeyTable (@name, @flag, @from, @to)

InputSchemeSetting 아래 글쇠 배열. ASCII 글쇠코드 → 값-식 매핑.

속성 의미 필수 기본값
name 배열 이름(표시용). 컴파일된 배열 이름으로 전달 아니오 ""
flag 배열 옵션 플래그. 대표 구현 기준 현재 무시
from 채워진 글쇠코드 범위의 시작(보통 인쇄가능 ASCII 시작) 아니오 33(0x21)
to 글쇠코드 범위의 끝(보통 ASCII 끝) 아니오 126(0x7E)

from/to 는 정수 파싱 실패 시 각각 33/126 으로 폴백한다. 대표 구현에서 from/to 는 범위 메타데이터로 보관만 되고, 실제 Key 적재는 개별 at 값으로만 이뤄진다(범위 밖 at 도 들어오면 그대로 저장).

1.10 Key (@at, @value)

글쇠 1개의 정의. InputSchemeSetting(인식부 섹션) 안에서만 글쇠표 항목으로 처리된다(다른 섹션의 Key 태그는 무시).

속성 의미 필수 기본값
at 기준 ASCII 글쇠코드(시프트되지 않은 US-QWERTY 문자, 0x21~0x7E). 정수 (누락/파싱 실패 시 정수 파싱 오류)
value 글쇠가 내는 값-식(C 연산자 문법). 키다운 시 평가되어 자모(H3|…)·명령(C0|…)·문자·항목전환(!A)·산술 결과를 낸다. 원문과 파싱된 식을 함께 보관하고, 컴파일 시 at → 식 맵으로 만든다 (누락 시 빈 식 평가)

value 의 식 문법·태그(H3|, C0|, !A)·변수(T,P,A~F,O) 상세는 §2 참조. value 파싱이 실패하면 글쇠 식 오류로 전체 파싱이 실패한다.

예:

<KeyTable name="3-final" from="33" to="126">
  <Key at="0x6B" value="H3|G_"/>            <!-- 'k' → 초성 ㄱ -->
  <Key at="0x24" value="T ? H3|0x1F4 : 0x24"/> <!-- 조합 중이면 토글(500), 아니면 '$' -->
</KeyTable>

1.11 GeneratorSetting (@object, @flag, …)

낱자 생성/조합부. 결합표·가상단위표·오토마타·백스페이스 규칙을 담는다.

속성 의미 필수 기본값
object 생성부 구현 클래스명. 관측값 CIme(빈), CNgsIme(기본), CNgsImeEx(고급). CNgsIme 접두로 한글 항목을 판별 아니오 ""
flag 생성 옵션 플래그. 대표 구현 기준 현재 무시
기타(flagex 등) 미해석(무시)

이 요소가 열리는 동안 섹션은 생성부(Generator)가 되며, 그 안의 자식표들이 채워진다. 닫히면 섹션은 비활성으로 돌아간다.

1.12 UnitMix (@unit, @a, @b, @to)

UnitMixTable 아래의 낱자 결합 규칙 1개. “갈래 unit 안에서 낱자 a 에 이어 b 가 들어오면 to 가 된다.” (메커니즘 상세는 §6.)

속성 의미 필수 기본값
unit 낱자 갈래. CHO/JUNG/JONG 중 하나 (다른 값이면 갈래 오류)
a 첫 낱자(mnemonic 또는 raw 코드). 갈래 문맥으로 해석 (해석 실패 시 낱자 오류)
b 이어지는 낱자. 일반 낱자, 또는 토글 센티넬 500(=H3|0x1F4, 같은-글쇠 된소리). 500 은 토글 코드로 치환되어 결합 키로 쓰인다. b 가 가상단위로 풀리면 결합 정의로는 오류 (해석 실패 시 낱자 오류)
to 결합 결과 낱자 (해석 실패 시 낱자 오류)

컴파일 결과는 (Category, a_cp, b_cp) → to_cp 맵. b="500" 인 경우 b_cp 는 토글 상수가 된다. 구체 mnemonic↔코드 대응과 토글 상수값은 본 사양 범위 밖이다.

상위 컨테이너 UnitMixTable 자체에 @predefined(예 DOOBEOLSIK/SEBEOLSIK)가 올 수 있다. 미리 정의된 자판 묶음 이름으로, 본 표를 그 기본 묶음으로 초기화한다(묶음 내용은 미확인).

1.13 VirtualUnit (@unit, @from, @to)

VirtualUnitTable 아래 가상 단위 1개. 내부 id(from)를 실제 낱자(to)에 별칭으로 묶는다. 오토마타/글쇠표가 구체 자모 대신 안정적인 내부 슬롯을 참조하게 한다(겹모음 앵커 모음 등). (메커니즘 상세는 §6.)

속성 의미 필수 기본값
unit 갈래(CHO/JUNG/JONG) (다른 값이면 갈래 오류)
from 가상 단위 id(정수). 예 128/129/130 계열 (누락/파싱 실패 시 정수 오류)
to 별칭이 가리키는 실제 낱자(mnemonic 또는 raw 코드) (해석 실패 시 낱자 오류)

컴파일 결과는 from_id → 자모 맵. 구체 id 와 대응 자모는 §6.4 의 관찰값 참조.

1.14 AutomataTable (@default, @predefined)

조합 상태기 컨테이너. Automata 행들을 담고, 시작 상태를 지정. (상태 전이 모델은 §4.)

속성 의미 필수 기본값
default 상태기의 시작 상태 id(정수 문자열). 정수로 읽어 시작 상태에 둔다 아니오 0
predefined 미리 정의된 오토마타 이름(예 SEQUENTIAL). 본 표를 그 기본 상태기로 초기화 아니오 없음

행이 하나도 없으면 컴파일된 오토마타 맵이 비고, 엔진은 내장 기본 휴리스틱으로 동작한다.

1.15 Automata (@state, @value, @default, @remark)

상태기의 한 상태에 대한 전이 규칙. H3| 낱자 입력 시 현재 상태의 value 식을 평가해 다음 상태/동작 코드를 얻고, 적용 불가 시 default 식을 쓴다. (의미·결과 코드는 §4.)

속성 의미 필수 기본값
state 이 규칙이 적용되는 현재 상태 id(정수). 키-식의 T 가 이 값을 읽는다 아니오 0(파싱 실패 시)
value 입력이 낱자일 때 평가하는 전이 식. 결과 정수 = 다음 동작/상태. 식으로 컴파일 (누락 시 빈 식; 식 오류면 오토마타 식 오류)
default value 가 적용되지 않을 때(낱자가 아닐 때 등)의 폴백 식 아니오 빈 식(식 오류면 오토마타 식 오류)
remark 사람이 읽는 주석(예 “초기 상태”). raw 모델에 보관되나 컴파일된 표로는 전달되지 않음(무시 가능) 아니오 ""

컴파일 결과는 state → {value, default} 맵.

예:

<AutomataTable default="0">
  <Automata state="0" value="1" default="0" remark="초기 상태"/>
  <Automata state="2" value="A&amp;&amp;A!=500 ? 0 : B||C||A==500 ? 2 : -2"
            default="0" remark="완성"/>
</AutomataTable>

1.16 Extra / Bksp (@key, @value1, @value2, @condition1, @condition2)

Extra 컨테이너(자체 속성 없음) 아래의 백스페이스 동작 규칙. 날개셋은 여러 “슬롯”(key="1".."4")을 두며, 그중 최소 슬롯 1·2 는 존재가 분명하다(슬롯 1 = 조합 중일 때의 동작, 슬롯 2 = 비조합 상태의 동작에 대응). 대표 구현은 물리 Backspace 하나에 대응하는 key="1" 슬롯만 컴파일에 사용한다(없으면 기본값). 나머지 슬롯은 raw 모델에 보관만 된다. 슬롯 3·4 의 정확한 정의는 (미확인). (동작 모델은 §5.4.)

속성 의미 필수 기본값
key 슬롯 번호(정수). 대표 구현 컴파일은 key==1 만 사용 아니오 0(파싱 실패 시)
value1 제1동작: 조합 중일 때의 삭제 단위/플래그. | 로 OR. 인식값: ByUnitStep/0=직전 한 타, 1=최하위 낱자 직전 한 타, 2=최하위 낱자 통째, BySyllable/3=글자 통째, BkspAttach=삭제 후 앞 글자에 재조합 부착, ReverseJLTRN=받침부터 역순(=최하위 낱자 직전 한 타로 취급) 아니오 "" → (LastKey, attach 없음)
value2 제2동작: 비조합 상태(앞 완성 글자) 삭제 단위/플래그. 인식 토큰은 value1 과 동일 아니오 "" → LastKey
condition1 제1동작 적용 조건. ReverseJLTRN 이 포함되면 조합 중 삭제 단위를 “최하위 낱자 직전 한 타”로 덮어쓴다 아니오 ""
condition2 제2동작 적용 조건. raw 보관만(컴파일에서 직접 분기에 쓰지 않음) 아니오 ""

컴파일 결과는 백스페이스 동작 한 개({composing, idle, attach}):

알 수 없는 토큰은 무시되고 기본(LastKey/attach 없음)으로 폴백한다. 4개 슬롯 각각이 정확히 어떤 상황(조합 중/직후 완성/경계/정방향)에 대응하는지의 본가 정의는 슬롯 3·4 에 대해 (미확인) — 대표 구현은 위 단순화된 1슬롯 모델만 구현한다.

예:

<Extra>
  <Bksp key="1" value1="ByUnitStep|BkspAttach" value2="BySyllable" condition1="0" condition2="0"/>
</Extra>
<!-- → composing=LastKey, idle=Syllable, attach=true -->

1.17 ShortcutTable / Shortcut 위치 주의

ShortcutTable 자체는 속성이 없는 컨테이너이며 EditorLayer 아래에 둔다. 적합한 파서는 Shortcut 태그를 트리 깊이와 무관하게 전역 단축글쇠 목록으로 수집하므로, ShortcutTable 래퍼가 없어도 Shortcut 은 인식된다(다만 본가 호환을 위해 래핑 권장). 각 Shortcut 속성 의미는 §1.4 참조.

1.18 무시(미해석) 요소 (Ignored / unimplemented)

다음은 날개셋 본가가 출력할 수 있으나 대표 구현이 현재 읽지 않는(조용히 무시하는) 요소다. 추후 구현 시 위 트리에서 해당 위치에 들어간다. (의미는 역설계 노트 기준, 다수 (미확인)):

요소 추정 위치 비고
KeyProgramTable InputSchemeSetting 아래 고급 인식부의 다운/업 타이밍 프로그램. 미해석
UnitAbbrTable GeneratorSetting 아래 낱자 약자표. 미해석
JackolanternTable GeneratorSetting 아래 특수 도깨비불 규칙. 대표 구현 미해석
UserCompoTable, UserCandiTable, UserKeyTable GeneratorSetting 아래 사용자 정의 조합/후보/글쇠. 미해석. UserKeyTable@doobeolchk 관측
HanSubstTable, UnitSubstTable GeneratorSetting 아래 한자/낱자 치환표. 미해석. HanSubstTable@numeric 관측

§2 값-식 언어 (KeyTable value expression)

<KeyTable> 의 각 글쇠는 고정된 문자가 아니라 정수 식(expression) 을 값으로 가진다. 글쇠를 누르면 이 식을 평가해 그 글쇠가 무엇을 내보낼지(완성/조합용 자모, 제어 명령, 또는 그대로 출력할 코드값)를 결정한다. 문법과 연산자 집합은 C 언어 연산자를 그대로 따르며, 렉서 + Pratt(우선순위 등반) 파서 + 평가기로 구현한다. 공식 문서(moogi.new21.org, ngs_menu1)도 “글쇠배열은 …수식으로 표현되며 …수식은 C언어 연산자의 문법을 따릅니다”라고 설명한다.

식은 KeyTable 뿐 아니라 AutomataTable 의 전이 규칙(<Automata value=…>)에도 같은 문법으로 쓰인다(§4). 차이는 어떤 문맥 변수가 의미를 갖느냐일 뿐이다(아래 §2.3).

2.1 어휘 (lexical tokens)

렉서가 인식하는 토큰은 다음과 같다.

토큰 부류 형태 비고
정수 리터럴 0x..(16진) 또는 10진 부호 없는 자릿수만; 음수는 단항 - 로 표현
식별자 [A-Za-z_][A-Za-z0-9_]* 문맥 변수, 태그 키워드(H3/C0), 자모 니모닉(_GG, O_) 모두 이 형태
다문자 연산자 \|\| && == != <= >= << >> 단문자보다 먼저 시도(longest-match)
단문자 연산자 \| ? : ^ & < > + - * / % ! ~ ( )  

주의할 점:

2.2 연산자 우선순위와 결합성

C 언어와 동일한 우선순위를 따른다. 이 사양은 모든 이항 연산자를 좌결합(left-associative) 으로, 삼항 ?: 만 가장 낮은 우선순위로 둔다(C 와 같이 사실상 우결합처럼 동작). 단항 ! - ~ 은 이항보다 강하다. 아래 표는 약한 결합(낮은 우선순위)에서 강한 결합(높은 우선순위) 순이다.

우선순위(약→강) 연산자 분류
최약 ?: 삼항(조건)
1 \|\| 논리합(단축 평가)
2 && 논리곱(단축 평가)
3 \| 비트 OR
4 ^ 비트 XOR
5 & 비트 AND
6 == != 동등 비교
7 < > <= >= 대소 비교
8 << >> 시프트
9 + - 가감
10 (최강 이항) * / % 승제·나머지
단항 ! - ~ 논리 NOT / 부정 / 비트 NOT

평가 의미론:

대표적 우선순위 함정은 <<^ 보다 강하다는 점이다. 119^(P&1)<<5119 ^ ((P&1) << 5) 로 묶인다(§2.7 예시 참조).

2.3 변수 (context variables)

식은 평가 시 주어지는 문맥에서 대문자 한 글자 변수를 읽는다. 이 사양이 모델링하는 변수는 다음과 같다.

변수 의미
T 오토마타/조합 상태 id. 0 = 한글 조합 중 아님. T != 0 ⇒ 조합 중. (key 식에서 가장 흔한 술어)
P 수식어(modifier) 비트마스크. bit0(P&1) = Shift. 상위 비트(Ctrl/Alt 등)는 불투명하게 취급
A 입력(방금 누른) 글쇠를 초성으로 본 서열값(없으면 0; 갈마들이 토글이면 500)
B 입력 글쇠를 중성으로 본 서열값
C 입력 글쇠를 종성으로 본 서열값
D 현재 조합 중인 음절이 이미 가진 초성 서열값
E 현재 조합 중인 음절이 이미 가진 중성 서열값
F 현재 조합 중인 음절이 이미 가진 종성 서열값
O 부가 비트(예: 입력이 두벌식 / 조합중이 두벌식 / 인위 생성). 세벌식이면 0

읽기:

(미확인 / 차이 주의) 일부 날개셋 설정·문서에는 P 가 Caps lock 점등, N 이 Num/Scroll lock 점등, 소문자(a~z)가 사용자 정의 변수, 그리고 다중 오토마타에서의 추가 상태 변수로 쓰인다는 언급이 있다. 대표 구현은 위 표의 변수만 모델링하며, P 를 Caps 가 아니라 Shift 를 담는 일반 수식어 마스크로, T 를 단일 오토마타 상태로 다룬다. lock 점등 변수(N 등)·사용자 변수·다중 오토마타 번호는 (미확인)(confidence: 변수 의미 MEDIUM, 추가 변수 존재 여부 미확인). 알 수 없는 변수를 만나면 평가는 오류를 낸다. (오토마타 경로의 실패-상황 변수 I,J,K,L,M,N 도 §4.2 참조: 현재 단순화/미구현.)

2.4 태그 prefix — “날개셋문자(nchar)” 인코딩

날개셋에서 글쇠가 돌려주는 값은 단순 정수가 아니라 종류 태그가 붙은 값(“nchar”: 한글 낱자, 비한글 일반 문자, 또는 지시를 내리는 비문자)이다. 식 문법에서 이 태그는 TAG|operand 형태로 나타나며, 맨 위 레벨의 비트 OR 가 아니라 값의 종류를 고르는 prefix 다. 파서는 식별자 H3/C0 바로 뒤에 | 가 오면 이를 태그로 보고, 다음 operand(숫자 또는 니모닉)를 한 단위로 읽는다.

Prefix 종류 operand 평가 결과
(없음) 일반 문자/계산값 정수 식 정수값 — 그대로 출력할 코드값
H3\| 한글 낱자(세벌식 낱자 형) 니모닉(_GG,O_) 또는 숫자 자모코드 낱자값 — 조합기/오토마타에 먹임
C0\| 제어/특수글쇠 명령 숫자 명령 id 명령값 — 글리프 대신 동작 수행

이 사양이 파싱·평가하는 것은 H3|(한글 낱자)와 C0|(명령) 두 태그다. 날개셋 포맷 계열에는 이 밖에도 여러 태그가 있다(개념만 기술하고 실제 코드값/서열은 본 사양 범위 밖).

태그 표기 개념(역설계 노트 기준) confidence
A3 다중 문자(한 글쇠가 여러 문자를 한꺼번에 냄) 미확인(대표 구현 미구현)
H3 세벌식 한글 낱자(초/중/종 위치 포함) — 대표 구현 구현됨 HIGH
H21 / H12 다중 한글(두 낱자를 묶어 한 번에) 미확인
H2 두벌식 한글 낱자 미확인
H2J 두벌식 한글의 변형(종성/조합 변형으로 추정) 미확인
C0 특수글쇠/제어 명령 — 대표 구현 구현됨 HIGH
C1 상태 전이(오토마타/조합 상태 변경 지시로 추정) 미확인
KY 글쇠 누름(다른 글쇠 입력을 흉내내는 지시로 추정) 미확인

일반 정수 리터럴도 암묵적으로 “문자” 태그를 갖는 셈이지만, 식 문법상으로는 prefix 없이 쓴다. H3/C0 외 태그는 같은 TAG|operand 골격을 따른다고 보는 것이 합리적이나, 정확한 operand 의미는 (미확인).

H3| operand: 자모 니모닉과 숫자 코드

H3| 의 operand 는 둘 중 하나다(상세는 §3).

C0| operand

C0| 의 operand 는 반드시 숫자다(니모닉을 주면 오류). 평가 결과는 명령값이다. 예: C0|0x82 = 한자 변환(공식 확인). 구체적 명령 id 표와 동작은 §5 참조.

2.5 숫자 특수값

H3|0x…… 의 숫자 operand 는 단순 자모 코드포인트가 아닐 수 있다. 이 사양은 다음 순서로 해석한다(상세는 §3.5).

  1. 500(= 0x1F4) → 갈마들이 토글 sentinel. 실제 자모가 아니라 “같은 글쇠를 다시 눌렀다”는 신호다(같은-키 된소리 토글: ㄱ→ㄲ→ㄱ…). 토글 낱자값으로 평가된다. 그래서 오토마타 식의 A==500 / A!=500 비교가 토글 입력을 구별한다.
  2. id << 16(하위 16비트가 0, 상위가 비0) → 가상 단위. n >> 16 을 가상 단위 id 로 본다. 예: 0x800000 → id 128, 0x810000 → id 129, 0x820000 → id 130. 가상 단위는 VirtualUnitTable 에서 실제 자모로 해석되는 별칭 슬롯이다(예: 128/129/130 = 복합모음 앵커 ㅗ/ㅜ/ㅡ).
  3. 그 외 → 조합용 자모 코드포인트. 유니코드 블록 범위로 초/중/종 위치를 추론한다(현대 U+11xx 계열 + 옛한글 확장-A/B; 구체적 경계는 §3.2 참조).

2.6 평가 결과 값

식 평가의 최종 값은 세 종류 중 하나다.

(한글 항목과 로마자/패스스루 항목은 식이 낱자값을 만들 수 있는지로 구별된다. 한글 조합 항목이면 KeyTable 식에 H3| 가 들어 있다.)

2.7 EBNF 와 예시

expr      := ternary
ternary   := binary ( "?" ternary ":" ternary )?      (* 삼항, C 와 동일 *)
binary    := unary ( binop binary )*                   (* 우선순위 등반; 모두 좌결합 *)
binop     := "||" | "&&" | "|" | "^" | "&"
           | "==" | "!=" | "<" | ">" | "<=" | ">="
           | "<<" | ">>" | "+" | "-" | "*" | "/" | "%"
unary     := ( "!" | "-" | "~" )? unary
           | primary
primary   := number
           | tagged
           | var
           | "(" ternary ")"
tagged    := ("H3" | "C0") "|" operand                 (* nchar 태그; "|" 는 OR 가 아니라 구분자 *)
operand   := number | ident                            (* C0| 는 number 만 허용 *)
number    := "0x" hexdigit+ | digit+                   (* 부호 없음 *)
var       := "T" | "P" | "A".."F" | "O"                (* 문맥 변수 *)
ident     := letter ( letter | digit | "_" )*          (* 변수 또는 자모 니모닉 *)

(binop 의 실제 결합 강도는 §2.2 표를 따른다. EBNF 의 binary 한 줄은 평탄화 표기이며, 파서는 우선순위별로 등반한다.)

예시:

T ? H3|_J : 0x23

조합 중(T != 0)이면 종성 ㅈ(H3|_J, 낱자)을, 아니면 리터럴 0x23(‘#’, 정수)을 낸다. 세벌식에서 숫자열/기호 글쇠가 조합 중에는 받침으로 동작하는 전형적 패턴이다.

119^(P&1)<<5

<<^ 보다 강하므로 119 ^ ((P&1) << 5) 로 묶인다. Shift 안 누름(P&1==0): 119 ^ 0 = 0x77 ='w'. Shift 누름(P&1==1): 119 ^ 0x20 = 0x57 ='W'. 즉 ^(P&1)<<5 는 ASCII bit5(=0x20)를 토글해 대소문자를 뒤집는 관용구다. 이 식은 낱자를 만들지 않으므로 로마자/패스스루 글쇠로 분류된다.

T ? H3|0x1F4 : 0x24

조합 중이면 0x1F4(=500) → 갈마들이 토글 sentinel(토글 낱자), 아니면 '$'(0x24). 이 토글이 같은-키 된소리 순환을 일으킨다.

A && A!=500 ? 0 : B||C||A==500 ? 2 : -2

AutomataTable “완성” 상태의 전이 식. 들어온 게 (토글 아닌) 초성이면 새 글자 시작(0), 중성·종성 또는 토글이면 현재 음절 유지(2), 그 밖이면 거부/방출(-2). 변수가 불리언이 아니라 서열 코드를 담기에 A!=500 / A==500 으로 토글을 가려낸다.


§3 한글 낱자 모델 · 니모닉 · 서열

날개셋 XML 의 글쇠 값 수식에서 한글을 가리키는 값은 H3|<operand> 형태를 가진다. H3 태그는 “이 값은 완성된 글자가 아니라 조합기(composer)에 먹일 한글 낱자(jamo unit)” 라는 뜻이고, <operand> 가 어느 낱자인지를 지정한다. 이 절은 그 operand 가 가리키는 낱자 모델, operand 를 쓰는 니모닉(mnemonic) 표기, 그리고 니모닉/숫자를 실제 자모로 푸는 해석 규칙과, 날개셋 오토마타가 내부에서 쓰는 서열(序列, sequence) 번호 개념을 정리한다.

3.1 낱자(unit) 모델

날개셋의 낱자 하나는 두 가지 정보로 구성된다.

낱자 모델은 (갈래, 코드포인트) 쌍으로 표현된다.

category ∈ { 초성(Cho), 중성(Jung), 종성(Jong) }
jamo = (category, codepoint)

여기서 핵심은 갈래와 코드포인트가 짝을 이뤄야 비로소 낱자가 결정된다는 점이다. 같은 “ㄱ” 이라도 초성 ㄱ(U+1100)과 종성 ㄱ(U+11A8)은 서로 다른 코드포인트를 가지므로, 갈래 정보 없이 자음 글자만으로는 어느 낱자인지 확정되지 않는다. 니모닉 표기(§3.3)가 위치를 밑줄로 표시하는 이유가 바로 이것이다.

H3| operand 가 풀린 결과는 세 종류의 낱자로 구분된다.

낱자 종류 의미 operand 예
일반 자모 보통의 한글 낱자(초/중/종성) _GG, O_, 0x114C
토글 같은-키 된소리 토글 sentinel (값 500 = 0x1F4) 0x1F4, 500
가상 단위 미해결 가상 단위 id (id<<16 인코딩) 0x800000(=128), 0x810000(=129)

토글과 가상 단위는 글자 정체가 아니라 조합 동작을 가리키는 특수 값이다. 500 은 “같은 글쇠를 다시 눌렀다” 는 신호(갈마들이/된소리 토글)이고, id<<16 형태(하위 16비트가 0, 상위가 비0)는 VirtualUnitTable 로 해소해야 하는 추상 슬롯 id 다(실제 자모 코드값과 충돌하지 않도록 상위 워드에 id 를 실어 구분).

3.2 갈래 추론: 코드포인트 영역으로의 분류

operand 가 숫자(raw 코드포인트)로 주어지면, 어떤 갈래인지는 그 코드포인트가 속한 유니코드 블록 범위로 정해진다. 이 사양이 쓰는 경계는 다음과 같다.

코드포인트 범위 갈래 비고
U+1100 – U+115F 초성 현대 + 옛 초성, 초성 채움문자 포함
U+1160 – U+11A7 중성 중성 채움문자 + 현대/옛 중성
U+11A8 – U+11FF 종성 현대 + 옛 종성
U+A960 – U+A97F 초성 Hangul Jamo Extended-A (옛 초성)
U+D7B0 – U+D7CA 중성 Hangul Jamo Extended-B (옛 중성)
U+D7CB – U+D7FF 종성 Hangul Jamo Extended-B (옛 종성)

즉 옛한글/확장 영역 코드포인트도 같은 영역-기반 규칙으로 초/중/종성이 자동 결정된다. 이 표 밖의 값(예: 일반 ASCII)은 한글 낱자가 아니므로 갈래를 얻지 못한다.

3.3 니모닉(mnemonic) 표기

operand 가 숫자가 아니면 니모닉 으로 본다. 니모닉은 자모의 로마자 약기호와 밑줄(_) 위치 로 갈래를 함께 적는 표기다.

3.3.1 핵심 토큰 (글자 정체)

밑줄을 떼고 남은 알파벳 토큰이 “어느 글자인가” 를 정한다. 단일 자음, 모음, 그리고 쌍/겹자음·복합모음 토큰이 있다.

이 핵심 토큰은 위치와 무관하게 호환 자모(U+31xx) 한 값으로 매핑된다. 호환 자모는 “초성 ㄱ” 도 “종성 ㄱ” 도 모두 같은 ㄱ(U+3131)으로 보는, 위치를 구분하지 않는 표준 낱자 글리프다. 실제 숫자 매핑값은 본 사양 범위 밖이다.

3.3.2 밑줄 위치 규칙

밑줄은 그 자모의 자리(갈래) 를 표시한다.

표기 형태 의미
_X (앞에 밑줄) 종성 _G=받침 ㄱ, _RG=받침 ㄺ, _Q=받침 ㅇ
X_ (뒤에 밑줄) 초성 또는 모음 G_=초성 ㄱ, A_=ㅏ, O_=ㅗ
X (밑줄 없음) 위치 미지정 (글자 정체로 추론) GG, WA, EUI

뒤에 밑줄(X_)은 “초성 자리거나 모음” 을 뜻한다. 자음이면 초성, 모음이면 중성으로 갈린다. 이는 모음에는 종성/초성 구분이 없기 때문이며, 모음의 핵심 토큰 자체가 자음과 겹치지 않아 글자 정체만으로 모음/자음을 구별할 수 있다.

3.3.3 EBNF (니모닉 문법)

mnemonic   := jong | leading | bare
jong       := "_" core            (* 앞 밑줄 → 종성 *)
leading    := core "_"            (* 뒤 밑줄 → 초성 또는 모음 *)
bare       := core                (* 밑줄 없음 → 글자 정체로 추론 *)
core       := consonant | cluster | vowel
consonant  := "G"|"N"|"D"|"R"|"L"|"M"|"B"|"S"|"Q"|"NG"|"J"|"C"|"K"|"T"|"P"|"H"
cluster    := "GG"|"DD"|"BB"|"SS"|"JJ"           (* 쌍자음 *)
            | "GS"|"NJ"|"NH"|"RG"|"RM"|"RB"|"RS"|"RT"|"RP"|"RH"|"BS"  (* 겹받침 *)
vowel      := "A"|"E"|"O"|"U"|"I"|"AE"|"EO"|"EU"
            | "YA"|"YAE"|"YEO"|"YE"|"YO"|"YU"
            | "WA"|"WAE"|"OI"|"UEO"|"WE"|"WI"|"EUI"

3.4 니모닉 → 자모 해석 규칙

니모닉 한 개를 실제 자모(갈래 + 조합용 코드포인트)로 푸는 절차는 다음과 같다.

  1. 밑줄 분리 — 앞 밑줄이면 종성 후보, 뒤 밑줄이면 (초성/모음) 후보, 없으면 미정. 남은 알파벳이 핵심 토큰이다.
  2. 글자 정체 결정 — 핵심 토큰 → 호환 자모(§3.3.1).
  3. 갈래 확정 — 우선순위:
    • 문맥(ctx) 이 주어지면(예: UnitMixTable 의 unit="CHO|JUNG|JONG" 처럼 상위 규칙이 갈래를 못 박는 경우) 그 갈래를 강제한다.
    • 그렇지 않으면 밑줄 위치 로 정한다(_X → 종성).
    • 그래도 미정(X_ 또는 bare)이면 글자 정체 로 정한다. 호환 자모가 모음이면 중성, 아니면 초성.
  4. 코드포인트 변환 — 확정된 갈래에 맞춰 호환 자모를 그 갈래의 조합용 코드포인트로 되돌린다(초성 U+1100 영역 / 중성 U+1160 영역 / 종성 U+11A8 영역).

해석 예 (테스트로 검증된 값):

니모닉 문맥 결과 갈래 조합용 cp 글자
G_ 없음 초성 U+1100 ㄱ 초성
_G 없음 종성 U+11A8 받침 ㄱ
A_ 없음 중성 U+1161
O_ 없음 중성 U+1169
EUI 없음 중성 U+1174
_RG 없음 종성 U+11B0 받침 ㄺ
Q_ 없음 초성 U+110B 초성 ㅇ
_Q 없음 종성 U+11BC 받침 ㅇ
RS JONG 종성 U+11B3 받침 ㄽ
GG CHO 초성 U+1101 초성 ㄲ
WA JUNG 중성 U+116A

마지막 세 줄은 밑줄 없는 bare 토큰이라도 문맥(UnitMix 의 갈래)이 있으면 그것으로 확정됨을 보여준다.

3.5 숫자 operand 해석

operand 가 0x.. 16진 또는 10진 정수면 다음 순서로 푼다.

  1. 값이 500(0x1F4) 이면 → 같은-키 토글.
  2. 하위 16비트가 0이고 상위가 비0이면(id<<16) → 가상 단위. 예: 0x800000→128, 0x810000→129, 0x820000→130.
  3. 그 외에는 조합용 자모 코드포인트 로 보고 §3.2 의 영역 규칙으로 갈래를 추론한다. 이 경로로 옛한글/확장 영역의 자모를 니모닉 없이 직접 지정할 수 있다(예: 0x114C = 옛이응 초성 ㆁ → 초성, 0x119E = 아래아 ㆍ → 중성).

3.6 호환 자모 다리 (compatibility-jamo bridge)

조합용 자모(U+1100/U+1160/U+11A8 영역)는 한 음절로 결합될 때만 정상적으로 렌더링되고, 홀로 출력되면 보이지 않거나 어중간하게 보일 수 있다. 그래서 낱자 하나를 독립적으로 내보낼 때 는 위치를 구분하지 않는 표준 호환 자모(U+3130 영역)로 환산해야 한다. 이 변환은 한글 자모의 유니코드 사실에 해당한다. (홑낱자 출력의 설정-단위 재정의는 FinalConvTable, §6.)

기본 환산은 갈래별로 이뤄진다(현대 자모면 호환 자모 U+31xx 반환, 옛한글이면 환산 없음).

초성  cp → 호환 자모(있으면)
중성  cp → 호환 자모(있으면)
종성  cp → 호환 자모(있으면)

라운드트립 예: 초성 ㄱ(U+1100) ↔ 호환 ㄱ(U+3131), 종성 ㄱ(U+11A8) ↔ 같은 호환 ㄱ(U+3131), 받침 ㄺ(U+11B0) ↔ 호환 ㄺ(U+313A). 초성·종성이 같은 호환 자모로 모이는 것이 핵심이다. 현대 자모 집합 밖(옛한글)이면 환산값이 없으며, 이때의 최종 환산은 상위 설정의 변환표(FinalConvTable 등)에 의존한다. (옛한글의 호환 자모 환산 규칙 세부는 본 절 범위 밖.)

3.7 서열(序列, sequence) — 개념만

날개셋 오토마타의 전이 수식은 입력/조합 중인 한글의 초·중·종성을 변수(A~F 류)로 읽어 비교·분기한다. 이때 변수가 담는 값은 유니코드 코드포인트가 아니라 날개셋 내부에서 자모마다 부여한 정렬 번호, 즉 서열번호 다. 같은 갈래 안에서 자모들을 일정 순서로 줄세운 1부터 시작하는 정수 인덱스라고 보면 된다.

서열의 성질(개념):

실제 서열 숫자표(코드포인트→서열 매핑 전체)는 본 사양서에 싣지 않는다(초성·중성·종성 갈래별 표와 (category, cp) 조회로 다룬다). 이 표는 갈래별로 코드포인트 오름차순 정렬되어 이진 탐색으로 조회되며, 표에 없는 코드포인트(한글 자모가 아닌 값)에는 서열이 없다.


§4 조합 오토마타 (AutomataTable)

AutomataTable 은 날개셋 입력기의 한글 조합 핵심이다. 글쇠가 낱자(H3|… 값, 즉 jamo unit)를 내놓을 때, 그 낱자를 현재 조합 중인 음절에 어떻게 합칠지(초/중/종성 어느 칸에 넣을지, 음절을 끊을지, 무시할지)를 상태 기계(state machine) 로 결정한다. 키 배열(KeyTable)이 “이 글쇠는 무슨 낱자인가”를 정하면(§2), 오토마타가 “그 낱자를 지금 상태에서 어떻게 처리하는가”를 정한다.

4.1 상태 기계 모델 (state-machine model)

오토마타는 언제나 하나의 정수 상태(state id) 를 가진다. 한글을 조합하고 있지 않은 상태는 0, 조합 중인 상태는 양의 정수다. 표 전체에는 시작 상태가 default 속성으로 지정된다(보통 0).

<AutomataTable default="0">
  <Automata state="0" value="…" default="…" remark="초기 상태"/>
  <Automata state="1" value="…" default="…" remark="미완성 상태"/>
  <Automata state="2" value="…" default="…" remark="한글 완성 상태"/></AutomataTable>

<Automata> 행은 하나의 현재 상태(state)에 대한 전이 규칙이다. 처리 흐름은 다음과 같다.

  1. 현재 상태가 S 일 때 새 낱자가 들어오면, 행 S 의 식을 평가한다.
  2. 식의 결과(정수)가 다음 동작/다음 상태가 된다.
  3. 양수면 “그 상태로 조합을 계속”, 0 이하는 아래 표(결과 코드)대로 음절 확정·무시·특수 융합을 뜻한다.

각 행에는 두 가지 식이 있다.

속성 이름 언제 평가되나
value 일반 식(value 식) 한글 조합이 가능하다고 가정하고, 다음에 어느 상태로 갈지를 결정하는 일반 상황(normal)
default 실패 식(default 식) 일반 식의 조합 시도가 실패했을 때, 조합을 어떻게 종료할지 결정하는 실패 상황(failure)

default 는 “그 외/항상” 같은 폴백이 아니라, 의미상 “낱자 결합·허용 한글 범위 제약 때문에 조합 시도가 실패한 뒤 어떻게 마무리할지”를 따로 적는 식이다. (개념 출처: 역설계 노트 및 공개 개념 설명.)

전이 평가는 현재 상태의 value 식을 먼저 평가하고, 정수가 안 나오면 default 식을 평가하며, 그래도 정수가 안 나오면 내장 휴리스틱 경로로 떨어진다.

r = automata[state].value 평가      // 일반 식
  └ 실패 → automata[state].default 평가   // 실패 식
      └ 실패 → 휴리스틱 폴백
결과 코드 r 해석

4.2 식에서 쓰는 변수 (context variables)

식은 KeyTable 과 같은 C-연산자 수식 언어를 쓰며(? :, ||, &&, |, ==, 산술 등; §2), 다음 변수들을 읽는다. 핵심은 변수의 의미가 일반 상황과 실패 상황에서 달라진다는 점이다.

변수 일반 상황 실패 상황
A, B, C 입력 글쇠의 초·중·종성 서열(코드). 그 낱자가 초성으로 쓰일 수 있으면 A≠0(그 초성 서열값), 중성이면 B, 종성이면 C. 없으면 0. (예: 중성 ㅏ → A,B,C = 0,1,0) 모두 0. 글쇠 정보는 I,J,K 로 옮겨감
T 언제나 0 실패 사유. 낱자 결합이 더 안 돼서 실패 = 1, 허용 한글 범위 제약에 걸려 실패 = 2 이상
I, J, K 언제나 0 실패한 입력 글쇠의 초·중·종성 서열값
L, M, N (쓰지 말 것; 직전 값이 그대로 유지됨) 허용 범위 제약 실패(T≥2)일 때 실패한 그 음절의 초·중·종성 코드 (개념상 D~FI~K 가 결합돼 만들어진 값)
D, E, F 조합 중인 음절의 초·중·종성 코드 (상황과 무관하게 의미 동일). 조합 중이 아니면 모두 0. (예: ‘까’ 조합 중 → D,E,F = ㄲ서열,ㅏ서열,0) 동일
O 부가 비트(0~7). 이번 글쇠가 두벌식 날개셋문자면 bit1, 직전까지 두벌식 문자로 조합 중이었으면 bit2 가 켜짐. 추가로 실제 타자가 아니라 bksp·무한 낱자 수정·특수글쇠 등으로 인위 생성 중이면 bit4 도 켜짐 동일
소문자 알파벳 사용자 변수. 자유롭게 값을 대입·확인. 글쇠 식에서 지정한 값과도 연동 동일

L~N 이 일반 상황에서 제공되지 않는 이유: 일반 상황의 계산은 낱자 결합을 시도하기 전에 일어나므로, 결합 결과(완성될 음절 코드)는 아직 알 수 없다. 그래서 결합 결과가 필요한 정보는 실패 상황에서만 L~N 으로 준다.

설계 권고: 가능하면 A,B,C(입력 글쇠)만으로 동작이 결정되도록 만드는 것이 좋다. D,E,F(조합 중 음절)까지 쓰면 더 정교한 오토마타를 더 적은 상태 수로 만들 수 있다.

이 사양의 문맥 변수는 현재 T,P,A,B,C,D,E,F,O 를 노출한다(§2.3). 오토마타 경로에서는 A,B,C 에 입력 낱자의 서열, D,E,F 에 조합 중 음절 각 칸의 서열을 채워 평가한다. 실패-상황 변수(I,J,K,L,M,N)와 사용자 소문자 변수, T≥2 의 다단계 실패 사유는 (미확인/단순화). 실제 서열 숫자값은 표로 옮기지 않는다.

4.3 결과(다음상태) 코드 의미 (result codes)

식의 결과를 r 이라 할 때:

r 이름 의미
양수 (임의의 n>0) 조합 계속 그 낱자를 현재 음절의 알맞은 칸에 넣고(차 있으면 결합/교체), 상태를 n 으로 바꿔 계속 조합
0 다음 글자로 조합 시작 현재 음절을 확정(commit) 하고, 이 낱자로 새 음절을 시작
-1 무시 이 입력을 무시(소비만, 조합 상태 불변)
-2 무한 낱자 수정 (overwrite) 음절을 확정하지 않고 같은 칸을 결합 또는 겹쳐쓰기(덮어쓰기). 상태 유지. 예: ‘안’ 조합 중 ㅎ→ ‘ㅎ’(초성 교체)

음수 결과는 단순한 “거부”가 아니라, 현재 조합 상태와 새 입력을 제각기 다른 방식으로 융합한 뒤 조합을 끝내거나 새로 시작하는 동작이다. 다음은 알려진 고급 음수 코드다. 예시는 ‘안’ 을 조합 중에 ㅎ(겹받침 ㄶ로 결합 가능) 또는 ㅇ(결합 불가)을 받았을 때의 결과로, | 는 새 음절 조합 시작 지점을 뜻한다.

r 이름 ㅎ 적용 ㅇ 적용
-3 이 글자를 결합시킨 후 조합 중단
-4 이 글자를 완성된 글자로 뺀 후 조합 중단 않| 안ㅇ|
-5 이 글자를 무시하고 조합 중단 안ㅎ| 안ㅇ|
-6 무한 낱자 수정 후 조합 중단 안| 안|
-7 조합 전체를 무효화 (조합 폐기) (조합 폐기)
-8 현 글자에 새로 조합 시작 | |
-9 현 글자를 대체 후 조합 중단 ㅎ| ㅇ|
-10 직전 타와 지금 입력을 다음 글자로 아 ㄶ| 아ㄴ ㅇ|
-11 지금 입력과 직전 타를 교환함

(위 -3..-11 의 분류·예시 결과는 개념 이해용 자료에 근거하며, 표현은 새로 기술. 일부 칸의 정확한 결과 글자는 미확인.)

결과 코드 처리 범위: 양수·0·-1·-2 는 위 표대로 정확히 처리된다. 그 외 음수(-3..-11)는 대표 구현 기준 보수적으로 “현재 음절 확정 후 이 낱자로 새 음절 시작”(사실상 0 과 같은 폴백)으로 처리하며, 정교화는 예정 상태다(미확인). -10/-11 같은 “직전 타 교환·이월”은 별도의 특수글쇠(C0 명령) 경로 — 직전 두 글쇠 교환(0x23), 마지막 타 분리(0x21) 등 — 로 부분 구현돼 있어, 오토마타 결과 코드와 의미가 겹친다(§5).

-2(무한 낱자 수정)는 다음과 같이 동작한다: 대상 칸이 비었으면 채우고, 차 있으면 UnitMixTable 결합 규칙이 있으면 결합, 없으면 교체(겹쳐쓰기) 한다. 직전 겹쳐쓰기 한 번은 따로 기억되어, 특수글쇠 “무한 낱자 수정 분리(0x13)/복원(0x14)”이 옛 낱자를 되살리거나 새 낱자를 다음 글자로 분리하는 데 쓰인다(§5.3).

4.4 동작 예시 (worked example)

세벌식 표를 모델로 읽으면, 일반적인 3상태 오토마타는 대략 다음과 같이 동작한다(상태 id: 0=초기, 1=미완성, 2=완성).

이는 “초성이 들어왔을 때만 다음 글자로 넘어가고, 중성·종성은 현재 글자를 계속 고친다”는 세벌식 동작을 그대로 인코딩한 것이다.

실제 동작 예:

k f      → ㄱ + ㅏ           → preedit "가"      (상태 1→2: 양수 계속)
k f x    → 가 + 받침 ㄱ       → preedit "각"      (상태 2 유지: 종성 보완)
k f h f  → 가 + ㄴ + ㅏ       → commit "가", preedit "나"  (상태 2 에서 초성 ㄴ → 0: 새 글자)
k / f    → ㄱ + ㅗ + ㅏ       → preedit "과"      (겹모음 결합 ㅘ)
k $ f    → ㄱ + 토글(500) + ㅏ → preedit "까"      (500: 음절 안에서 된소리 토글, 상태 유지)

4.5 모아치기와의 관계 (relation to 모아치기 / chord input)

세벌식은 초·중·종성 글쇠 역할이 분명해서 한 음절을 이루는 낱자들을 거의 순서에 무관하게(또는 동시에 가깝게) 칠 수 있다 — 이것이 모아치기다. 오토마타는 여기에서 두 가지로 기여한다.

(개념 근거: 역설계 노트와 공개 개념 자료.)


§5 특수글쇠(C0) 및 Backspace 동작

날개셋 값-식에서 C0|N 형태는 특수글쇠(special key) 를 뜻한다(§2.4). 일반 낱자 투입(H3|…)이나 문자 리터럴과 달리, 조합 중인 음절을 편집 하거나 조합 흐름을 제어 하는 명령(command)이다. 코드 N(하위 1바이트)이 동작을 고른다. 이 절은 인식되는 코드 목록, 각 코드의 의미, 그리고 물리 Backspace 키의 동작 모델(<Bksp>)을 다룬다.

아래 동작 설명은 역설계로 관찰한 동작과 역설계 노트를 바탕으로 새로 기술한 것이다. 서열·코드 상수 자체의 구체 숫자는 본 사양 범위 밖이다.

5.1 특수글쇠가 처리되는 방식

한 음절에 투입된 단위(낱자/토글)의 순서를 이력(history)으로 보관한다. 대부분의 편집 특수글쇠는 슬롯(초/중/종성)을 직접 건드리지 않고, 이력을 편집한 뒤 처음부터 재생(replay) 해 음절과 오토마타 상태를 다시 맞춘다. 슬롯만 손대면 이후 Backspace 가 이력과 어긋나 깨지기 때문이다.

특수글쇠 N  ──▶  history 편집(삭제/이동/교환/복원)
            ──▶  replay: 현재 음절·오토마타 상태 재구성
            ──▶  결과 { commit, preedit, consumed, delete_before }

IBus/Wayland 환경에서 불가능하거나(예: 커서 이동, forward-delete) 별도 서브시스템이 필요한 코드(한자 후보 변환)는 대표 구현에서 구현되지 않았고, 기본 동작(현재 음절 확정) 으로 떨어진다.

5.2 C0 코드별 동작과 구현 상태

범례: 구현됨 = 대표 구현이 전용 동작을 수행. 폴백 = 현재 음절을 확정하고 끝(전용 동작 미구현). (미확인) = 명세 추정이며 검증 못 함.

코드 동작(요지) 대표 구현 상태
0x2 초성만 삭제하고 같은 글자 계속 조합 구현됨
0x3 중성만 삭제 구현됨
0x4 종성만 삭제 구현됨
0x5 초성을 앞 글자로 이동(앞 확정 글자에 결합, 그 성분을 앞쪽에) 구현됨(surrounding-text 필요)
0x6 중성을 앞 글자로 이동 구현됨(동상)
0x7 종성을 앞 글자로 이동 구현됨(동상)
0x8 초성을 뒤 글자로 분리(현재 음절 확정, 초성으로 새 음절) 구현됨
0x9 중성을 뒤 글자로 분리 구현됨
0xA 종성을 뒤 글자로 분리 구현됨
0xB 커서 한 칸 앞으로 이동 (미확인) 폴백(확정만)
0xC 커서 한 칸 뒤로 이동 (미확인) 폴백(확정만)
0xD 조합 중단(확정) (미확인) 폴백(확정만)
0xE 조합 중단 변형 (미확인) 폴백(확정만)
0xF 커서/줄 관련 이동 (미확인) 폴백(확정만)
0x10 Delete(커서 뒤 글자 삭제) (미확인) 폴백(미지원: forward-delete)
0x11 Delete 변형 (미확인) 폴백(미지원)
0x12 도깨비불: 종성 끝 자음만 떼어 다음 글자 초성으로 (예 +조합 ) 구현됨
0x13 무한 낱자 수정 분리: 직전 겹쳐쓰기를 취소해 옛 낱자 복원 + 새 낱자를 다음 글자로 (예 확정 + 조합 ) 구현됨(직전 1회 한정)
0x14 무한 낱자 수정 복원: 직전 겹쳐쓰기를 취소해 옛 낱자로 되돌림 (예 ㅏ→ㅐ 직후 누르면 ) 구현됨(직전 1회 한정)
0x15 초성만 남기고 중·종성 삭제 구현됨
0x16 중성만 남기고 초·종성 삭제 구현됨
0x17 종성만 남기고 초·중성 삭제 구현됨
0x18 초성↔종성 맞바꾸기(두벌식 받침 입력용; 대응 낱자 없으면 무동작) 구현됨
0x19 Backspace 부분동작: 직전 한 타 취소 구현됨
0x1A Backspace 부분동작: 최하위 낱자의 직전 한 타 구현됨
0x1B Backspace 부분동작: 최하위 낱자 전체 구현됨
0x1C Backspace 부분동작: 글자(음절) 전체 구현됨
0x1D 현재 조합 글자를 앞 글자에 결합(재결합, 앞으로) 구현됨(surrounding-text 필요)
0x1E 동상 + 두벌식: 초성뿐인 현재 글자의 초성을 종성으로 바꿔 결합 구현됨(동상)
0x1F 뒤 글자와 재결합(forward) (미확인) 폴백(미지원: forward-delete)
0x20 동상 + 두벌식 변환 (미확인) 폴백(미지원)
0x21 마지막 한 타를 분리해 다음 글자로 (예 +조합 ) 구현됨
0x22 앞뒤 글자 교환 (미확인) 폴백(확정만)
0x23 직전 두 글쇠(낱자) 교환 구현됨(조합 중 두 낱자 한정)
0x82~0x85 후보(한자) 변환 관련 폴백(별도 후보 서브시스템 미구현)
0x88, 0x89 Backspace(일반): 조합/달라붙기 가능할 때만 소비 구현됨
0x8A, 0x8B Backspace(항상 가로챔): 비조합·미달라붙기여도 글쇠 소비(원시 문자 미입력) 구현됨

명세상 0x82~0x85(한자 후보), 0x88~0x8B(Backspace 1~4)처럼 0x80 대 코드가 따로 있다. 대표 구현은 Backspace 4종 중 “항상 소비” 여부만 구분하고, 후보 변환 코드는 후보 윈도/한자 사전이 없어 폴백한다.

5.3 동작 그룹별 설명

낱자 삭제 (0x2~0x4) / 낱자만 남기기 (0x15~0x17) 같은 메커니즘이다. 삭제할 낱자 갈래 집합을 정해 이력에서 그 갈래의 단위를 모두 빼고 재생한다. 0x2{초성} 제거, 0x15{중성, 종성} 제거(=초성만 남김) 식이다.

낱자 뒤로 이동 (0x8~0xA) 지정 성분의 단위를 이력에서 떼어내고, 남은 성분으로 현재 음절을 확정한 다음, 떼어낸 단위를 새 음절로 재투입한다. 모아치기(여러 낱자를 거의 동시에 침)와 연동해 +조합 중 으로 가르는 동작이 여기 해당한다. 새 음절 시작이므로 오토마타 상태를 시작 상태로 초기화한다.

낱자 앞으로 이동 (0x5~0x7) 및 재결합 (0x1D/0x1E) 앞에 이미 확정된 글자(직전 음절 스택의 맨 위)를 되살려, 현재 조합 중 낱자들을 그 위에 다시 결합하고, 합쳐진 글자를 조합 상태로 만든다. 앱 화면의 옛 앞 글자는 delete_before=1 로 지우게 한다. 0x5~0x7 은 지정 성분 단위를 결합 순서상 앞쪽으로 재배치하고, 0x1E/0x20 은 두벌식 처리로 초성뿐인 현재 글자의 초성을 종성으로 바꿔 결합한다.

중요: 이 그룹은 surrounding-text(앞 확정 글자 읽기·삭제)가 켜져 있을 때만 동작한다. 프런트엔드가 미지원이면 앱 버퍼와 내부 상태가 어긋나므로 무동작(현재 preedit 유지)으로 떨어진다.

커서/조합 제어 (0xB~0xF), Del (0x10/0x11) 커서 이동·조합 중단·forward-delete 류는 IBus/Wayland 한글 조합 모델에서 직접 구현하기 어렵거나 불가능해 모두 폴백(현재 음절 확정)한다. 세부 의미는 (미확인).

도깨비불 (0x12) 종성의 마지막 자음만 떼어 다음 글자의 초성으로 넘긴다. 떼어낸 종성 자음은 초성 코드로 바꾼 뒤 새 음절을 시작한다. ㄴㅎ으로 친 +조합 .

무한 낱자 수정 분리/복원 (0x13/0x14) “무한 낱자 수정” 은 같은 칸에 결합 규칙이 없는 낱자가 또 오면 이전 낱자를 덮어쓰는(교체) 동작이다(§4.3). 직전 1회의 겹쳐쓰기만 (갈래, 옛, 새) 로 기억한다.

두 코드만은 진입 시 “직전 겹쳐쓰기” 기록을 무효화하지 않는다(다른 모든 특수글쇠는 무효화). 겹쳐쓴 낱자가 이미 다른 편집으로 사라졌으면, 사라진 낱자를 되살리는 유령 입력을 막기 위해 무동작한다.

초·종성 맞바꾸기 (0x18) 초성↔종성을 서로 바꿔 다시 조합한다(중성은 유지). 대응 낱자가 없는 경우(ㄸ/ㅃ/ㅉ 초성, 일부 겹받침 등 변환 불가)는 안전하게 무동작.

Backspace 부분동작 (0x19~0x1C) 물리 Backspace의 4가지 삭제 단위를 각각 별도 특수글쇠로 노출한 것이다. 백스페이스 단위로 매핑된다(§5.4 참조): 0x19=직전 한 타, 0x1A=최하위 낱자의 직전 한 타, 0x1B=최하위 낱자 전체, 0x1C=글자 전체.

마지막 한 타 분리 (0x21) / 직전 두 글쇠 교환 (0x23) 0x21 은 가장 최근 입력 단위 하나를 떼어 다음 글자로 옮긴다(+조합 ). 0x23 은 이력의 마지막 두 단위 순서를 바꿔 재생한다(조합 중 두 낱자에 한정; 커서 앞 확정 문자와의 교환은 미지원). 0x22(앞뒤 글자 교환)는 폴백.

Backspace 1~4 (0x88~0x8B) 임의 글쇠에 Backspace를 배당하기 위한 코드. 0x88/0x89 는 일반 Backspace처럼 동작하고(조합 중이 아니고 달라붙기도 못 하면 글쇠를 응용에 넘김), 0x8A/0x8B 는 그런 경우에도 글쇠를 항상 가로채 원시 문자 입력을 막는다.

5.4 Backspace 모델 (<Bksp>)

물리 Backspace 키 한 개는 설정의 <Bksp key="1"> 슬롯 하나에 대응한다(대표 구현은 key==1 만 사용; §1.16). 각 슬롯은 두 가지 동작과 그 판단 기준을 가진다.

Bksp        = "<Bksp" SP "key=" qkey
                  SP "value1="     qval   (* 제1동작: 조합 중일 때 *)
                  SP "value2="     qval   (* 제2동작: 비조합(앞 완성 글자) *)
                  SP "condition1=" qcond
                  SP "condition2=" qcond "/>" ;
qval        = '"' value-token { "|" value-token } '"' ;
value-token = bksp-unit | "BkspAttach" ;
bksp-unit   = "ByUnitStep" | "BySyllable" | "0" | "1" | "2" | "3" ;
qcond       = '"' { cond-token } '"' ;   (* 예: "ReverseJLTRN", "0" *)

삭제 단위 — value 토큰 또는 condition 의 판단 기준에서 정해진다.

단위 value 토큰 의미
LastKey ByUnitStep, 0 직전에 입력된 한 타만 취소(겹낱자/겹모음/갈마들이 토글을 정확히 한 단계 분해). 기본값.
LowestLastKey 1 최하위 낱자(종성→중성→초성 순으로 채워진 첫 칸)의 직전 한 타.
LowestWhole 2 최하위 낱자 전체(몇 타에 넣었든 통째로).
Syllable BySyllable, 3 글자(음절) 전체를 한 번에.

condition(판단 기준) — 삭제 단위가 value 가 아니라 condition 에 실리는 경우가 있다. 특히 ReverseJLTRN(최하위 낱자 우선, 받침부터 역순)은 condition1 에 오므로, condition1ReverseJLTRN 을 포함하면 조합 중 단위를 LowestLastKey 로 강제한다. value 토큰의 ReverseJLTRN 도 같은 단위로 본다.

value1/value2 (제1·제2 동작)

(미확인) 대표 구현의 비조합 Backspace 경로는 현재 idle 단위 값을 따로 적용하지 않고, BkspAttach 되살리기 시 항상 composing 단위 한 번을 적용한다. 즉 idle 은 컴파일·보존되지만 동작에는 아직 반영되지 않는다.

BkspAttach (앞 글자 달라붙기) value1·value2 중 어느 쪽에든 BkspAttach 가 있으면 attach=true. 켜져 있고 조합 중이 아닐 때 Backspace를 누르면, 직전 확정한 음절(직전 음절 스택 맨 위)을 되살려 조합 상태로 만든 뒤(=앞 글자에 “달라붙기”), 그 음절에서 composing 단위만큼 한 단계 지운다. 앱의 옛 확정 글자는 delete_before=1 로 함께 지운다. 되살릴 음절이 없으면 글쇠를 응용에 넘긴다.

연타 지속성(streak) Backspace를 연달아 누르는 동안에는 최초로 결정된 삭제 단위를 유지한다. 비-Backspace 입력이 들어오면 해제된다. 날개셋의 “연타 시 한 번 정해진 동작을 계속” 거동에 해당한다.

처리 흐름:

Backspace
  ├ 조합 중?
  │   ├ 예 → streak 있으면 그 단위, 없으면 composing 으로 결정·기록
  │   │       → 단위 삭제 → replay → preedit 갱신, consumed=true
  │   └ 아니오
  │        ├ attach && 직전 음절 있음
  │        │     → 앞 음절 되살림 → composing 한 단계 삭제
  │        │     → preedit, delete_before=1, consumed=true
  │        └ 아니면 → consumed=false (응용이 직접 삭제)

컴파일 기본값 <Bksp key="1"> 슬롯이 없으면 composing=LastKey, idle=LastKey, attach=false 가 기본이다. 알 수 없는 value 토큰은 무시되고 기본 단위가 유지된다.


§6 EditorLayer 테이블 및 낱자 결합 (FinalConv · Shortcut · UnitMix · 기타)

이 절은 EditorLayer 의 전역 테이블 두 가지(FinalConvTable, ShortcutTable)와 GeneratorSetting 안의 낱자(jamo) 결합 테이블(UnitMixTable, VirtualUnitTable), 그리고 각 테이블에 붙는 flag 비트의 알려진 의미를 다룬다. 요소·속성의 구조적 정의는 §1에, 여기서는 의미와 메커니즘에 집중한다. 구조적 위치는 다음과 같다.

EditContextSetting
├─ EditorLayer flag="…"
│  ├─ ShortcutTable    →  Shortcut*      (전역 단축글쇠)
│  └─ FinalConvTable   →  FinalConv*     (조합용/옛 자모 → 호환 자모)
└─ InputLayer
   └─ InputEntry
      └─ GeneratorSetting
         ├─ UnitMixTable     →  UnitMix*      (낱자 결합 규칙)
         └─ VirtualUnitTable →  VirtualUnit*  (가상 단위 별칭)

파서는 이들을 편집기 계층(단축글쇠·홑낱자 변환)과 입력 항목(낱자 결합·가상 단위)별로 받아 두었다가, 컴파일 시점에 엔진용 표로 묶는다.

6.1 FinalConvTable / FinalConv — 조합용 자모를 호환 자모로

FinalConvTable := "<FinalConvTable>" FinalConv* "</FinalConvTable>"
FinalConv      := "<FinalConv from=" CodePoint " to=" CodePoint "/>"
CodePoint      := "\"0x" HEX+ "\"" | "\"" DEC+ "\""

<FinalConv> 항목은 코드포인트 한 쌍 (from, to) 이다.

이 표의 방향은 항상 조합용·옛 자모 → 호환 자모 한 방향이며, 홑낱자(standalone) 출력 전용이다. 즉 완성된 음절의 일부가 아니라, 조합 버퍼에 자모 하나만 떠 있는 상태(미완성 초성/중성/종성, 또는 옛한글 잔여물)를 화면에 보여줄 때, 보이지 않는 조합용 자모 대신 사람이 읽는 ㄱ/ㅏ/… 모양으로 정규화한다. 이것은 조합 도중에만 작동하지, 일반 텍스트를 사후에 바꾸는 변환이 아니다.

처리:

홑낱자 환산(jamo):
    호환값 = final_conv[jamo.cp]  if 있으면
           else jamo 의 기본 호환 자모
    호환값을 문자로 변환
측면 근거
방향 조합용/옛 → 호환(U+31xx) from/to 가 명확한 Unicode 블록 매핑
적용 시점 홑낱자 출력 시에만 완성 음절 변환 아님
자료구조 코드포인트→코드포인트 맵 from/to 정수 쌍

위치별로 다른 조합용 자모가 같은 호환 자모로 모이는 점에 유의(예: 초성 ㄱ U+1100 과 종성 ㄱ U+11A8 이 모두 호환 ㄱ U+3131 로 간다). 호환 자모는 초/중/종 위치를 구분하지 않기 때문이다. 구체적인 from/to 숫자값은 기본 호환표 및 설정 파일을 참조한다(개념만 여기 기술).

6.2 ShortcutTable / Shortcut — Editor Layer 전역 글쇠

ShortcutTable 은 어떤 입력 항목(InputEntry)보다 먼저 인식되는 전역 단축글쇠를 모은다. 한/영 전환, 한자 변환, CapsLock 처리 같은 “입력기 차원의 명령”이 여기 산다.

ShortcutTable := "<ShortcutTable>" Shortcut* "</ShortcutTable>"
Shortcut      := "<Shortcut key=" VkName
                   (" modifier=" FlagList)?
                   " usage=" Usage
                   " value=" Value "/>"
VkName        := "\"VK_" IDENT "\""        ; 예: VK_HANGUL, VK_HANJA, VK_CAPITAL
Usage         := "\"IME_SWITCH\"" | "\"KEYCHAR\"" | …
Value         := "\"!" LETTER "\""         ; 입력 항목 전환
               | "\"C0|" Number "\""       ; 명령 주입
               | …                          ; 그 밖의 값-식
FlagList      := Flag ("|" Flag)*

Shortcut 은 네 필드를 갖는다.

Shortcut {
    key:      VK_* 가상 키 이름 (그대로 보존)
    modifier: '|' 로 쪼갠 수식 플래그 목록
    usage:    값 해석 방식
    value:    동작 (전환 / 명령 / 식)
}

파서는 key/modifier/usage/value 를 문자열로만 보존하고 의미 해석은 프런트엔드(IME 프런트)에 맡긴다. 컴파일도 단축글쇠 목록을 그대로 넘긴다.

6.2.1 key — 가상 키 이름

Windows 가상 키 코드(VK_*) 명칭을 쓴다. 자주 보이는 것:

key 물리 키
VK_HANGUL 한/영
VK_HANJA 한자
VK_CAPITAL CapsLock

6.2.2 usagevalue 해석 방식

usage 의미
IME_SWITCH value입력 항목 전환 명령이다. 예: !A
KEYCHAR value마치 입력된 듯 주입되는 문자/명령값이다. 예: C0|0x82(한자 변환)

6.2.3 value 식의 형태

6.2.4 modifier — 수식 플래그

'|' 로 OR 결합된 플래그 목록. CapsLock 단축글쇠에서 관찰되는 것:

플래그 추정 의미 confidence
DONT_EAT 키를 입력기가 먹어치우지 않고 OS 로도 흘려보냄(CapsLock 자체 토글은 유지) HIGH (이름 자명)
KEEP_LAMP (Caps/Num) 램프·LED 상태를 건드리지 않음 HIGH (이름 자명)

사용 예: key="VK_HANGUL" usage="IME_SWITCH" value="!A" 는 한/영 키로 입력 항목을 토글한다. key="VK_HANJA" usage="KEYCHAR" value="C0|0x82" 는 한자 키로 한자 변환 명령을 쏜다. key="VK_CAPITAL" modifier="DONT_EAT|KEEP_LAMP" usage="IME_SWITCH" value="!A" 는 CapsLock 을 항목 전환에 쓰되 잠금/램프는 건드리지 않는다.

6.3 UnitMixTable / UnitMix — 낱자 결합

<UnitMix> 한 행은 “한 갈래(category) 안에서 낱자 a 에 이어 낱자 b 가 들어오면 to 가 된다”는 결합 규칙이다. 한 타로 못 넣는 복잡한 낱자(겹받침, 이중모음, 된소리)를 둘로 쪼개 입력하게 해준다.

UnitMixTable := "<UnitMixTable>" UnitMix* "</UnitMixTable>"
UnitMix      := "<UnitMix unit=" Category " a=" Unit " b=" UnitOrToggle " to=" Unit "/>"
Category     := "\"CHO\"" | "\"JUNG\"" | "\"JONG\""
Unit         := "\"" Mnemonic "\"" | "\"0x" HEX+ "\""   ; 니모닉 또는 raw 코드
UnitOrToggle := Unit | "\"500\""                         ; 500 = 같은-키 토글

raw 모델:

UnitMix {
    unit: CHO / JUNG / JONG (그 외 값이면 갈래 오류)
    a:    첫 낱자
    b:    이어지는 낱자 또는 토글
    to:   결합 결과 낱자
}

6.3.1 컴파일: 결합표로 평탄화

컴파일은 각 행을 (Category, a_cp, b_cp) -> to_cp 형태의 결합 맵으로 펼친다.

combine[(unit, a_cp, b_cp)] = to_cp

b 는 피연산자 해석 규칙에 따라 세 경우로 갈린다.

b 해석 b_cp 비고
일반 자모 그 자모의 cp 일반 낱자 코드포인트
토글 (값 500) 토글 상수 같은-키 토글
가상 단위 낱자 오류(가상 단위는 b 로 불가)

런타임에서는 (cat, a_cp, b_cp) 키로 결합표를 조회한다.

6.3.2 같은-키 토글: b="500"

b="500"(= 0x1F4) 은 실제 자모가 아니라 “같은 글쇠를 다시 눌렀다”는 sentinel 이다(§3.1). 이를 토글 상수로 환산해 결합 키에 넣는다. 같은 갈래에서 대칭쌍을 이루면 된소리 토글이 된다.

동작
unit="CHO" a="G_" b="G_" to="GG" 연타 경로: ㄱ 그리고 ㄱ → ㄲ
unit="CHO" a="G_" b="500" to="GG" 같은-키 재타 경로: ㄱ → ㄲ
unit="CHO" a="GG" b="500" to="G_" 같은-키 재타 경로: ㄲ → ㄱ (토글)

두 경로(b="G_" 의 연타, b="500" 의 같은-물리키 재타)가 모두 ㄲ 을 만든다. 이것이 갈마들이/같은-글쇠 된소리 토글로, Shift 없이 한 키가 ㄱ↔ㄲ 을 순환하게 한다(confidence HIGH). 500 은 키 테이블에서 H3|0x1F4 형태로 조합 도중에 공급된다(§2.7 예시). JONG 결합은 결과가 받침이라도 피연산자에 자음 니모닉을 그대로 쓴다(갈래 문맥이 JONG 이므로 종성으로 해석됨).

실제 결합 숫자표(어떤 a+b 가 어떤 to 로 가는지)는 본 사양 범위 밖이다. 여기서는 메커니즘만 기술한다.

6.4 VirtualUnitTable / VirtualUnit — 가상 단위 별칭

<VirtualUnit> 은 내부 id(from)를 한 갈래 안의 실제 낱자(to)로 별칭(alias)짓는다. 키 테이블이나 오토마타가 “지금 어떤 구체 자모가 들었든 안정적인 내부 슬롯 번호”로 모음을 가리킬 수 있게 한다.

VirtualUnitTable := "<VirtualUnitTable>" VirtualUnit* "</VirtualUnitTable>"
VirtualUnit      := "<VirtualUnit unit=" Category " from=" Number " to=" Unit "/>"

모델·컴파일:

VirtualUnit { unit: Category, from: id, to: 낱자 }

// compile():
각 v 에 대해:
    j = v.to 를 코드포인트(갈래 v.unit)로 변환   // 실패 시 낱자 오류
    virtual_units[v.from] = j                     // from(id) -> 자모

자주 보이는 매핑은 이중모음 앵커 모음 ㅗ/ㅜ/ㅡ 다(to= 값으로 직접 드러나므로 confidence HIGH): 128→ㅗ(O_), 129→ㅜ(U_), 130→ㅡ(EU). 이들은 뒤따르는 모음과 합쳐 ㅘ/ㅙ/ㅚ, ㅝ/ㅞ/ㅟ, ㅢ 를 만드는 “이중모음의 앞 절반” 자리표다. 오토마타의 ㅗ/ㅜ 자기충돌 가드(같은 앵커가 두 번 오면 결합 거부; §4.4)와 짝을 이룬다. 숫자 operand id<<16 인코딩은 §3.5 참조.

6.5 flag 비트의 알려진 의미

여러 요소에 flag(또는 modifier) 속성이 붙는다. 파서는 이를 '|' 기준 분해해 문자열 목록으로 보존하며(EditorLayer 의 flag, Shortcut 의 modifier), 의미 해석은 상위 계층에 맡긴다. 알려진 비트:

위치 플래그 추정 의미 confidence
EditorLayer flag DEL_MOVE 삭제 시 커서 이동 관련 편집 옵션 (미확인)
EditorLayer flag ARROW_MOVE 화살표 키 이동 관련 편집 옵션 (미확인)
Shortcut modifier DONT_EAT 키를 먹지 않고 OS 로도 전달 HIGH (이름 자명)
Shortcut modifier KEEP_LAMP Caps/Num 램프 상태 보존 HIGH (이름 자명)
InputSchemeSetting flag / KeyTable flag / GeneratorSetting flag "0" 항목/테이블별 옵션 비트필드 (미확인)

flag="0" 은 “특별 옵션 없음”으로 보면 무난하다. EditorLayer 의 편집 플래그(DEL_MOVE, ARROW_MOVE)는 이름에서 편집기 거동 옵션임이 짐작되나, 정확한 비트 의미는 보존만 하고 동작에 쓰지 않으므로 (미확인) 으로 표기한다. 그 외 테이블의 flag 정수값은 비트필드일 가능성이 높으나 비트별 의미는 미확인이다.

6.5.1 참고: 기타 GeneratorSetting 테이블

Extra/Bksp(백스페이스 삭제 단위, §5.4), AutomataTable(조합 상태기, §4) 등 다른 GeneratorSetting 하위 테이블은 별도 절에서 다룬다. UnitAbbrTable, JackolanternTable(특수 도깨비불 규칙), UserCompoTable, HanSubstTable 등 일부 테이블은 대표 구현 기준 현재 파싱하지 않고 무시한다(§1.18). 이들은 향후 확장 지점이다.


§7 Conformance & confidence

본 사양의 기준선은 적합한(conformant) 파서/생성기가 실제로 읽고 컴파일하는 동작이며, 본 문서의 모든 동작 기술은 역설계로 관찰한 동작과 공개 공식 자료에 대조해 작성했다.

7.1 적합성 권고 (conformance recommendations)

7.2 미확인 항목 정리 (open / unverified items)

다음은 본 분석 범위에서 확정하지 못했거나, 대표 구현이 아직 구현하지 않은 항목이다.

영역 미확인 내용 위치
version 0x500 의 의미, 다른 버전 값에서의 스키마 차이 §0.3
무시 요소 KeyProgramTable, UnitAbbrTable, JackolanternTable, UserCompoTable/UserCandiTable/UserKeyTable, HanSubstTable/UnitSubstTable 의 정확한 스키마·의미 §1.18
값-식 변수 P=Caps lock·N=Num/Scroll lock 점등 변수, 소문자 사용자 변수, 다중 오토마타 추가 상태 변수의 존재 여부(대표 구현은 T,P,A–F,O 만 모델링) §2.3, §4.2
값-식 태그 A3, H21/H12, H2, H2J, C1, KY 태그의 정확한 operand 의미(대표 구현은 H3/C0 만 구현) §2.4
C0 명령 0x82C0|n 명령 id 의 정확한 수치 의미; 0xB~0x11, 0x1F/0x20, 0x22, 0x82~0x85 동작(대표 구현 폴백) §5.2
오토마타 결과 코드 -3~-11 의 정교한 동작·일부 예시 결과 글자(대표 구현은 0로 폴백) §4.3
오토마타 실패-변수 I,J,K,L,M,NT≥2 다단계 실패 사유(단순화/미구현) §4.2
Bksp 4개 슬롯(key="1".."4") 각각의 본가 정의(슬롯 1·2 는 존재 확인, 3·4 는 미확인); idle 단위의 비조합 경로 미반영 §1.16, §5.4
flag 비트 DEL_MOVE, ARROW_MOVE, 테이블별 flag 정수의 비트별 의미 §6.5
옛한글 옛한글의 호환 자모 환산 규칙 세부 §3.6

confidence 등급은 본문 각 표에 HIGH/MEDIUM/LOW/(미확인)으로 병기했다. “이름이 자명한” 플래그(DONT_EAT, KEEP_LAMP)와 공식 문서로 확인된 사실(C0|0x82=한자 변환, 값-식이 C 연산자 문법을 따름)은 HIGH, 역설계로 검증된 동작(H3/C0, 토글 500, 가상 단위, 양수/0/-1/-2 결과 코드)도 HIGH 다.


§8 Sources

본 사양은 다음 공개 자료의 개념 설명과 역설계로 관찰한 동작을 근거로 작성했다.

위 공식 URL 들은 개념 설명(레이어 모델, 수식의 C-연산자 문법, C0|0x82=한자 변환 등)의 출처다. 코드값·서열·동작 세부의 1차 근거는 역설계로 관찰한 동작과 역설계 노트다.


스키마

본 사양의 기계 검증용 XSD 는 두 형태로 제공한다(본문은 동일, 스키마 헤더만 다르며 반드시 동기화한다):

파일 용도
schema/nalgaeset.xsd 정본. targetNamespace 있음(§0.4 의 선택적 식별자). 네임스페이스를 부여한 문서 검증용.
schema/nalgaeset-no-namespace.xsd 실제 날개셋이 내보내는 맨몸(no-namespace) 파일을 그대로 검증할 때 쓴다. 정본에서 targetNamespace·기본 xmlns 만 제거한 것(§0.4).

세 파일 종류 모두 단독 검증된다: 종합 설정(.set)은 루트 EditContextSetting, 유형(.ist)은 InputEntry, 글쇠배열(.key)은 KeyTable 를 각각 전역(루트) 요소로 선언한다(§0.1).

맨몸 인스턴스 검증 예(libxml2):

xmllint --noout --schema schema/nalgaeset-no-namespace.xsd 내자판.xml

관측 범위와 lax 모델링. 스키마는 실제 날개셋 표본(두벌식·세벌식·신세벌식·로마자 등)과 본 사양이 기술하는 요소를 모두 받아들이도록 맞췄고, 필수 속성 누락·갈래 오타·정수 형식 위반·미선언 루트 등은 거부한다. 다만 표본에서 내부 구조가 충분히 드러나지 않은 표(KeyProgramTable, UnitAbbrTable, UnitSubstTable, HanSubstTable, UserCandiTable, UserCompoTable, UserKeyTable, JackolanternTable; §1.18)는 과대 규정을 피해 자식·속성을 관용 허용(lax)한다. 구조가 더 확인되면 좁힐 것이다.