
가상 머신(VM)의 Windows에서 작업하다 한영 전환 때문에 흐름이 끊겼습니다. 전환키가 기대대로 전달되지 않거나, 필요한 순간에 입력 모드를 바꾸기 어려웠습니다. 제 작업 환경에서 겪은 문제였습니다. 한영키를 계속 고치는 대신, 한영 모드를 바꾸지 않고 쓰는 도구를 직접 만들어 사용하기로 했습니다.
그렇게 시작한 Hanautomata는 Windows 트레이에서 동작하는 입력 도우미입니다. 같은 키열을 한글과 영문 후보로 해석하고, 단어 경계에서 입력을 확정합니다. macOS에서 소스와 순수 로직을 검사하고 Windows에서 실제 입력 경로를 확인한 뒤, 2026년 10월 9일 0.4.0 공개 베타로 공개했습니다.
한영 전환이 어려운 환경에서, 전환 동작 자체를 줄였습니다.
실제 화면과 코드를 함께 보며 작은 입력 도구의 구조를 설명합니다.
macOS 빌드 통과와 Windows 입력 성공은 별도로 검증했습니다.
1. 불편을 설명하는 대신, 쓸 수 있는 도구를 만들었습니다
원격 환경에서는 손에 있는 키보드와 실제 프로그램이 실행되는 Windows 사이에 여러 층이 있습니다. 호스트 운영체제의 단축키, 원격 접속 프로그램의 키 전달, 게스트의 입력 상태가 함께 작용합니다. 제가 겪은 현상의 원인을 이 중 하나로 단정할 수는 없었습니다. 다만 글을 써야 하는데 한영 전환 때문에 멈춘다는 사실은 분명했습니다.
한국어 설명 중에 API 이름을 쓰고 다시 한국어로 돌아가는 작업은 흔합니다. 이때마다 현재 모드를 확인하는 대신, 입력한 단어를 보고 한글인지 영문인지 결정하면 어떨까 생각했습니다. dkssudgktpdy를 치면 안녕하세요를 후보로 보여 주고, hello world는 영어로 남기는 방식입니다.
첫 목표는 작았습니다. 관리자 권한이나 서버를 준비하지 않고, 지금 쓰는 Windows에서 실행할 수 있어야 했습니다. 그래서 사용자 권한의 트레이 앱으로 시작했습니다. AI 코딩 도구와 구현·실행·실패 확인을 반복했고, 만들어진 실행 파일을 제 환경에 설치해 다시 사용했습니다. 개발 산출물은 제가 다음 작업을 이어 갈 때 쓰는 도구가 됐습니다.
필요성이 가장 큰 곳은 한영 전환이 불편한 VM·원격 Windows 작업입니다. 한글 설명과 영어 기술 용어를 자주 섞어 쓰는 경우에도 도움이 될 수 있습니다. 반면 이 도구가 모든 원격 환경의 키보드 문제를 해결하는 것은 아닙니다. Windows 앱이 일반 입력을 받을 수 있고, Hanautomata가 그 입력 칸을 확인할 수 있어야 합니다.
2. 타이핑하면 후보가 뜨고, Space에서 확정됩니다
Hanautomata를 처음 실행하면 입력 연습창이 열립니다. 타이핑 중에는 편집 칸 옆에 작은 후보창이 나타나고, Space를 누르면 선택된 단어와 공백이 실제 편집 칸에 들어갑니다. 아래는 설치된 0.4.0 베타의 연습창에 야간이 표시된 모습입니다.

후보가 마음과 다르면 ; 또는 F2로 바꿉니다. Space로 확정한 직후에도 F2로 직전 단어를 바꿀 수 있습니다. 다만 같은 창·같은 입력 칸에서 15초 안에 사용하는 기능이며, 커서를 옮기거나 다른 곳을 클릭한 뒤까지 이전 단어를 추적하지는 않습니다. 이 경계는 다른 글자를 잘못 바꾸지 않기 위한 선택입니다.
이미 입력된 문구를 고칠 때는 선택 후 Shift+F2를 사용합니다. 한영 상태를 잘못 알고 입력한 글자를 선택하면, 한글과 영타를 그 자리에서 뒤집습니다.

