[Unreleased]

[1.20.1] - 2026-09-13

Fixed

  • Fixed a case where merely clicking the tray icon or opening the settings window could stop romaji-input completion while the IME was on
    • Caused by IME state read during a brief focus move to the tray/settings window being mistaken for the actually-focused app's state, poisoning internal belief tracking
  • Fixed IME re-application misfiring on every press of a key (e.g. the Conversion key) that was also registered as `right_thumb_key` and as an IME auto-detection watch key (`keys.ime_detect.on`), which could conflict with Google Japanese Input's own conversion feature and cause a stray "あ" to be typed
    • The duplicate registration is now detected and disabled at config-load time, with a tray warning shown
    • Also fixed a related gap where reloading a config that changes the thumb key itself would check this duplication against the old cached thumb key instead of the new one

[1.20.0] - 2026-09-12

Added

  • You can now explicitly set what a solo tap of the Non-conversion/Conversion key does to the IME on/off/toggle state, instead of relying on auto-detecting GJI/MS-IME's own key settings
    • New settings items (`muhenkan_solo_tap_ime_action`/`henkan_solo_tap_ime_action`) let you force "always turn on/off/toggle". For environments where IME control doesn't work because it clashes with GJI/MS-IME's own keymap settings
  • Bug reports now automatically attach your current GJI/MS-IME key-assignment settings
    • Supported for both the new simple key-assignment UI and the legacy detailed key-customization UI. No extra steps needed on your part

Fixed

  • Changed when awase writes its auto-start registry entry, as a mitigation for Windows Defender sometimes flagging awase.exe as persistence-malware-like behavior
    • Previously awase rewrote the registry entry unconditionally on every startup as a self-heal; now it only writes when you actually toggle the "Start automatically" checkbox in the settings window (effectiveness unverified; a proper code-signing fix is planned)
  • Fixed auto-start silently failing after installation in some environments
    • The executable had no application manifest, causing Windows' Program Compatibility Assistant to incorrectly mark it as needing to "Run as administrator"
  • Identified and fixed several additional remaining causes of a stray "@" being typed when pressing the physical Han/Zen, Non-conversion, or Conversion keys in Windows Terminal with Google Japanese Input
    • Causes included duplicate IME-on sends (reduced from up to 3 down to 2, including a gap specific to the Standard profile), a race between probe reads and issuing IME operations, and double-firing between delegate and shadow-toggle handling
  • Fixed GJI's auto-detected Non-conversion/Conversion delegate swallowing the physical key press even when you had explicitly chosen "always pass it through" in the settings window
  • Fixed Google Japanese Input sometimes mis-converting input like "ようするに" ("yō-suru-ni") into "よゅするに"
  • Fixed the physical "Katakana/Hiragana/Romaji" key sometimes being unable to switch back to hiragana after switching to katakana
  • Fixed an unrelated cached IME-on state being restored when focus moved to a different input field hosted by Explorer right after a Non-conversion key operation in Chrome
  • Added a retry of the key send for the case where a physical IME-correction key press in Windows Terminal with MS-IME is ignored and romaji keeps being displayed as-is (partial mitigation)

[1.19.0] - 2026-09-06

Added

  • The tray icon can now check whether a newer version is available
    • The right-click menu shows a newer version when one exists, with a direct link to the download page. No periodic background network activity is performed — the check only happens when you open the menu. Can be disabled via `general.update_check` in `config.toml`
  • Added a settings-screen preset that turns Caps Lock (Eisu) into an extra Ctrl key
    • Uses Windows' built-in Scancode Map mechanism (via the registry) and can be enabled/disabled from the settings window (requires administrator privileges; a Windows restart is needed for the change to take effect)
  • `[[keymap]]` (per-app key reassignment) targets (`to`) can now be a sequence of multiple keystrokes
    • Previously only a simple one-key-to-one-key substitution was supported; a single press can now send several key operations in sequence
  • Google Japanese Input (GJI) users can now assign the Non-conversion/Conversion and Hiragana/Katakana keys the meaning of turning the IME on/off/toggling it
    • Addresses a case where, even when these keys are configured as NICOLA thumb keys, mismatched GJI-side settings could cause thumb-shift conversion not to resume correctly after turning the IME back on

