Sumire Japanese Input Mode Switching: Hiragana, Katakana, and Romaji Handling

Sumire handles Japanese input mode switching through a state-driven architecture in IMEService that toggles between Hiragana, Katakana, and Romaji (English) layouts using KeyAction events, with Katakana cycling through full-width and half-width variants via a three-state counter in countToggleKatakana.

Sumire is the Japanese-only keyboard layout activated when TenKeyQWERTYMode.Sumire is set in the kazumaproject/japanesekeyboard repository. This specialized input method provides seamless transitions between Japanese kana input and QWERTY romanization through systematic mode management implemented primarily in IMEService.kt.

Understanding Sumire's Three Input States

Sumire operates through three distinct logical states that determine both keyboard layout and character processing:

  • Hiragana: The default Japanese state displaying standard kana keys (あ‑ん) via InputMode.ModeJapanese
  • Katakana: Character conversion state within the Japanese layout, cycling between full-width and half-width Katakana using KeyAction.ToggleKatakana
  • Romaji (English): QWERTY alphabet layout accessed through InputMode.ModeEnglish or KeyAction.SwitchToEnglishLayout

Mode Initialization in IMEService

When an input view starts, the service checks the current TenKeyQWERTYMode in onStartInputView to determine the initial layout. According to the source code at [IMEService.kt lines 1114‑1122](https://github.com/kazumaproject/japanesekeyboard/blob/master/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/IMEService.kt#L1114-L1122), the initialization logic sets customKeyboardMode based on the current input configuration:

if (qwertyMode.value == TenKeyQWERTYMode.Sumire) {
    when (mainView.keyboardView.currentInputMode.value) {
        InputMode.ModeJapanese -> {
            customKeyboardMode = KeyboardInputMode.HIRAGANA
            updateKeyboardLayout()
        }
        InputMode.ModeEnglish -> {
            /* Romaji path handled separately */
        }
        InputMode.ModeNumber -> {
            customKeyboardMode = KeyboardInputMode.SYMBOLS
            updateKeyboardLayout()
        }
    }
}

This initialization establishes whether the keyboard starts in Japanese (Hiragana) or English (Romaji) mode before any user interaction occurs.

Layout Generation Based on Input Mode

The method createNewKeyboardLayoutForSumire() constructs the visual keyboard layout by evaluating customKeyboardMode. As implemented at [IMEService.kt lines 4756‑4785](https://github.com/kazumaproject/japanesekeyboard/blob/master/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/IMEService.kt#L4756-L4785), the layout builder uses a when expression to render distinct key sets:

when (customKeyboardMode) {
    KeyboardInputMode.HIRAGANA -> { /* Hiragana layout construction */ }
    KeyboardInputMode.ENGLISH  -> { /* Romaji QWERTY layout construction */ }
    KeyboardInputMode.SYMBOLS -> { /* Symbol layout construction */ }
}

Hiragana Layout Construction

When customKeyboardMode equals KeyboardInputMode.HIRAGANA, the keyboard displays standard Japanese kana keys. This layout serves as the base for both Hiragana and Katakana input, as Katakana conversion happens at the string processing level rather than through layout changes.

Romaji (English) Layout Construction

Switching to Romaji mode triggers the KeyboardInputMode.ENGLISH branch, which rebuilds the keyboard with QWERTY alphabet keys (a‑z). This represents a complete layout swap rather than a character conversion.

The Katakana Toggle Mechanism

Unlike the binary switch between Hiragana and Romaji layouts, Katakana mode operates through a three-state cycle applied to the current input string. When users press the dedicated toggle key mapped to KeyAction.ToggleKatakana, the system increments countToggleKatakana and applies character conversion accordingly.

At [IMEService.kt lines 5549‑5589](https://github.com/kazumaproject/japanesekeyboard/blob/master/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/IMEService.kt#L5549-L5589), the cycle logic appears as:

when (countToggleKatakana) {
    0 -> { 
        _inputString.update { it.hiraganaToKatakana() } 
        countToggleKatakana++ 
    }
    1 -> { 
        _inputString.update { it.toHankakuKatakana() } 
        countToggleKatakana++ 
    }
    2 -> { 
        _inputString.update { it.toHiragana() } 
        countToggleKatakana = 0 
    }
}

The conversion utilities reside in the core module's [String.kt](https://github.com/kazumaproject/japanesekeyboard/blob/master/core/src/main/java/com/kazumaproject/core/domain/extensions/String.kt):

  • hiraganaToKatakana(): Converts full-width Hiragana to full-width Katakana (lines 11‑18)
  • toHankakuKatakana(): Converts to half-width Katakana (lines 90‑104)
  • toHiragana(): Reverses the conversion back to Hiragana (lines 227‑242)

The UI reflects the current Katakana state through currentKatakanaKeyIndex, stored in the dynamic key map under "katakana_toggle_key" at [IMEService.kt lines 4629‑4632](https://github.com/kazumaproject/japanesekeyboard/blob/master/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/IMEService.kt#L4629-L4632).

Romaji Mode Activation

When users trigger KeyAction.SwitchToEnglishLayout, the service transitions from Japanese to English input by updating customKeyboardMode and rebuilding the layout. As shown at [IMEService.kt lines 5862‑5870](https://github.com/kazumaproject/japanesekeyboard/blob/master/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/IMEService.kt#L5862-L5870):

customKeyboardMode = KeyboardInputMode.ENGLISH
createNewKeyboardLayoutForSumire()

If the user has enabled sumireEnglishQwertyPreference, the mode temporarily falls back to the standard QWERTY engine (TenKeyQWERTQMode.TenKeyQWERTY) while preserving the Sumire UI chrome.

Dynamic Key State Management

Every Sumire layout creation passes a mutable state map to KeyboardDefaultLayouts.createFinalLayout() to ensure visual consistency with the current mode. At [IMEService.kt lines 4661‑4667](https://github.com/kazumaproject/japanesekeyboard/blob/master/app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/IMEService.kt#L4661-L4667), the dynamic states include:

val dynamicStates = mapOf(
    "enter_key"          to currentEnterKeyIndex,
    "dakuten_toggle_key" to currentDakutenKeyIndex,
    "space_convert_key"  to currentSpaceKeyIndex,
    "katakana_toggle_key" to currentKatakanaKeyIndex
)

This map ensures that toggle keys display the correct iconography based on whether the input is currently in Hiragana, full-width Katakana, or half-width Katakana states.

Summary

  • Sumire uses TenKeyQWERTYMode.Sumire to activate its Japanese-only layout system
  • Hiragana is the default KeyboardInputMode.HIRAGANA state displaying kana keys
  • Katakana cycles through three conversion states (full-width → half-width → Hiragana) using countToggleKatakana without changing the physical layout
  • Romaji switches to KeyboardInputMode.ENGLISH for QWERTY input via complete layout reconstruction
  • All mode transitions flow through IMEService.handleKeyAction() and trigger createNewKeyboardLayoutForSumire() to refresh the keyboard view

Frequently Asked Questions

How does Sumire differ from standard QWERTY mode when switching to English input?

Sumire provides a dedicated English mode accessed through KeyAction.SwitchToEnglishLayout that sets customKeyboardMode to KeyboardInputMode.ENGLISH, whereas standard QWERTY mode (TenKeyQWERTYMode.TenKeyQWERTY) uses a different layout engine entirely. If sumireEnglishQwertyPreference is enabled, Sumire falls back to the standard QWERTY engine while maintaining its visual styling.

Why doesn't Katakana have its own keyboard layout like Hiragana and Romaji?

Katakana input reuses the Hiragana keyboard layout but applies string-level conversion through String.hiraganaToKatakana() and String.toHankakuKatakana() extensions. This design choice allows users to maintain muscle memory for key positions while toggling between Japanese script variants, with the countToggleKatakana counter tracking whether the output should render as Hiragana, full-width Katakana, or half-width Katakana.

Where are the character conversion functions defined in the source code?

The extension functions for Japanese character conversion reside in the core module at [core/src/main/java/com/kazumaproject/core/domain/extensions/String.kt](https://github.com/kazumaproject/japanesekeyboard/blob/master/core/src/main/java/com/kazumaproject/core/domain/extensions/String.kt). These include hiraganaToKatakana() for full-width conversion, toHankakuKatakana() for half-width conversion, and toHiragana() for reverse conversion back to Hiragana script.

How does the keyboard remember which Katakana state is active?

The system maintains currentKatakanaKeyIndex as part of the dynamicStates map passed to KeyboardDefaultLayouts.createFinalLayout(), specifically under the key "katakana_toggle_key". This index corresponds to the current position in the countToggleKatakana cycle (0 for Hiragana, 1 for full-width Katakana, 2 for half-width Katakana), ensuring the toggle button displays the correct icon when the keyboard refreshes.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →