MilkyWayIME is a Korean TSF IME project for Windows.
한국어 문서는 README.ko.md를 참고하세요.
- Separate the user's base layout from Korean composition.
- Convert input labels through the selected base layout to fixed QWERTY/libhangul tokens for Korean composition.
- Interpret shortcuts from the input labels reported by Windows/TSF.
- Support Hanja and symbol candidate selection from the current composing single Hangul unit.
- Keep the project extensible for future custom layouts.
MilkyWayIME delegates Hangul composition to libhangul.
- TSF integration stays in the project.
- Layout selection, key normalization, shortcut resolution, and session state stay in the project.
- The actual Hangul composition engine is isolated behind
src/adapters/libhangul/. HANGUL_IC_OPTION_AUTO_REORDERis enabled so reordered jamo input such asㅏ+ㅇ -> 아follows the same composition behavior asNavilIME.- The upstream dependency is included as the
external/libhangulgit submodule. external/libhangulremains an external dependency project in the solution.
This repository currently contains an early but manually testable TSF path:
Visual Studio 2026 Communitysolution and project filesMilkyWayIME.Internalas a build-reuse static library for repo-owned codeMilkyWayIME.Tsfas the only production DLL projectsrc/enginefor layout, session, and shortcut model boundariessrc/tsffor the initial Windows TSF composition lifecycle layer and the minimum COM text service runtimesrc/adapters/libhangulfor the statically linkedlibhangulintegration boundarysrc/adapters/dictionaryfor static Hanja and symbol dictionary lookupsrc/ui/candidateandsrc/tsf/candidatefor candidate list presentation and TSF UI element integrationdata/layoutsfor layout schema samples and future custom layout datatestsfor unit, layout, and integration test structure
Base layout data describes the user's current key-label arrangement. Its mapping
direction is QWERTY/libhangul token position -> current base layout label.
Omitted keys are identity mappings.
During Korean composition, MilkyWayIME inverts the selected base layout:
input label -> QWERTY/libhangul token -> libhangul
For example, in Colemak the fixed QWERTY s position is labeled r.
Therefore input label R maps back to libhangul token s, producing ㄴ in
two-beolsik. Shortcuts are resolved from the original input label, not from the
Hangul token.
MilkyWayIME exposes the current user settings through the language bar menu.
The supported built-in base layouts are us_qwerty and colemak. Korean
layouts use libhangul:<id> IDs such as libhangul:2 and libhangul:3f.
The selected layouts are stored under
HKCU\Software\MilkyWayIME\Settings and loaded when the text service starts.
Only the selected IDs are persisted:
BaseLayoutId
KoreanLayoutId
Layout definitions, libhangul XML, and mapping tables are not copied into the settings store.
There is no dedicated settings window yet, and Ctrl+Alt+O is intentionally not
registered as a settings shortcut.
Future custom Korean layouts should be written as libhangul XML, not as
MilkyWayIME JSON. The XML id becomes the MilkyWayIME Korean layout ID through
the libhangul:<id> form; for example, XML id="my-sebeol" becomes
libhangul:my-sebeol.
Future custom base layouts should use MilkyWayIME JSON under the same direction as the built-in samples:
{
"id": "my_colemak_variant",
"displayName": "내 콜맥 변형",
"keys": {
"s": "r"
}
}The base JSON loader is connected to unit tests, the keyboard-matrix
development tool, and the TSF runtime. The TSF runtime loads base layout JSON
once when the text service is created from:
%APPDATA%\MilkyWayIME\layouts\base
Malformed files are skipped independently. Duplicate base layout IDs override earlier definitions, including built-in IDs. Existing TSF instances do not reload JSON automatically; restart the target app after changing layout files.
Current builds still compile external/libhangul with ExternalKeyboard=NO
and ENABLE_EXTERNAL_KEYBOARDS=0, so runtime custom Korean XML loading remains
a separate future step.
MilkyWayIME/
MilkyWayIME.sln
MilkyWayIME.*.vcxproj
docs/
external/libhangul/
data/
src/
tests/
tools/
installer/
Visual Studio baseline:
- Visual Studio 2026 Community
- MSVC toolset
v145installed with that IDE - Windows SDK
10.0.26100.0 MilkyWayIME.slnas the only supported build entry point
Command line build:
git submodule update --init --recursive
& "C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\amd64\MSBuild.exe" `
".\MilkyWayIME.sln" `
/t:Build `
/p:Configuration=Debug `
/p:Platform=x64 `
/mThis solution is Windows-only. CMake and cross-platform build paths are no longer used.
Current output paths:
build\MilkyWayIME.Tsf\x64\Debug\mwime_tsf.dllbuild\MilkyWayIME.Tests.Unit\x64\Debug\mwime_tests.exebuild\MilkyWayIME.Tests.Tsf\x64\Debug\mwime_tsf_tests.exe
The first installer target is an x64 WiX v6 MSI:
.\installer\build-installer.ps1Use -SkipSolutionBuild for a fast MSI-only rebuild after binaries already
exist. MSI ICE validation is skipped by default for speed; add -ValidateMsi
when you need full WiX/MSI validation.
The GitHub Actions workflow at .github\workflows\build-installer.yml runs on
the windows-2025-vs2026 image, prints the installed MSVC toolsets, builds the
same Release x64 MSI, and uploads it as an artifact. It derives the MSI version
from a vX.Y.Z tag, an optional manual workflow input, or
0.1.<GITHUB_RUN_NUMBER>.
The script builds Release|x64, packages mwime_tsf.dll and the us_qwerty /
colemak base layout JSON samples, then produces:
build\installer\bin\Release\MilkyWayIME.msi
The MSI installs to %ProgramFiles%\MilkyWayIME and runs regsvr32 as an
elevated custom action so DllRegisterServer / DllUnregisterServer handle
COM and TSF registration. It registers the TSF profile but does not call
InstallLayoutOrTip to enable it for the current user.
Release binaries are built with the static MSVC runtime (/MT), so the MSI does
not need to bundle the Visual C++ Redistributable. Current limitations: x64 only
and no locked-DLL upgrade/uninstall handling. Close applications using the IME
before upgrading or uninstalling.
After a Debug|x64 solution build, register the development DLL with:
tools\register-msvc-debug.cmdUnregister it with:
tools\unregister-msvc-debug.cmdRun both scripts from an elevated Command Prompt.
The registration script copies build\MilkyWayIME.Tsf\x64\Debug\mwime_tsf.dll
to %ProgramW6432%\MilkyWayIME\mwime_tsf.dll, registers that installed copy
through regsvr32, and restarts ctfmon.exe so the TSF profile refreshes.
Runtime Hanja and symbol lookup uses static tables compiled into the DLL.
Regenerate the committed static Hanja and symbol tables with:
tools\generate-static-hanja.cmdThe generator reads external\libhangul\data\hanja\hanja.txt and
external\libhangul\data\hanja\mssymbol.txt, then updates
src\adapters\dictionary\generated_hanja_data.cpp. Normal builds and runtime
lookup do not depend on the generator or the txt/bin data files.
The unregister script defaults to %ProgramW6432%\MilkyWayIME\mwime_tsf.dll
and calls the DLL's DllUnregisterServer export through regsvr32.
Use the current build only as a developer smoke test target.
- Build
Debug|x64fromMilkyWayIME.sln. - Run an elevated Command Prompt and register the DLL with
tools/register-msvc-debug.cmd. - Re-open the target app, for example Notepad.
- Switch to the
MilkyWayIMEprofile and verify:- Hangul composition starts, updates, and commits.
Backspace,Space,Enter,., and?end or update composition as expected.VK_HANGULcommits the current syllable and toggles IME open/close state.- The language bar or tray input-mode indicator switches between
가andA. - The language bar menu can switch base and Korean layouts and keeps the selection
under
HKCU\Software\MilkyWayIME\Settings. - The profile icon uses the MilkyWayIME brand icon instead of the plain text fallback.
- Losing focus commits the current syllable instead of dropping it.
- The current composing last syllable is shown with a dotted underline when the target app honors TSF display attributes.
한followed by the Hanja key opens Hanja candidates, number keys orEntercommit the selected candidate, andEsckeeps the composing text.- A selected Hangul prefix opens Hanja candidates; a selected Hanja prefix opens Hangul reverse-conversion candidates.
- With no selection or composition, the Hanja key converts the Hangul or Hanja run immediately before the caret, and repeated Hanja key presses cycle through dictionary-resolved segments without committing the current candidate.
ㅁfollowed by the Hanja key opens symbol candidates including※.- Candidate colors follow the Windows app light/dark theme and high contrast system colors.
Candidate lookup is exact dictionary lookup over the selected prefix or caret run segment; morphology, particle splitting, and selection-internal searching remain out of scope.
Run the test binaries directly after a solution build:
.\build\MilkyWayIME.Tests.Unit\x64\Debug\mwime_tests.exe
.\build\MilkyWayIME.Tests.Tsf\x64\Debug\mwime_tsf_tests.exe