요 며칠간 개인적으로 잘 된 일도 있었고 잘 안 풀린 일도 있는 채로 다사다난한 시간을 보냈으나.. 그 어느 것도 나의 코딩을 가로막을 수는 없다. 열차는 시각표대로 무조건 달린다. 건널목에서 충돌 사고가 나도 질량과 관성 때문에 장애물을 그냥 밀고 쭉쭉 나아갈 뿐이다.
그래서 드디어 <날개셋> 한글 입력기가 7.11 이래로 무려 7개월간의 수련을 마치고 7.4 버전이 완성되었다.
원하는 기능들을 다 집어넣은 건 아니지만 한번 역에 정차하여 쉬어 가게 됐다. 이 달부터는 학기 마무리 준비를 해야 하는 관계로, 더 작업은 하고 싶어도 할 수 없기 때문이다.
5월은 안 넘긴 걸 기쁘게 생각한다. 의도했던 건 아닌데 5월 31일은 공교롭게도 <날개셋> 한글 입력기 3.0 출시의 딱 10주년 타이밍이기도 하다. 2004년 5월 31일 + 10년이다.
3.0은 최초로 유니코드 API 도입, 입력 스키마와 문자 생성기 계층 구분, 단축글쇠 테이블, 수식 기반의 오토마타, 지금과 같은 64비트 크기의 입력 단위, TSF를 인식하는 에디팅 엔진, 가변 길이 옛한글 등 오늘날 내 프로그램의 근간을 닦은 버전이었다. 2.5 이후로 거의 9개월 동안 프로그램을 밑바닥부터 다시 만들었었다.
물론 지금 보면, 기술적 디테일이나 사용자 인터페이스는 그야말로 내가 겁도 없이 이런 허접한 프로그램을 대회에 출품하고 사용자에게 공개했다 싶을 정도로, 민망할 정도로 허접하기 그지없었다.
그러나.. 포니를 개발한 뒤에야 에쿠스가 나올 수 있었듯이, 그런 개허접한 3.0이 있었기 때문에 그 뒤로 꾸준히 후속 기술이 개발되고 기능이 추가되어 무려 7.4까지 나올 수 있었던 건 자명한 사실이다. 이제 7.4를 바탕으로 올가을쯤에 7.5가 나와서 잔여 과업들을 완수해 준다면, <날개셋> 한글 입력기는 거의 대망의 완전체가 도달하지 않을까 싶다.
1. 입력 엔진 부분의 대대적인 리팩터링
예전에도 한번 소개한 적이 있듯, <날개셋> 한글 입력기에는 한 번에 한 낱자가 아니라 초중종 낱자를 한꺼번에 입력하는 기능이 있다. 그리고 그냥 입력하는 정도가 아니라 두 번에 걸쳐 입력하는 기능이 있다. 예를 들어 "받침ㅆ+다"를 배당하여 '이' 다음에 '있다'를 곧바로 만든다거나, '가' 다음에 '갔다'를 바로 만드는 게 가능하다.
극단적인 예로, 한 글쇠에다 '받침ㅋ+쌰'를 배당한다. 수식으로는 'H12|SS|YA|_K'라고 표현된다. 그 뒤, 허용 한글 범위를 KSX1001 완성형으로 맞춰서 2350자만 입력 가능하게 바꾼다.
이 상태에서 '가' 입력 중에 그 글쇠를 누르면.. '가ㅋ쌰'가 찍히는 게 맞다. '갘'은 조합이 안 되니 ㅋ이 다음 글자로 떨어져 나가고, '쌰'도 완성형에 없는 한글이기 때문에 조합이 더 진행되지 못하고 끊어지는 게 맞다. 그러나 현재 7.11 버전은 'ㅋ가쌰'가 된다. 중첩 입력을 처리하는 로직이 완전하지 못하기 때문이다.
또한 이 경우 원래 조합하던 글자에 이어서 총 2개의 글자가 추가로 완성되는 것이기 때문에 삽입이 아닌 '겹침' 모드에서는 2개의 글자가 추가로 덮어써져야 한다. 그러나 7.11은 그것도 깔끔하게 처리되지 못하고 여전히 삽입만 되고 있다.
이렇듯 NLP 기술이 하나도 없는 단순 한글 입력기 같아도 <날개셋> 한글 입력기는 서로 영향을 끼치는 입력 관련 각종 옵션과 변수들을 제어하는 게 굉장히 복잡하다. 가짓수와 가짓수를 서로 고려하다 보면 가능성이 곱셈이 되어 버려서 통제를 못 하게 된다. 각 변수들을 있는 그대로 각개격파하여 덧셈으로 유지되게 해야 한다.
굳이 저런 극단적인 상황에서의 매끄러운 처리까지 생각하는 게 아니더라도, <날개셋> 한글 입력기의 핵심 엔진 부분은 지난 10여 년 동안 다양한 기능이 추가되는 과정에서 매우 심하게 지저분해졌으며 구조적으로 심각한 한계를 드러내고 있었다. 그래서 대대적인 리팩터링이 불가피했다.
한참 옛날에 만들어 놨던 코드의 모든 로직과 의미를 다시 읽으며, 머리를 쥐어뜯고 피말리는 작업이 계속되었다.
그 결과, 단독으로 1천 줄이 넘던 핵심 함수의 일부를 2개의 함수로 떼어내고, 반복적인 패턴이 발견되는 일련의 루틴들을 별도의 클래스로도 빼냈다. 복잡한 입력, 이동, 지우기 동작을 제한된 element만으로 추상화해 낸 것이다.
특히 재귀호출이 필요한 부분과 그렇지 않은 부분을 확실히 분리했으며, 중복 무한순환 재귀호출을 감지하여 막는 부분을 더욱 똑똑하고 논리 오류가 없게 개선했다.
기능 추가도 아니고 동일한 기능을 구현하는 방식만 바꾸는 데 거의 50일이 걸렸다. 이 디자인이 과연 최선의 디자인인지 스스로 확신을 얻는 데도 긴 고뇌의 시간이 필요했다.
새로운 체계 덕분에 각종 지저분한 중복 코드가 없어지고, 지저분한 임시 변수나 비트 플래그가 없어지고, 그럼에도 불구하고 입력기의 논리적인 버그가 없어질 때마다 본인은 거의 엑스터시에 가까운 환희를 경험했다.
결합 축약 테이블에 의한 입력 순서 축약은 입력 타이밍이 아니라 bksp 지우기 동작이 실제로 일어날 때 행해지게 바꿨고,
특히 겹침 모드에서 배경의 글자를 덮어쓰는 개수를 계산하는 건, 입력 동작의 결과를 보고 공통된 post-processing 과정에서 한번에 알아서 계산하게 바꿨다.
이렇게 만들어진 출력 action은 구현체에 따라 IME에서는 WM_IME_*메시지로, TSF 환경에서는 TSF interface 함수 호출로, 자체 에디터에서는 말 그대로 내부 조작으로 seamless하게 변환되어 나간다. Windows 95부터 8.1까지 버전 불문하고 32비트, 64비트 불문하고 모두 똑같이 동작하는 건 물론이고 말이다.
이번 작업 덕분에 <날개셋> 한글 입력기의 코드는 소프트웨어공학적인 품질이 크게 향상되었으며, 이를 토대로 다른 새로운 입력 기능들도 손쉽게 확장해 넣을 수 있게 되었다.
2. 고급 입력 스키마
이번 7.4 버전에서는 종전의 '동시입력 스키마'를 대체하는 '고급 입력 스키마'가 추가되었다. 아직 넣고 싶은 기능이 100% 다 구현된 건 아니지만 어쨌든 이로써 입력 스키마와 문자 생성기가 모두 (1) 빈 (2) 기본 (3) 고급이라는 3단계 계층이 갖춰지게 됐다.
빈 입력 스키마는 아무 글쇠도 스스로 처리하지 않고 응용 프로그램에 그대로 넘겨 주는 잉여이다.
기본 스키마는 우리가 지금까지 써 온 대로, 키보드에서 통상적인 문자 입력용으로 쓰이는 47개 글쇠에다 Shift 조합을 포함한 94개 자리의 keydown을 인식한다. 거기에다 사용자가 별도로 지정한 글쇠의 keydown을 추가로 인식하거나, 기존 47개 글쇠를 부분적으로 인식하지 않게 하는 기능을 액세서리 차원으로 제공한다. 추가 글쇠는 Ctrl/Alt/Shift/Win 같은 modifier 조합을 옵션으로 가질 수 있다.
이에 덧붙여 고급 입력 스키마는 지정한 글쇠에 대해서 keydown뿐만 아니라 keyup(글쇠를 뗀 것)을 모두 인식할 수 있으며, 각 상황별로 이 글쇠를 처리할지의 여부를 모두 수식으로 지정 가능하다. 또한 이 keydown 이벤트가 몇 번째 연타인지, 그리고 이 이벤트가 발생한 시각(밀리초 단위)이 언제인지 같은 정보도 변수로 제공된다(예전에 기록한 시각과의 차이를 계산하는 데 활용 가능). 기본 입력 스키마에는 존재하지 않던 정보들이다.
그래서 이를 이용하면 한 글쇠를 0.n초 이상 오래 누른 것, 혹은 0.n초 이내에 눌렀다가 뗀 것, 어떤 두 글쇠를 연달아 누른 것, 굳이 Shift+X가 아니라 Shift를 한번 눌렀다 떼고 나서 다음 X를 순차적으로 누른 것 같은 복잡한 글쇠 동작을 모두 인식할 수 있으며, 글쇠를 오래 누르고 있어도 연타는 한 번 또는 n회 이내만 인식시킬 수도 있다. 기본 입력 스키마에다가 옵션으로 넣으려고 했으나 이론적인 기반을 마련하지 못해 지금까지 전혀 구현을 못 하고 있던 변칙적인 글쇠 인식은 전부 고급 입력 스키마를 통해 general하게 구현 가능해졌다.
단, 고급 입력 스키마는 기본 입력 스키마처럼 modifier 조합 같은 게 없다. 오로지 어떤 글쇠의 눌렀다 떼는 것에만 초점이 가 있으며, 두 글쇠의 조합은 각각의 글쇠가 눌러졌을 때 사용자가 변수에다 해당 글쇠가 눌렸다는 것을 일일이 판단함으로써 모든 로직을 수동으로 구현해야 한다. 기본 입력 스키마보다 설계 철학이 더 저수준이기 때문이다.
기본 입력 스키마는 날개셋문자를 있는 그대로 차근차근 보내는 것만 가능하다. 그러나 고급 입력 스키마는 사용자가 지정한 수식값에 따라서 지금 조합 중인 문자를 덮어쓰고 조합을 무조건 새로 시작시킬 수 있으며, 지금 조합을 무조건 종료한 뒤에 조합을 새로 시작시킬 수도 있다. 전자는 'ㄱ+ㅏ'를 '가'가 아니라 'ㅏ'로 바꾸는 기능이며, 후자는 'ㄱㅏ'로 바꾸는 것이라고 생각하면 이해하기 쉽다. 자기와 연결되어 있는 문자 생성기의 상태를 무시하고 입력을 보내는 게 가능하다는 뜻이다.
이런 고급 입력 스키마가 고급 입력기라는 문자 생성기와 만나면 활용 가능성은 더욱 커지는 건 두 말할 나위가 없다. 평상시에는 일반적인 방법으로 한 타씩 한글을 입력하지만, 특수한 글쇠 두어 개를 동시에 누르거나 한 글쇠를 오래 누른다거나 하면 미리 지정해 둔 '습니다', '000' 같은 글자 묶음이 지금 조합을 무시하거나 종료시킨 상태에서 곧장 입력되게 할 수 있기 때문이다.
더 자세한 개념과 기능 설명에 대해서는 고급 입력 스키마를 꺼낸 뒤, "고급 글쇠 인식 옵션" 페이지에서 F1 도움말을 참고하면 된다. 앞으로 이걸 이용한 창의적인 문자 입력 방식이 많이 고안되어 나오면 좋겠다. 예제 템플릿 수식 같은 거라도 더 넣어서 고급 입력 스키마에 대한 사용 접근성을 더 개선하는 게 추후 과제로 남아 있다.
또한 지금 만들어 놓은 입력 설정을 그대로 유지하면서 기반 루틴만 '기본'이던 것을 '고급'으로 업그레이드하는 방법이 없는 게 문제라면 문제임을 인정한다. 기반 루틴을 바꾸고 나면 글쇠배열 같은 입력 설정은 다시 세팅을 해야 한다.
다음 버전인 7.5에서는 이번 7.4에서 실험적으로 구현한 기능을 바탕으로, 한글의 동시 입력에 특화된 보정 기능들이 추가될 예정이다.
3. 고급 입력기 -- 한글 출력 치환
입력 스키마에 이어 문자 생성기에도 '고급 입력기'에 신선한 기능이 새로 추가되었다.
잠시 개념을 좀 복습하자면, 빈 입력기는 아시다시피 오토마타, 조합, 후보 변환 같은 게 없이 문자를 있는 그대로 완성된 형태로만 보낼 수 있는 제일 원초적인 문자 생성기이다. 영문 같은 문자에나 적합하다.
기본 입력기는 그야말로 한글 한 글자를 조합하는 데 필요한 온갖 복잡 화려한 <날개셋> 한글 입력기의 핵심 기능들이 모두 구현되어 있는 문자 생성기이다.
그리고 고급 입력기는 기본 입력기의 기능들을 바탕으로, 비한글 문자의 custom 조합과, 한글 입력과 비한글 입력을 서로 연동하는 액세서리 기능이 추가적으로 들어있다. 설계 철학이 이러하다는 걸 염두에 두도록 하자.
이번 7.4에서는 '한글 출력 치환'이라는 기능이 고급 입력기에 추가되었다. 언뜻 보기에 이것은 편집기 계층에 존재하는 '최종 변환 규칙'의 입력기 계층 버전처럼 보이기 쉬우나, 성격이 그것과는 약간 다르다.
한글 출력 치환은 초중종성 낱자별로 동작하는 버전과 글자 전체 단위로 동작하는 버전이 따로 존재한다.
전자는 가상 낱자를 가리면서 동작하고--다시 말해 세벌식에서 겹모음용 ㅗ/ㅜ와 홑모음용 ㅗ/ㅜ를 구분한다는 뜻--
후자는 그걸 따지지 않고 그냥 겉으로 보이는 한글 전체의 모양만 따지며 동작한다.
낱자 버전부터 설명하도록 하겠다.
초중종이 각각 ABC로 구성된 한글이 있고, 초중종 A, B, C에 대해 각각 1, 2, 3이라는 문자열로 출력 치환하는 규칙이 존재한다면.. ABC라는 한글은 대략 1A2BC3이라고 바뀌어 출력되게 된다. 즉, 한글의 앞뒤로 비한글 일반 문자가 삽입되며 특히 중성에 치환 규칙이 존재하면 한글 자체가 초/중종 두 글자로 찢어진다.
이런 기능이 왜 필요하며 무슨 용도로 쓸 수 있을까?
주된 활용 방법 중 하나는, 한글 입력 과정에서 현행 한글 코드에 존재하지 않는 복잡한 겹낱자를 잠시 표현해야 할 때, 이를 여러 개의 기존 낱자로 풀어서 표현하는 것이다. 물론, 123 말고 ABC 자체의 형태를 바꾸려면 기존 가상 낱자 규칙을 쓰면 된다. 따라서 낱자 출력 치환은 가상 낱자 규칙과도 연계해서 활용하면 좋다.
이번 7.4에서는 천지인이나 나랏글 같은 휴대전화 입력 방식 예제가 다 이 기능을 사용하여 다시 만들어져 있다.
종성 부분을 보면, 내부적으로는 받침 ㅃ, ㄸ, ㅉ이지만 겉으로는 초성 ㅃ, ㄸ, ㅉ이 다음 글자에 가 있는 것처럼 화면에 나타나는데, 가상 낱자를 써서 받침 ㅃ, ㄸ, ㅉ을 0으로 치환하여 원래 있던 자리에서는 없애 버리고, 그 대신 출력 치환 규칙에다가 초성 ㅃ, ㄸ, ㅉ을 대신 출력하게 한 것이다.
ㄴ+ㅇ, ㄱ+ㅆ, ㄱ+ㅊ 같은 받침이야 더 말할 필요도 없다. 300 이상의 가상의 받침을 설정한 뒤, 가상 낱자 규칙에다가는 ㄴ, ㄱ 같은 앞부분 받침만 나타나게 하고, 뒷부분 받침은 출력 치환 규칙으로 지정했다. 한글 한 글자를 조합하는 걸로 두 글자 이상의 한글이 한꺼번에 나타나게 하는 걸 이런 이론 기반으로 구현해 냈다.
단, 외부 모듈의 경우 한글 조합이 길이가 한 글자를 넘어가면 응용 프로그램에 따라서는 조합 중인 문자가 제대로 표현되지 않을 수 있으므로 주의가 필요하다.
다음으로 글자 버전은.. 쉽다. 말 그대로 지금 조합 중인 한글을 다른 문자로 바꿔서 보여 주는 것 그 이상도 이하도 아니다. 한글 입력 방식을 한글로 다른 문자를 입력하는 데 고스란히 활용할 수 있으며, 덕분에 사용자 정의 조합 기능을 쓸 일도 크게 줄어든다.
이것 덕분에 아래아한글 97 이래로 지금까지 구현된 적이 없던.. 한글로 일본 문자 입력이 가능해졌다. 이번 버전에서는 히라가나/가타카나를 종전과 같은 로마자 기반 사용자 정의 조합뿐만 아니라, 한글 출력 치환으로 구현한 예제 파일이 새로 추가됐다.
이와 관련하여, "한글 출력 범위(=문자 집합) 제한"에도 유용한 기능이 하나 추가됐다. 지금까지는 KSX1001 2350자, 한컴 2바이트 완조형, 한양 PUA 완성형처럼 완전 legacy 잉여 문자 집합을 생색내기로 흉내 내는 기능만 있었던 반면, 바로 <날개셋> 고급 입력기의 한글 출력 치환 규칙이 존재하는 글자만 허용하는 기능이 새로 추가된 것이다.
한글로 일본어 문자를 입력하는 예제 파일을 써 보면, 일본어 치환이 존재하지 않는 한글은 아예 조합이 되지 않고 낱자가 다음 글자로 튕기는 걸 볼 수 있다.
(다만, 지금까지 사용자 정의 조합으로 구현되어 있던 구결 입력 방식은, 그냥 외장형 "사용자 후보 변환"으로 입력하는 데이터 파일로 형태를 바꿨다. 한 한글에 대응하는 구결 문자가 여럿 있기 때문에 후보 변환이 더 적절하다고 판단되어서이다.)
4. 그 밖에
이번 7.4에서 이뤄 낸 위의 1~3 아이템들은 생각만 해도 후련하다. 왜 이런 기능들이 무려 2014년에 와서야 실현된 걸까. ㅠ.ㅠ 일반 사용자의 입장에서야 <날개셋> 편집기에 다른 에디터에도 있는 기능들이 덩달아 들어가기를 더 원할지 모르고 현실적으로는 외부 모듈의 안정성 개선이 더 중요하게 느껴질지 모르나, 본인의 입장에서는 그런 건 개발 방향과 직접적인 관계가 없거나 최소한 부가적인 요소들이다.
<날개셋> 한글 입력기의 개발에서 본인이 가장 중요하게 여기는 건 한글 입력과 관련된 기술을 한데 통합할 수 있는 이론 연구와 구현이다. 그러니 편집기는 10년 전이나 지금이나 똑같은 촌스럽기 그지없는 MDI 프로그램 외형이지만, 그 속의 깊이는 갈수록 심오해지고 있다. 이번 7.4가 개발 기간이 괜히 길었던 게 아니며, 7.2나 7.3을 건너뛰고 괜히 바로 7.4로 간 게 아니다.
프로그램 버전이 7.x대까지 가고 나니 프로그램의 완성도는 충분히 정착한 듯하며, 이를 토대로 지금까지 못 하고 있던 long-term 이론 연구를 최대한 진행했다.
고급 입력 스키마와 고급 입력기는 모두 ngs3 모듈이 아니라 ngsx라는 플러그 인 모듈이 담당하고 있는데, 이런 대규모 작업 덕분에 드디어 ngsx의 프로그램 크기가 <날개셋> 편집기 ngsedit의 크기를 근소하게 추월했다.
분량이 벌써 굉장히 길어진 관계로, 이 항목에서는 고급 입력기와 관련된 변화 사항을 조금만 더 얘기하고 나머지 새 버전 자랑은 다음 하편으로 미루도록 하겠다. ㅎㅎ 그러고 보니 타자연습도 빨랑 업데이트하고 저거 얘기도 해야 되는데..
7.4에서는 한글 로마자 입력 방식의 근간인 글쇠 치환 규칙이 동작하는 방식이 살짝 바뀌었다. 새로운 기능 추가가 아니라 변경임. 글쇠 치환 규칙에 존재하던 잡다한 옵션들이 모두 없어지고 이들의 구현 방식이 다른 대체제로 바뀌었다.
caps lock 무시 옵션이 없어졌기 때문에 이제는 기반 영문 글쇠배열이 caps lock을 구분하여 동작하지 않도록 바뀌어야 한다. 이것은 글쇠배열 편집기를 우클릭한 후 "전체 간소화 → 수식 제거"를 선택하면 된다. 하지만 간단히 한글 로마자 입력 빠른설정만 다시 실행해 줘도 7.4 버전 기준에 맞는 로마자 입력 방식이 다시 세팅된다.
shift 음절 강제 구분 옵션도 없어졌으며, 조합을 하는 낱자와 조합을 안 하는 낱자는 두벌식/세벌식 한글 타입으로 오토마타 차원에서 구분을 한다. 비슷한 메커니즘이 이미 네벌식 예제 입력 방식에서도 쓰인 적이 있다.
다만 이것 때문에 현재 한글로부터 글자판 입력 문자열을 구하는 방식이 제대로 동작하지 않고 있는데, 이것은 7.5에서 해당 알고리즘을 싹 다시 구현할 때 문제를 개선할 예정이다.
끝으로, 두벌식 처리 옵션도 없어졌다. 두벌식 한글로 치환되는 글쇠는 언제나 초성과 종성이 현재의 오토마타 상태에 따라 자동으로 구분되어 두벌식으로 처리된다. 번거로운 절차를 없앴다. 이 점 착오 없으시기 바란다.
Posted by 사무엘