dkssudgktpdy가 그대로 입력되어 있습니다.
Enter도 후보를 확정하지만 Enter 자체를 대상 앱에 전달합니다. 채팅 앱에서는 메시지가 전송될 수 있으므로 처음에는 연습창에서 Space로 동작을 확인하는 편이 좋습니다. 키별 동작과 적용 범위에 자세한 설명을 두었습니다.
3. 옵션은 트레이의 ‘한’ 아이콘에 모았습니다
창을 닫으면 프로그램이 종료되는 대신 트레이로 들어갑니다. 파란 원 안의 ‘한’ 아이콘을 더블클릭하면 입력 연습창을 다시 열 수 있습니다. 마우스 오른쪽 버튼을 누르면 옵션 메뉴가 나옵니다. 종료도 이 메뉴에서 합니다.


나머지 항목은 동작을 바로 실행하는 메뉴입니다. ‘자동 판별 켜짐’은 F12와 같은 일시정지·재개 스위치이고, ‘입력 연습 및 상태’는 연습창을 다시 엽니다. ‘미확정 조합 복사’는 확정되지 못하고 보관된 조합을 클립보드로 복사합니다. 그림 1 아래쪽의 주황색 안내가 그 보관 상태를 알려 줍니다. ‘개인 학습 초기화’는 기억한 선택을 모두 지우며, 괄호 안 숫자는 현재 기억한 항목 수입니다.
민감도는 복잡한 엔진을 바꾸는 스위치가 아닙니다. 통계 판별기가 결정을 보류하는 폭을 바꿉니다. 보수는 확실한 경우에만 한글로 바꾸고, 적극은 상대적으로 약한 근거에서도 한글 후보를 고릅니다. 기본값은 표준입니다. 학습을 켜도 자동 판별 결과를 스스로 정답으로 간주해 계속 학습하지 않습니다.
4. 작은 앱 안에서 입력·판별·출력을 분리했습니다
Hanautomata는 Windows의 정식 입력기 목록에 등록되는 입력기(IME)가 아닙니다. 키 입력을 관찰하고 단어를 조합한 뒤 결과를 보내는 시스템 전역 입력 도우미입니다. 가볍게 실행해 바로 쓴다는 목표에 맞춰 C#과 Windows Forms, .NET Framework 4.8을 사용했습니다.
전체 구조를 한 장으로 그리면 다음과 같습니다. 가운데는 입력이 지나가는 경로이고, 주변은 입력 대상 확인·사용자 선택·연결 복구 기능입니다.

입구에는 저수준 키보드 후크가 있습니다. 후크는 UI 스레드와 분리된 전용 스레드에서 동작합니다. 키를 받는 경로에 무거운 접근성 조회나 화면 작업을 몰아넣지 않는 것이 중요했습니다. 편집 대상은 별도 스레드의 FocusMonitor가 Windows 접근성 API인 UI Automation으로 확인합니다.
가운데에는 순수 로직을 담당하는 Core.cs가 있습니다. 두벌식 키열을 한글로 조합하고, 같은 입력의 한글·영문 후보를 비교합니다. 출력은 InputController가 순서를 관리하며 Windows의 SendInput으로 Unicode 문자를 보냅니다. 후보를 보여 주는 작은 창과 실제 편집 칸의 출력은 분리되어 있습니다.
이 분리가 macOS 개발에도 도움이 됐습니다. Windows 전용 API를 실제 호출해야 하는 부분과, 어느 운영체제에서든 계산 결과를 검사할 수 있는 부분을 나눴기 때문입니다. 구체적인 스레드·판별 순서는 공개 설계 노트에 정리했습니다.
5. 한글과 영어를 고르는 데 클라우드는 필요하지 않았습니다
처음부터 대형 언어 모델에 입력을 보내는 구조를 택하지 않았습니다. 키를 누를 때마다 네트워크 응답을 기다리는 구조는 이 도구의 목적과 맞지 않았습니다. 실행 중에는 로컬에 포함된 규칙·어휘·통계 표를 사용합니다. 서버, 계정, API 키가 필요하지 않습니다.
판별은 한 번의 큰 추측으로 끝나지 않습니다. 주소·경로·식별자 등 바꾸면 곤란한 입력을 먼저 보호합니다. 직접 선택한 이력, 영어 보호 어휘와 한국어 형태 규칙을 적용하고, 남은 입력에는 한글 음절과 영어 글자 쌍의 통계를 비교합니다. 여기서 글자 두 개가 이어지는 빈도를 보는 모델을 바이그램(bigram)이라고 합니다.
같은 키열을 한글로 읽었을 때의 점수와 영문으로 읽었을 때의 점수를 비교합니다.
판별 점수 = log10 P(한글 후보) − log10 P(영문 키열)
점수가 +T 이상이면 한글
점수가 −T 이하면 영문
그 사이면 보류: 원문을 유지하고 후보를 제시
T: 보수 3.0 / 표준 2.0 / 적극 1.5
이 식은 통계 단계의 요약입니다. 앞선 보호 규칙이 우선하고, 보류 구간에서는 직전 단어의 언어와 공개 단어 목록을 추가로 참고합니다. go처럼 영어이면서 한글 ‘해’로도 읽히는 입력은 사용자의 의도를 완벽히 알 수 없습니다. 그래서 후보 변경과 되돌리기를 함께 설계했습니다.
개인 학습 역시 이 원칙을 따릅니다. 사용자가 후보를 바꾸고 확정한 선택을 저장하며, 문장 전체나 연속 키 기록은 저장하지 않습니다. 다만 직접 선택한 단어의 키열은 읽을 수 있는 로컬 JSON에 남습니다. 앞 단어는 원문 대신 SHA-256 지문으로 저장합니다. “아무 데이터도 남기지 않는다”고 설명할 수 있는 구조는 아닙니다.
자동 판별 중의 접근성 조회는 입력 칸의 속성을 확인하는 용도입니다. Shift+F2를 요청할 때는 변환할 선택 영역의 글자를 읽습니다. UI Automation으로 읽지 못하면 복사 경로를 사용하고 클립보드의 글자 내용을 복원합니다. 실행 동작과 데이터 경계는 보안 설명에 공개했습니다.
6. macOS와 Windows를 오가며 검증을 쌓았습니다
개발은 필요한 기능을 붙여 실행하고, 실패한 입력을 다음 검사의 재료로 삼는 방식으로 진행했습니다. 첫 버전에서 두벌식 조합과 트레이 실행을 만들었습니다. 이후 개인 선택, 혼합어, 후크 연결 복구, 선택 영역 변환을 더했습니다. 공개 단계에서는 개인 개발 표본을 배포하는 대신 공개 코퍼스로 모델 표를 다시 만들었습니다.

