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:
- Inflates the tablet layout – Sets
tabletView.isVisible = trueand attaches theTabletKeyboardViewinstance. - Initializes the key map – Instantiates
KeyMap()and associates eachKeyenum with its corresponding physical button on the tablet view. - Registers listeners – Sets the view’s
setOnFlickListenerandsetOnLongPressListenercallbacks to the sameFlickListenerandLongPressListenerimplementations 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
pressedKeyrecord, emitsflickListener?.onFlick(GestureType.Down, …), and initiates the long-press timer. - ACTION_MOVE: Calls
getGestureType(event)to analyze movement vectors, returningFlickLeft,FlickTop,FlickRight,FlickBottom, orTap. ThesetFlickInActionMove(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 viaflickListener?.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.Sumirein the core domain state, serving as the dedicated tablet mode in the JapaneseKeyboard hierarchy. - Layout initialization occurs in
IMEService.ktthroughcreateNewKeyboardLayoutForSumire(), which makes the tablet view visible and registers shared listeners. - Gesture consistency is maintained by reusing the same
FlickListenerandLongPressListenerinterfaces across all keyboard modes. - Enhanced detection in
TabletKeyboardView.ktincludes aGestureDetectorfor 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →