NeoMutt  2025-12-11-911-gd8d604
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
keymap.c
Go to the documentation of this file.
1
22
28
29#include "config.h"
30#include <ctype.h>
31#include <limits.h>
32#include <stdbool.h>
33#include <stdlib.h>
34#include <string.h>
35#include "mutt/lib.h"
36#include "gui/lib.h"
37#include "keymap.h"
38#include "module_data.h"
39
43static struct Mapping KeyNames[] = {
44 // clang-format off
45 { "<PageUp>", KEY_PPAGE },
46 { "<PageDown>", KEY_NPAGE },
47 { "<Up>", KEY_UP },
48 { "<Down>", KEY_DOWN },
49 { "<Right>", KEY_RIGHT },
50 { "<Left>", KEY_LEFT },
51 { "<Delete>", KEY_DC },
52 { "<BackSpace>", KEY_BACKSPACE },
53 { "<Insert>", KEY_IC },
54 { "<Home>", KEY_HOME },
55 { "<End>", KEY_END },
56 { "<Enter>", '\n' },
57 { "<Return>", '\r' },
58#ifdef KEY_ENTER
59 { "<KeypadEnter>", KEY_ENTER },
60#else
61 { "<KeypadEnter>", '\n' },
62#endif
63 { "<Esc>", '\033' }, // Escape
64 { "<Tab>", '\t' },
65 { "<Space>", ' ' },
66 { "<Hash>", '#' },
67 { "<Semicolon>", ';' },
68 { "<DoubleQuote>", '"' },
69 { "<Quote>", '\'' },
70 { "<Backslash>", '\\' },
71 { "<Backtick>", '`' },
72 { "<Dollar>", '$' },
73 { "<Less>", '<' },
74 { "<Greater>", '>' },
75#ifdef KEY_BTAB
76 { "<BackTab>", KEY_BTAB },
77#endif
78#ifdef KEY_NEXT
79 { "<Next>", KEY_NEXT },
80#endif
81 /* extensions supported by ncurses. values are filled in during initialization */
82
83 /* CTRL+key */
84 { "<C-Up>", -1 },
85 { "<C-Down>", -1 },
86 { "<C-Left>", -1 },
87 { "<C-Right>", -1 },
88 { "<C-Home>", -1 },
89 { "<C-End>", -1 },
90 { "<C-Next>", -1 },
91 { "<C-Prev>", -1 },
92
93 /* SHIFT+key */
94 { "<S-Up>", -1 },
95 { "<S-Down>", -1 },
96 { "<S-Left>", -1 },
97 { "<S-Right>", -1 },
98 { "<S-Home>", -1 },
99 { "<S-End>", -1 },
100 { "<S-Next>", -1 },
101 { "<S-Prev>", -1 },
102
103 /* ALT+key */
104 { "<A-Up>", -1 },
105 { "<A-Down>", -1 },
106 { "<A-Left>", -1 },
107 { "<A-Right>", -1 },
108 { "<A-Home>", -1 },
109 { "<A-End>", -1 },
110 { "<A-Next>", -1 },
111 { "<A-Prev>", -1 },
112 { NULL, 0 },
113 // clang-format on
114};
115
121{
122 return KeyNames;
123}
124
132{
133 struct Keymap *km = MUTT_MEM_CALLOC(1, struct Keymap);
134
135 km->len = len;
137 memcpy(km->keys, keys, len * sizeof(keycode_t));
138
139 return km;
140}
141
146void keymap_free(struct Keymap **pptr)
147{
148 if (!pptr || !*pptr)
149 return;
150
151 struct Keymap *km = *pptr;
152 FREE(&km->macro);
153 FREE(&km->desc);
154 FREE(&km->keys);
155
156 FREE(pptr);
157}
158
163void keymaplist_free(struct KeymapList *kml)
164{
165 struct Keymap *km = NULL;
166 struct Keymap *km_tmp = NULL;
167 STAILQ_FOREACH_SAFE(km, kml, entries, km_tmp)
168 {
169 STAILQ_REMOVE(kml, km, Keymap, entries);
170 keymap_free(&km);
171 }
172}
173
181struct Keymap *keymap_compare(struct Keymap *km1, struct Keymap *km2, size_t *pos)
182{
183 *pos = 0;
184
185 while ((*pos < km1->len) && (*pos < km2->len))
186 {
187 if (km1->keys[*pos] < km2->keys[*pos])
188 return km2;
189
190 if (km1->keys[*pos] > km2->keys[*pos])
191 return km1;
192
193 *pos = *pos + 1;
194 }
195
196 return NULL;
197}
198
204void keymap_get_name(int c, struct Buffer *buf)
205{
206 const char *name = mutt_map_get_name(c, KeyNames);
207 if (name)
208 {
209 buf_addstr(buf, name);
210 return;
211 }
212
213 if ((c < 256) && (c > -128) && iscntrl((unsigned char) c))
214 {
215 if (c < 0)
216 c += 256;
217
218 if (c < 128)
219 {
220 buf_addch(buf, '^');
221 buf_addch(buf, (c + '@') & 0x7f);
222 }
223 else
224 {
225 buf_add_printf(buf, "\\%d%d%d", c >> 6, (c >> 3) & 7, c & 7);
226 }
227 }
228 else if ((c >= KEY_F0) && (c < KEY_F(256))) /* this maximum is just a guess */
229 {
230 buf_add_printf(buf, "<F%d>", c - KEY_F0);
231 }
232 else if ((c < 256) && (c >= -128) && IsPrint(c))
233 {
234 buf_add_printf(buf, "%c", (unsigned char) c);
235 }
236 else
237 {
238 buf_add_printf(buf, "<%ho>", (unsigned short) c);
239 }
240}
241
248bool keymap_expand_key(struct Keymap *km, struct Buffer *buf)
249{
250 if (!km || !buf)
251 return false;
252
253 for (int i = 0; i < km->len; i++)
254 {
255 keymap_get_name(km->keys[i], buf);
256 }
257
258 return true;
259}
260
266void keymap_expand_string(const char *str, struct Buffer *buf)
267{
268 if (!str)
269 return;
270
271 for (; *str; str++)
272 {
273 keymap_get_name(*str, buf);
274 }
275}
276
285int parse_fkey(char *str)
286{
287 char *t = NULL;
288 int n = 0;
289
290 if ((str[0] != '<') || (mutt_tolower(str[1]) != 'f'))
291 return -1;
292
293 for (t = str + 2; *t && mutt_isdigit(*t); t++)
294 {
295 n *= 10;
296 n += *t - '0';
297 }
298
299 if (*t != '>')
300 return -1;
301 return n;
302}
303
312int parse_keycode(const char *str)
313{
314 char *end_char = NULL;
315 long int result = strtol(str + 1, &end_char, 8);
316
317 /* allow trailing whitespace, eg. < 1001 > */
318 while (mutt_isspace(*end_char))
319 end_char++;
320
321 /* negative keycodes don't make sense, also detect overflow */
322 if ((*end_char != '>') || (result < 0) || (result == LONG_MAX))
323 {
324 return -1;
325 }
326
327 return result;
328}
329
337size_t parse_keys(const char *str, keycode_t *d, size_t max)
338{
339 int n;
340 size_t len = max;
341 char buf[128] = { 0 };
342 char c;
343 char *t = NULL;
344
345 mutt_str_copy(buf, str, sizeof(buf));
346 char *s = buf;
347
348 while (*s && len)
349 {
350 *d = '\0';
351 if ((*s == '<') && (t = strchr(s, '>')))
352 {
353 t++;
354 c = *t;
355 *t = '\0';
356
358 if (n != -1)
359 {
360 s = t;
361 *d = n;
362 }
363 else if ((n = parse_fkey(s)) > 0)
364 {
365 s = t;
366 *d = KEY_F(n);
367 }
368 else if ((n = parse_keycode(s)) > 0)
369 {
370 s = t;
371 *d = n;
372 }
373
374 *t = c;
375 }
376
377 if (!*d)
378 {
379 *d = (unsigned char) *s;
380 s++;
381 }
382 d++;
383 len--;
384 }
385
386 return max - len;
387}
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition buffer.c:204
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
bool mutt_isspace(int arg)
Wrapper for isspace(3)
Definition ctype.c:96
int mutt_tolower(int arg)
Wrapper for tolower(3)
Definition ctype.c:126
bool mutt_isdigit(int arg)
Wrapper for isdigit(3)
Definition ctype.c:66
Convenience wrapper for the gui headers.
void keymap_get_name(int c, struct Buffer *buf)
Get the human name for a key.
Definition keymap.c:204
void keymaplist_free(struct KeymapList *kml)
Free a List of Keymaps.
Definition keymap.c:163
struct Mapping * keymap_get_key_names(void)
Get the KeyNames lookup table.
Definition keymap.c:120
void keymap_expand_string(const char *str, struct Buffer *buf)
Get a human-readable key string.
Definition keymap.c:266
bool keymap_expand_key(struct Keymap *km, struct Buffer *buf)
Get the key string bound to a Keymap.
Definition keymap.c:248
void keymap_free(struct Keymap **pptr)
Free a Keymap.
Definition keymap.c:146
struct Keymap * keymap_compare(struct Keymap *km1, struct Keymap *km2, size_t *pos)
Compare two keymaps' keyscodes and return the bigger one.
Definition keymap.c:181
size_t parse_keys(const char *str, keycode_t *d, size_t max)
Parse a key string into key codes.
Definition keymap.c:337
int parse_fkey(char *str)
Parse a function key string.
Definition keymap.c:285
struct Keymap * keymap_alloc(size_t len, keycode_t *keys)
Allocate space for a sequence of keys.
Definition keymap.c:131
static struct Mapping KeyNames[]
Key name lookup table.
Definition keymap.c:43
int parse_keycode(const char *str)
Parse a numeric keycode.
Definition keymap.c:312
Key private Module data.
Keymap handling.
short keycode_t
Type for key storage, the rest of neomutt works fine with int type.
Definition keymap.h:31
int mutt_map_get_value(const char *name, const struct Mapping *map)
Lookup the constant for a string.
Definition mapping.c:85
const char * mutt_map_get_name(int val, const struct Mapping *map)
Lookup a string for a constant.
Definition mapping.c:42
#define IsPrint(ch)
Definition mbyte.h:39
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
Convenience wrapper for the library headers.
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition string.c:586
#define STAILQ_REMOVE(head, elm, type, field)
Definition queue.h:441
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition queue.h:400
String manipulation buffer.
Definition buffer.h:36
A keyboard mapping.
Definition keymap.h:43
keycode_t * keys
Key sequence.
Definition keymap.h:49
char * macro
Macro expansion (op == OP_MACRO)
Definition keymap.h:44
char * desc
Description of a macro for the help menu.
Definition keymap.h:45
short len
Length of key sequence (unit: sizeof (keycode_t))
Definition keymap.h:48
Mapping between user-readable string and a constant.
Definition mapping.h:33