How Sumire Handles Tablet-Specific Keyboard Layouts with Gesture Detection in JapaneseKeyboard

Sumire implements tablet-optimized keyboard layouts by detecting the TenKeyQWERTYMode.Sumire state in IMEService.kt, inflating a TabletKeyboardView, and routing all touch events through a shared gesture pipeline that supports flick, tap, long-press, and double-tap interactions.

Sumire serves as the dedicated tablet mode within the JapaneseKeyboard IME hierarchy, providing a full-sized layout optimized for larger screens while maintaining gesture parity with the ten-key and QWERTY modes. The implementation reuses the generic key-handling logic through shared listener interfaces, ensuring consistent flick gestures and input behavior across all device form factors. Understanding how Sumire handles tablet-specific keyboard layouts with gesture detection requires examining the mode detection logic, view initialization, and the touch event processing pipeline.

Activating Sumire Tablet Mode

The IME detects tablet mode through the TenKeyQWERTYMode sealed class defined in core/src/main/java/com/kazumaproject/core/domain/state/TenKeyQWERTYMode.kt. When TenKeyQWERTYMode.Sumire is active, the service triggers a specialized layout creation pathway distinct from the standard phone layouts.

Detecting TenKeyQWERTYMode.Sumire

In app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/IMEService.kt, the onStartInputView method checks the current mode value to determine which keyboard view to inflate:

if (qwertyMode.value == TenKeyQWERTYMode.Sumire) {
    mainLayoutBinding?.let { mainView ->
        when (mainView.keyboardView.currentInputMode.value) {
            InputMode.ModeJapanese -> { … }
            InputMode.ModeEnglish  -> {
                customKeyboardMode = KeyboardInputMode.ENGLISH
                createNewKeyboardLayoutForSumire()
            }
            InputMode.ModeNumber   -> {
                customKeyboardMode = KeyboardInputMode.SYMBOLS
                createNewKeyboardLayoutForSumire()
            }
        }
    }
}

Creating the Tablet Layout

The createNewKeyboardLayoutForSumire() method, located around line 1120 in IMEService.kt, performs three critical initialization steps:

  1. Inflates the tablet layout – Sets tabletView.isVisible = true and attaches the TabletKeyboardView instance.
  2. Initializes the key map – Instantiates KeyMap() and associates each Key enum with its corresponding physical button on the tablet view.
  3. Registers listeners – Sets the view’s setOnFlickListener and setOnLongPressListener callbacks to the same FlickListener and LongPressListener implementations used by the ten-key and QWERTY keyboards.

This approach ensures that Sumire leverages the existing key-processing infrastructure while presenting a layout optimized for tablet screen real estate.

Gesture Detection Architecture

All gesture handling for the tablet view resides in tabletkey/src/main/java/com/kazumaproject/tabletkey/TabletKeyboardView.kt (lines 707–1082). The class implements View.OnTouchListener and contains a specialized GestureDetector that enhances the base flick detection with tablet-specific interactions.

Touch Event Pipeline

The onTouch implementation starting at line 998 processes all touch events through a standardized pipeline:

  • ACTION_DOWN: Creates a pressedKey record, emits flickListener?.onFlick(GestureType.Down, …), and initiates the long-press timer.
  • ACTION_MOVE: Calls getGestureType(event) to analyze movement vectors, returning FlickLeft, FlickTop, FlickRight, FlickBottom, or Tap. The setFlickInActionMove(gestureType) method updates the pop-up preview and notifies the listener.
  • ACTION_UP: Resolves the final gesture type and, if the key maps to a KeyTapFlickInfo, emits the appropriate character via flickListener?.onFlick.
  • ACTION_POINTER_DOWN/UP: Handles two-finger gestures for "small-flick" operations (used for small dakuten and handakuten), forwarding these to setFlickActionPointerDown.

English Mode Double-Tap Detection

The tablet view instantiates a GestureDetector that remains active exclusively when the current input mode is English:

