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

> Discover how Sumire handles Japanese input mode switching between Hiragana, Katakana, and Romaji. Learn about its state-driven architecture and key event handling for seamless typing.

- Repository: [Kazu/japanesekeyboard](https://github.com/kazumaproject/japanesekeyboard)
- Tags: deep-dive
- Published: 2026-03-05

---

**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`](https://github.com/kazumaproject/japanesekeyboard/blob/main/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`](https://github.com/kazumaproject/japanesekeyboard/blob/main/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:

```kotlin
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`](https://github.com/kazumaproject/japanesekeyboard/blob/main/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:

```kotlin
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`](https://github.com/kazumaproject/japanesekeyboard/blob/main/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:

```kotlin
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/main/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`](https://github.com/kazumaproject/japanesekeyboard/blob/main/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`](https://github.com/kazumaproject/japanesekeyboard/blob/main/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):

```kotlin
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`](https://github.com/kazumaproject/japanesekeyboard/blob/main/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:

```kotlin
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/main/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.