키맵

sophonz ADE의 하드웨어 키보드 단축키와 화면 키바 — 기본 제공 키맵, 에이전트 키, 파일 형식, 직접 만든 키맵을 가져오는 방법.

키맵은 cmd+t, ctrl+b 다음 c처럼 하드웨어 키 조합을 앱 동작에 연결하는 JSON 파일입니다: 새 창, 다음 페인, Compose 열기 같은 것들이죠. 키맵이 다루지 않는 키는 그대로 터미널로 전달되므로, 키맵은 단축키를 더할 뿐 입력을 가로채지 않습니다. iOS와 Android는 같은 파일 형식, keymap v1을 읽으므로 폰에서 내보낸 키맵을 다른 플랫폼에서도 그대로 쓸 수 있습니다.

같은 파일에 화면 키바도 적을 수 있습니다. 어떤 줄이 있고 줄마다 어떤 키가 있고 키마다 무엇을 보내는지(키바). 이 부분이 없는 파일은 앱에 들어 있는 기본 키바를 씁니다.

앱에는 읽기 전용인 기본 키맵 세 개가 들어 있고 원하는 만큼 직접 가져올 수 있습니다.

기본 제공 키맵 세 가지

템플릿용도주요 단축키
Default대부분의 Mac 앱이 쓰는 Cmd 키 구성 그대로.⌘T 새 창 · ⌘W 닫기 · ⌘[ ⌘] 이전/다음 창 · ⌘1–⌘9 창 번호로 이동 · ⌘⇧[ ⌘⇧] 이전/다음 세션 · ⌘↩ Compose 열기·보내기 · ⌘= ⌘- ⌘0 글자 크기 · ⌘K 지우기 · ⌥⇥ ⌥\`` 전환기 · 에이전트용 ⌘.중단,⌘Z되감기,⌘⇧O전체 기록,⌘⇧E편집기,⌘⇧A` 에이전트 키다운로드
tmux-styletmux를 다루던 손놀림 그대로 앱을 다루고 싶을 때.프리픽스 ctrl+b 다음 c 새 창 · , 이름 바꾸기 · n p 다음/이전 · 0–9 창 번호로 이동 · x 닫기 · % " 분할 · z 줌 · o 다음 페인 · s 세션 목록 · w 창 목록 — 그 밖에 ⌘↩ Compose, ⌘C/⌘V 복사·붙여넣기, 전환기, Default의 에이전트 키는 프리픽스 밖에서 동작다운로드
Minimal터미널을 건드리지 않고 최소한만.⌘↩ ⌘⇧C Compose 열기 · ⌘↩ 보내기 · esc/⌘W/⌘. 닫기 · ⌘⇧M 마이크 · ⌘C/⌘V 복사·붙여넣기 — 그 외에는 아무것도 없음다운로드

가져오기와 내보내기

설정 → 키와 입력 → 하드웨어 키보드 → 키맵에 기본 세 개와 직접 추가한 키맵이 함께 나오고, 지금 쓰는 키맵이 어느 것인지도 보입니다.

  • Export는 지금 쓰는 키맵을 .sophonz-keymap.json 파일로 저장합니다. 백업하거나 다른 기기로 옮길 때 씁니다.
  • Import는 그 파일을 키바까지 다시 읽어들입니다. 들어오는 즉시 검사하므로, 문제가 있는 파일은 이유와 함께 거부되고 아무것도 바뀌지 않습니다. 통과하면 목록에 추가되어 바로 전환할 수 있습니다.

기본 키맵 세 개는 수정하거나 지울 수 없고 가져온 키맵은 자유롭게 고치거나 지울 수 있습니다.

파일 형식

{
  "$schema": "https://www.sophonz.io/schemas/keymap-v1.json",
  "format": "sophonz-keymap",
  "version": 1,
  "name": "My keys",
  "platform": "any",
  "options": { "optionAsMeta": true, "tmuxPrefix": { "enabled": false, "key": "ctrl+b" } },
  "bindings": [
    { "action": "window.new", "keys": "cmd+t" },
    { "action": "compose.send", "keys": "cmd+enter", "when": "compose" }
  ],
  "prefixBindings": [ { "action": "window.new", "key": "c" } ]
}
필드
format, version필수: "sophonz-keymap"과 1.
name필수, 1~40자.
platform기본값 any, 또는 ios, android — 어디서 만들었는지 기록만 할 뿐, 모든 앱이 모든 키맵을 그대로 읽습니다.
options.optionAsMetaOption(⌥)이 Esc+키를 보내는, 터미널에서 흔히 쓰는 Meta 방식입니다. 기본값 true; 끄면 Option으로 악센트 문자를 입력할 수 있습니다.
options.tmuxPrefix{ enabled, key }. 켜면 앱이 프리픽스 키(ctrl+b 또는 ctrl+a)를 직접 잡아채고 그다음 누른 키를 prefixBindings로 처리합니다. 끄면 프리픽스를 포함한 모든 키가 그대로 tmux로 전달됩니다.
bindings[]{ action, keys, when? } — 아래 참고.
prefixBindings[]{ action, key } — 프리픽스 바로 다음에 누르는 키 하나(수정자 없이).
keyBar화면 키바 — 키바 참고. 없어도 됩니다.

이 필드들 외에는 최상위 객체에도, 각 바인딩에도 다른 속성을 넣을 수 없습니다.

키

키는 mod+mod+key 형태로, 모두 소문자로 씁니다.

  • 수정자는 이 순서로, 각각 한 번씩만: cmd, ctrl, opt(alt도 되고 opt로 읽힙니다), shift. Android에서 cmd는 Meta입니다.
  • 키는 a–z, 0–9, f1–f12, 또는 이름 있는 키 — enter, esc, tab, space, backspace, delete, up, down, left, right, home, end, pageup, pagedown — 또는 [ ] , . / ; ' \ - = ` 중 하나입니다.
  • Shift는 키가 아니라 여전히 수정자입니다: tmux의 %는 shift+5, "는 shift+', US 배열에서 +는 shift+=입니다.

