How to Add QWERTY Layout Support Alongside the Traditional Japanese Flick Layout

You can add QWERTY layout support to the Japanese Keyboard project by enabling the QWERTY preference toggle, instantiating the QWERTY view in the KeyboardViewPagerAdapter, and wiring the layout switch in IMEService to toggle between FlickKeyboardView and QWERTYKeyboardView based on the QWERTYMode state flow.

The kazumaproject/japanesekeyboard repository provides a flexible Android IME framework that supports both traditional Japanese flick input and standard QWERTY layouts. If you want to add QWERTY layout support alongside the traditional Japanese flick layout, the codebase already contains the necessary components—you only need to connect the preference toggle, view instantiation, and mode switching logic.

Step 1: Enable the QWERTY Preference

The first step is to surface the QWERTY option to users via the settings UI. The file app/src/main/res/xml/pref_qwerty.xml defines the toggle switches that control QWERTY behavior, including options for enabling up and down flick detection on the QWERTY keys.

When a user toggles these preferences, the changes propagate through the settings fragment and update the keyboard view state. Ensure this preference XML is included in your main settings hierarchy so users can access the QWERTY configuration panel.

Step 2: Instantiate the QWERTY View

Once the preference is enabled, you must ensure the QWERTY keyboard view is available for display. The KeyboardViewPagerAdapter located at app/src/main/java/com/kazumaproject/markdownhelperkeyboard/setting_activity/ui/keyboard_size_setting/adapter/KeyboardViewPagerAdapter.kt manages three distinct pages: Ten-Key (Japanese), QWERTY, and Custom.

The adapter creates the appropriate view based on position constants (TEN_KEY_PAGE_POSITION, QWERTY_PAGE_POSITION). To add QWERTY support, verify that the adapter returns a non-null QWERTYKeyboardView for the QWERTY page position. This view is instantiated using the application context and configured with the appropriate layout and listeners.

Step 3: Wire the Layout Switch

The core switching logic resides in the IME service. The IMEService.kt file at app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/IMEService.kt observes a StateFlow<QWERTYMode> named _qwertyMode defined in core/src/main/java/com/kazumaproject/core/domain/state/QWERTYMode.kt.

The QWERTYMode enum includes states such as Default, Romaji, and CapsLock. When the user selects QWERTY from the settings or via a toggle, the service updates this flow, triggering a view replacement. The service removes the current FlickKeyboardView and attaches a QWERTYKeyboardView, preserving the setOnKeyboardActionListener interface so input handling remains consistent.

Step 4: Provide a Default QWERTY Layout

To render keys on the QWERTY view, you must define the layout structure. The KeyboardDefaultLayouts object in custom_keyboard/src/main/java/com/kazumaproject/custom_keyboard/layout/KeyboardDefaultLayouts.kt provides static definitions for Hiragana, English, and Symbol layouts.

You can add QWERTY support by extending this object with a Romaji layout method or by creating a new XML layout file. For XML-based layouts, inflate the resource inside QWERTYKeyboardView using view binding (QwertyLayoutBinding). For programmatic layouts, construct a KeyboardLayout data class with rows of KeyInfo objects and call qwertyKeyboardView.setRomajiKeyboard(layout).

Step 5: Customize QWERTY Appearance

Finally, allow users to fine-tune the QWERTY appearance through the settings UI. The QwertyMarginSettingFragment.kt at app/src/main/java/com/kazumaproject/markdownhelperkeyboard/setting_activity/ui/qwerty_button_size/QwertyMarginSettingFragment.kt provides sliders and inputs for adjusting key margins and text size.

The QwertyKeyboardSizePreview.kt component renders a live preview of these changes. These UI components read from and write to the shared preferences, which the QWERTYKeyboardView observes to update its rendering dynamically.

Code Examples

Enabling the QWERTY Preference in Settings

// In SettingsFragment (or wherever you load preferences)
val qwertyEnableSwitch = findPreference<SwitchPreferenceCompat>("qwerty_enable_flick_up_preference")
qwertyEnableSwitch?.setOnPreferenceChangeListener { _, newValue ->
    // Persist the setting and notify the keyboard view
    qwertyKeyboardView.enableFlickUpDetection = newValue as Boolean
    true
}

