forked from WHC/Hermit
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.
143 lines
3.8 KiB
C
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
|