Plain ctrl+글자, esc, tab은 바인딩하면 경고가 뜹니다 — 터미널이 그 키들을 써야 하기 때문이고, 기본 키맵도 그 키들을 절대 가져가지 않습니다. ctrl+space, 🌐, Caps Lock은 시스템의 한/영 전환 키라 아예 바인딩할 수 없습니다. 아래에서 다룹니다.

when

바인딩은 둘 중 한 맥락에서 동작합니다.

  • terminal(기본값) — 터미널에 포커스가 있을 때.
  • compose — Compose 시트가 열려 있을 때. compose.send, compose.close, compose.mic에는 반드시 필요하고, 다른 동작에는 쓸 수 없습니다.

prefixBindings에는 when이 없습니다. 프리픽스를 누르고 있는 터미널에서만 의미가 있기 때문입니다.

동작 목록

동작하는 일
compose.openCompose 시트를 엽니다
compose.sendCompose 초안을 보냅니다 — when: compose에서만
compose.close보내지 않고 Compose를 닫습니다 — when: compose에서만
compose.mic초안에 음성 받아쓰기를 시작합니다 — when: compose에서만
window.new새 창을 엽니다
window.close현재 창을 닫습니다
window.prev, window.next이전/다음 창으로 이동합니다
window.goto.0 … window.goto.9번호로 창에 바로 이동합니다
window.rename현재 창 이름을 바꿉니다
window.list알약 시트(세션, 창, pane 고르기)를 엽니다
session.prev, session.next이전/다음 세션으로 이동합니다
session.listwindow.list와 같은 알약 시트를 엽니다
pane.next다음 페인으로 이동합니다
pane.zoom현재 페인을 확대/축소합니다
pane.split.right, pane.split.down페인을 분할합니다
font.bigger, font.smaller, font.reset터미널 글자 크기를 바꿉니다
edit.copy, edit.paste복사하거나 붙여넣습니다
terminal.clear터미널을 지웁니다
switcher.windows, switcher.sessions창/세션 전환기를 엽니다 — 아래 참고
keybar.toggle키바를 열거나 닫습니다(하드웨어 키보드가 있으면 닫힌 채 시작)
keyboard.onscreen화면 키보드를 보이거나 숨깁니다
window.goto.ask창 번호를 물어보고 그 창으로 갑니다
session.detach세션에서 나갑니다(detach)
agent.interrupt에이전트를 멈춥니다(Esc)
agent.rewindEsc 두 번: Claude Code는 되감기, Codex는 이전 메시지 수정
agent.mode에이전트 모드를 바꿉니다(Shift+Tab)
agent.newline보내지 않고 줄을 바꿉니다(Ctrl+J, 모르는 에이전트는 Alt+Enter)
agent.transcript에이전트의 전체 기록(Claude Code는 Ctrl+O, Codex는 Ctrl+T)
agent.editor입력을 $EDITOR에서 편집합니다(Ctrl+G)
keybar.agent키바의 에이전트 줄을 보이거나 숨깁니다