private val gestureDetector =
    GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
        override fun onDoubleTap(e: MotionEvent): Boolean {
            return if (currentInputMode.get() == InputMode.ModeEnglish) {
                val key = pressedKeyByMotionEvent(e, 0)
                if (key == Key.KeyKuten) {
                    hideAllPopWindow()
                    enableCapsLock()
                    skipNextTouches = true
                }
                true
            } else false
        }
    })

This implementation enables a double-tap shortcut on the period key (Key.KeyKuten) to toggle caps-lock in English mode, a tablet-specific optimization for faster text entry.

Flick and Multi-Touch Handling

The getGestureType() function analyzes motion event coordinates to determine flick direction, while setFlickActionPointerDown manages multi-touch scenarios. These methods map physical gestures to KeyInfo data (such as KeyInfo.flickLeft), ensuring that flick gestures on the tablet produce the same character outputs as the ten-key layout.

Implementation Example

The following code demonstrates the complete flow from mode selection to gesture handling:

// Switch to Sumire mode
tenKeyQWERTYMode.update { TenKeyQWERTYMode.Sumire }

// IMEService creates the tablet layout
private fun createNewKeyboardLayoutForSumire() {
    mainLayoutBinding?.tabletView?.apply {
        isVisible = true
        keyboardView.setOnFlickListener(flickListener)
        keyboardView.setOnLongPressListener(longPressListener)
    }
}

// TabletKeyboardView processes gestures
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
    if (currentInputMode.get() == InputMode.ModeEnglish) {
        gestureDetector.onTouchEvent(event!!)
    }
    
    when (event?.action) {
        MotionEvent.ACTION_DOWN -> {
            pressedKey = detectKeyAt(event.x, event.y)
            flickListener?.onFlick(GestureType.Down, pressedKey, null)
        }
        MotionEvent.ACTION_MOVE -> {
            val gesture = getGestureType(event)
            if (gesture != GestureType.Null) {
                setFlickInActionMove(gesture)
            }
        }
        MotionEvent.ACTION_UP -> {
            val finalGesture = getGestureType(event)
            currentKeyInfo?.let { info ->
                flickListener?.onFlick(finalGesture, pressedKey, 
                    info.flickFor(finalGesture))
            }
        }
    }
    return true
}

Summary

  • Sumire is defined as TenKeyQWERTYMode.Sumire in the core domain state, serving as the dedicated tablet mode in the JapaneseKeyboard hierarchy.
  • Layout initialization occurs in IMEService.kt through createNewKeyboardLayoutForSumire(), which makes the tablet view visible and registers shared listeners.
  • Gesture consistency is maintained by reusing the same FlickListener and LongPressListener interfaces across all keyboard modes.
  • Enhanced detection in TabletKeyboardView.kt includes a GestureDetector for double-tap shortcuts in English mode and custom vector analysis for flick directions.
  • Multi-touch support handles two-finger gestures for small dakuten and handakuten inputs, identical to the ten-key implementation.

Frequently Asked Questions

How does Sumire detect tablet mode versus phone mode?

The IME checks the TenKeyQWERTYMode state in IMEService.kt. When qwertyMode.value == TenKeyQWERTYMode.Sumire, the system calls createNewKeyboardLayoutForSumire() instead of the standard phone layout methods, inflating TabletKeyboardView rather than the compact mobile views.

What gesture types does the Sumire tablet layout support?

Sumire supports flick gestures (up, down, left, right), tap, long-press, and double-tap (specifically for caps-lock toggle on the period key in English mode). It also handles two-finger gestures for small dakuten and handakuten character inputs, maintaining feature parity with the ten-key layout.

Where is the gesture detection logic implemented in the source code?

The primary implementation resides in tabletkey/src/main/java/com/kazumaproject/tabletkey/TabletKeyboardView.kt between lines 707 and 1082. Key methods include onTouch() (line 998), getGestureType() for vector analysis, and setFlickActionPointerDown() for multi-touch handling.

Does Sumire use different listeners than the standard QWERTY keyboard?

No. Sumire registers the same FlickListener and LongPressListener instances used by the ten-key and QWERTY keyboards via setOnFlickListener() and setOnLongPressListener(). This design ensures consistent behavior and reduces code duplication across the different input modes.

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 →