Switching to QWERTY from the IME Service

private fun switchToQwerty() {
    // Update the shared flow – observers in KeyboardViewPagerAdapter will react
    _qwertyMode.value = QWERTYMode.Romaji

    // Directly replace the view if you keep a reference
    val qwertyView = QWERTYKeyboardView(this)
    qwertyView.setOnKeyboardActionListener(qwertyListener)
    keyboardContainer.removeAllViews()
    keyboardContainer.addView(qwertyView)
}

Adding a Custom QWERTY Layout in KeyboardDefaultLayouts.kt

fun defaultQwertyRomajiLayout(): KeyboardLayout {
    // Define rows of keys – each key is a `KeyInfo` that holds the label, code, etc.
    val rows = listOf(
        listOf(KeyInfo("Q", "q"), KeyInfo("W", "w"), /* … */ KeyInfo("P", "p")),
        listOf(KeyInfo("A", "a"), /* … */ KeyInfo("L", "l")),
        listOf(KeyInfo("Z", "z"), /* … */ KeyInfo("M", "m"))
    )
    // Convert rows into the library's `KeyboardLayout` data class
    return KeyboardLayout(rows.flatten(), emptyMap(), columns = 10, rows = 4)
}

Then load it:

qwertyKeyboardView.setRomajiKeyboard(
    KeyboardDefaultLayouts.defaultQwertyRomajiLayout()
)

Updating the ViewPager Adapter

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    val binding = LayoutInflater.from(parent.context)
        .inflate(R.layout.qwerty_layout, parent, false)
    val qwertyView = QWERTYKeyboardView(parent.context)
    return ViewHolder(binding.apply { root.addView(qwertyView) })
}

Summary

  • Enable the preference by including pref_qwerty.xml in your settings to expose QWERTY toggles to users.
  • Instantiate the view through KeyboardViewPagerAdapter to ensure the QWERTY page is available alongside the Ten-Key and Custom pages.
  • Wire the switch in IMEService.kt by observing the QWERTYMode state flow and swapping between FlickKeyboardView and QWERTYKeyboardView.
  • Define the layout by extending KeyboardDefaultLayouts.kt with Romaji key definitions or by inflating a custom XML layout in QWERTYKeyboardView.
  • Customize appearance via QwertyMarginSettingFragment.kt to let users adjust key margins and text size for the QWERTY layout.

Frequently Asked Questions

What is the difference between FlickKeyboardView and QWERTYKeyboardView?

FlickKeyboardView implements the traditional Japanese flick behavior where users swipe in different directions to select characters, while QWERTYKeyboardView provides a standard QWERTY layout with dynamic margins, caps-lock handling, and optional up/down flick detection. Both extend ConstraintLayout and implement setOnKeyboardActionListener, allowing the IME service to treat them uniformly.

How does the IME service know when to switch layouts?

The IME service observes a StateFlow<QWERTYMode> defined in core/src/main/java/com/kazumaproject/core/domain/state/QWERTYMode.kt. When the user selects QWERTY from settings or toggles the mode, the flow emits a new state (such as Romaji or Default), triggering IMEService.kt to replace the current FlickKeyboardView with a QWERTYKeyboardView.

Can I customize the QWERTY key sizes and margins?

Yes, the QwertyMarginSettingFragment.kt file provides a dedicated UI for adjusting QWERTY key margins and text size. These settings persist to shared preferences, which QWERTYKeyboardView reads to update its rendering dynamically. You can also programmatically set margins via the view's layout parameters if you need custom defaults.

Is it possible to use both layouts simultaneously?

While users cannot physically display both keyboards at the same time in the same input field, the architecture supports rapid switching between them without restarting the IME. The KeyboardViewPagerAdapter holds both views in memory (Ten-Key, QWERTY, and Custom pages), and the IME service can instantly swap the active view based on the current QWERTYMode, effectively allowing simultaneous availability with zero-latency switching.

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 →