agent.* 액션은 지금 pane의 에이전트가 그 일에 읽는 키를 보내므로, 바인딩 하나가 Claude Code, Codex, Gemini CLI 모두에서 맞게 동작합니다. 이 액션이 생기기 전의 앱은 이것을 쓴 파일을 거부합니다.

compose.send, compose.close, compose.mic은 prefixBindings로 쓸 수 없습니다 — 이 동작들은 Compose 안에서만 있고, 프리픽스는 터미널에서만 동작하기 때문입니다.

제한과 검증

문제가 있는 파일은 통째로 거부되고 아무것도 바뀌지 않으며, 모든 문제가 JSON 경로와 함께 나열됩니다. 예: bindings[3].keys: "cmd+tt" is not a key. 스키마와 각 앱의 검증기가 똑같이 확인하는 항목:

  • 올바른 JSON, 객체 형태, format과 version이 정확히 일치.
  • 알 수 없는 속성·동작·키가 없고, 그 동작이 허용하지 않는 when도 없음.
  • name은 1~40자.
  • 같은 when 안에서 같은 키를 두 바인딩이 함께 쓰지 않음, prefixBindings에서 같은 키를 두 번 쓰지 않음.
  • bindings는 최대 200개, prefixBindings는 최대 100개.
  • 파일 자체는 최대 64 KB.
  • keyBar 안에서: 줄 id는 겹치지 않고, 키마다 send, text, char, action, toggle 중 정확히 하나가 있고, 토글 키마다 보이고 숨길 줄이 있어야 합니다.

키바

키바의 줄은 지금 쓰는 키맵에서 옵니다. 설정 → 키와 입력 → 키 바 → 배치에서 고칩니다. 프리셋에서 시작해 줄과 키를 끌어서 순서를 바꾸고 숨기거나 지우고 직접 추가하고 키마다 보내는 것을 바꿀 수 있습니다. 기본 키맵은 먼저 복사합니다. 키바의 키를 길게 누르면 누르지 않고 무엇을 보내는지 보여 줍니다(⇧tab — Shift+Tab · Claude Code: 권한 모드 전환). 화살표처럼 반복되는 키는 반복하는 동안 보여 주고, 누른 채 말하는 마이크 키는 보여 주지 않습니다.

프리셋줄
Default첫 줄(멀티플렉서·에이전트 토글, ctrl, alt, esc, tab, 화살표), 에이전트 줄, 멀티플렉서 줄, 나머지 키. 키바가 없는 키맵이 쓰는 배치입니다.다운로드
tmux멀티플렉서 줄을 늘 펼쳐 두고, 에이전트 줄은 없습니다.다운로드
Minimal첫 줄과 짧은 나머지 키 줄.다운로드
Claude Code, Codex, Any agentpane에서 무엇이 실행되든 한 에이전트의 키를 늘 보여 줍니다.Claude Code · Codex · Any agent

Android는 예전처럼 나머지 키 줄이 첫 줄 바로 아래, 멀티플렉서 줄이 맨 아래에 있습니다.

에이전트 키

에이전트 줄은 st가 지금 pane에서 보는 에이전트(Claude Code, Codex, Gemini CLI)를 따라가고 에이전트가 없으면 따로 나오지 않습니다. 줄 맨 앞의 키(codex ▾)나 설정 → 키와 입력 → 키 바 → 에이전트 키에서 한 에이전트로 고정할 수 있고, 에이전트 줄로 에이전트가 실행 중일 때만 / 항상 / 숨김을 고릅니다.

키보내는 것Claude CodeCodexGemini CLI
escEsc중단, 대화상자 닫기턴 중단, 거절취소
esc escEsc, Esc입력 지우기, 또는 되감기이전 메시지 수정입력 지우기, 이전 대화 보기
⇧tabShift+Tab권한 모드협업 모드(Plan)승인 모드
⇧← ⇧→Shift+Left, Shift+Right질문에 답하기, 다음·이전 질문; 대기 중인 마지막 메시지 수정
1 2 3그 숫자선택지 고르기선택지 고르기선택지 고르기
^JCtrl+J줄바꿈줄바꿈줄바꿈
^OCtrl+O전체 기록펼치기/접기
^TCtrl+T할 일 목록전체 기록TODO 목록
^BCtrl+B백그라운드로(tmux에서는 두 번)
^GCtrl+G$EDITOR에서 입력 편집$EDITOR에서 입력 편집
^YCtrl+YYOLO