macOS에서는 .NET SDK 9로 같은 소스를 검사했습니다. 전체 Windows 앱은 .NET Framework 4.8 참조 어셈블리로 컴파일하고, 순수 로직 검사는 .NET 9에서 실행했습니다. 이를 통해 문법·타입 오류와 판별 로직의 회귀를 빠르게 찾을 수 있었습니다.
그러나 macOS에서 컴파일했다는 사실은 Windows 후크가 키를 받고, 접근성 API가 입력 칸을 찾으며, 대상 앱에 문자가 들어간다는 뜻이 아닙니다. Windows에서는 실제 .NET Framework 런타임으로 다시 빌드하고, 전용 시험창에서 후크부터 최종 출력까지 검사했습니다. macOS에서도 개발·검사할 수 있는 Windows 앱이지, macOS용 입력 앱을 출시한 것은 아닙니다.
출처는 0.4.0 검증 기록입니다. macOS 수치는 공개 코퍼스 전환 당시의 기록이며, Windows 출시 보완 커밋을 macOS에서 다시 실행한 수치로 확대하지 않았습니다. 최종 공개 커밋은 GitHub Actions의 Linux 교차 검사와 Windows 빌드·검사에서도 통과했습니다.
마지막에는 검사한 실행 파일을 그대로 ZIP에 담았습니다. GitHub에 올린 ZIP을 다시 다운로드해 내부 체크섬을 확인하고, 그 파일로 설치했습니다. 소스가 맞는지뿐 아니라 독자가 받게 될 파일이 검사한 파일과 같은지도 확인하고 싶었습니다.
7. 실패한 실험이 검증의 경계를 알려 주었습니다
가장 큰 교훈은 “등록에 성공했다”와 “동작한다”가 다르다는 점이었습니다. 0.3.0 개발 과정에서 후크 상태를 감시하려고 Raw Input을 등록했습니다. 그런데 해당 클라우드 Windows PC에서는 등록 뒤 후크 콜백이 들어오지 않았고, 최초 기능 검사 100개 중 68개가 실패했습니다.
이전 실행 파일과 대조하고 등록 경로를 분리해 확인했습니다. 결국 시작부터 후크 호출이 오지 않는 환경에서는 Raw Input 감시를 해제하고 기존 연결 검사로 돌아가도록 보완했습니다. 이후 확장된 기능 검사 101개가 통과했습니다. 그림 1의 상태 줄에 보이는 ‘감시 호환모드’가 이 대체 경로입니다. Windows 내부 원인이나 다른 PC에서의 재현 여부까지 규명한 것은 아닙니다.
0.4.0에서도 실패는 있었습니다. 개인 학습이 꺼졌는지 확인하려고 사용한 rm/그가 공개 모델의 문맥 점수만으로 바뀌었습니다. 모델 판정과 학습 여부가 한 검사에 섞여 있었던 것입니다. 보호 어휘 wbs로 검사 토큰을 바꾸어 학습 기능을 분리했습니다. 검사 의도를 유지하면서 무엇을 검증하는지 더 분명하게 만든 수정입니다.
배포에서도 기존 패키지 폴더의 파일이 다음 ZIP에 섞이는 문제를 찾았습니다. 매번 새 임시 폴더에서 패키징하도록 바꿨습니다. ZIP 안의 설치 스크립트가 개발 폴더를 찾던 문제도 실제 다운로드 경로에서 드러났습니다. 앱의 알고리즘만큼 설치 경로와 배포 파일을 검사하는 일이 중요했습니다.
현재의 한계도 남아 있습니다. 짧은 단어·이름·신조어는 오판할 수 있습니다. 비밀번호·읽기 전용 칸과 관리자 권한으로 실행한 앱에서는 의도적으로 기본 입력기로 통과합니다. 게임의 Raw Input, 보안 데스크톱, 터미널, 일부 웹 편집기에서는 동작하지 않을 수 있습니다. 입력 칸을 안전하게 확인하지 못할 때도 원래 입력기로 통과합니다.
실물 PC의 물리 키보드, 여러 실제 외부 앱, 다른 PC의 정상 Raw Input 경로, 실제 로그오프 후 로그인은 아직 검증하지 않았습니다. 베타 빌드는 서명되지 않았으며, 단어 표본의 통과율을 일반 문장 정확도로 환산할 수도 없습니다. 따라서 지금의 공개 버전은 0.4.0 베타입니다.
8. 공개 소스를 받아 자신의 환경에서 확인할 수 있습니다
초기 개발 이름은 HanFlow였습니다. 같은 이름의 다른 프로젝트와 구별하기 위해 공개할 때 Hanautomata로 바꿨습니다. 현재 코드와 배포의 정본은 peterkimpmp/hanautomata입니다. 이전 설치본이 있다면 이전 가이드를 먼저 확인하면 됩니다.
사용하려면 Releases에서 Hanautomata-0.4.0-win.zip과 SHA256SUMS.txt를 받습니다. Windows 10/11과 .NET Framework 4.8이 필요합니다. 체크섬을 확인한 뒤 압축을 풀고, EXE와 config를 같은 폴더에 둔 상태에서 실행합니다.
# 다운로드한 ZIP이 배포 체크섬과 같은지 확인
Get-FileHash .\Hanautomata-0.4.0-win.zip -Algorithm SHA256
# 압축을 푼 앱 폴더에서, 현재 사용자에게 설치할 경우
powershell -NoProfile -ExecutionPolicy Bypass -File .\install.ps1
개발자는 같은 소스의 검증 경로를 따라갈 수 있습니다.
# Windows: 저장소 루트에서
.\build.ps1 -Test
.\build.ps1 -Integration
.\tests\ReleaseTests.ps1
# macOS·Linux: .NET SDK 9 환경에서
dotnet build tests/dotnet/Hanautomata.App.Net48 -c Release
dotnet run --project tests/dotnet/Hanautomata.Tests -f net9.0 -c Release
코드는 MIT 라이선스입니다. 공개 모델 표와 관련 데이터는 한국어·Simple English 위키백과에서 만들었고 CC BY-SA 4.0 조건으로 배포합니다. 코드의 라이선스와 데이터의 라이선스는 같지 않습니다. 출처와 생성 범위는 NOTICE에 명시했습니다.
처음의 문제는 거창하지 않았습니다. 지금 쓰는 VM에서 한영 입력 때문에 멈추고 싶지 않았습니다. 필요한 도구를 만들고 바로 사용하니, 책상 위의 설계에서 보이지 않던 입력·포커스·배포 문제가 드러났습니다. macOS와 Windows를 오가며 검사한 과정은 그 실패를 구분하고 다시 확인하는 방법이 됐습니다.
시작은 짧게 해볼 수 있습니다. 연습창에서 dkssudgktpdy와 hello world를 각각 입력하고 Space를 눌러 보세요. 후보가 다른 경우에는 F2를 사용해 봅니다. 그다음 평소 쓰는 앱 한 곳에서 같은 입력을 확인하고, 앱 이름과 기대한 결과·실제 결과를 남기면 자신의 환경에 맞는 검증 기록이 됩니다.
김태영 · Project Research · 2026년 10월 9일 제품·화면 기준: Hanautomata v0.4.0-beta. 실제 캡처와 공개 소스·검증 기록을 바탕으로 작성했습니다.