NeoMutt  2025-12-11-79-gf03987
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
42struct Mapping KeyNames[] = {
43 // clang-format off
44 { "<PageUp>", KEY_PPAGE },
45 { "<PageDown>", KEY_NPAGE },
46 { "<Up>", KEY_UP },
47 { "<Down>", KEY_DOWN },
48 { "<Right>", KEY_RIGHT },
49 { "<Left>", KEY_LEFT },
50 { "<Delete>", KEY_DC },
51 { "<BackSpace>", KEY_BACKSPACE },
52 { "<Insert>", KEY_IC },
53 { "<Home>", KEY_HOME },
54 { "<End>", KEY_END },
55 { "<Enter>", '\n' },
56 { "<Return>", '\r' },
57#ifdef KEY_ENTER
58 { "<KeypadEnter>", KEY_ENTER },
59#else
60 { "<KeypadEnter>", '\n' },
61#endif
62 { "<Esc>", '\033' }, // Escape
63 { "<Tab>", '\t' },
64 { "<Space>", ' ' },
65#ifdef KEY_BTAB
66 { "<BackTab>", KEY_BTAB },
67#endif
68#ifdef KEY_NEXT
69 { "<Next>", KEY_NEXT },
70#endif
71 /* extensions supported by ncurses. values are filled in during initialization */
72
73 /* CTRL+key */
74 { "<C-Up>", -1 },
75 { "<C-Down>", -1 },
76 { "<C-Left>", -1 },
77 { "<C-Right>", -1 },
78 { "<C-Home>", -1 },
79 { "<C-End>", -1 },
80 { "<C-Next>", -1 },
81 { "<C-Prev>", -1 },
82
83 /* SHIFT+key */
84 { "<S-Up>", -1 },
85 { "<S-Down>", -1 },
86 { "<S-Left>", -1 },
87 { "<S-Right>", -1 },
88 { "<S-Home>", -1 },
89 { "<S-End>", -1 },
90 { "<S-Next>", -1 },
91 { "<S-Prev>", -1 },
92
93 /* ALT+key */
94 { "<A-Up>", -1 },
95 { "<A-Down>", -1 },
96 { "<A-Left>", -1 },
97 { "<A-Right>", -1 },
98 { "<A-Home>", -1 },
99 { "<A-End>", -1 },
100 { "<A-Next>", -1 },
101 { "<A-Prev>", -1 },
102 { NULL, 0 },
103 // clang-format off
104};
105
113{
114 struct Keymap *km = MUTT_MEM_CALLOC(1, struct Keymap);
115
116 km->len = len;
118 memcpy(km->keys, keys, len * sizeof(keycode_t));
119
120 return km;
121}
122
127void keymap_free(struct Keymap **pptr)
128{
129 if (!pptr || !*pptr)
130 return;
131
132 struct Keymap *km = *pptr;
133 FREE(&km->macro);
134 FREE(&km->desc);
135 FREE(&km->keys);
136
137 FREE(pptr);
138}
139
144void keymaplist_free(struct KeymapList *kml)
145{
146 struct Keymap *km = NULL;
147 struct Keymap *km_tmp = NULL;
148 STAILQ_FOREACH_SAFE(km, kml, entries, km_tmp)
149 {
150 STAILQ_REMOVE(kml, km, Keymap, entries);
151 keymap_free(&km);
152 }
153}
154
162struct Keymap *keymap_compare(struct Keymap *km1, struct Keymap *km2, size_t *pos)
163{
164 *pos = 0;
165
166 while ((*pos < km1->len) && (*pos < km2->len))
167 {
168 if (km1->keys[*pos] < km2->keys[*pos])
169 return km2;
170
171 if (km1->keys[*pos] > km2->keys[*pos])
172 return km1;
173
174 *pos = *pos + 1;
175 }
176
177 return NULL;
178}
179
185void keymap_get_name(int c, struct Buffer *buf)
186{
187 const char *name = mutt_map_get_name(c, KeyNames);
188 if (name)
189 {
190 buf_addstr(buf, name);
191 return;
192 }
193
194 if ((c < 256) && (c > -128) && iscntrl((unsigned char) c))
195 {
196 if (c < 0)
197 c += 256;
198
199 if (c < 128)
200 {
201 buf_addch(buf, '^');
202 buf_addch(buf, (c + '@') & 0x7f);
203 }
204 else
205 {
206 buf_add_printf(buf, "\\%d%d%d", c >> 6, (c >> 3) & 7, c & 7);
207 }
208 }
209 else if ((c >= KEY_F0) && (c < KEY_F(256))) /* this maximum is just a guess */
210 {
211 buf_add_printf(buf, "<F%d>", c - KEY_F0);
212 }
213 else if ((c < 256) && (c >= -128) && IsPrint(c))
214 {
215 buf_add_printf(buf, "%c", (unsigned char) c);
216 }
217 else
218 {
219 buf_add_printf(buf, "<%ho>", (unsigned short) c);
220 }
221}
222
229bool keymap_expand_key(struct Keymap *km, struct Buffer *buf)
230{
231 if (!km || !buf)
232 return false;
233
234 for (int i = 0; i < km->len; i++)
235 {
236 keymap_get_name(km->keys[i], buf);
237 }
238
239 return true;
240}
241
247void keymap_expand_string(const char *str, struct Buffer *buf)
248{
249 for (; *str; str++)
250 {
251 keymap_get_name(*str, buf);
252 }
253}
254
263int parse_fkey(char *str)
264{
265 char *t = NULL;
266 int n = 0;
267
268 if ((str[0] != '<') || (mutt_tolower(str[1]) != 'f'))
269 return -1;
270
271 for (t = str + 2; *t && mutt_isdigit(*t); t++)
272 {
273 n *= 10;
274 n += *t - '0';
275 }
276
277 if (*t != '>')
278 return -1;
279 return n;
280}
281
290int parse_keycode(const char *str)
291{
292 char *end_char = NULL;
293 long int result = strtol(str + 1, &end_char, 8);
294
295 /* allow trailing whitespace, eg. < 1001 > */
296 while (mutt_isspace(*end_char))
297 end_char++;
298
299 /* negative keycodes don't make sense, also detect overflow */
300 if ((*end_char != '>') || (result < 0) || (result == LONG_MAX))
301 {
302 return -1;
303 }
304
305 return result;
306}
307
315size_t parse_keys(const char *str, keycode_t *d, size_t max)
316{
317 int n;
318 size_t len = max;
319 char buf[128] = { 0 };
320 char c;
321 char *t = NULL;
322
323 mutt_str_copy(buf, str, sizeof(buf));
324 char *s = buf;
325
326 while (*s && len)
327 {
328 *d = '\0';
329 if ((*s == '<') && (t = strchr(s, '>')))
330 {
331 t++;
332 c = *t;
333 *t = '\0';
334
336 if (n != -1)
337 {
338 s = t;
339 *d = n;
340 }
341 else if ((n = parse_fkey(s)) > 0)
342 {
343 s = t;
344 *d = KEY_F(n);
345 }
346 else if ((n = parse_keycode(s)) > 0)
347 {
348 s = t;
349 *d = n;
350 }
351
352 *t = c;
353 }
354
355 if (!*d)
356 {
357 *d = (unsigned char) *s;
358 s++;
359 }
360 d++;
361 len--;
362 }
363
364 return max - len;
365}
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:185
void keymaplist_free(struct KeymapList *kml)
Free a List of Keymaps.
Definition keymap.c:144
void keymap_expand_string(const char *str, struct Buffer *buf)
Get a human-readable key string.
Definition keymap.c:247
bool keymap_expand_key(struct Keymap *km, struct Buffer *buf)
Get the key string bound to a Keymap.
Definition keymap.c:229
void keymap_free(struct Keymap **pptr)
Free a Keymap.
Definition keymap.c:127
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:162
size_t parse_keys(const char *str, keycode_t *d, size_t max)
Parse a key string into key codes.
Definition keymap.c:315
int parse_fkey(char *str)
Parse a function key string.
Definition keymap.c:263
struct Keymap * keymap_alloc(size_t len, keycode_t *keys)
Allocate space for a sequence of keys.
Definition keymap.c:112
struct Mapping KeyNames[]
Key name lookup table.
Definition keymap.c:42
int parse_keycode(const char *str)
Parse a numeric keycode.
Definition keymap.c:290
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:40
#define FREE(x)
Definition memory.h:63
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:48
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:583
#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