에이전트가 없을 때의 줄은 esc esc, ⇧tab, ⇧← ⇧→, 1 2 3, ⌥⏎(Alt+Enter)입니다. Shift+Enter 키는 없습니다. ^J가 같은 일을 합니다.

keyBar

"keyBar": { "groups": [
  { "id": "main", "layout": "fit", "keys": [
    { "toggle": "mux" }, { "action": "mod.ctrl", "label": "ctrl" }, { "send": "left", "repeat": true } ] },
  { "id": "codex", "title": "Codex", "when": "agent:codex", "toggle": "agent", "keys": [
    { "action": "agent.pick" },
    { "label": "⇧←", "send": "shift+left", "hint": { "en": "Codex: answer its questions", "ko": "Codex: 질문에 답하기" } },
    { "label": "esc esc", "text": ["\u001b", "\u001b"] } ] }
] }
필드
groups[]위에서 아래로 1–12줄.
id필수, 겹치지 않음. 소문자·숫자·-, 소문자로 시작, 24자까지.
title1–24자.
whenalways(기본), mux(멀티플렉서가 있을 때만), agent:claude, agent:codex, agent:gemini, agent:generic(st가 아는 에이전트가 없을 때).
toggle이름. 같은 이름의 토글 키가 그 이름을 가진 줄을 모두 보이고 숨깁니다. 처음에는 보이고, agent 줄만 에이전트가 실행 중일 때 보입니다.
layoutscroll(기본: 키 크기 그대로, 줄이 옆으로 스크롤) 또는 fit(키가 너비를 나눠 가짐).
hidden파일에는 남기고 보이지 않게.
keys[]1–60개. 키마다 send, text, char, action, toggle 중 정확히 하나, 그리고 label(1–12자, 없으면 하는 일로 만듦), hint(문자열, 또는 언어별 {"en": …, "ko": …}), repeat, wide.
send하드웨어 키보드가 보내는 그대로의 키 — 위의 키에서 cmd만 뺀 것: shift+tab, shift+left, ctrl+b, opt+enter. 키바의 ctrl·alt가 더해집니다.
text적힌 그대로 보냅니다. 목록이면 조금씩 사이를 두고 따로 보내서 Esc, Esc가 두 번 누른 것으로 닿습니다.
char글자 하나. 키바의 ctrl·alt가 적용됩니다.
action위의 액션 중 compose.send, compose.close를 뺀 것(compose.mic은 받아쓰기), 또는 mod.ctrl, mod.alt(고정되는 수정자), agent.pick(에이전트 고르기).
toggle그 토글 이름을 가진 줄을 보이고 숨깁니다. 그런 줄이 있어야 합니다.

머신이 지원하지 않는 멀티플렉서 동작의 키와 해당되지 않는 줄의 토글은 빠집니다.

에디터도 검증합니다

파일 맨 위의 $schema 줄은 keymap-v1.json, JSON Schema 2020-12 문서를 가리킵니다. VS Code를 비롯해 JSON Schema를 지원하는 에디터는 이 줄을 자동으로 읽어서, 잘못된 키나 알 수 없는 동작에 빨간 밑줄을 긋고 둘 다 자동완성까지 제공합니다 — 앱에 가져오기 전에 에디터 안에서 바로.

한/영 전환

iOS에서는 Ctrl+Space, 🌐(지구본 키), Caps Lock이, Android에서는 Ctrl+Space, Shift+Space, 한/영 키가 시스템 자체의 입력 전환 키입니다. 앱은 이 키들을 절대 가로채지 않습니다 — 앱이 없는 것처럼 그대로 시스템에 전달되므로, 입력 중에 영어와 한글을 오가는 동작은 항상 작동합니다.

전환기

switcher.windows(기본값 ⌥⇥)와 switcher.sessions(기본값 ⌥`)는 수정자를 누르고 있는 동안 동작합니다: 키를 누르면 전환기가 뜨고, 수정자를 누른 채로 더 누를 때마다 선택이 옮겨가며(Shift를 더하면 반대 방향), 수정자를 놓으면 선택한 것으로 전환됩니다. Esc로 취소할 수 있습니다.