How Shift+Letter Triggers Alphabet Mode Entry on Linux Fcitx5 with Karukan
Karukan detects Shift+letter combinations in its Fcitx5 front-end by checking for uppercase keysyms or Shift-modified ASCII alphabetic characters, then immediately switches the input_mode to Alphabet and inserts the character directly without romaji conversion.
Karukan is a Japanese input method engine that implements intelligent romaji-to-kana conversion for Linux systems via Fcitx5. Understanding how it handles Shift+letter alphabet mode entry on Linux Fcitx5 is crucial for users who need to seamlessly switch between Japanese kana and direct ASCII input. The implementation relies on detecting specific key combinations in the core engine logic and dynamically switching the input mode before processing the character.
Detecting Shift+Letter Combinations
The detection logic resides in karukan-im/src/core/engine/input.rs within the main key processing flow. When the engine receives a printable character event, it evaluates whether the combination constitutes a Shift+letter press using a dual-check strategy:
// karukan-im/src/core/engine/input.rs
if let Some(ch) = key.to_char()
&& !key.modifiers.control_key
&& !key.modifiers.alt_key
{
// Detect Shift+letter: uppercase keysym OR Shift modifier + ASCII alphabetic
let is_shift_alpha =
ch.is_ascii_uppercase() || (shift_active && ch.is_ascii_alphabetic());
// ... mode switching logic
}
This approach accounts for Fcitx5 implementation variations where the system may emit either a lowercase keysym with the Shift flag set, or an already-uppercase keysym. The shift_active variable represents the current modifier state from the KeyEvent struct.
Switching from Hiragana/Katakana to Alphabet Mode
When is_shift_alpha evaluates to true while the engine is in Hiragana or Katakana mode, the code performs an immediate state transition:
if is_shift_alpha && self.input_mode != InputMode::Alphabet {
self.input_mode = InputMode::Alphabet;
self.flush_romaji_to_composed();
}
The mode switch sets self.input_mode to InputMode::Alphabet, defined in karukan-im/src/core/engine/types.rs. The flush_romaji_to_composed() call ensures any pending kana conversion is cleared before entering alphabet mode, preventing partial romaji sequences from contaminating the ASCII input.
The InputMode enum supports three distinct states:
Hiragana– Standard romaji-to-hiragana conversionKatakana– Forces output to katakana charactersAlphabet– Direct ASCII insertion without conversion
Handling Shift+Letter During Active Composition
Karukan handles Shift+letter even when the user has already started composing kana. The process_key_composing function in karukan-im/src/core/engine/input.rs contains similar detection logic with additional safeguards:
// karukan-im/src/core/engine/input.rs (process_key_composing)
if is_shift_alpha && self.input_mode != InputMode::Alphabet {
// If we were in Katakana, bake it first so the pre-edit stays sane
if self.input_mode == InputMode::Katakana {
self.bake_katakana();
}
self.input_mode = InputMode::Alphabet;
self.flush_romaji_to_composed();
self.live.text.clear(); // reset live-conversion buffer
}
If the engine was in Katakana mode, it first calls bake_katakana() to commit the existing katakana state before switching. The live conversion buffer is cleared to ensure the pre-edit display accurately reflects the transition to direct ASCII input.
Character Insertion and Case Preservation
Once in Alphabet mode, the engine preserves the uppercase nature of the input:
let ch = if self.input_mode == InputMode::Alphabet && is_shift_alpha {
ch.to_ascii_uppercase()
} else {
ch
};
return self.input_buf.insert(&ch.to_string());
This bypasses the romaji-to-hiragana converter entirely, inserting the character directly into the pre-edit buffer. The mode indicator (displayed via karukan-im/src/core/engine/display.rs) updates to show "[A]" for Alphabet mode, providing visual feedback that the shift was successful.
Fcitx5 Integration and Testing
The behavior is validated through FFI tests in karukan-fcitx5/src/ffi/tests.rs, which simulate Shift+letter sequences against the engine:
// Simulating a Shift-A press in a Fcitx5 test (simplified)
let mut engine = Engine::default(); // starts in Hiragana mode
engine.process_key(&KeyEvent::new(Keysym::KEY_A, Shift::Pressed));
// → engine.input_mode == InputMode::Alphabet
// → pre-edit shows "A"
The C FFI layer in karukan-fcitx5/src/lib.rs exposes these capabilities to the Fcitx5 framework, ensuring that Linux users experience consistent alphabet mode entry regardless of their specific Fcitx5 configuration.
Summary
- Dual detection strategy: Karukan checks for
ch.is_ascii_uppercase()orshift_active && ch.is_ascii_alphabetic()to handle varying Fcitx5 keysym behaviors. - Immediate mode switch: The engine sets
self.input_mode = InputMode::Alphabetand flushes pending conversions viaflush_romaji_to_composed(). - Composition-aware handling: During active composition,
process_key_composingcallsbake_katakana()if needed before switching modes. - Direct insertion: Characters bypass the romaji converter and insert directly into
input_bufwith uppercase preservation. - Source locations: Core logic resides in
karukan-im/src/core/engine/input.rswith theInputModeenum defined inkarukan-im/src/core/engine/types.rs.
Frequently Asked Questions
How does Karukan distinguish between Shift+letter and regular letter input?
Karukan checks both the character case and modifier state using ch.is_ascii_uppercase() || (shift_active && ch.is_ascii_alphabetic()). This catches both uppercase keysyms and lowercase keysyms with active Shift modifiers, ensuring reliable detection across different Fcitx5 configurations.
What happens to pending kana conversion when switching to alphabet mode?
The engine calls flush_romaji_to_composed() immediately upon switching to Alphabet mode. This clears any pending romaji-to-kana conversion state, ensuring that partial sequences do not interfere with the direct ASCII input.
Can I trigger alphabet mode with Shift+letter while composing kana?
Yes. The process_key_composing handler specifically supports this case. If you were in Katakana mode, the engine first invokes bake_katakana() to finalize the existing composition, then switches to Alphabet mode and clears the live conversion buffer to maintain pre-edit consistency.
Where is the mode indicator displayed in the Fcitx5 interface?
The mode indicator is rendered by the display logic in karukan-im/src/core/engine/display.rs, which shows "[A]" for Alphabet mode alongside the pre-edit text. This visual feedback confirms that Shift+letter successfully triggered the alphabet mode entry.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →