Skip to content

C2b: Customizable swipe-from-key shortcuts (down/sideways/any-key) #37

Description

@AsafMah

Part of #17. This issue is not shortcut rows and not the shelved swipe-up-symbol-popup idea.

Actual target

Make selected non-letter/control/punctuation keys support a slide-to-target interaction like Shift/Symbol/Numpad already do.

This is not a coarse directional shortcut system.

Correct mental model:

press source key
-> enter a temporary target layer / action surface
-> slide to a target key/action
-> release to dispatch that target
-> restore the previous keyboard state

Examples:

press Enter/action key -> slide to JOIN_NEXT / FORCE_NEXT_SPACE / UNDO_WORD / hide keyboard
press period           -> slide to punctuation/action targets
press comma            -> slide to emoji/settings/custom targets

The actions are not the missing part. JOIN_NEXT, FORCE_NEXT_SPACE, UNDO_WORD, toolbar actions, editor actions, and layout actions already exist as key codes / toolbar actions. The missing capability is letting a source key expose/select those existing targets through the same kind of press-slide-release interaction users already know from Shift/Symbol/Numpad.

JOIN_NEXT is only an example target, not the feature itself.

How Shift / Symbol / Numpad work today

Current modifier-key sliding is slide-to-target, not direction binding.

Pipeline:

layout JSON label
-> resolved KeyCode
-> Key.isModifier()
-> PointerTracker drag/sliding path
-> KeyboardState hard-coded press/release handling
-> user lands on another key in the temporary layer
-> KeyboardState.onFinishSlidingInput() restores momentary layout state

Grounding:

  • app/src/main/assets/layouts/functional/functional_keys.json
    • declares labels such as shift, symbol_alpha, numpad, period, action.
  • app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyLabel.kt
    • maps labels to key specs / key codes.
    • shift becomes !code/key_shift.
    • symbol_alpha, symbol, alpha become KeyCode.SYMBOL_ALPHA, KeyCode.SYMBOL, KeyCode.ALPHA.
  • app/src/main/java/helium314/keyboard/keyboard/internal/KeyboardCodesSet.java
    • maps !code/key_shift, !code/key_enter, etc. to integer key codes.
  • app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyCode.kt
    • isModifier() returns true for SHIFT, SYMBOL_ALPHA, ALPHA, SYMBOL, NUMPAD, and hardware modifier codes.
  • app/src/main/java/helium314/keyboard/keyboard/PointerTracker.java
    • allows drag selection when the source key is a modifier.
    • calls onReleaseKey(sourceCode, withSliding = true) when the finger leaves the source key.
    • continues tracking the finger over the newly visible/selected target keys.
    • calls onFinishSlidingInput() on finger-up.
  • app/src/main/java/helium314/keyboard/keyboard/internal/KeyboardState.kt
    • hard-codes SHIFT, SYMBOL_ALPHA, SYMBOL, ALPHA, and NUMPAD in onPressKey / onReleaseKey.
    • uses SwitchState.MOMENTARY_* states to restore the previous layout in onFinishSlidingInput().

Important consequence: the existing model is not (source + direction) -> action. The selected target comes from where the finger lands after the temporary layer/state is active.

Existing action model to reuse

Do not invent new actions for #37.

Existing action representation:

  • app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyCode.kt
    • defines special action key codes, including JOIN_NEXT, FORCE_NEXT_SPACE, UNDO_WORD, NUMPAD, IME_HIDE_UI, arrows, clipboard actions, etc.
  • app/src/main/java/helium314/keyboard/latin/utils/ToolbarUtils.kt
    • ToolbarKey enum names assignable toolbar actions.
    • getCodeForToolbarKey(ToolbarKey) maps toolbar actions to key codes.
    • custom toolbar key codes are persisted as ToolbarKey,KeyCode,LongpressKeyCode entries in Settings.PREF_TOOLBAR_CUSTOM_KEY_CODES.
  • app/src/main/java/helium314/keyboard/settings/dialogs/ToolbarKeysCustomizer.kt
    • existing UI already lets a toolbar key map to custom key codes.
  • app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java
    • dispatches existing action key codes such as JOIN_NEXT, FORCE_NEXT_SPACE, and UNDO_WORD.

#37 should route selected targets through the same key-code dispatch path used by toolbar keys, not directly call feature-specific methods.

Recommended implementation shape

1. Add source-key action layers, not directional bindings

