Files
CST-agent/include/cst_keymap.h
T
WHC b28bca2cfc TUI: kitty keyboard protocol, word movement and deletion keys
Query CSI ? u at startup and push the disambiguate flag on the alternate
screen when the terminal answers; CSI u reports are mapped back to legacy
input (Shift/Ctrl+Enter insert a newline, Ctrl+Backspace deletes a word).
Ctrl/Alt+Left/Right move by word, Ctrl/Alt+Delete delete the next word.
Our define_key codes move above the range ncurses uses for terminfo
extended keys.
2026-10-06 01:52:48 +08:00

143 lines
3.8 KiB
C

#ifndef CST_KEYMAP_H
#define CST_KEYMAP_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Key codes: a Unicode code point (control characters included: ctrl+a = 1),
* a CST_K_* special key, optionally OR'ed with CST_KEY_ALT. */
#define CST_KEY_SPECIAL 0x110000
#define CST_KEY_ALT 0x400000
enum {
CST_K_UP = CST_KEY_SPECIAL,
CST_K_DOWN,
CST_K_LEFT,
CST_K_RIGHT,
CST_K_HOME,
CST_K_END,
CST_K_PGUP,
CST_K_PGDN,
CST_K_BTAB, /* shift+tab */
CST_K_DEL,
CST_K_INS,
CST_K_CTRL_HOME,
CST_K_CTRL_END,
CST_K_CTRL_UP,
CST_K_CTRL_DOWN,
CST_K_ALT_UP,
CST_K_ALT_DOWN,
CST_K_F1, /* CST_K_F1 + n - 1 for f1..f12 */
CST_K_LAST = CST_K_F1 + 11
};
typedef enum {
CST_KA_NONE = 0,
/* general */
CST_KA_PALETTE,
CST_KA_KEYS,
CST_KA_MODE,
CST_KA_APPROVAL,
CST_KA_NEWLINE,
CST_KA_REDRAW,
CST_KA_QUIT,
/* view */
CST_KA_TOGGLE_TOOL,
CST_KA_TOGGLE_THOUGHT,
CST_KA_THINKING_ALL,
CST_KA_DETAILS,
CST_KA_TODO,
CST_KA_SIDEBAR,
CST_KA_SCROLL_UP,
CST_KA_SCROLL_DOWN,
CST_KA_LINE_UP,
CST_KA_LINE_DOWN,
CST_KA_TOP,
CST_KA_BOTTOM,
/* session */
CST_KA_NEW_SESSION,
CST_KA_SESSIONS,
CST_KA_UNDO,
CST_KA_RETRY,
CST_KA_COMPACT,
CST_KA_COPY,
CST_KA_EXPORT,
/* model */
CST_KA_MODEL,
CST_KA_PROVIDER,
CST_KA_EFFORT,
/* extensions */
CST_KA_AGENTS,
CST_KA_SKILLS,
CST_KA_PLUGINS,
CST_KA_COUNT
} cst_key_action_t;
typedef struct {
const char *name; /* keybinds.json key, e.g. "new_session" */
const char *group; /* "General", "View", ... */
const char *desc;
const char *slash; /* equivalent slash command, or NULL */
} cst_key_action_info_t;
const cst_key_action_info_t *cst_key_action_info(int action);
int cst_key_action_find(const char *name); /* CST_KA_NONE when unknown */
/* "ctrl+p", "shift+tab", "alt+enter", "f1", "pgup", "x" → code; -1 if bad. */
int cst_key_parse(const char *s);
/* code → canonical name ("ctrl+x", "tab", "alt+up", ...). */
const char *cst_key_name(int code, char *buf, size_t n);
/* Kitty keyboard protocol ("disambiguate" flag): the report CSI cp;1+mods u
* (mods: 1 shift, 2 alt, 4 ctrl) → the input a legacy terminal would send,
* so the rest of the TUI needs no changes. Alt becomes an Esc prefix;
* shift/ctrl+enter become alt+enter (newline) and ctrl+backspace becomes
* alt+backspace (delete word); shift+tab is CST_K_BTAB. Writes up to two codes
* to out and returns how many (0 when the report means nothing to us). */
int cst_key_from_kitty(int cp, int mods, int out[2]);
#define CST_KEYMAP_MAX 128
typedef struct {
int action;
int keys[2];
int nkeys;
int user; /* from keybinds.json */
} cst_binding_t;
typedef struct {
int leader;
cst_binding_t b[CST_KEYMAP_MAX];
int n;
} cst_keymap_t;
void cst_keymap_defaults(cst_keymap_t *km);
/* Apply keybinds.json text over the defaults:
* {"leader":"ctrl+x", "palette":"ctrl+p", "new_session":["<leader> n","f2"],
* "todo":"none"}
* Returns 0, or -1 with a message (bad entries are skipped, the rest apply). */
int cst_keymap_apply_json(cst_keymap_t *km, const char *json, char *err,
size_t err_sz);
/* Defaults + <config>/keybinds.json when present. */
int cst_keymap_load(cst_keymap_t *km, char *err, size_t err_sz);
#define CST_KM_NONE 0
#define CST_KM_MATCH 1
#define CST_KM_PREFIX 2
/* seq of 1 or 2 keys → CST_KM_*; *action set on a match. */
int cst_keymap_lookup(const cst_keymap_t *km, const int *seq, int n,
int *action);
/* "ctrl+x n, f2" (or "" when unbound). */
void cst_keymap_describe(const cst_keymap_t *km, int action, char *buf,
size_t n);
/* One line per conflict ("ctrl+o: toggle_tool, toggle_thought"); returns the
* number of conflicts. */
int cst_keymap_conflicts(const cst_keymap_t *km, char *buf, size_t n);
#ifdef __cplusplus
}
#endif
#endif