Skip to content

feat: game-friendly floating keyboard, offline hotword packs, nine-key gestures, package-by-feature layout - #121

Merged
Slacker-LLC merged 3 commits into
mainfrom
feat/game-keyboard-hotwords-modules
Oct 3, 2026
Merged

Slacker-LLC merged 3 commits into
mainfrom
feat/game-keyboard-hotwords-modules

Conversation

@Slacker-LLC

Copy link
Copy Markdown
Owner

What

Floating (game) keyboard

  • Slim toolbar in floating mode: keyboard switch, quick phrases, emoji, more, hide (no text edit / undo).
  • Landscape floating window uses the portrait width and portrait key rows.
  • Long-press the top zone to drag, in addition to the drag handle.

26-key / nine-key

  • Comma key beside the space bar: tap for comma, long press for period. Symmetric bottom row with a centered space bar.
  • Nine-key: wider space bar, narrower 123 / mode keys; long press offers digit + lower/upper letters; swipe up types the digit (setting, exported with user data).
  • English mode no longer auto-capitalizes; keys show lowercase. 26-key letters one size smaller.

Hotword packs (offline, no INTERNET permission)

  • New hotword module: bundled packs (tech, apps, games; games off by default) and user-imported text lists, managed from About & data.
  • Voice: same-sounding spans in the final text are replaced with the pack spelling (the streaming Paraformer model cannot take decoder hotwords).
  • Typing: enabled pack words whose full pinyin equals the composition rank right behind the top candidate.

Architecture

  • Flat package split into theme, core, editor, data, setup, widget, floating, handwriting, rime, candidate, hotword, voice, panel, keyboard; the root package keeps the service, activities and the JNI class.
  • Voice depends on VoiceSessionHost / VoiceEditorContext instead of the keyboard view and the service.
  • ArchitectureLayeringTest pins the allowed dependency directions.

Fixes found while verifying

  • InputStream.readNBytes (API 33) in the hotword import would crash on Android 8-12; replaced.
  • Fallback lexicon had no per-character frequencies, so until librime finished deploying, "ni" + first candidate committed the rare variant 伱 instead of 你. It now ranks by the bundled Rime 8105 weights. This also reproduced on main.

Verification

  • Unit tests and lint (0 errors) pass.
  • Full instrumented suite passes on an API 36 emulator (124 tests, 1 pre-existing skip).
  • scripts/core_regression.sh passes 19/19 against the live service on a fresh data directory; it now waits for rimeReady before the candidate steps.
  • Release checks pass.

Known limitations

  • Nine-key swipe-up and the long-press selector were verified with synthesized touches, not a finger on a device.
  • The voice hotword correction needs the microphone and model and was not exercised end to end.
  • Typing boost only matches the exact full pinyin in 26-key Chinese mode.
  • While librime deploys on first start, partial picks are unavailable (fallback engine limitation).
  • ImeKeyboardView (~3000 lines) and LocalVoiceImeService (~1800 lines) are still large; splitting ImeKeyboardView.Listener is the next step toward Gradle modules.

🤖 Generated with Claude Code

Slacker-LLC and others added 3 commits October 3, 2026 15:47
…re layout

Floating keyboard
- Slim toolbar in floating mode (no text edit/undo, quick-phrase shortcut).
- Landscape floating window uses the portrait width and portrait key rows.
- Long-press the top zone to drag, in addition to the drag handle.

26-key / nine-key
- Comma key beside the space bar: tap for comma, long press for period.
- Symmetric 26-key bottom row with a centered space bar; narrower mode key.
- Nine-key bottom row: wider space bar, narrower 123 and mode keys.
- English mode no longer auto-capitalizes; keys show lowercase letters.
- 26-key letters one size smaller (KEY_LETTER_COMPACT_SP).
- Nine-key long press offers digit plus lower/upper letters; swipe up types
  the digit, with a setting (exported with user data).

Hotword packs (offline)
- New hotword module: bundled packs (tech, apps, games) and user-imported
  text lists, switchable per pack, managed from About & data.
- Voice: replace same-sounding spans in final text with the pack spelling
  (the streaming Paraformer model cannot take decoder hotwords).
- Typing: enabled pack words whose full pinyin matches the composition are
  ranked right behind the top candidate.

Architecture
- Split the flat package into theme, core, editor, data, setup, widget,
  floating, handwriting, rime, candidate, hotword, voice, panel, keyboard;
  the root package keeps the service, activities and the JNI class.
- Voice depends on VoiceSessionHost / VoiceEditorContext instead of the
  keyboard view and the service.
- ArchitectureLayeringTest pins the allowed dependency directions.

Tests: unit suite and the 123-test instrumented suite pass on an API 36
emulator.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- Replace InputStream.readNBytes (API 33) with a bounded read; the import
  would have crashed on Android 8-12.
- Use the SDK-aware window insets path in HotwordPacksActivity.
- Add zh/en translations for the hotword activity label.
- Write the byte-order mark in HotwordParser as an escape sequence.

Found by :app:lintDebug; the emulator is API 36, so instrumented tests did
not catch the first two.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Until librime has finished deploying (first start after an install or a data
clear, minutes on the emulator), candidates come from the Kotlin fallback.
Its character table has no frequencies, so every character tied at 0 and
the first one in file order won: typing "ni" and picking the first candidate
committed the rare variant 伱 instead of 你.

- Load per-character weights from the bundled Rime 8105 table (same corpus
  and scale as the phrase weights) and use them for ranking.
- core_regression.sh now waits for rimeReady before the candidate steps;
  partial picks need native candidates and cannot pass while Rime deploys.

The four failures seen in core_regression.sh (033, 035, 036, 041) also
occurred on main; with this change and the wait the script passes 19/19 on
a fresh data directory.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@Slacker-LLC
Slacker-LLC merged commit 18f6f6e into main Oct 3, 2026
7 checks passed
@Slacker-LLC
Slacker-LLC deleted the feat/game-keyboard-hotwords-modules branch October 3, 2026 10:14
Slacker-LLC added a commit that referenced this pull request Oct 3, 2026
…friendly floating keyboard (#122)

## What
Second public beta. Sets `VERSION` to `0.0.2-beta.1` (versionCode 201)
and turns `[Unreleased]` into the `0.0.2-beta.1` section, which becomes
the GitHub Release notes.

Highlights: offline hotword packs for voice and typing, nine-key long
press and swipe-up digits, symmetric 26-key row with a comma/period key,
no auto-capital in English mode, game-friendly floating keyboard.

## Impact
- Publishes as a pre-release (not latest), arm64 only, signed with the
release key.
- Upgrade over `0.0.1-beta.1` keeps user data; the first start redeploys
the Rime dictionary (versionCode is the deploy marker).

## Verification
- `python3 scripts/release_check.py check` passes; script unit tests
pass.
- The code in this release was merged in #121 with a green CI and a full
instrumented run.
- This PR touches release files, so CI rehearses the whole release
pipeline with a throwaway key.

## Next
After merge: tag `v0.0.2-beta.1` on the merge commit.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: limuzi013 <128580527+limuzi013@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant