- enableEdgeToEdge() before super.onCreate() for proper inset handling - SFTP rendered at Box level (outside terminal Column) so Scaffold bottomBar with navigationBarsPadding() reaches the nav bar edge - SFTP only composed when active tab (prevents invisible touch blocking) - Status bar + 41dp top padding on SFTP overlay for tab bar visibility - Removed windowInsetsPadding from terminal Column (edge-to-edge handles it) - Cleaned unused imports and debug parameters - docs: number row modes in KEYBOARD.md, SFTP folder reconnect done in FUTURE.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
7.9 KiB
Keyboard System
Last updated: 2026-04-03 See also:
docs/GLOSSARY.mdfor abbreviations
Glossary
| Abbrev | Name | Description |
|---|---|---|
| TV | Terminal View | Terminal surface — displays sessions, receives input |
| AKB | Android Keyboard | System IME (Gboard, Samsung, etc.) |
| CKB | Custom Keyboard | Our Canvas-based keyboard (lib-terminal-keyboard) |
| AQB | AKB QuickBar | QuickBar when using the Android Keyboard |
| CQB | CKB QuickBar | QuickBar when using the Custom Keyboard |
Architecture
Two keyboard modes, selected in Settings → Keyboard → Keyboard Type:
┌─────────────────────────────────────────┐
│ TV (TerminalSurfaceView) │
├─────────────────────────────────────────┤
│ QuickBar (AQB or CQB) │ ← always visible (if enabled)
├─────────────────────────────────────────┤
│ CKB (custom keyboard pages) │ ← only in CKB mode
│ — or — │
│ AKB (system IME, managed by Android) │ ← only in AKB mode
└─────────────────────────────────────────┘
CKB Mode
- Our custom Canvas keyboard (
lib-terminal-keyboard) renders below the QB - System IME is explicitly hidden (
softInputEnabled = false) - CQB keys: ESC, TAB,
:,~,|, arrows, Shift+Tab, vim, nano, tmux, screen - CKB settings: language, height, page indicators, key colors, hints, repeat delay, long press delay
- CQB settings: position, size, color
AKB Mode
- System IME manages itself (Android handles show/hide)
- CKB view is hidden (
container.visibility = GONE) - AQB sits above the system keyboard or at screen top
- AQB settings: position, size, color (independent from CQB)
Preferences
Shared (both modes)
| Pref | Key | Default |
|---|---|---|
| Keyboard type | keyboard_type |
"custom" |
| Haptic feedback | haptic_feedback |
true |
| Show QuickBar | quick_bar_visible |
true |
CKB-only
| Pref | Key | Default |
|---|---|---|
| Language | keyboard_language |
"en" |
| Height (portrait) | keyboard_height_percent |
0.27 |
| Height (landscape) | keyboard_height_landscape |
0.27 |
| Same size both | keyboard_same_size_both |
true |
| Page indicators | show_page_indicators |
true |
| Key color preset | key_color_preset |
"default" |
| Key color custom | key_color_custom |
"" |
| Show hints | show_key_hints |
true |
| Key repeat delay | key_repeat_delay |
400 |
| Long press delay | long_press_delay |
350 |
CQB (Custom Keyboard QuickBar)
| Pref | Key | Default |
|---|---|---|
| Position | quick_bar_position |
"above_keyboard" |
| Size | quick_bar_size |
42 |
| Color preset | qb_color_preset |
"default" |
| Color custom | qb_color_custom |
"" |
AQB (Android Keyboard QuickBar)
Positions: top, vertical_left, vertical_right, none (no above_keyboard/below_keyboard — no CKB to be relative to)
| Pref | Key | Default |
|---|---|---|
| Position | aqb_position |
"top" |
| Size | aqb_size |
42 |
| Color preset | aqb_color_preset |
"default" |
| Color custom | aqb_color_custom |
"" |
Settings UI
Settings → Keyboard section adapts based on keyboard_type:
CKB selected: Haptic, Show QB, Type selector, "Keyboard Settings" button → opens KeyboardSettingsDialog (two tabs: Keyboard + QuickBar)
AKB selected: Haptic, Show QB, Type selector, "QuickBar Settings" button → opens KeyboardSettingsDialog.showAqb() (position, size, color only)
Key Files
| File | Purpose |
|---|---|
lib-terminal-keyboard/ |
Standalone keyboard library (Canvas, JSON layouts, language packs) |
TerminalKeyboard.kt |
Entry point, Builder, touch handling, popup management |
KeyboardView.kt |
ViewPager2 for swipeable keyboard pages |
KeyboardPageView.kt |
Canvas rendering + hit testing per page |
QuickBarView.kt |
Canvas QB with infinite scroll, menu keys, modifier highlights |
ModifierStateManager.kt |
CTRL/ALT/SHIFT state machine (IDLE ↔ ARMED on tap, long-press → LOCKED) |
KeyboardSettingsDialog.kt |
CKB+CQB settings dialog + AQB settings dialog + KeyboardPreview composable |
QuickBarCustomizerScreen.kt |
QB key/app customizer — two-tab Compose dialog (pro) |
QuickBarCustomizer.kt |
Key pool, serialization, defaults for QB customizer |
TerminalPreferences.kt |
DataStore prefs for all keyboard settings |
SettingsScreen.kt |
Compose settings UI with mode-aware keyboard section |
TerminalPane.kt |
Wires keyboard to terminal (CKB visibility, QB, key events) |
MainActivity.kt |
Keyboard instance lifecycle, QB/CKB attachment, size routing |
QuickBar Keys
CQB (Custom Keyboard mode)
Defined in layout_qwerty.json → quickBar.keys:
ESC, TAB, :, ~, |, ←, →, Shift+Tab, vim, nano, tmux, screen
AQB (System Keyboard mode)
Separate key set via QuickBarView.systemKeyboardQuickBarKeys():
CTRL, ESC, TAB, :, /, ←, →, ↑, ↓, HOME, END, PGUP, PGDN, F1-F12. Uses minimum key width (36dp) based on smallest key weight.
QuickBar Customizer (Pro)
Full-screen dialog for customizing QB keys and app shortcuts. Two tabs:
- Keys tab: Active keys with drag-and-drop reorder (drag handle) and delete (trashcan). Available keys in a 4-column grid with tap-to-add (+). 55 keys in the master pool (4 modifiers + 13 navigation + 26 symbols + 12 F-keys).
- App Shortcuts tab: Drag-and-drop reorder, add/remove apps (trashcan + drag handle). Expand to see/edit individual key maps with drag-and-drop reorder (label + action). Action format: hex bytes (
01 63), escape sequences (\eOP), or text macros (\rfor Enter).
Access: KB Settings → QuickBar tab → Customize button, or AQB Settings → Customize button.
CQB and AQB have independent custom configurations stored in DataStore (cqb_custom_keys, cqb_custom_apps, aqb_custom_keys, aqb_custom_apps). Empty = use defaults from JSON layout.
Key files:
| File | Purpose |
|---|---|
QuickBarCustomizerScreen.kt |
Compose UI — two-tab dialog, dialogs for add/edit |
QuickBarCustomizer.kt |
QuickBarKeyPool (master key list), serialization, resolveKeys() |
Number Row Modes
Setting: number_row_mode (default "left"). Options:
| Mode | Behavior |
|---|---|
top |
Dedicated number row above QWERTY (legacy) |
left |
Mini numpad (3×3+1) on the left side, keyboard takes remaining width |
right |
Mini numpad on the right side |
hidden |
No number row; numbers via long-press on QWERTY keys with top-right corner hints |
Mini Section (JSON)
Defined in layout_qwerty*.json under "mini" key:
"mini": { "widthPercent": 10, "rows": [...] }
Model: MiniSection in KeyboardLayout.kt. Parsed by LayoutParser.parseMiniSection().
Implementation
NumberRowTransform.kt— transforms the parsed layout based on mode (removes number row, adds hints for hidden)TerminalKeyboard.attachMiniTo(container)— creates aKeyboardPageViewfor the mini section with touch handling- In
MainActivity:LinearLayoutwith weighted children (mini + main) insideAndroidView.clipChildrenre-enabled afterattachToto prevent SurfaceView rendering issues.
Temporary Hide (CKB only)
- Tab bar kebab menu → "Hide keyboard" / "Show keyboard" toggles
ckbHiddenCompose state (not a pref change) - CKB view hidden, QB stays visible
- Tapping TV fires
onTapShowKeyboard→ resetsckbHidden - Does not affect AKB mode (system IME has its own show/hide)