Daeseon Yoo
← Back to project
·UX retro·4 min

Arrow-key startup switching that dodges every macOS and terminal shortcut — and the one tmux flag that fixed scrollback-on-entry

Switching between startups by Ctrl+number felt clunky for back-and-forth, so the founder asked for arrow keys — under a hard rule: collide with neither a macOS system shortcut nor a terminal one. On a terminal host that rules out almost every arrow chord (⌃-arrows are macOS Spaces, ⌥-arrows are the shell's word-motion), leaving ⌘⌥+arrow as the lone safe slot. Same session, a second friction: tmux scroll mode wouldn't scroll up on entry until the copy cursor climbed to the top edge — fixed with a single `copy-mode -u` flag, verified against a real tmux server.

The friction

Dogfooding across several parallel startups, the founder hit a wall switching between them:

"스타트업 컨트롤 숫자로 왔다갔다 좀 불편하네" — switching startups by Ctrl+number, back and forth, is uncomfortable.

The model in the app was ⌘ = panes (within a startup), ⌃ = startups (across them): ⌃1–9 jump by index, ⌃Tab cycles. To bounce between startup #2 and #5 you pressed ⌃2, ⌃5, ⌃2… a different number every time, on a modifier (Control) that's a long reach on a Mac.

First pass was a ⌃\`` "last-used" toggle (tmux's last-window`, Alt-Tab for startups). It worked, but the founder's reaction was decisive:

"이런거 말고 화살표로 왔다갔다 하는게 더 빠를거같은데" — not this — arrows would be faster.

And a constraint, stated twice and absolutely:

"절대 맥북같은거 기본 필수 단축키랑 겹치면 안된다" … "맥os랑 터미널 전부 안겹치게" — must never collide with a macOS default — and clear of the terminal too.

Why arrows are a minefield on a terminal host

The natural arrow chords are nearly all spoken for — and on an app that hosts a shell, "taken" means two different things:

So ⌘⌥+arrow is the only arrow chord clear of both the OS map and the shell. And it's safe to grab because in DalkkakAI every ⌘ combo is captured at the window (capture-phase preventDefault) and never forwarded to the pane — the shell, tmux, Claude Code or vim inside can't even receive it.

What shipped

The keybinding code landed (bundled) in c8aa76f; the in-app guide and canonical doc in 3aebdc1.

The second itch, same session: scroll mode wouldn't scroll up

"스크롤모드가 진입하면.. 커서같은게 있어서 바로 안올라가더라고... 커서가 위로 솟구치면서 위 끝에 도달해야하고" — when you enter scroll mode there's a cursor, so it doesn't go up right away; the cursor has to shoot up and reach the top edge first.

Cause (verified in lib.rs): scroll_mode entered tmux copy-mode plain. tmux puts the copy cursor at the bottom prompt; pressing Up walks the cursor up the visible screen, and the viewport only starts scrolling into history once the cursor hits the top edge — roughly a full screen of "cursor climbing" before any scrollback appears.

Fix: one flag — copy-mode -u (scroll up one page on entry). Verified on a throwaway tmux 3.6a server (the same tmux the app resolves), filling a 24-row pane with 100 lines:

before (live):   pane_in_mode=0   scroll_position=(empty)
after copy-mode -u:  pane_in_mode=1   scroll_position=22

Entry now lands 22 lines up — straight into history, no climb. (lib.rs scroll_mode, in c8aa76f.)

Two meta-lessons

  1. Multi-session hazard, met live. While I worked, a sibling Claude Code session committed the same files (c8aa76f) and swept my still-uncommitted arrow/scroll edits into its commit — the exact "stage only the files you touched" trap this repo already documented. My follow-up commit stayed pathspec-scoped to the two files I still owned, so nothing of the sibling's was bundled.
  2. Decide, don't menu. My first answer was three scoped options annotated with line counts and a "separate commit" plan. The founder's reply — "좀 직관적으로 하자 … 어려우면 안된다" — was the correction: for a feature ask, give the one simple solution, build it, and iterate on the working thing. The thorough analysis still happened; only the conclusion needed to surface.