Skip to content

feat(html): mobile virtual keyboard and touch UX improvements#1504

Open
someonegg wants to merge 6 commits intotsl0922:mainfrom
someonegg:mobile-keyboard-touch-ux
Open

feat(html): mobile virtual keyboard and touch UX improvements#1504
someonegg wants to merge 6 commits intotsl0922:mainfrom
someonegg:mobile-keyboard-touch-ux

Conversation

@someonegg
Copy link
Copy Markdown

@someonegg someonegg commented Mar 18, 2026

Summary

This PR delivers a mobile-focused UX upgrade for ttyd and includes related fixes in the same series.

Commits included:

Features

Virtual Keyboard Panel

  • A draggable on-screen keyboard appears automatically on touch devices.
  • Uses a dynamic top section (2 rows, 6 keys) and a fixed bottom section.
  • Built-in dynamic keys include:
    • action keys: enter, space, batch_input
    • navigation keys: up, down, left, right, home, end, pageup, pagedown, wheel_up, wheel_down
    • common symbols and lowercase letters a-z
  • Custom key IDs from mobileKeyboardCustomKeys can also be used in mobileKeyboardLayouts.
  • Fixed section provides Esc, Tab, Shift, Alt, Ctrl, and Copy/Paste.
  • Drag the header bar to reposition the panel anywhere on screen.
  • Tap (or click) the header bar to cycle dynamic layouts in configured order.
  • Tap modifier keys to toggle their state (highlighted when active).
  • Copy/Paste button switches between copy and paste based on text selection.

Tap Selection

  • Double-tap: select the word under the cursor.
  • Triple-tap: select the entire line.
  • Shift + Triple-tap: select all visible lines in the current viewport.
  • Alt + Triple-tap: select all text in the terminal buffer.

Hold Repeat

  • Hold starts after mobileKeyboardHoldDelayMs (default: 300 ms).
  • Non-wheel keys repeat at mobileKeyboardHoldIntervalMs (default: 120 ms).
  • Wheel keys repeat at mobileKeyboardHoldWheelIntervalMs (default: 120 ms).
  • Modifiers apply to key repeat; wheel repeat ignores modifiers.

Details

Client Options

  • -t enableMobileKeyboard=true: enable the mobile virtual keyboard panel, auto-detect touch (default: false). On touch devices this also controls selection-copy behavior: when enabled, tap selection is on and automatic copy-on-selection is off; when disabled, tap selection is off and automatic copy-on-selection is on
  • -t mobileKeyboardOpacity=0.8: set the keyboard panel opacity (default: 0.72, range: 0.0-1.0)
  • -t mobileKeyboardScale=1.2: set the keyboard panel scale (default: 1.0)
  • -t 'mobileKeyboardCustomKeys=[{"id":"tmux_copy_mode","label":"C-b [","combo":["Ctrl+b","["]}]': define custom dynamic keys (array of {id,label,combo}; combo is a sequence like Ctrl+b, [). id must match ^[a-z][a-z0-9_]{0,31}$, and __proto__, prototype, constructor, toString, valueOf are forbidden. The default web UI predefines six tmux keys: tmux_copy_mode (C-b [), tmux_detach (C-b d), tmux_new_window (C-b c), tmux_prev_window (C-b p), tmux_next_window (C-b n), tmux_list_windows (C-b w)
  • -t 'mobileKeyboardLayouts=[["home","up","end","left","down","right"]]': set dynamic layouts for the top section (6 keys per layout). In the default web UI, 3 pages are active by default: page 1 ["home","up","end","left","down","right"], page 2 ["enter","up","batch_input","left","down","right"], page 3 ["enter","up","space","tmux_next_window","down","tmux_list_windows"]
  • Per-key auto layout switch: each mobileKeyboardLayouts item can also be an object {"key":"xxx","page":n}. When page is set, pressing that key sends its action first, then switches to the target layout page (page is 1-based). Invalid, non-integer, or out-of-range page values are ignored for switching while key dispatch still works.
  • -t mobileKeyboardHoldDelayMs=300: set hold trigger delay in milliseconds for mobile virtual keys (default: 300)
  • -t mobileKeyboardHoldIntervalMs=120: set hold repeat interval in milliseconds for non-wheel keys (default: 120)
  • -t mobileKeyboardHoldWheelIntervalMs=120: set hold repeat interval in milliseconds for wheel keys (default: 120)

Main Files

  • html/src/components/terminal/xterm/mobile-keyboard.ts (new)
  • html/src/components/terminal/xterm/index.ts (integration/lifecycle/options/events)
  • html/src/components/app.tsx (defaults)
  • html/src/style/index.scss (mobile panel/touch styles)
  • man/ttyd.man.md (source markdown docs)
  • man/ttyd.1 (generated from man/ttyd.man.md)

Testing

Automated

cd html
yarn run check
yarn test
yarn run build

Manual Checklist

  • iOS Safari/Chrome: mobile keyboard panel renders and can be dragged.
  • iOS Safari/Chrome: virtual keys send expected input.
  • iOS Safari/Chrome: modifier key toggle feedback works.
  • iOS Safari/Chrome: copy/paste actions work from the mobile panel.
  • iOS Safari/Chrome: hold-repeat behavior works with configured timing.
  • iOS Safari/Chrome: multi-tap selection behavior works as expected.
  • Desktop behavior remains unchanged.
  • Android device testing (not available in current environment).

Compatibility

  • Mobile enhancements are touch-device oriented and configurable via client options.
  • Existing desktop interaction model remains unchanged.
  • No breaking CLI/API changes introduced.

@someonegg someonegg changed the title feat(html): add mobile virtual keyboard and touch optimizations for iOS/Android feat(html): mobile virtual keyboard and touch UX improvements Mar 18, 2026
@someonegg
Copy link
Copy Markdown
Author

someonegg commented Mar 18, 2026

@someonegg someonegg force-pushed the mobile-keyboard-touch-ux branch from 51ca63c to 7fb5a3a Compare March 18, 2026 07:40
@someonegg someonegg force-pushed the mobile-keyboard-touch-ux branch from 7fb5a3a to bbcb50e Compare March 18, 2026 09:39
@tsl0922 tsl0922 force-pushed the main branch 4 times, most recently from ee05f21 to a9b2d19 Compare March 20, 2026 05:39
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