For each supported source key, define a small temporary target surface:

SourceKey -> temporary target layout/action layer

MVP source keys:

  • ACTION_KEY / Enter key family
  • PERIOD
  • COMMA

MVP target entries should resolve to existing ToolbarKey / key-code actions.

2. Reuse the slide-to-target mechanics where possible

The implementation should be closer to Shift/Symbol/Numpad than to space/delete swipes:

on source-key press:
  keep normal tap behavior pending

when finger slides out far enough:
  open/show a temporary action target layer or popup
  cancel long-press/repeat timers
  enter a slide-selection mode

while moving:
  track the target key/action under the finger

on release:
  if a target is selected, dispatch its existing key code
  else, preserve/cancel according to normal slide semantics
  restore previous keyboard/action surface

The target surface could be implemented as one of:

  • a real temporary keyboard layer, closest to Symbol/Numpad behavior;
  • a popup-key/action panel anchored to the source key;
  • a small action row/palette that reuses toolbar key rendering/labels.

Prefer the smallest approach that preserves the real press-slide-release interaction.

3. Canonicalize source keys deliberately

Do not key only on raw primaryCode for Enter.

The bottom-right action key can resolve to different codes depending on editor state (Enter, Shift+Enter, Next, Previous, custom action). The user-facing source is still “the action/enter key.”

Use a small canonical source enum, for example:

ACTION_KEY = Constants.CODE_ENTER, KeyCode.SHIFT_ENTER, KeyCode.ACTION_NEXT, KeyCode.ACTION_PREVIOUS, editor action key variants
PERIOD     = Constants.CODE_PERIOD
COMMA      = ','

Period/comma are safer as raw character source keys. The action/enter key needs canonicalization.

4. Do not add Enter/period/comma to KeyCode.isModifier() as a shortcut

That would be too broad.

Adding them to isModifier() would:

  • make PointerTracker treat them like layout modifiers everywhere;
  • make InputLogic ignore them in modifier branches;
  • affect typing timers and gesture gating;
  • blur true modifier/layout switching with configurable action layers.

If a shared abstraction is needed, split the concept: true keyboard modifiers vs slide-source keys.

5. Preserve existing conflict paths

MVP should not take over these until explicitly reviewed:

  • SPACE: already has horizontal/vertical swipe, touchpad mode, cursor movement, language switching, and toggle-numpad options.
  • DELETE: already has delete slider behavior.
  • letter keys: used by glide typing and the C2a: Swipe-up to key symbol popup (MVP) #32 failure mode.
  • Shift/Symbol/Numpad: existing behavior is hard-coded layout sliding and should remain unchanged unless deliberately migrated later.
  • shortcut rows: already exclude modifiers and swipers; this should not reopen the old shortcut-row ambiguity.

MVP acceptance

  • A source key such as ACTION_KEY or PERIOD can open a temporary target action surface by press-slide, not by raw direction detection.
  • Releasing on a target dispatches an existing action/key code.
  • Tapping the source key without sliding keeps normal behavior unchanged.
  • Existing Shift/Symbol/Numpad slide-to-target behavior is unchanged.
  • Existing space/delete swipe behavior is unchanged.
  • Letter-key glide typing is unchanged.
  • No new action is required; JOIN_NEXT remains just an example target.

Test plan

  • Parser/model tests for source-key target configuration.
  • Behavior tests or focused manual QA proving:
    • Enter/period tap still emits the original key.
    • press-slide-release from Enter/period dispatches the selected target action.
    • release outside a target does not emit a random directional action.
  • Regression coverage for:
    • Shift/Symbol/Numpad sliding still restores layouts through onFinishSlidingInput().
    • Space swipe still routes through existing horizontal/vertical/touchpad paths.
    • Delete slider still routes through existing delete-pointer path.
    • Letter-key gesture typing still starts normally.

Non-goals

  • Not adding JOIN_NEXT as a new action; it already exists and is already assignable elsewhere.
  • Not coarse (source + direction) -> action shortcuts.
  • Not shortcut-row swipes.
  • Not swipe-up-to-key-symbol popup (C2a: Swipe-up to key symbol popup (MVP) #32).
  • Not true simultaneous combo keys (C2c: Combo keys (true-simultaneous) #33).
  • Not arbitrary letter-key swipes in MVP.
  • Not replacing existing Shift/Symbol/Numpad sliding in the first pass.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions