키맵
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-style | tmux를 다루던 손놀림 그대로 앱을 다루고 싶을 때. | 프리픽스 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.optionAsMeta | Option(⌥)이 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.open | Compose 시트를 엽니다 |
compose.send | Compose 초안을 보냅니다 — 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.list | window.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.rewind | Esc 두 번: 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 agent | pane에서 무엇이 실행되든 한 에이전트의 키를 늘 보여 줍니다. | Claude Code · Codex · Any agent |
Android는 예전처럼 나머지 키 줄이 첫 줄 바로 아래, 멀티플렉서 줄이 맨 아래에 있습니다.
에이전트 키
에이전트 줄은 st가 지금 pane에서 보는 에이전트(Claude Code, Codex, Gemini CLI)를 따라가고 에이전트가 없으면 따로 나오지 않습니다. 줄 맨 앞의 키(codex ▾)나 설정 → 키와 입력 → 키 바 → 에이전트 키에서 한 에이전트로 고정할 수 있고, 에이전트 줄로 에이전트가 실행 중일 때만 / 항상 / 숨김을 고릅니다.
| 키 | 보내는 것 | Claude Code | Codex | Gemini CLI |
|---|---|---|---|---|
esc | Esc | 중단, 대화상자 닫기 | 턴 중단, 거절 | 취소 |
esc esc | Esc, Esc | 입력 지우기, 또는 되감기 | 이전 메시지 수정 | 입력 지우기, 이전 대화 보기 |
⇧tab | Shift+Tab | 권한 모드 | 협업 모드(Plan) | 승인 모드 |
⇧← ⇧→ | Shift+Left, Shift+Right | 질문에 답하기, 다음·이전 질문; 대기 중인 마지막 메시지 수정 | ||
1 2 3 | 그 숫자 | 선택지 고르기 | 선택지 고르기 | 선택지 고르기 |
^J | Ctrl+J | 줄바꿈 | 줄바꿈 | 줄바꿈 |
^O | Ctrl+O | 전체 기록 | 펼치기/접기 | |
^T | Ctrl+T | 할 일 목록 | 전체 기록 | TODO 목록 |
^B | Ctrl+B | 백그라운드로(tmux에서는 두 번) | ||
^G | Ctrl+G | $EDITOR에서 입력 편집 | $EDITOR에서 입력 편집 | |
^Y | Ctrl+Y | YOLO |
에이전트가 없을 때의 줄은 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자까지. |
title | 1–24자. |
when | always(기본), mux(멀티플렉서가 있을 때만), agent:claude, agent:codex, agent:gemini, agent:generic(st가 아는 에이전트가 없을 때). |
toggle | 이름. 같은 이름의 토글 키가 그 이름을 가진 줄을 모두 보이고 숨깁니다. 처음에는 보이고, agent 줄만 에이전트가 실행 중일 때 보입니다. |
layout | scroll(기본: 키 크기 그대로, 줄이 옆으로 스크롤) 또는 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로 취소할 수 있습니다.