Fixed

  • Fixed stray kana characters sometimes appearing at the start of text input in the settings and bug-report windows (`awase-settings.exe`)
    • The IMM32 control-capability learning cache was keyed only by window class name, which let unrelated processes' mislearned state leak across processes via `winit`'s (the GUI framework's) generic class name (the same family as an earlier, single-process version of this bug). Fixed by including the process name in the cache key
  • Fixed Shift+physical Kana key (the "Katakana/Hiragana/Romaji" key on JIS keyboards) not switching to katakana conversion
    • With Google Japanese Input, holding Shift while pressing the Kana key should trigger Windows' standard katakana conversion, but this had been unconditionally disabled as a side effect of an earlier fix. Also fixed the Kana key alone not being able to switch back to hiragana once in katakana mode
  • Fixed the tray's "Clear learning cache" menu item doing nothing when clicked
  • Fixed characters occasionally being dropped or appearing out of order during Japanese input in some apps
  • Fixed Windows Terminal's automatic IME-state correction firing at an almost unbounded rate even when it wasn't actually needed
  • Added a tray notification for the case where pressing a physical IME key once can leave the NICOLA conversion engine stuck indefinitely until the focused window changes, with the key's own character being typed literally instead
    • A full fix for the underlying cause proved difficult, so for now awase only lets you know when this happens
  • Fixed a stray "@" being typed in Windows Terminal with Google Japanese Input
  • Fixed text input in the settings and bug-report windows sometimes feeling sluggish
    • An internal state-check routine was being re-run excessively even when focus hadn't changed, generating a large volume of log writes
  • Fixed the wrong symbols for the thumb-shift 0/- keys on the genuine Fujitsu "FMV-KB232" layout (should be 『 』 rather than { })
  • Rewrote settings-window warning messages to remove ADR numbers, raw key codes, and internal jargon (chord, warmup, etc.), making them clearer for general users
  • Fixed editing certain `config.toml` fields (IME-detection key settings) in an external editor while the settings window was open causing those changes to be silently discarded the moment "Apply" was pressed
  • Excluded keys that can never actually fire (IME-only virtual keys) from the "from" candidates in the shortcut-reassignment tab
  • Renamed the settings item "Thumb-shift On/Off" to "Thumb-shift Input / Romaji Input" and moved it to the advanced settings tab, since it's not something most people need to touch day to day
    • Addresses feedback that it was easily confused with the neighboring "IME On/Off" (the Windows-side IME state); it was first renamed to "awase Enabled/Disabled", but that still read as implementation jargon ("engine", "enabled/disabled") to beginners, so the wording was changed again to name the two input modes directly instead of using On/Off phrasing

[1.18.0] - 2026-09-02

Added

  • Added a "keystroke sequence" feature to `.yab` (run multiple actions from a single key, equivalent to Yamabuki's `CV4D`)
    • Disabled by default. Setting `keystroke_sequence = "on"` in `config.toml` lets a single `.yab` cell chain multiple actions with a `+` separator (e.g. outputting a character and then confirming it with Ctrl+M in one key). Named macros defined with `[[keystroke_macro]]` can be reused across keys via `@name`
    • There is no GUI toggle yet; it can only be enabled by editing `config.toml` directly. Existing `.yab` files keep working unchanged when the feature is enabled
  • Added a layout for the genuine Fujitsu thumb-shift keyboard "FMV-KB232", `layout/nicola_kb232.yab`
    • This keyboard turned out to have a symbol arrangement that matches none of the bundled layouts. Adopted the layout as provided by the reporter, verified on their own hardware
  • Added startup diagnostics for config and layout files
    • Lint warnings for malformed `.yab` quoting and `config.toml` validation warnings — some of which previously only appeared in the log — are now surfaced together in a tray balloon notification at startup
    • Also added a collapsible diagnostics list to the settings window so these can be re-checked at any time
  • Added detection and notification for a stuck kana-lock state in Teams (WebView2/MS-IME)
    • Reads the OS kana-lock state directly and, when it diverges from what awase expects while you keep typing, shows a tray notification with guidance. Automatic recovery is not possible, so only guidance is provided

Fixed

  • Fixed the physical "Eisu"/"Kana" keys sometimes not working while using PowerToys' "Mouse Without Borders"
    • Caused by two independent bugs. Fixed a regression that was dropping injected key events it should have passed through, and added an opt-in setting (`app_overrides.input_relay_apps`, empty by default) that stops awase from taking IME-control ownership of MWB's relay window. Thumb-shift character conversion itself keeps working as before
  • Fixed the NICOLA three-key simultaneous-keystroke arbitration skipping its timing check entirely when the next key arrived with an extremely tight overlap right after the previous key was released, producing an incorrect conversion (e.g. typing "しょうにん" could come out as "しいピん")
  • Fixed a custom `.yab` file that fails to load as UTF-8 silently falling back to the bundled layout, with no indication of which file was ignored
    • A dialog now explains the cause and the substitute layout whenever this fallback occurs, and opens the settings window automatically
  • Added hover tooltips to every field in the tray's bug-report window

[1.17.0] - 2026-08-31

Added

  • Added a NICOLA layout, `layout/nicola_keytop.yab`, that outputs the symbols actually printed on a standard JIS keyboard's keytops (@, [, ], :, ¥, ^), and made it the default for new installs (with one exception: @ is assigned to "、" (Japanese comma) by the official NICOLA spec, so it only outputs @ while a thumb-shift key is held)
    • The previous default, `layout/nicola.yab`, used Backspace/Escape as software substitutes at the physical key positions the official NICOLA spec leaves undefined. Prompted by a bug report from a KB232 (Fujitsu FMV-KB232) keyboard user ("symbols don't match the keytops", report `01M15R86FJW24278GGD3ETS9QX`), the new layout follows the convention used by other implementations such as Benizara and DvorakJ
    • Upgrading an existing install does not change the contents of `layout/nicola.yab` or the `default_layout` setting (by design, so a file you may have hand-edited in the Layout Editor tab is never silently overwritten). To switch, manually set `default_layout` to `"nicola_keytop.yab"`
    • The same keytop symbols (^ and ¥ on the digit row, [ on the Q row) were also added to `layout/nicola_f.yab` for genuine Fujitsu thumb-shift keyboards (the two positions on the home row occupied by the dedicated backspace/cancel keys remain unassigned as before). On this keyboard, every position besides the dedicated key next to "ん" is a standard JIS symbol key, so switching to `nicola_f.yab` per the README no longer drops any symbols
  • Added a "Disabled Apps" tab to the settings window, so `disable_apps` (apps where awase is disabled entirely) can be edited from the GUI
    • Previously required editing config.toml directly. Useful as a workaround for a bug where the physical "Eisu" key stops working while using PowerToys' "Mouse Without Borders"; you can now add the affected apps to the list yourself
    • "App-specific overrides" (a more advanced override requiring a process name + class name) remain hidden from the GUI
  • Reorganized the settings window's tab names and order: "Basic Settings" → "General Settings", "Detailed Settings" → "Advanced Settings". Reordered the tabs by frequency of use (General Settings, Key Settings, Layout Editor, Advanced Settings, Disabled Apps, Shortcuts)
  • Added settings-window sliders (Advanced Settings) for the simultaneous-keystroke three-key arbitration margin and the overlap-shortfall margin
    • Added `timing_margin_percent` (the threshold above which timing alone decides which key a three-key sequence pairs with, default 30%) and `min_overlap_margin_percent` (the threshold below which the overlap between the previous key and a thumb key is considered too small, default 0%) as sliders
    • Also removed the confirm mode (`confirm_mode`) and speculative-output delay (`speculative_delay_ms`) settings from the settings window. Most users leave these at the default `wait`, and exposing the other modes added complexity for little benefit. Change them by editing `config.toml` directly if needed
    • If `confirm_mode = "speculative"` (now deprecated) is set, it is now automatically read as `two_phase` (with `speculative_delay_ms=0`, which behaves identically)
  • Added a settings-window preset to swap the JIS keyboard's "Eisu" (alphanumeric) key with Windows' CapsLock key
    • Uses Windows' standard Scancode Map mechanism (via the registry); can be enabled/disabled from the settings window (requires administrator privileges, and a Windows restart to take effect)
  • Made `[[keymap]]` (per-app shortcut-key reassignment) actually take effect
    • Editing it in the settings window and saving it to config.toml already worked, but it was never wired into the actual key-processing path, so setting it had no effect — a dead feature. It is now wired up and behaves as configured

Fixed

  • Fixed simultaneous-keystroke detection effectively never taking KeyUp (key-release) events into account
    • A long-standing regression introduced in March 2026, with two real-world consequences
    • The overlap-shortfall check (which should treat a chord as two solo taps when the previous key and a thumb key barely overlap) had never actually worked since it was introduced
    • For some keys that send a raw key code as-is (e.g. a physical key with no layout mapping), releasing the key could leave the OS believing it was still held down
  • Fixed the IME state sometimes getting out of sync right after startup when a Win32 app such as Notepad already had focus, causing the first input to convert incorrectly
    • Caused by a gap in the startup focus-sync logic; the mismatch previously persisted until focus moved to another app and back

[1.16.1] - 2026-08-25

Fixed

  • Fixed the first character sometimes being typed literally right after a focus change (e.g. returning from Alt+Tab)
    • In Windows Terminal with MS-IME (TSF) and similar setups, the first keystroke after a focus change could be sent before the IME state had resynced, producing wrong output such as "rの" instead of "という"
    • The first keystroke after a focus change is now held until resync completes
  • Fixed the solo-repeat engine-off hotkey (`engine_off_solo_repeat`, an emergency escape for a stuck Ctrl key) sometimes not working
    • Its default key was the muhenkan key, so setups that also assigned muhenkan to a thumb key or the IME on/off key made the hotkey completely unresponsive. The default key was changed to Insert, and it now works independently of the thumb-key assignment
    • Also fixed two cases where the hotkey could fail to fire after five taps, or become permanently unresponsive after firing once
    • The config key was renamed from `engine_off_solo_triple` to `engine_off_solo_repeat` (the old name is still accepted in existing config files)
  • Fixed a case in Google Japanese Input (GJI) where the first character typed right after a TSF cold start could be lost without a trace
    • Happened right after resuming typing following 20+ seconds of inactivity. When a character is lost, it is now safely resent after confirming the focus generation hasn't changed
  • Fixed the settings window (awase-settings) silently failing to start on environments without a graphics driver
    • It now automatically falls back to software rendering on startup failure, and shows a dialog with the cause and a fix when that also fails

[1.16.0] - 2026-08-23

Added

  • Added a way to report bugs directly from the tray icon
    • Pick a symptom category, optionally attach a description, a journal/awase.log excerpt, an internal state snapshot, the config file (config.toml), and the layout file (.yab), review and edit the preview, then send it to a private intake form
    • The submission has a size cap (512 KiB); if exceeded, attached logs are automatically shrunk to fit
  • Improved simultaneous-keystroke detection accuracy for the thumb keys
    • When the overlap between the previous key and a thumb key is too small, the previous behavior always treated it as a simultaneous chord. Now an n-gram model is used to tie-break between "chord" and "two solo taps" (falling back to the safer solo-tap interpretation when no model is available, to avoid accidentally triggering IME conversion)

Fixed

  • Fixed installation failing with a confusing OS error when the Visual C++ Redistributable (vcruntime140.dll) is missing
    • Both the MSI and ZIP installers now detect the missing runtime at install time and show a message with a download link, aborting the install instead of failing later at first launch
  • Fixed the config file (config.toml) or layout file (.yab) sometimes being lost during an upgrade
    • The MSI installer's issue was in the component overwrite ordering during a major upgrade; the ZIP installer's overwrite behavior was aligned with the same fix
  • Fixed the ZIP installer (install.ps1, etc.) failing with a syntax error on Japanese Windows environments
    • Caused by the PowerShell scripts' character encoding (UTF-8 without a BOM), which Windows PowerShell 5.1 was misreading as the system ANSI code page
  • Fixed a stray "@" being typed right after confirming a candidate in Google Japanese Input (GJI), e.g. in Windows Terminal
  • Fixed the IME sometimes failing to correctly turn back on after a focus change, in some environments
  • Improved a case where keystrokes would be buffered for several seconds during continuous typing and then flushed all at once, in some environments
  • Fixed a warm-up key sent as a TSF cold-start workaround for Google Japanese Input (GJI) occasionally forcing a switch into hiragana mode as a side effect

[1.15.0] - 2026-08-17

Added

  • Added a key to toggle the IME on/off (keys.ime_toggle)
    • New "IME ON/OFF key" field in the settings window's "Keys" tab. Defaults to the Kanji key
    • If MS-IME has Ctrl+Space / Shift+Space bound to IME toggling, it's auto-detected from the registry and used alongside the manual setting
    • When GJI (Google Japanese Input) is detected, the IME on/off/toggle keys declared in config1.db are also recognized automatically
  • Added a setup-assist popup when GJI (Google Japanese Input) is detected
    • If the Muhenkan-key solo-tap setting is "always send" while still relying on GJI's default character-type-switch behavior, a dialog now asks whether to switch to the safer dedicated-Fn-key (F21) scheme
    • Agreeing writes the binding into GJI's config file (config1.db); GJI needs to be restarted for it to take effect
  • Added F13–F20 as selectable candidates for the thumb-shift on/off toggle hotkey in the shortcut remapping tab
    • For users with programmable keyboards that expose F13–F20. Previously only F1–F12 were selectable
    • F21–F24 are reserved internally for the GJI dedicated-Fn-key feature above and are intentionally excluded from the selectable candidates

Changed

  • Removed the tray's "IME state" submenu (toggling between hiragana / full-width katakana / full-width alphanumeric / half-width alphanumeric / half-width katakana / direct input)
    • Also removed the settings window's "IME conversion-mode policy (observe/force)" setting
    • Along with this, removed the internal tracking of the charset axis (kana shape) itself (ADR-094). This has no effect on the alphanumeric-vs-kana judgment that the thumb-shift engine's activation depends on
    • The tray's "Reset state" item remains, but "Roman" was dropped from its label and it no longer forces the Roman-mode bit (it only resets Engine ON / Caps OFF / Hiragana)
  • Reorganized the settings window's "Keys" tab
    • Unified the internal term "Engine" to "Thumb Shift" in the UI (e.g. "Engine control" → "Thumb Shift ON/OFF")
    • Moved "IME ON/OFF key" above "Thumb Shift ON/OFF" in the display order
    • Removed the "IME Detection" tab (settings for passively detecting external IME state changes via half-width/full-width keys, etc.) from the GUI. Almost no one changes these defaults; advanced users can still edit [keys.ime_detect] in config.toml directly
    • Simplified the Muhenkan/Henkan solo-tap suppression setting from two checkboxes into a single dropdown: "always ignore" (default) / "always send" (no change to the default behavior)
    • Extended each tab's hover-hint hit area to cover the actual control (dropdown, button, etc.), not just its label text

Fixed

  • Fixed the full-width hyphen "-" being typed as a long vowel mark "ー"
    • Occurred in apps that receive symbols via the VK/TSF path, such as Chrome/Firefox
    • Caused by awase's internal symbol-to-key table mapping both "-" and "ー" to the same key, since the IME's romaji-to-kana conversion has a special rule that turns the "-" key into the long-vowel mark
  • Fixed an issue where releasing Alt right after certain operations could switch input to JIS-kana direct input
    • With MS-IME, the "hiragana" key that awase sends internally when releasing the temporary "IME-ON half-width alphanumeric" toggle could, if it coincided with Alt being held, trigger MS-IME's own input-method switch into JIS-kana mode. Fixed by skipping this internal send while Alt or Win is held
  • Fixed repeated internal IME-OFF processing shortly after turning the IME off with Ctrl+Muhenkan on Windows Terminal + MS-IME
    • Even though the IME was correctly staying off, awase would sometimes misread the conversion-mode value as "the IME reopened" and keep resending the IME-OFF key. Fixed by adding a minimum interval (3 seconds) before allowing a resend

[1.14.0] - 2026-08-10

Added

  • Added nicola_f.yab, a layout for genuine Fujitsu thumb-shift keyboards (FKB7628-801 and similar)
    • Built from Yamabuki R's NICOLA-F.yab and a physical-layout survey of real FKB7628-801 photos; the kana placement is identical to standard NICOLA
    • The physical key layout and scan codes are the same as a JIS keyboard, so you can use it by just changing default_layout to nicola_f.yab while keeping keyboard_model = "jis"
  • Widened how much of a Yamabuki R-compatible .yab layout file awase can load
    • Added support for 9 special keywords (Insert, the 4 arrow keys, Home/End/PageUp/PageDown), VK direct specification via V+hex, F1–F24 specification via +number, and escape sequences inside quotes
    • Verified that all 15 real files bundled with Yamabuki R 1.62 parse without errors
    • Added a VK code editing UI to the layout editor (awase-settings)
    • Some faces (e.g. the 6 alphanumeric faces, some pinky-shift faces) and simultaneous-character-key shift layouts are accepted but not yet functional (parsing succeeds, but the feature itself isn't implemented)

Fixed

  • Removed the "Start automatically at logon?" confirmation dialog that used to appear on first launch after an MSI/ZIP install
    • Both the MSI installer and the ZIP distribution's install.ps1 already registered auto-start in the registry unconditionally, which made this dialog effectively unreachable
    • Changed the behavior to match: auto-start is now enabled by default with no prompt. You can turn it off from the tray menu or the settings window

[1.13.1] - 2026-08-09

Changed

  • awase now launches automatically immediately after the MSI installation finishes
    • Previously, nothing would start until the next login even after installing; you had to launch it manually or sign out/restart
    • Uses Return="asyncNoWait" so the installer completes without waiting for the resident app to exit
  • Added an "Uninstall awase" shortcut to the Start Menu
    • On some environments the "Apps & Features" uninstall entry was not being registered, so this shortcut was added as an alternative uninstall path that doesn't depend on that entry being visible
    • Invokes msiexec /x [ProductCode] directly

[1.13.0] - 2026-08-09

Added

  • Added a setting (conv_mode_policy, disabled by default) that periodically force-corrects drift in the IME/conversion mode
    • As a workaround for cases where the actual IME conversion mode (alphanumeric/hiragana/katakana × half-width/full-width) drifts from awase's own intent for some reason, you can now select "Force" from the Advanced tab in the settings screen
    • When enabled, every time input resumes from a cold state, the mode is force-written back to whatever is selected in the tray menu. This has no effect on IME ON/OFF itself
  • When Muhenkan/Henkan is assigned to a thumb key, a solo tap while not composing is now fully suppressed by default
    • MS-IME assigns "kana toggle" to a solo Muhenkan tap by default; when awase was not composing and passed the raw key through, this default MS-IME binding could hijack it and switch the IME mode unexpectedly
    • Suppression is now the default (can be turned off in settings for users who want the key's native function)
  • Added "Alphanumeric" to the engine-control/IME-control and IME-detection key pickers
    • It previously worked correctly when hand-written into config.toml; it was simply missing from the settings-screen dropdown

Fixed

  • Fixed a bug where punctuation ("。"/"、"), the long-vowel mark ("ー"), and Shift-plane symbols ("!"/"?"/"~"/"+" etc.) could be emitted half-width immediately after the IME/TSF was cold
    • Caused by the raw-VK symbol-sending path skipping the cold-start warmup check that romaji sending always performs
  • Fixed a bug where a pinky-shift chord (e.g. Shift+1 for "!") could turn into a half-width symbol in apps such as LINE, or occasionally freeze all key input for about 5 seconds
    • A safeguard meant to counter MS-IME's own "solo Shift tap switches to alphanumeric mode" misdetection was also firing in a case where it wasn't needed (the symbol itself bypasses the IME entirely), temporarily rewriting the conversion mode -- the shared root cause of both symptoms. Narrowed the safeguard to fire only where it's actually needed (the persistent half-width-alphanumeric input toggle)
  • Fixed a bug where, immediately after switching windows, only the first character typed could come out as raw alphanumeric
    • Caused by an insufficiently strict readiness check right after a focus change sometimes judging the IME "ready" prematurely
  • Fixed a bug where, after a notification popup briefly stole focus, only the first character of the next input could turn into an unintended character
  • Fixed a bug in apps such as LINE where the same character could be committed multiple times in a row
    • Caused by deciding too eagerly that a window's class didn't support IME control. Made the decision more conservative
  • Fixed a bug where the IME could unexpectedly enter katakana conversion mode with no user action, and normal IME ON/OFF operations couldn't recover it
  • Fixed a bug where, after explicitly turning the IME OFF, the engine could turn itself back ON a few hundred ms to a few seconds later with no user action
  • Fixed a bug where the IME could stay effectively ON for up to about 8 minutes after being turned OFF
  • Fixed a bug where, after opening the search UI (Windows key), Ctrl+Henkan/Muhenkan stopped actually turning the IME ON/OFF
  • Prevented "Alt+Kana" (an MS-IME input-method-switching shortcut) from unintentionally firing and locking the IME into JIS-kana input
    • Because Win32 has no API to switch the romaji/JIS-kana input method from outside, and awase cannot recover once this happens, this key combination is now detected and suppressed as a preventive measure (can be opted out of in settings)

[1.12.0] - 2026-08-01

Added

  • Added an "About awase" dialog to the tray
    • Addresses a user request: previously the version could only be checked from the installed file name
    • Both the tray menu and the settings screen (awase-settings) now show the current version (CARGO_PKG_VERSION) and let you open the homepage (https://awase.cc)
  • The tray's layout-selection menu now shows a checkmark next to the currently active layout
    • As with the Caps Lock and IME-state menu items, it's now clear at a glance which layout is active when you open the right-click menu
  • Changed layout changes made via "Apply" in the settings screen to take effect without a restart
    • Previously, thresholds and key settings reloaded immediately on "Apply", but the layout was excluded and only took effect after a restart
  • Changed the engine-control/IME-control key pickers, IME-detection tab, and toggle hotkey to combo-box selection
    • Key assignment is now selection-based rather than free-text entry, reducing the chance of typos

Fixed

  • Fixed a bug where selecting a layout and clicking "Apply" in the settings screen -- or even restarting the PC -- did not actually switch to the selected layout
    • Real-world .yab files (such as nicola.yab) often have a comment-only header with no internal name line. Selecting a copied/renamed file (e.g. my_nicola.yab) then failed to match default_layout (which is specified by file name), silently falling back to a different layout
    • Consolidated layout identification into a single matching routine keyed on file name (without extension)
  • Fixed a bug where "Save As" on a .yab file produced a corrupted line, with a section name leaking into the internal name line
    • Caused by the fallback for an unset name incorrectly adopting the first section name when loading a .yab whose header consisted only of ; comments
  • Fixed a bug on Windows Terminal (Google Japanese Input) where pressing the Hankaku/Zenkaku key left the IME showing ON while NICOLA conversion stopped working
    • Caused by a single physical key press triggering two separate signals to GJI: awase's own SendInput(VK_IME_ON), and a delayed resend of the original physical key that had been passed through -- with the later-arriving physical key overwriting the conversion mode
    • Unified the physical-key delivery decision to depend on whether a direct GJI/MS-IME control mechanism actually actuates, rather than on the app's profile (details: docs/known-bugs.md BUG-46)

[1.11.0] - 2026-07-28

Added

  • Added the ability to select Enter as a thumb key
    • Enter (VK_RETURN) can now be assigned to left_thumb_key/right_thumb_key (added "Enter" to the thumb-key choices in the settings screen)
    • As with Space, when Enter is assigned as a thumb key, a solo tap emits a raw VK_RETURN (confirming conversion) even while the candidate window is shown (unlike Muhenkan/Henkan, emitting a raw VK_RETURN during composing is a legitimate IME function)
    • Shift+Enter is emitted immediately as a literal Enter (soft line break) without waiting for chord detection
    • The settings are enter_thumb_ignore_composing_guard/enter_thumb_shift_literal (default true). Shown in the settings screen only when Enter is a thumb key

Fixed

  • Fixed a bug where right-clicking the tray icon showed no context menu at all
    • Caused by an earlier refactor that mistakenly judged the handler unreachable and removed it. In fact, both the tray right-click notification and the menu-selection confirmation were only ever delivered to that removed handler, so neither the context menu itself nor any of its items (IME mode switching, "reset state", etc.) could be triggered anymore
    • Restored the handler and confirmed right-click → menu display on real Windows hardware
  • Fixed a bug where, with the IME icon still showing ON, NICOLA conversion stopped working and could not be recovered via Ctrl+Shift+Henkan or the tray's "Reset state"
    • App: Windows Terminal. IME: Google Japanese Input (GJI)
    • Caused by Ctrl+Shift+Henkan being unable to recover from a context-driven Inactive state while user_enabled=true, and by the tray menu commands (Reset state, IME mode switching, etc.) targeting the wrong window because opening the menu itself steals focus to awase's own tray window
    • Fixed Ctrl+Shift+Henkan to also fire on a context-driven Inactive state, and fixed the tray menu commands to explicitly target the window that had focus immediately before the menu was shown
  • Fixed a bug where, while using GJI, the IME-OFF correction key was resent in an unbounded loop at the observation interval (roughly every 20-45ms), producing behavior that looked like a key being mashed
    • App: Windows Terminal (Imm32Unavailable/TsfNative family, classified as a Blacklist app by the force-tsf judgment). IME: GJI
    • Drift correction (the automatic fixup for a desired/observed mismatch) could not feed its result back into the observation side, so the same VK_IME_OFF kept being sent on every observe tick without the mismatch ever clearing, discarding the warm state each time
    • Added a cooldown that skips resending within a fixed window (400ms) of the previous correction
  • Fixed a bug in Alt-key thumb-key impersonation where the "impersonation active" flag stayed set after key-up, causing subsequent unrelated Alt presses to be miscorrected as well
    • Discovered by a test that ran on real Windows hardware for the first time after the GCP Spot self-hosted runner was introduced. Fixed so the retained state is always reset to false at key-up
  • Fixed a bug where, on a cold session after a long idle in GJI (TsfNative apps such as Windows Terminal), reactive literal-detect was skipped entirely based only on a confirm-key hint, leaving the leading romaji unconverted and output as a literal
    • Caused by promoting the confirmed flag without checking the GJI probe's actual measurement (whether it had settled). Fixed to only grant the exemption after checking the actual measurement
  • Fixed a bug where, in GJI (TsfNative apps such as Windows Terminal), a "session already confirmed" state carried across focus changes and long idle periods, so a leading character that leaked out as a literal in a brand-new cold session was never detected
    • Changed the confirmed flag from a boolean to the generation (a counter that advances on every cold start) at which it was confirmed, so it is automatically invalidated once the generation advances
  • Fixed a bug where the MS-IME cold-start protection (the gate that prevents the leading character from becoming a literal right after IME turns ON) only applied to TSF-mode apps, leaving Vk-injection-mode apps (Chrome/Edge/Electron and other apps that default to TsfNative) unprotected
    • Extended the gate to Vk injection mode as well
  • Fixed a bug where the NICOLA layout (both JIS and US) had a non-standard "yo" assigned to left-thumb-shift + ;
    • An audit of the official NICOLA spec across all 44 key positions found that left-thumb-shift + ; is undefined in the spec, and the "yo" assignment was a repository-specific addition; reverted it to undefined (none)
    • The right-thumb-shift + u-row "vu" is likewise undefined in the spec but kept, since it's an intentional extension shared with the Yamabuki-family implementation (benizara)

[1.10.1] - 2026-07-20

Fixed

  • layout/nicola.yab/nicola_us.yab: Fixed a bug where the number-row left/right thumb shift produced duplicate "6"/"7" for the keys "4" and "5"
    • Since the very first commit, both the left and right thumb-shift number rows had duplicated bracket symbols as 4:[ 5:] 6:[ 7:], and the Japanese corner brackets 「」 did not exist anywhere on the number row
    • Fixed to 4:「 5:」 (Muhenkan+4 → 「, Henkan+5 → 」), leaving 6:[ 7:] unchanged
  • Fixed a bug where startup failures exited silently with no indication to the user
    • awase.exe is built with windows_subsystem = "windows" and has no console, so if startup failed for any reason — a missing config.toml, a TOML syntax error, an unknown key name for left_thumb_key/right_thumb_key, keyboard-hook registration failure (e.g. blocked by security software), or tray-icon creation failure — double-clicking it would just vanish in an instant with no way to tell what went wrong
    • On startup failure, a MessageBoxW now shows the error and a cause-specific remedy. TOML syntax errors include the line number, column number, and the offending line, so it's clear exactly what to fix

[1.10.0] - 2026-07-19

Added

  • Added cell copy/paste (history-based) to the "Layout Editor" tab
    • Select a cell and press "Copy" and its value is automatically pushed to the top of the history (up to 4 entries, retained even across shift planes)
    • The history is shown as a row of buttons, and a single click pastes directly into the selected cell (because it does not go through the text field, the result is exactly the same value as the source cell, including the kana conversion of romaji)
    • Copying the same value again does not create a duplicate; it simply moves it to the top of the history
  • US layout: Added the ability to impersonate thumb keys with the left/right Alt keys
    • Because the US layout has no Muhenkan/Henkan keys on either side of the space bar, a setting was added to let the left/right Alt keys impersonate left_thumb_key/right_thumb_key (left_alt_impersonates_thumb_key/right_alt_impersonates_thumb_key, default false). This lets awase accomplish, on its own, the same thing as an external remapper like PowerToys
    • It only takes effect while the engine is ON; while OFF the keys act as normal Alt so Alt+Tab and the like are not broken. Left and right can be configured independently, and while held down the state is fixed at the moment of the keypress to prevent stuck modifiers
    • Shown in the settings screen (awase-settings) only when the US layout is selected
  • US layout: Added a composing-time fallback for the Space thumb key and immediate emission of Shift+Space
    • When Space is assigned as a thumb key, a solo tap can now emit VK_SPACE (advancing conversion candidates) even while the candidate window is shown (unlike Muhenkan/Henkan, emitting a raw VK_SPACE during composing is a legitimate IME function)
    • Shift+Space is emitted immediately as a literal space without waiting for chord detection
    • The settings are space_thumb_ignore_composing_guard/space_thumb_shift_literal (default true). Shown in the settings screen only when Space is a thumb key
  • Settings screen: Automatically reset/restore the default hotkey values when switching between the US and JIS layouts
    • Switching to the US layout now clears the JIS-oriented default hotkey values (Muhenkan/Henkan keys, etc.) to empty, and switching back to JIS restores the JIS defaults

Fixed

  • BUG-31: Fixed a bug where characters were silently lost during continuous typing in Microsoft Teams
    • App: Microsoft Teams (TeamsWebView, Chromium-based, Vk mode). IME: Google Japanese Input (GJI)
    • Reproduction: Immediately after confirming with Enter, even though the state was warm (GjiFsm::OnWarm), a physical NativeF2Down (non-TSF) event unconditionally issued MarkCold+GjiCompositionReset, killing the warm-maintenance timer, so subsequent romaji got caught in a per-VK confirm race and some was lost (field report: part of "5せっしょん" was silently dropped)
    • Added a guard to ignore NativeF2Down while warm
  • BUG-30: Fixed a bug where characters that had been correctly entered were mistakenly backspaced while the GJI candidate window was visible
    • The candidate window's SHOW event (edge-triggered) and its live visible state (level-triggered) were separate sensors, and there was no protection during visibility when SuspectedLiteral was detected. Added a veto that holds off backspacing while visible, and unified the literal-detect logic across TSF/Chrome
  • Alt thumb-key impersonation: Fixed a bug where the OsModifierHeld bypass disabled NICOLA chord detection entirely
    • The vk rewrite itself was being done correctly, but a separate path derived from GetAsyncKeyState (modifiers.alt) was still returning the physical Alt press as-is, so BypassReason::OsModifierHeld was misfiring in three places. Fixed to correct modifiers.alt during impersonation
  • Alt thumb-key impersonation: Fixed a bug where in some environments the vk arrived as the generic VK_MENU, so impersonation never triggered
    • In some environments the WH_KEYBOARD_LL vkCode arrives as the generic VK_MENU rather than the left/right-distinguished VK_LMENU/VK_RMENU, so a comparison based only on direct matching was always false. Fixed to distinguish left/right using the LLKHF_EXTENDED flag
  • Settings screen: Fixed a bug where the "Apply" button was always disabled
    • awase-settings.exe's config-reload notification was using FindWindowW to look for a nonexistent window class name (awase_msg_window), so the notification never reached awase.exe (awase_tray_window). Fixed to the correct class name, and on failure it now explicitly logs via log::warn!
  • Settings screen: Fixed a bug where config.toml path resolution was asymmetric with awase.exe
    • awase.exe can specify an explicit path via a command-line argument, but awase-settings.exe ignored it, risking editing a different config.toml. Aligned the priority order, and also added a feature that always displays the path being edited at the top of the screen
  • Settings screen: Fixed an issue where long validation-warning text was cut off by the button row and not shown

Changed

  • Greatly simplified the GJI/Chrome cold-start warmup architecture
    • After several days of real-machine soak testing (60+ cold events, zero suspected literals) confirmed no corruption, the wait-queue (the ColdReason×long_idle matrix of WarmupKind::FreshF2/ReWarmup/ProbeWithSettle etc.) and the sacrificial-key mechanism (SacrificialWarmupCoro/ImeOffOnWarmupFsm) were physically removed, consolidating onto the per-VK confirm approach that sends romaji one character at a time and confirms each
    • Unified the per-VK confirm loops that were duplicated between Chrome (probe_fsm.rs) and TSF (gji_warmup_coro.rs) into a shared implementation (net -82 lines)
    • Finalized the addition of scan codes to Chrome VK sends, promoting it from experimental to permanent behavior
    • As the foundation supporting the above, added StepCoro::prime() (self-priming without a dummy input) to the internal dependency crate timed-fsm

[1.9.1] - 2026-07-12

Added

  • Added a "Layout Editor" tab to the settings screen (edit .yab in place)
    • Merged the standalone awase-yab-editor binary into awase-settings and deleted it (the code is worth reusing, but a separate binary was judged not worth it; the cost of keeping two binaries in sync across CI, distribution, and the installer outweighed the practical benefit)
    • All four planes (normal / left thumb shift / right thumb shift / little-finger shift) can be edited via the flow: click a cell in a keyboard-style grid to select it → choose the type (keystroke / literal / special key / none) and edit → apply
    • The former "Romaji" and "Key sequence" types were consolidated into "keystroke," auto-detected by the input (whether it is alphabetic). If you enter a key that does not exist on a JIS keyboard, an error is shown in real time and the apply button is disabled
    • Even if you enter symbols/alphanumerics in full-width, they are automatically converted to half-width, so the input side does not need to be conscious of half/full width
    • Supports Open / Save / Save As / Reload, and the Ctrl+S / Ctrl+O / Ctrl+Shift+S / F5 shortcuts

Fixed

  • Fixed an issue where the settings screen's "Layout Editor" tab (formerly the Preview tab) did not display / crashed
    • Unified layouts_dir/config.toml path resolution onto awase::paths::resolve_relative_to_exe, fixing a bug where layout/nicola.yab directly under the workspace root could not be found when launched from under target/debug/ via cargo run/cargo build
    • Re-showed the tab that had been hidden on 2026-07-06 (c3fa08e) on the grounds that "the layout preview implementation was not solid yet"
    • Fixed a bug where opening the tab caused a silent forced termination (the cause was that egui::Grid does not allow cursor movement via in-row add_space(). Blocked by the two issues above, it had never once been rendered with real data, so this was a latent bug no one had hit)
    • Added log file output (awase-settings.log) + a panic hook to awase-settings. Because the GUI subsystem has no console, panics had previously left nothing in any log
    • Fixed an issue where .yab was loaded synchronously every time the tab was opened, lengthening the interval between window creation and the first render; changed to lazy loading

[1.9.0] - 2026-07-11

Added

  • Persistent "IME-ON half-width alphanumeric" toggle via a left Shift solo tap (BUG-25, MS-IME support)
    • Added a persistent toggle where a solo tap of the left Shift key (press → release without any intervening key) switches to half-width alphanumeric input while keeping the IME open. Another solo tap returns to normal kana input
    • This replaces BUG-15's "half-width alphanumeric while Shift is held" (hold approach). It keeps the existing safety net that cancels out MS-IME's false detection of a Shift solo tap during a Shift+character chord (the Shift plane of .yab), while removing only the ASCII pass-through layer (shift_plane_halfwidth) that was specific to the hold approach
    • A right Shift solo tap always performs only the safety-net restore, and pressing it during the persistent toggle also acts as an "emergency release"
    • For GJI (Google Japanese Input), three entry mechanisms were tested on real hardware — scan-code-tagged VK injection, IMC write, and scan=0 VK injection — but none worked (CapsLock contamination, or SendInput not even reaching the hook), so the feature was disabled for GJI (MS-IME only). See docs/known-bugs.md BUG-25 and docs/experiments.md entries 06–09
  • Changed Ctrl+Henkan pressed while the IME is ON to reset to hiragana + romaji + CapsLock OFF
    • Previously it only responded to an IME OFF→ON transition, but now, even when the IME is already ON, pressing Ctrl+Henkan re-confirms the input mode by aligning it to hiragana, romaji, and CapsLock OFF
    • Added a guard that targets only the case of a Ctrl-only modifier plus a single VK_CONVERT press, so that unrelated IME-ON paths such as Ctrl+Shift+Henkan (the EngineOn combo) are not falsely detected

[1.8.9] - 2026-07-11

Added

  • US (ANSI 104) keyboard support

    • Added US-layout-specific scan-code ⇔ physical-position tables (scan_to_pos_us/pos_to_scan_us) to crates/awase-windows/src/scanmap.rs, and wired them to be selected according to KeyboardModel::{Jis,Us}
    • Reintroduced the general.keyboard_model ("jis"/"us") setting. The field of the same name had been removed on 2026-07-06 as "never once wired up"; this time it was revived after actually wiring it all the way through .yab parsing and HookConfig (the hook's scan_to_pos table selection)
    • Corrected KeyboardModel::Us.row_sizes()'s row0 from 13 to 12 (the grave key is treated as off-grid since it has no physical key mapping. The old value was an error in never-executed, unverified code)
    • Added the US-layout layout/nicola_us.yab (the columns for JIS-only keys removed from layout/nicola.yab. The values of the shared scan codes are reused as-is)
    • Extended AppConfig::validate to warn at startup validation when keyboard_model = "us" yet defaults that assume Muhenkan/Henkan keys (left_thumb_key/right_thumb_key and each hotkey under [keys]) remain
    • Added JIS/US selection, layout-preview tracking, and thumb-key candidates to the settings screen (awase-settings)
    • The Linux/macOS side is not covered this time (remains fixed at KeyboardModel::Jis)
  • Discovered that assigning Ctrl/Alt/Win to a thumb key does not work (engine/tests.rs)

    • We once recommended VK_LMENU/VK_RMENU (Alt) as a thumb-key substitute for the US layout, but it turned out that the KeyDown of that key itself immediately hits ModifierState::is_os_modifier_held() → the OsModifierHeld of bypass_reason, so it never enters PendingThumb at all and is passed straight through (chord detection itself does not work). Not just Alt but Ctrl/Win are likewise impossible
    • This constraint is pinned by test_ctrl_alt_win_thumb_key_never_enters_pending_due_to_os_modifier_bypass. Shift is not subject to is_os_modifier_held(), so it can reach PendingThumb (test_thumb_alone_timeout_suppressed_when_thumb_is_os_modifier confirms the suppression of a solo tap), but its interaction with the Shift-plane feature is untested
    • Also added a defense to timeout_pending_thumb that, when the thumb key is an OS modifier, suppresses raw VK emission of a solo tap regardless of composing (propagating modifier_key into ClassifiedEvent/PendingThumbData)
    • Withdrew Alt from the recommendations in config.rs / config.toml.sample / awase-settings, and now suggest F13-F24 (assuming physical remapping on a programmable keyboard) / VK_SPACE as substitutes
  • Fixed the emergency Engine OFF via solo Muhenkan repeats being too prone to misfiring

    • Simply mashing the Muhenkan key to recover from a misread conv mode right after waking from sleep (stuck at katakana) caused the "solo triple-tap of Muhenkan turns the engine OFF" mechanism (ADR-055) — prepared as an emergency escape for a stuck Ctrl — to misfire, setting user_enabled to false in a real-machine case (2026-07-08). Once triggered, user_enabled did not come back with normal key operations like Ctrl+Henkan (ime_on), leaving a "nothing fixes it" state
    • Raised the required repeat count from 3 to 5 (SOLO_OFF_TRIGGER_COUNT, src/engine/nicola_fsm.rs) to make misfires less likely
    • Now shows a tray notification when triggered, so the user can immediately understand "the engine has emergency-stopped" and "it can be recovered with Ctrl+Shift+Henkan." See the addendum in docs/adr/055-engine-off-solo-triple.md
  • Fixed a bug in Chrome/Edge where a single misread of the conv mode actually locked GJI into katakana (BUG-19)

    • The GetForegroundWindow()-based conv reading (get_ime_conversion_mode_raw_timeout) could momentarily pick up an incorrect katakana conv while focus bounced between Chrome_WidgetWin_1 and the GJI candidate popup (Windows.UI.Input.InputSite.WindowClass), and ConvModeMgr unconditionally committed this
    • Eager warmup (send_eager_tsf_warmup) took the committed misread at face value and actually sent VK_DBE_KATAKANA → the transient misread got locked in as GJI's real state, turning all subsequent input into katakana, and furthermore the KatakanaShadowOff rescue logic repeatedly bounced IME OFF/ON, inducing leading-character literal leaks
    • Added debouncing limited to a non-katakana→katakana transition (the same "confirm over 2 consecutive ticks" pattern as ImeKindDebounce) to ConvModeMgr::update_from_conv
    • Addendum: The above only protected the warmup side (ConvModeMgr); classify_conv_transition (belief updates, engine sync such as KatakanaShadowOff) was re-interpreting raw conv directly and was defenseless against the same misread. Changed classify_conv_transition's argument from conv: u32 to a ConvMode derived from ConvModeMgr::get(), so that warmup and belief/engine-sync reference the same committed value. See docs/known-bugs.md BUG-19
    • Addendum 2: Even in a debounced state, if a conv misread fired KatakanaShadowOff/NativeToggleShadowOff right after the user explicitly turned the IME OFF, it would spoof UserImeSetIntent{Command} and directly rewrite desired_open, causing a separate-path recurrence where the engine returned to ON on its own. Separated this into EngineSync::ReportOpenInference, which no longer rewrites desired_open but merely records it as an ObserverReported (ObservationSource::ConvOpenInference, Medium confidence). The actual correction decision is delegated to the existing drift correction (BUG-20 already fixed the OFF direction too). Also added a source-aware gate that never fires a correction from this observation alone as long as there has never been any explicit user intent
  • Fixed a bug during Chrome input where a single misdetection of the CLSID-based IME kind caused GjiFsm to be rebuilt per word and cold to keep firing (BUG-17)

    • The gji-io-monitor worker thread was propagating single flips of ITfInputProcessorProfileMgr::GetActiveProfile — which it polls every 2 seconds — to the main thread as-is via WM_IME_KIND_CHANGED, and set_active_ime_kind unconditionally created a new warmup strategy (GjiFsm/MsImeStrategy) on every kind change → discarding the established OnWarm/OnComposing
    • The very fact that Chrome cold-start reinit sends a real VK_IME_OFF→VK_IME_ON toggle became the trigger for the misdetection, forming a self-amplifying loop of "reinit → misdetection → GjiFsm rebuild → next word is cold too → reinit again → …" (in field logs, cold_seq climbed 392→401 per word, and two "StartComposition while engine off" warnings were observed at 2146ms intervals, nearly matching the CLSID polling period)
    • Added ImeKindDebounce to tsf/gji_monitor.rs so that a new kind is not committed until it is observed on 2 consecutive ticks. See docs/known-bugs.md BUG-17
    • Addendum 3: Even after debouncing, cold_warmup.rs::preamble() (run on every cold warmup) unconditionally wrote conv_mode.get() back to the real IME, so a once-mistakenly-committed belief kept being re-asserted on every focus bounce, leaving a path that self-amplified. Added ConvModeMgr::needs_conv_restore_write/mark_conv_restore_written to limit the restore write to the same committed mode to just once
    • Addendum 4: The above throttle was wired only into the IMM32 write-back paths of cold_warmup.rs/probe_io.rs, leaving only output/mod.rs::send_eager_tsf_warmup — the very thing the root-cause analysis had named (the charset selection of eager warmup, which fires at high frequency on every confirm key) — defenseless. Applied the same throttle here too, limiting the sending of charset-changing warmup keys (F1/F0 family) for an already-committed mode to once
    • Addendum 5: Since the user confirmed they had never manually selected katakana / half-width alphanumeric from the IME tray and have no plans to do so, a DIAG_FORCE_HIRAGANA_CHARSET diagnostic flag was added, starting an experiment that disables the charset-following logic (F1/F0 warmup, IMM32 conv_target write-back, F1 leading warmup prefix) wholesale and always treats it as Hiragana (observation/logging themselves continue; only acting on it is stopped)
  • Fixed a bug where the first character right after turning the IME ON, though correctly converted, got an unnecessary BS correction (BUG-24)

    • is_partial_literal() (tsf/warmup/literal_detect_fsm.rs) was judging partial literals not by the confirmation signal of the romaji it just sent (candidate window SHOW / GJI I/O change) but by the unrelated proxy indicators nc_fired/gji_resumed (whether there was a response to a different F2 warmup key) that had been settled before sending. Right after ColdReason::requires_settle() (FocusChange/NativeF2Consumed/SetOpenTrue — which can occur even when the IME is already ON), under DIAG_DISABLE_PROACTIVE_TSF_WARMUP (a diagnostic flag that disables cold-start proactive warmup wholesale and relies only on reactive detection), the confirmation send that is the source of this proxy indicator is itself unconditionally skipped, so nc_fired became structurally always false, and it reproduced reliably on real hardware
    • Also identified and fixed a side effect where composition_fsm.rs::ConfirmKeyDown and platform.rs::on_reinject_key unconditionally issued MarkCold/GjiCompositionReset even for warm confirm keys (Enter/Space/Escape) (the extra cold marking during continuous typing was increasing the exposure of literal-detect)
    • Added a mechanism (the literal_session_confirmed family in tsf/observer.rs, DIAG_LITERAL_SESSION_SKIP) that, once literal-detect has been confirmed once within an IME session (from the start of typing to the candidate window HIDE), skips the detection process itself until the session ends, so as not to slow down responsiveness
    • The above alone did not fix the first character of the session itself (the one that first passes through is_partial_literal()), so ultimately the design was changed to, for the first character of a session only, send the romaji's VKs one at a time and confirm the sent VK's own CompositionConfirmed/SuspectedLiteral before sending the next VK (ProbeAction::TransmitSingleVk, gji_warmup_coro.rs). The "which VK's effect is it" ambiguity that arose from sending two VKs together was structurally resolved by inserting a deliberate confirmation point between VK sends. The symptom's resolution was confirmed on real hardware
    • See docs/known-bugs.md BUG-24

[1.8.6] - 2026-07-07

Fixed

  • Fixed Teams (TeamsWebView) being misclassified as still a target of IMM32 cross-process control
    • Microsoft Teams's main window class TeamsWebView was not listed in IMM32_UNAVAILABLE_CLASSES and was handled as the Standard classification, so unreliable IMM32 open-status reads were being attempted despite it being Chromium-based like the Chrome family. Added it to be classified as Imm32Unavailable / TsfNative like Chrome_*
    • Along with this, added sanitize_focus_probe_open_status() to the completion handling of kp_stage_focus_probe, adding a defense that, if the current_app_profile at apply time does not support IMM32 open status (Imm32Unavailable/TsfNative), forcibly discards probe.ime_on. This stops trusting a stale probe.ime_on even for apps whose classification changes later

Changed

  • Wired empirically-learned IMM32 capabilities into focus-profile determination (unreachable-path audit B5)
    • ImmCapabilityStore (which learns from ImmGetDefaultIMEWnd=NULL detection and exceeding an IME detection-miss threshold, and persists to cache.toml) had, until now, only learned and saved, with no consumer that changed behavior
    • On focus updates, classes whose static classification is Standard but whose learned value is Unavailable are now demoted to Imm32Unavailable (so that IMM-broken apps not listed in the static list no longer incur wasteful SendMessageTimeoutW)
    • Promotion is not performed (static Imm32-unavailable / TSF-native knowledge takes priority). Demotion self-releases via Works recovery learning. Demotions are auditable via the [imm-learning] profile demoted INFO log, and mislearning is cleared by hand-editing [imm_capability] in cache.toml
    • Note: learned entries already accumulated in an existing cache.toml take effect immediately. If an unexpected demotion occurs, check the logs
  • Cleanup based on the unreachable-path audit (2026-07-06, 5 parallel perspectives)
    • Removed 2 orphan WM handlers (WM_PROCESS_DEFERRED / WM_IME_KEY_DETECTED) and a group of enum variants with zero construction sites (ImeEffect::RequestRefresh, ActivationState::Pending+PendingReason, InactiveReason::NonTextFocus, DecisionOrigin, DetectionSource::UiaAsync, ConvModeAuthority::TemporarilyUnowned, ColdReason::SessionExpired, ChordKind::CtrlHenkanImeOn+ImeEvent::ChordStarted)
    • Removed an event-driven wakeup mechanism that was firing on nothing (win32-async::AtomicWatcher + notify_all, the write-only composition_probe counter) (waiting had already been replaced by polling)
    • Simplified an always-false condition (used_eager_path), folded away EffectOrigin/SetOpen.origin that had become always-true, and removed a dead write (GjiState::OnCold.saw_native_f2)
    • All of these were confirmed via repository-wide grep and individual verification of the evidence chain as "values that do not exist at runtime / paths that are not taken." No behavior change

Fixed

  • MS-IME cold start — Fixed leading-character literalization right after IME ON (BUG-13, "を"→"wお")
    • MsImeStrategy assumed "MS-IME is always warm" and had no cold-start protection, so sends within ~130-300ms (measured) right after an IME OFF→ON transition literalized the leading VK
    • Introduced a confirm-then-transmit of the same type as the GJI probe rather than a fixed wait: when ImeModeFsm has not confirmed NATIVE, romaji is deferred to MsImeReadyCoro, and it is sent the moment the NATIVE bit is confirmed via IMC_GETCONVERSIONMODE polling (10ms interval)
    • MS_IME_READY_CONFIRM_MS (400ms) is a safety valve only (in environments where IMC cannot be read, it forces the send + a give-up latch to prevent every keypress from becoming a probe)
    • See docs/known-bugs.md BUG-13

Added

  • Detect conflicting MS-IME key assignments and guide the user to disable them
    • When MS-IME's "Muhenkan key = IME-off" / "Henkan key = IME-on" assignments are enabled, a solo tap of Muhenkan/Henkan that awase passes through flips the IME state on the OS side only, diverging from belief (real machine 2026-07-06: a Muhenkan tap 92ms after IME ON produced "IME OFF, Engine ON," turning thumb-shift input into raw romaji)
    • On the first WM_IME_KIND_CHANGED where the active IME is confirmed to be MS-IME, it reads IsKeyAssignmentEnabled / KeyAssignmentMuhenkan / KeyAssignmentHenkan under HKCU\Software\Microsoft\IME\15.0\IMEJP\MSIME, and on a conflict shows a warning popup. "Yes" directly opens ms-settings:regionlanguage-jpnime (the Microsoft IME settings page)
    • The check itself is skipped while GJI is in use. The registry is read-only (no automatic rewriting/disabling is performed)

Changed

  • Removed settings that had lost their meaning
    • keyboard_model: layout parsing was fixed to JIS and it had never once been wired up (the settings screen's jis/us selection had no effect)
    • output_mode: already replaced by per-app auto-injection method selection (InjectionMode); it was a write-only dead setting
    • hook_mode: consolidated onto Relay (Filter was a legacy path untested since the arrival of the relay-family features, so it was removed implementation and all)
    • Leaving these keys in an old config.toml is harmless (they are ignored). Also deleted the pre-separation old built-in settings GUI (gui/main.rs, an orphan file)
    • confirm_mode survives as a live setting (still defaults to wait). The n-gram-family detailed settings are wired so the UI enables them only when the "n-gram prediction" mode is selected
  • Added UI for per-app overrides and the emergency-escape key to the settings screen
    • New "Per-app" tab: app_overrides (force_text / force_bypass / force_vk / force_tsf) and post_bypass (pass-through of tmux prefixes etc.) can now be edited from the GUI
    • Key settings tab: added engine_off_solo_triple (solo triple-tap to turn the engine OFF, for emergency escape when Ctrl is stuck)
  • Temporarily hid the "Per-app" and "Preview" tabs from the side panel
    • "Per-app" is an advanced feature, so its GUI-ification was deferred, leaving it to direct editing of config.toml
    • "Preview" (layout preview) is temporarily hidden because its implementation is not solid yet (future work)
    • Both implementations themselves remain, and config.toml's app_overrides / post_bypass / layout settings are valid as before

[1.8.5] - 2026-07-06

Fixed

  • Fixed an issue where the settings screen became unusable across DPI transitions on multiple displays (a7d3e53, 7cb1625, 7207413)
    • Moving to a display with a different DPI scale caused the window not to fit on the destination monitor, pushing the Apply/Cancel buttons off-screen
    • Auto-clamp to the monitor size + moved the buttons to an always-visible bottom panel + set a minimum window size
    • Narrow widths are handled by reflow (reduced-scale keyboard diagram, wrapping of keymap rows), and a scrollbar is shown only when it still doesn't fit. Increased the default width to 580px (previously the right edge of the preview was cut off)

[1.8.4] - 2026-07-06

Added

  • Added F13-F24 to the thumb-key choices (8951418)
    • For users who assign F13-F24 to thumb positions on a programmable keyboard (QMK/ZMK etc.)
    • Also added parsing of VK_F13–VK_F24 to VkCode::from_name

[1.8.3] - 2026-07-06

Fixed

  • Fixed an issue where the Engine always went OFF about 500ms after focusing Edge/Chrome (BUG-07) (0d67f20)
    • The TsfGate's bypass-commit handling was injecting a false write_focus_probe(false) observation on every refresh without running a probe (the false premise that "non-TSF windows have no Japanese IME," a revert of ce45b82)
    • In Imm32Unavailable, which has no real observation path, the false Low false dominated belief and was uncorrectable. The architecture_guard pins the call sites of write_focus_probe to the real probe path
  • Fixed an issue where messages originating from worker threads did not reach the main thread (BUG-09) (69f271d)
    • post_to_main_thread's PostMessageW(NULL) is "a post to the calling thread itself," so WM_IME_KIND_CHANGED from gji-io-monitor was being lost → even in an MS-IME environment the warmup strategy stayed as the default GjiFsm and wandered (a split-brain where the detection layer is correct but only the output layer is broken)
    • Changed to PostThreadMessageW(engine_thread_id()) + an IME-kind pull sync at message-loop start. Confirmed on real hardware a switch to MsImeStrategy 3ms after MicrosoftIme detection
  • Fixed an issue where pressing a physical hiragana key did not turn the IME ON in MS-IME (BUG-10) (9d5040b)
    • The unconditional Suppress of the physical F2 (VK_DBE_HIRAGANA) in TSF mode was paired with the GJI strategy's "F2 substitute send" contract, but in MsImeStrategy no substitute was sent, making it eat-and-run (Engine ON but real IME OFF divergence)
    • Limited the Suppress to the GJI strategy (f2_warmup_owned), passing the physical key through for MS-IME
  • Defense against JIS-kana input caused by a kana-lock flip from synthetic VK_KANA (BUG-08) (b38d67f)
    • A synthetic VK_KANA pair at an interval impossible for a physical press (135µs) was passed through, flipping GJI from romaji to JIS-kana input
    • Swallow LLKHF_INJECTED-tagged VK_KANA in the hook, and added diagnostic logging on all VK_KANA arrivals to identify the injection source

Reverted / Disabled

  • Disabled the application of UIA asynchronous focus classification (BUG-11/BUG-12) (d941721, f88e89b)
    • The delivery fix for BUG-09 exposed two-stage real harm in a receive handler that ran for the first time ever (cache-key mix-up → Edge permanently NonText; even after fixing, a recurrence from the structural mismatch between (pid,class) cache granularity and the browser's within-window element granularity)
    • Changed the handler to log-only, deliberately reverting to the proven behavior from before the delivery fix. Sync classification (known classes, WS_EX_NOIME, MSAA) remains as before
  • Withdrew the firing of JIS-kana auto-restore (restore_roman) under TsfNative (92fddc8, f88e89b)
    • Under MS-IME × TsfNative, conv's ROMAN=0 is a false positive, and the restore write bounced conv back and forth between 0x19⇄0x09, inducing spurious Engine/IME ON during direct input
    • Changed to a spec that fires only in the is_roman_reliable=true context (effectively disabled on the TsfNative idle path). See docs/experiments.md entry 03 for the background

[1.8.2] - 2026-07-05

Fixed

  • Fixed an issue in LINE etc. where subsequent input characters were lost while the drain queue was being processed (233b6e3)
    • If a new Unicode character arrived while UnicodeColdWarmupFsm was in flight, the FSM was overwritten and deferred_chars was lost
    • Added push_deferred_unicode_chars to TickableFsm so that an in-flight FSM can be appended to, avoiding the overwrite
  • Fixed an issue where GJI warmup (VK_A+BS) misfired right after startup in an MS-IME environment (b694ffc)
    • The gji_monitor thread did not send WM_IME_KIND_CHANGED at startup, delaying the switch to MsImeStrategy
    • After the initial IME-kind detection, it now unconditionally posts WM_IME_KIND_CHANGED, applying the correct warmup strategy from right after startup

Refactoring

  • Extracted the unicode-cold-warmup logic into helper methods (60a0b79)
    • Added start_unicode_cold_warmup / flush_unicode_cold_deferred_chars to WindowsPlatform, consolidating duplicate code between send_keys and dispatch_gji_response
  • Reduced deep nesting and duplication via method extraction (b0cd4e9, c4900a3, f5023b4)
    • Consolidated duplicate blocks in probe_io.rs with fmt_conv() / store_gji_warmup_if_probing()
    • Turned a 2-line idle calculation into a function with observer::gji_idle_ms() (removed 6 sites)
    • Turned the 4-line gji_on_event + dispatch_gji_response pattern into 1 line with dispatch_gji_event() (5 methods)
    • Turned the 3-line IME OFF→ON notification pattern into 1 line with Output::on_f22_f21_sent() (2 sites)
    • Turned VK-run formatting into a function with KeyInjector::format_vk_run() (shared by the 3 send_vk_runs* methods)
    • Unified 7 raw SendInput sites onto the existing win32::send_input_safe() and removed the unsafe blocks

[1.8.1] - 2026-07-05

Fixed

  • Fixed an issue where the IME's internal recognition (belief) and the actual OS-side IME state diverged during fast focus transitions such as Alt+Tab (dd6f208, 08ce474, 11ee689, 435e2d3)
    • Fixed the GJI force-IME-ON guard to look at "the actually active IME kind" rather than "the survival of the GJI process," resolving double-sending of VK_DBE_HIRAGANA in an MS-IME environment
    • Wired a settle barrier (settle_until) right after a focus transition, guarding all call paths of Engine/ImeEffect::SetOpen (keyboard input, focus-change notifications, IME-refresh polling, hotkeys, etc.) in a single sweep at the two sites execute_from_loop/execute_from_hook
    • Unified onto is_effectively_tsf_native the 5 sites that had misjudged Windows Terminal (CASCADIA_HOSTING_WINDOW_CLASS) as "non-TSF native," overlooking that the classification priority of AppImeProfile::from_class_name never classifies it as TsfNative
  • Fixed an issue where the BrokenAppBootstrap force guard overrode the user's explicit OFF intent (a06ad69)

[1.8.0] - 2026-07-05

Added

  • Established an observation-admission layer (ObservationAdmission) via FocusEpoch + ImmLikeTicket (604cf99, 569bf0f, 67e63ad, 1345d95) (ADR-077)
    • Manages focus transitions by epoch, structurally rejecting stale observations to fundamentally prevent the misobservation chains of ImmCross apps
    • Added shadow-grace suppression to ImmCrossProbe, enforcing epoch matching on all paths
    • Added rejection counters and dump-time logging to make the observation-admission situation visible
  • Changed the settings screen so thumb keys can be selected via a dropdown (9e1621a)
    • Left/right thumb-key assignments can now be changed directly from a dropdown UI, applying setting changes immediately
  • MSI/ZIP can now be downloaded directly from the website (877b1af, 15c6ff5, 21eadb1)
    • Added links to download the latest GitHub Releases assets directly from awase.cc

Fixed

  • Fixed an issue in ImmCross apps where the engine stopped while still in kana mode after IME ON (81f6576, e4378c6)
    • Suppressed the ObservedKana observation right after IME ON in ImmCross apps, resolving the case where the engine was mistakenly deactivated
  • Fixed an issue in MS-IME + ImmCross apps where romaji mode was not maintained at IME ON (91631a0, 1969cd3, 4c02f2e)
    • Force ROMAN mode before IME ON in MS-IME, and skip forcing romaji when ObservedKana
  • Unified IME-kind determination from process existence to the CLSID API, supporting dynamic IME switching (e6456b2, ce252fe)
    • Abolished the GJI-fixed policy and determine the IME kind via the CLSID API at runtime, supporting dynamic switching of GJI/MS-IME
  • Fixed an issue where a black console window appeared when launching the settings screen (49d4f31)
  • Fixed thumb-key changes from the settings screen to apply immediately (6cd1178)
  • Fixed to not perform immediate drift correction on HwndCache-derived intents (d418035)
  • Classified XamlExplorerHostIslandWindow as NonText (a8d9a00)

Refactoring

  • Migrated all ImmCrossProbe to epoch matching and removed shadow grace (f478ee7)
  • Abolished TipDetector's file cache and unified onto an in-process OnceLock only (9e0ecf0)

[1.7.1] - 2026-07-02

Fixed

  • Fixed an issue in ImmCross apps like LINE where the engine stopped after switching from GJI alphanumeric to hiragana (4bcf8b0)
    • Because GJI does not set the ROMAN bit even in alphanumeric mode, classify_transition could not detect the return to hiragana, so ObservedEisu lingered and the engine became Inactive(NotRomajiInput)
    • Added a stale-recovery branch to classify_ime_snapshot that auto-resets to AssumedRomaji the moment conv_mode changes to non-alphanumeric in an ImmCross app

Refactoring

  • Unified ImmCrossProbe's input_mode updates to go through classify_fetched_snapshot (c2c8b55)
    • Applied the three-layer separation of Observe → pure decision → belief to the ImmCrossProbe handler, removing inline determination

[1.7.0] - 2026-07-02

Added

  • Auto-detect a state where alphanumeric direct input is happening with the IME left ON (ObservedEisu) and switch to IME OFF (direct input) (30e6c5f, 1ef82ca, 754a7a4) (ADR-074)
    • Added InputModeState::ObservedEisu to explicitly distinguish "shadow=ON but actually half-width alphanumeric direct input"
    • When idle_conv_check detects ObservedEisu, it automatically issues IME OFF + Engine deactivation
    • The case where ObservedEisu lingers right after SetOpen(true) is reset to AssumedRomaji, immediately reactivating the Engine
  • Replaced the tray menu's "Reset internal state" with a process restart (a720c7a)
    • When the FSM / IME state is broken, the entire process can now be restarted with mouse operations alone to return to a completely clean state
    • Positioned as the only reliable means of resetting runtime-determined state, such as the in-process fixing of the GJI kind determination (active_ime_kind) (ADR-073)

Changed

  • Extended warmup-send VKs to support Charset (hiragana / katakana / JIS-kana) (536d93a)
    • Consolidated the TSF warmup send when GJI is inactive (e.g. when MS-IME is in use) into a single decision point, eliminating skip omissions
  • Introduced a single gate for conv_mode changes via ConvModePolicy (2826248, cc9f745, af3b776) (ADR-064)
    • Added a conv_mutation_allowed gate to Output, making writes to conv_mode verifiable in one place
    • Replaced is_romaji_mode: bool with the ConvModePolicy type to clarify the meaning

Fixed

  • Fixed a group of bugs where Ctrl+Henkan / Ctrl+Muhenkan did not work correctly in MS-IME (f527a18, baff902, 301e911, 48a667a)
    • Fixed a bug where Ctrl+Henkan did not make MS-IME hiragana / did not return from half-width alphanumeric
    • Unified MsImeDirectStrategy's DirectInput switch onto the idempotent VK_IME_OFF
    • Once GJI is confirmed, forbid mistaken demotion to MS-IME (in-process fixing, ADR-073)
  • Fixed IME misrecognition / keystroke loss on ImmCrossProbe / GJI+TsfNative focus (496926c, 489cdf1, 15ac8d8, 500dab6) (ADR-071, ADR-075)
    • Fixed a bug where ImmCrossProbe misrecognized the IME state on Qt / GJI focus
    • Changed the GJI+TsfNative IME OFF send from a VK_KANJI toggle to the idempotent VK_IME_OFF
    • Fixed a bug where a subsequent key was lost while a TSF cold-start probe was running, turning "にゅうりょく" into "にうりょく" (moved ownership of the deferred VK queue from the probe machine to TsfWarmupCoordinator)
  • Fixed an IME/Engine desync caused by a re-sync omission of conv_mode_authority (e2199e7, c887da8, 1f96598) (ADR-072)
    • Re-sync conv_mode_authority on every IME apply completion, resolving the issue where a stale authority value lingered right after a panic reset or on the second Ctrl+Henkan
    • Made the already_matched determination consistent across all IME kinds, and fixed it to not mistakenly mix in candidate_was_seen
  • Fixed a group of IME/NICOLA-engine state-sync bugs in katakana / JIS-kana mode (66bfc33, 58fa2ac, e8b09de, 927f2a2, 0f652ae)
    • Fixed a bug where the NICOLA engine stayed OFF after switching to katakana mode / was returned to hiragana after selecting half-width katakana in the tray
    • Correctly reflect JIS-kana / katakana mode changes made via the taskbar into belief
    • Suppressed the mistaken downgrade of HanKata → ZenKata
  • Fixed Engine state-sync omissions / misdetection caused by idle-conv-check (0f75b5b, ea3da7f, ed862bb, a325df7, 29bc9c4)
    • Fixed a bug where the Engine did not recover on a katakana+shadow=OFF or HanAlpha→Hiragana transition
    • Fixed Chrome IME-state misrecognition after ALT+TAB, and a tray desync (user_enabled=true but ime_on=false)
  • Consolidated GJI cold-start / partial-literal countermeasures into SacrificialWarmup (VK_A+BS) (6c1732d, 22c3905)
    • Replaced with a warmup based on VK_IME_OFF→ON + write_bytes detection, ensuring compatibility with vim etc.
  • Fixed a bug where the engine got stuck on the first keystroke after waking the PC from sleep (c4df99b) (ADR-076)
    • Fixed a bug where, right after waking from sleep, read_ime_state_fast temporarily returned is_japanese_ime=false and the engine deactivated with NotJapaneseIme
    • Compute the grace-period determination before set_is_japanese_ime inside apply_focus_probe, suppressing downgrades to false while shadow grace is active (updates to true are always allowed)
    • Made the grace protection of imc_open and is_japanese_ime symmetric
  • Fixed a bug where a named-mutex race caused startup to fail on process restart (bb84696)
    • A bug in the "process restart" tray feature added in this version itself

Internal

  • Completed all 21 tasks of the cohesion refactor, H-1 through M-5: resolved circular dependencies among type definitions, removed direct OS-global calls from the state layer, split PlatformState into FocusStore/GateStore/KeymapStore and Runtime into FocusTracker/RefreshScheduler/ImeCoordinator (ADR-069) (a7a1e23, 811036a, 8aad49a)
  • Renamed ApplyBeliefOpenBelief and consolidated into the reduce_open_belief pure function (concentrating the IME-apply decision logic in one place and making it easy to unit-test) (ADR-070) (1e09e90, 8c34984)
  • Introduced a RuntimeOutbox/RuntimeRequest event bus and removed the OutputRuntime reverse dependency (with_app()) (4782e3e, 7568180)
  • Extracted TsfWarmupCoordinator / KeyInjector / ImeApplyPlanner from the bloated Output (03ebfc9, e1993bf, 080e96d)
  • Moved ConvMode/Charset determination to the nicola crate and made it pure functions, relaxed the #[cfg(windows)] gate to per-module granularity, and added Linux unit tests (ADR-065) (b1ab86f, 5ee724b, b27a218)

[1.6.0] - 2026-06-29

Added

  • Full Microsoft IME support (45edf19, 56cd9a5)
    • Idempotent ON/OFF control via MsImeDirectStrategy (VK_DBE_HIRAGANA / VK_DBE_ALPHANUMERIC) (ADR-063)
    • Switch between GJI / MS-IME at runtime via WM_IME_KIND_CHANGED
  • Dynamic GJI CLSID discovery via TSF EnumProfiles (55233f0, 005f0a6)
    • Migrated from process-name dependence to CLSID-based IME-kind determination
    • Persist the CLSID to cache.toml to reduce the cold-start cost after a restart

Changed

  • Migrated GJI IME control to VK_IME_ON/OFF (0x16/0x1A) — no config1.db patch needed (b271aee, 8c39b8e)
    • Completely removed gji.rs (config1.db patching, process management) (-692 lines)
    • Removed "GJI Setup / Teardown" from the tray menu; no first-install work required
    • Confirmed VK_IME_ON/OFF behavior on real hardware in Chrome / WezTerm / Windows Terminal (2026-06-28)
    • Removed the gji_keybinds_ok flag and the Observer's config1.db monitoring loop
  • Unified IME-kind determination onto a CLSID basis (2d5cfe9)
    • Removed the gji_write_idle_ms heuristic to improve determination accuracy

Fixed

  • Fixed a bug in WezTerm where the first character after Enter (e.g. "な") suddenly disappeared (3ffbe66)
    • Promote nc_fired in ReinjectConfirmKey + TSF mode to suppress LiteralDetect misdetection
  • Fixed a BS burst caused by LiteralDetect misfiring while MS-IME is active (699ab5f)
  • Panic reset now returns to romaji-hiragana even from katakana / JIS-kana states (a88bb36, 6ee20bf)
    • Force NATIVE | FULLSHAPE | ROMAN via IMC_SETCONVERSIONMODE and drop KATAKANA
    • Return to romaji-hiragana even from half-width katakana (including JIS-kana input mode) / full-width katakana

[1.5.0] - 2026-06-27

Added

  • Added "Reset internal state" to the tray menu (1591593)
    • When the IME state or FSM is broken, the internal state can be initialized with mouse operations alone
    • Can be reliably reset even in situations where the keyboard is not working properly (ADR-052)
  • Introduced StepCoro — a timer-driven coroutine foundation (e548e63)
    • Replaced GjiWarmupFsm / LiteralDetectFsm / SacrificialWarmupFsm / TsfProbeMachine with StepCoro (ADR-053)
    • Intermediate variables of FSM states can be written as local variables of the coroutine, greatly reducing code volume
    • Promoted to the timed_fsm::coro module (118b3cf)
  • Persist InjectionMode in cache.toml (c6fed60)
    • Added InjectionModeStore to remember the injection mode across sessions
    • Reduce the cold-start cost after a restart (ADR-058)
    • Merged imm_cache.toml into cache.toml (10918c2)
  • InjectionMode post-hoc promotion: auto-promote on GJI write_bytes observation (68c24e1)
    • Judge via WriteTransferCount whether the keys sent in Unicode mode right after focus were processed by GJI
    • If GJI is working, auto-promote injection_mode to Tsf (ADR-062)
  • Unicode long-cold support: UnicodeColdWarmupFsm (70d3fed)
    • After a long idle in Unicode mode, send a VK_IME_ON poke and confirm GJI has started up before sending characters
    • Hold off character sending until GJI responds to prevent partial literals
  • Added a startup check for competing software (9875c2c)
    • If a NICOLA-capable IME such as Yamabuki is running at the same time, warn via a balloon notification (ADR-060)

Changed

  • Migrated auto-start from schtasks to the HKCU\Run registry (0d09d80)
    • Starts immediately at logon (no 30-second delay needed), and can be registered without administrator privileges (ADR-059)
    • Old schtasks tasks are automatically deleted at startup (584897a)
  • Added Windows Terminal to force_tsf (4e49ee1)
    • Reliably enable GJI composition, improving conversion accuracy in Windows Terminal

Fixed

  • Skip IME-key injection while the Win key is held (6469f51)
    • Fixed the malfunction where Win+A opened the Start menu (ADR-061)
  • Prevent mistaken IME-key sends on virtual-desktop switch (a97173a)
    • Fixed a focus-guard omission where IME keys were mistakenly sent to LINE etc. right after switching virtual desktops
  • Remove partial-literal remnants with BS (f3ff84d)
    • When TSF literal recovery gives up, delete the literal characters left in the terminal with BS
  • Turned the resend after partial-literal detection into SacrificialWarmup (62ad28b)
    • Unified the resend after partial-literal detection onto a safe warmup flow
  • Added IPC settle waiting after an early HIDE in SacrificialWarmup Phase2 (88d562f)
    • After the candidate window is HIDEd early, wait until the GJI IPC completes before releasing the next input
  • Changed Unicode long-cold from a lone VK_IME_ON to a VK_IME_ON+VK_A+BS sacrificial key (6cb175f)
    • Reliably increase GJI's WriteTransferCount to improve cold-determination accuracy
  • Record the shadow value as a surrogate observation under TsfNative/Imm32Unavailable (1e77002)
    • Even in windows where IMM32 is unavailable, save shadow_on as an observed value to stabilize state estimation

Internal

  • Bulk-replaced #[allow] with #[expect] (all crates) (c2b0685)
    • Adapts to the strengthened lints of Rust 2024 edition; the compiler warns once the suppression reason is no longer needed
  • Made unsafe extern explicit (Rust 2024 lint compliance) (f645d3c)
  • Migrated awase-settings to edition 2024 (ee2487c)
  • Removed GjiWarmupFsm / StartLiteralDetect (dead-code removal after the StepCoro migration) (f01d401)
  • Raised MSRV to 1.85 (timed_fsm::coro uses async/await syntax)

[1.4.0] - 2026-06-25

Added

  • Added the [[post_bypass]] setting: a setting to NICOLA-skip the keystroke immediately following a command key, such as tmux (Ctrl+B) or screen (a67ebb5)
    • The target key and wait time can be specified in the [[post_bypass]] section
    • Added tmux-oriented comments and a config example to the TOML sample (49b8343)
  • Introduced SacrificialWarmup: resolve the partial literalization of Chrome cold-start and WezTerm long-idle with a self-sacrificing VK_A+BS batch (28fc97a, 16a288d)
    • Pre-correct Chrome's "kおのなかで"-type partial literal in the warmup phase
    • Resolve the case where WezTerm enters an Engine-ON/IME-OFF state after a long idle
    • Limited to long-cold + TSF mode only to prevent performance degradation in normal times (d02ec44)
  • Implemented ImeModeFsm + ChromeGjiReinitFsm: added an FSM that, after sending F22→F21, confirms GJI has settled into Hiragana mode before allowing the next input (2c8d647)
  • Improved the Chrome LiteralDetector to a WriteTransferCount basis: judge composition completion by the number of bytes written to the pipe, suppressing mistaken BS (c7ef500)
  • Update belief on all F21/F22 send paths + suppress FocusChange right after a VK: raise the reliability of the IME-mode state and reduce unnecessary re-probes (1a0e54e)

Fixed

Complete fix of the Ctrl+J problem

  • Fixed an issue where Ctrl+J did not reach tmux while the IME was ON (32a037d)
    • TsfGate was mistakenly sending Ctrl+J during IME ON to the GJI warmup path
  • Re-fixed the issue where Ctrl+J was hijacked by GJI (ee0b1fd)
  • Fixed an issue where a modifier's early release after a Ctrl bypass mistakenly suppressed J↑ (bd51ea1)
  • Fixed to NICOLA-skip the next key right after a Ctrl+key bypass (ddb6b58)
    • Eliminated the case where the key right after a bypass was mistakenly judged as a thumb-shift chord

Stabilization of SacrificialWarmup

  • Fixed a bug where it terminated immediately at gate=Bypass (0426fb6)
  • Send VK_A+BS in the same batch to prevent a character flash (af906b1)
  • Take the write_bytes baseline before sending VK_A and adjusted the threshold to 350B (26bc0fe)
  • Force-reset GJI with F22→F21 on a Chrome cold timeout (9630acb)
  • After confirming Chrome is warm, wait for HIDE before resending the real romaji (2355761)
  • Fixed the IPC race where "おお" disappeared on an early HIDE after a VK_A+BS atomic batch (123efb1)
  • Fixed a drain-ordering bug where composition_was_seen became false on the first tick (e40a2eb)

WezTerm

  • Fixed the second-character literalization after a WezTerm long-idle with the PendingGjiConfirm state (7041b20)
  • Sync injection_mode right after focus, and re-initialize with F22→F21 on Unicode long-cold (6ecb8e9)
  • Fixed the HWND cast type to *mut c_void (implicit conversion to isize is UB at the Windows API boundary) (ff1f092)

GJI FSM

  • Dispatch WarmupComplete immediately on StartProbe in Unicode mode (fix for the OnCold stuck bug) (444e9a6)
  • Fixed to maintain the proactive probe on a FocusChange right after ImeOn (782f10d)
  • Added a generation guard to FocusChange spawn_local polling (preventing double application) (90c9962)

Other

  • Added a post_bypass field to ValidatedConfig (build-error fix) (089858d)
  • Downgraded the Unknown → real-value IME state transition from a drift WARN to an initial-confirm DEBUG (4347928)
  • Fixed a type mismatch where a u64 was being passed to sleep_ms (ddc6be3)

Internal

  • Ported HoldingGate / GateAction to the timed-fsm crate: consolidate the gate logic in the library layer to improve reusability (ebbc9e4)
  • Added to_hwnd() to HwndId to consolidate raw casts in one place (1932948)
  • Reference gji_candidate_visible via env (removed direct polling) (19f4372)
  • Removed the unnecessary plan / observations fields from SacrificialResend (61c4c12)

[1.3.0] - 2026-06-23

Fixed

  • Fixed an issue where ALT+TAB could not be pressed consecutively (d6cb1a4)
    • When sending F21/F22 (IME ON/OFF keys) on every focus change, ALT was temporarily released, so the ALT+TAB switcher mistook it as "ALT released = confirm"
    • F21/F22 are GJI-only virtual VKs, so they work correctly even when sent while holding ALT
  • Fixed the "kお" cold-start bug after a GJI long-idle (e4a6248, c571acf)
    • Fixed the case where, after GJI is idle for 8–10 seconds or more, the first keystroke partially literalizes ("こ"→"kお")
    • Improved to batch F2 together even on a medium idle (7–10 seconds) when GJI times out unresponsive (2159dca)
  • Fixed partial literals ("kお", "seつぞく") (5562b6a, d54f5b1, 125d2c1)
    • Set gji_resumed after a GJI I/O response to rescue partial literals
    • Enable LiteralDetect in TSF mode as well (preventing the recurrence of "seつぞく")
    • Fixed the partial-literal BS count from chars.len() to a fixed 2
  • Improved the Chrome-path LiteralDetector (c279fc7)
    • Switched to new_gji_resumed to suppress literal misdetection after a GJI resume
  • probe-fsm: Fixed F2 double-sending / delay (d195c43, 4de228b)
    • Suppress F2 double-sending into the TSF batch on the ReWarmup/non-eager path
    • Skip fresh F2 + NameChangeWait when GJI is pre-idle to reduce delay
  • composition-fsm: Fixed to correctly maintain the Long cold state (c96598f)

Added

  • Created GjiWarmupFsm: introduced a GJI-cold-start-warmup-dedicated FSM to make the warm-up logic independent (fcd1b82, f768944)
  • Created LiteralDetectFsm: a literal-detection FSM shared by the warm path and GJI post-transmit (8608062, 660ee19)
  • Created ChromeProbe: swapped pending_tsf to Box<dyn TickableFsm> and added a Chrome-dedicated probe (51901c0)
  • Added ColdKind::Medium: classify GJI idle time into Long / Medium / Short to optimize the warmup strategy (bf3eade)
  • Transmit immediately when the candidate is visible in NameChangeWait: shorten the probe wait time in WezTerm by up to 300ms (25182eb)

Internal

  • Defined the TickableFsm trait: TsfProbeMachine / GjiWarmupFsm / LiteralDetectFsm / ChromeProbe implement a common interface (d22e987)
  • Defined the ImeWarmupStrategy trait: abstracted so that GjiFsm / MsImeStrategy can be handled through a unified interface (eb8b9d4)
  • Large-scale GjiFsm refactoring: separated ProbeStatus into Authorized+Executing and removed 3 Cells, moved OutputActiveGuard to Output (0ca92b2, 65e0a1a)
  • transport refactoring: extracted PassthroughQueue and consolidated the F2 case into PhysicalKeyDisposition::plan() (3cfc57b, 005ed17)

[1.2.0] - 2026-06-21

Added

  • Added GjiFsm: introduced an FSM that infers GJI's (Google Japanese Input's) internal composition state (b152c7e)
    • Phase 2a: connected GjiFsm to Output and wired FocusChange / ImeOn / ImeOff / WarmupComplete (bb228c2)
    • Phase 2b: wired CompositionReset / KeyInput and turned is_composition_warm into an FSM (d49c516)
    • Phase 3: switched is_composition_warm to the GjiFsm SSOT (2b6d25f)
    • Phase 4: removed the legacy epoch warm tracking and consolidated GjiFsm as the SSOT (588ea32)
  • Enhanced panic logging: added a hook that records the location and message on a panic to awase.log (de0226a)
  • Auto-generate the changelog page: added a GitHub Actions workflow to auto-generate changelog.html from CHANGELOG.md (efc4310, 6fb7a38)

Fixed

  • Fixed the F2+S race of WezTerm TSF cold start and the false-positive BS after gji_resumed (b754277)
  • Fixed hiragana injection from IME ON carry-over on a CoreWindow cache miss (1c5cc91)
  • Fixed a debug_assert panic where StartProbe was overwritten during a NICOLA chord (a5a9412)
  • Chrome: Fixed to force-send the programmatic F2 even when the f2_gji_long_idle flag is enabled (43dca5a)
  • probe: Fixed to reset consecutive_count on SetOpenTrue as well (cbd1946)
  • tray: Explicitly handle WM_CLOSE to prevent an unintended shutdown (c924eed)

Internal

  • probe-fsm: organized the FSM layer boundary by introducing TransmitPlan / ProbeObservations (3c36f21)
  • chord management: fully consolidated into ImeStateHub (Phase 2 complete) (fd17da0)
    • Consolidated chord start/end decisions into the reducer (a7218e0)
    • Promoted pending_warmup_on_keyup to CompositionFsm (f3b0448)
  • transport: separated suppress_physical into PhysicalKeyDisposition (8a045bb)
  • Clippy pedantic compliance (CI Rust 1.96) (881f824)

[1.1.1] - 2026-06-20

Fixed

  • Fixed the IME-OFF Engine-ON state after a Chrome → WezTerm focus switch (12dd094, 56f5e49)
    • Changed to force-send GJI F21 ignoring shadow_on on entry to TsfNative
    • Changed the belief on a TsfNative cache miss from carry-over (true) to the safe default OFF
    • Extended the focus cache TTL from 5 seconds to 1 hour (resolving the issue where leaving and returning to a window with IME ON was treated as a cache miss)
    • Skip cache saving for short focus (< 100ms) (preventing notification popups etc. from overwriting a normal state)
  • Fixed the LiteralDetect false positive after WezTerm gji_resumed (the case where "あ" became "a") (da8dad1)
  • Implemented early composition confirmation after WezTerm gji_resumed (detect the GJI I/O change to shorten the wait time) (aa8a79d)
  • Fixed the comp-probe RUNTIME re-entrant borrow bug (shadow_on / jp were always false) (2225578)
  • nicola-fsm: Fixed a bug where the shift counter lingered on a solo repeat (a53344b)

Internal

  • Added GJI process I/O statistics (ReadOperationCount / ReadTransferCount) to the monitoring log (93236a8)

[1.1.0] - 2026-06-20

Important Changes

  • Changed the GJI keybindings from F13/F14 to F21/F22 (7f8291f)
    • F21/F22 are virtual keys that do not exist on a real keyboard and do not generate VT escape sequences
    • The Nop binding configuration in WezTerm / Windows Terminal is no longer needed
    • When upgrading, be sure to re-run "Set up Google Japanese Input" from the tray menu

Added

  • Automatic GJI keybind monitoring: if the F21/F22 entries are erased from config1.db, detect it within 30 seconds and auto-re-register (58557e9)
  • Tray menu expansion: added GJI teardown and an auto-start toggle (e67cb49)

Fixed

  • Fixed leading-character literalization after a WezTerm long-idle ("こ"→"ko") (LiteralDetect + BS resend approach) (84e6942)
  • Fixed the GJI IME-ON failure bug: F21 was ignored due to a missing DirectInput\tF21\tIMEOn entry (9d11cd7)
  • Fixed a partial literal in Teams / Chrome (conversion failure of "kおんな"→"こんな") (3744457, 040f8f8)
  • Fixed the LiteralDetect false positive after a GJI long-idle (a6b4c0d)

Performance

  • Shortened the probe wait time right after a focus change from 300ms to 100ms (improving input responsiveness) (23052fb)

Documentation

  • Updated F13/F14 → F21/F22 across all awase.cc pages, and removed the WezTerm Nop configuration steps

Internal

  • Removed the KeySeq mechanism of the TSF probe (dead code) (550781f)

[1.0.1] - 2026-06-15

Fixed

  • Fixed the "んい→に" conversion bug in Chrome VK mode (71a4d68)
  • Fixed a bug where a stale ime_on=false lingered on entry to Imm32Unavailable (bfad1a8)
  • Fixed KeyUp while Ctrl/Alt/Win is held to be bypassed symmetrically with on_key_down (5904d67)
  • executor: Fixed the mistaken firing of a deferred timer by running the Timer immediately in Relay mode (71ebfb9)
  • executor: Fixed the push of the event queue (VecDeque) to push_back (3823f12)

Documentation

  • Heavily renewed the landing page (added technical differentiation and the origin of the name)
  • Added a Usage page (usage.html) (covering the settings screen, all config.toml items, and emergency-operation procedures)
  • Added an Internals page (internals.html)
  • Greatly expanded the FAQ
    • Shift misses during fast typing
    • Idempotent IME control rather than a toggle in Google IME
    • Four symptoms that tend to occur with other tools (Yamabuki R etc.) and their countermeasures
    • F21/F22 Nop configuration steps for Windows Terminal / WezTerm
  • Unified terminology in comments (IMM → IMM32, IME-ON/OFF → IME ON/OFF, Henkan/Muhenkan → Henkan/Muhenkan)

Removed

  • Removed awase-gji-setup.exe from the distribution (the feature is already integrated into the awase main body)

Internal

  • config: promoted to a #[serde(default)] struct and removed the group of 18 default_* functions (-142 lines)
  • vk: introduced enum VkMarker to type-unify the marker selection by bool/fn_ptr
  • fsm / nicola_fsm / ngram: cleaned up duplicate code, wrapper functions, and dead code (total -270 lines)
  • rustfmt / clippy formatting

[1.0.0] - 2026-06-14

The first stable release.

Full Changelog: https://github.com/cuzic/awase/compare/v0.1.0...v1.0.0