Text Composing & Editor Instance
Relevant source files
The following files were used as context for generating this wiki page:
- app/src/main/kotlin/dev/patrickgold/florisboard/ime/text/composing/Composer.kt
- app/src/main/kotlin/dev/patrickgold/florisboard/ime/editor/AbstractEditorInstance.kt
- app/src/main/kotlin/dev/patrickgold/florisboard/ime/editor/EditorContent.kt
- app/src/main/kotlin/dev/patrickgold/florisboard/ime/editor/FlorisEditorInfo.kt
- app/src/main/kotlin/dev/patrickgold/florisboard/ime/editor/EditorRange.kt
The Text Composing & Editor Instance system forms the core text processing engine of the keyboard. Its primary purpose is to bridge the gap between user key presses and the target application's text field, managing complex state synchronization, cursor positioning, and dynamic text transformations known as "composing."
This system ensures that the keyboard maintains an accurate internal representation of the text field's state (selections, composing regions, and surrounding text) while providing extensibility for language-specific rules. It handles everything from simple character appending to rule-based character transformations required for complex scripts.
Sources: app/src/main/kotlin/dev/patrickgold/florisboard/ime/editor/AbstractEditorInstance.kt, app/src/main/kotlin/dev/patrickgold/florisboard/ime/text/composing/Composer.kt
Architecture and Core Components
The architecture is built around the management of EditorContent through an AbstractEditorInstance. This setup allows the keyboard to track the current state of the input field asynchronously and handle updates from the Android system's InputConnection.
Editor Instance Management
The AbstractEditorInstance class serves as the base controller. It manages the lifecycle of an input session, from the moment a text field gains focus (handleStartInput) to when it loses focus (handleFinishInput). It maintains state flows for the current EditorContent, cursor capitalization modes, and editor metadata (FlorisEditorInfo).
The following diagram illustrates the relationship between the primary editor components:
Data Structures
| Class | Description |
|---|---|
EditorContent | Represents a snapshot of the text, selection, and composing region. |
EditorRange | Represents a start and end point in the text, used for cursor position or selection. |
FlorisEditorInfo | Wraps Android's EditorInfo to provide typed access to input attributes and initial states. |
LastCommitPosition | Tracks the position of the last committed text to assist in determining the composing region. |
Sources: app/src/main/kotlin/dev/patrickgold/florisboard/ime/editor/EditorContent.kt, app/src/main/kotlin/dev/patrickgold/florisboard/ime/editor/EditorRange.kt, app/src/main/kotlin/dev/patrickgold/florisboard/ime/editor/AbstractEditorInstance.kt:446-478
Text Composing Logic
Text composing refers to the process of transforming characters as they are typed. This is essential for languages where multiple key presses might combine into a single glyph or where specific sequences trigger character substitutions.
The Composer Interface
The Composer interface defines how text transformations occur. It takes the precedingText (text already in the field) and the character toInsert, then returns an action specifying how many characters to delete and what new string to insert.
Implementation Variants:
- Appender: The default fallback. It performs no transformation and simply inserts the character (returns
0 to toInsert). - WithRules: A rule-based composer that uses a
Map<String, String>to define substitutions. It checks if the current input sequence matches a defined rule (e.g., "a" + "e" -> "æ"). It prioritizes longer rules by sorting them by length.
Sources: app/src/main/kotlin/dev/patrickgold/florisboard/ime/text/composing/Composer.kt:25-70
Editor Content State Flow
The system uses a reactive state flow to keep the keyboard UI and logic in sync with the Android input system. AbstractEditorInstance maintains an expectedContentQueue to handle the asynchronous nature of InputConnection updates.
Selection and Update Flow
When the cursor moves or text changes, the Android system calls onUpdateSelection. The AbstractEditorInstance processes this through handleSelectionUpdate.
Character Commitment
The commitChar function is the primary entry point for normal typing. It coordinates with the Composer and InputConnection to perform batch edits.
- Read Context: It retrieves the necessary number of characters before the cursor based on the
Composer.toReadvalue. - Determine Actions: It calls the active composer's
getActions. - Execute Edit: It starts a
beginBatchEdit. If a transformation is required, it uses the composing region to "overwrite" characters without explicit deletion calls to prevent flickering in the target application. - Sync State: It updates the
expectedContentQueueso the next system update is handled correctly.
Sources: app/src/main/kotlin/dev/patrickgold/florisboard/ime/editor/AbstractEditorInstance.kt:265-310
Configuration and Metadata
The system behavior is heavily influenced by the FlorisEditorInfo and InputAttributes.
Input Attributes
The keyboard adapts its behavior based on flags provided by the target application:
- Rich Input: Determines if features like suggestions and composing regions are enabled.
- Raw Input: If true, the system falls back to basic key events and disables complex editor tracking.
- Caps Mode: The
AbstractEditorInstanceautomatically calculates theactiveCursorCapsMode(None, Words, Sentences, or All) by inspecting the text context usingTextUtils.getCapsMode.
Sources: app/src/main/kotlin/dev/patrickgold/florisboard/ime/editor/FlorisEditorInfo.kt:33-55, app/src/main/kotlin/dev/patrickgold/florisboard/ime/editor/AbstractEditorInstance.kt:233-242
Summary
The Text Composing & Editor Instance system provides a robust, state-aware framework for text entry. By centralizing text state in EditorContent and using a flexible Composer interface, the project supports a wide range of input scenarios from standard Latin typing to complex, rule-based scripts. The use of a batch-edit synchronization strategy ensures a smooth user experience by minimizing UI flickering and maintaining cursor consistency across asynchronous system updates.