NeoMutt  2025-12-11-769-g906513
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
get.c
Go to the documentation of this file.
1
22
28
29#include "config.h"
30#include <ctype.h>
31#include <stdbool.h>
32#include <stddef.h>
33#include <unistd.h>
34#include "mutt/lib.h"
35#include "config/lib.h"
36#include "core/lib.h"
37#include "gui/lib.h"
38#include "get.h"
39#include "menu/lib.h"
40#include "globals.h"
41#include "keymap.h"
42#include "menu.h"
43#include "module_data.h"
44#ifdef USE_INOTIFY
45#include "monitor.h"
46#endif
47
49static const int MaxKeyLoop = 10;
50
51// It's not possible to unget more than one char under some curses libs,
52// so roll our own input buffering routines.
53
56
60void mutt_flushinp(void)
61{
64 ARRAY_SHRINK(&mod_data->macro_events, ARRAY_SIZE(&mod_data->macro_events));
65 flushinp();
66}
67
73struct KeyEvent *array_pop(struct KeyEventArray *a)
74{
75 if (ARRAY_EMPTY(a))
76 {
77 return NULL;
78 }
79
80 struct KeyEvent *event = ARRAY_LAST(a);
81 ARRAY_SHRINK(a, 1);
82 return event;
83}
84
91void array_add(struct KeyEventArray *a, int ch, int op)
92{
93 struct KeyEvent event = { ch, op };
94 ARRAY_ADD(a, event);
95}
96
101void array_to_endcond(struct KeyEventArray *a)
102{
103 while (!ARRAY_EMPTY(a))
104 {
105 if (array_pop(a)->op == OP_END_COND)
106 {
107 return;
108 }
109 }
110}
111
119{
121 array_add(&mod_data->unget_key_events, ch, OP_NULL);
122}
123
130void mutt_unget_op(int op)
131{
133 array_add(&mod_data->unget_key_events, 0, op);
134}
135
144void mutt_push_macro_event(int ch, int op)
145{
147 array_add(&mod_data->macro_events, ch, op);
148}
149
161
162#ifdef USE_INOTIFY
169{
170 /* ncurses has its own internal buffer, so before we perform a poll,
171 * we need to make sure there isn't a character waiting */
172 timeout(0);
173 int ch = getch();
174 timeout(1000); // 1 second
175 if (ch == ERR)
176 {
177 if (mutt_monitor_poll() != 0)
178 ch = ERR;
179 else
180 ch = getch();
181 }
182 return ch;
183}
184#endif /* USE_INOTIFY */
185
202{
203 static const struct KeyEvent event_abort = { 0, OP_ABORT };
204 static const struct KeyEvent event_repaint = { 0, OP_REPAINT };
205 static const struct KeyEvent event_timeout = { 0, OP_TIMEOUT };
206
207 if (!OptGui)
208 return event_abort;
209
211
212 struct KeyEvent *event_key = array_pop(&mod_data->unget_key_events);
213 if (event_key)
214 return *event_key;
215
216 if (!(flags & GETCH_IGNORE_MACRO))
217 {
218 event_key = array_pop(&mod_data->macro_events);
219 if (event_key)
220 return *event_key;
221 }
222
223 int ch;
224 SigInt = false;
226 timeout(1000); // 1 second
227#ifdef USE_INOTIFY
229#else
230 ch = getch();
231#endif
233
234 if (SigInt)
235 {
237 return event_abort;
238 }
239
240 if (ch == KEY_RESIZE)
241 {
242 timeout(0);
243 while ((ch = getch()) == KEY_RESIZE)
244 {
245 // do nothing
246 }
247 }
248
249 if (ch == ERR)
250 {
251 if (!isatty(STDIN_FILENO)) // terminal was lost
252 mutt_exit(1);
253
254 if (SigWinch)
255 {
256 SigWinch = false;
258 return event_repaint;
259 }
260
262 return event_timeout;
263 }
264
265 if (ch == mod_data->abort_key)
266 return event_abort;
267
268 if (ch & 0x80)
269 {
270 const bool c_meta_key = cs_subset_bool(NeoMutt->sub, "meta_key");
271 if (c_meta_key)
272 {
273 /* send ALT-x as ESC-x */
274 ch &= ~0x80;
276 return (struct KeyEvent) { '\033', OP_NULL }; // Escape
277 }
278 }
279
280 return (struct KeyEvent) { ch, OP_NULL };
281}
282
287void km_error_key(const struct MenuDefinition *md)
288{
289 if (!md)
290 return;
291
292 struct Keymap *key = km_find_func(md, OP_HELP);
293 if (!key)
294 {
295 mutt_error(_("Key is not bound"));
296 return;
297 }
298
299 struct Buffer *buf = buf_pool_get();
300 keymap_expand_key(key, buf);
301 mutt_error(_("Key is not bound. Press '%s' for help."), buf_string(buf));
302 buf_pool_release(&buf);
303}
304
312{
314 char *pp = NULL;
315 char *p = s + mutt_str_len(s) - 1;
316 size_t l;
317 int i, op = OP_NULL;
318
319 while (p >= s)
320 {
321 /* if we see something like "<PageUp>", look to see if it is a real
322 * function name and return the corresponding value */
323 if (*p == '>')
324 {
325 for (pp = p - 1; pp >= s && *pp != '<'; pp--)
326 ; // do nothing
327
328 if (pp >= s)
329 {
330 i = parse_fkey(pp);
331 if (i > 0)
332 {
333 mutt_push_macro_event(KEY_F(i), 0);
334 p = pp - 1;
335 continue;
336 }
337
338 l = p - pp + 1;
339 for (i = 0; mod_data->key_names[i].name; i++)
340 {
341 if (mutt_istrn_equal(pp, mod_data->key_names[i].name, l))
342 break;
343 }
344 if (mod_data->key_names[i].name)
345 {
346 /* found a match */
347 mutt_push_macro_event(mod_data->key_names[i].value, 0);
348 p = pp - 1;
349 continue;
350 }
351
352 /* See if it is a valid command
353 * skip the '<' and the '>' when comparing */
354 struct Buffer *buf = buf_pool_get();
355 buf_strcpy_n(buf, pp + 1, l - 2);
356
357 for (enum MenuType j = 0; j < MENU_MAX; j++)
358 {
359 op = km_get_op_menu(j, buf_string(buf));
360 if (op != OP_NULL)
361 break;
362 }
363
364 buf_pool_release(&buf);
365
366 if (op != OP_NULL)
367 {
369 p = pp - 1;
370 continue;
371 }
372 }
373 }
374 mutt_push_macro_event((unsigned char) *p--, 0); /* independent 8 bits chars */
375 }
376}
377
387 int key_len, struct KeymapMatchArray *kma)
388{
389 if (!md || !keys || !kma)
390 return 0;
391
392 struct SubMenu **smp = NULL;
394
395 ARRAY_FOREACH(smp, &md->submenus)
396 {
397 struct Keymap *km = NULL;
398
399 STAILQ_FOREACH(km, &(*smp)->keymaps, entries)
400 {
401 bool match = true;
402
403 for (int i = 0; i < key_len; i++)
404 {
405 if (keys[i] != km->keys[i])
406 {
407 match = false;
408 break;
409 }
410 }
411
412 if (match)
413 {
415 if (km->len == key_len)
416 fmatch = KEY_GATHER_MATCH;
417 else
418 fmatch = KEY_GATHER_LONGER;
419
420 flags |= fmatch;
421
422 struct KeymapMatch kmatch = { md->id, fmatch, km };
423 ARRAY_ADD(kma, kmatch);
424 }
425 }
426 }
427
428 return flags;
429}
430
437struct KeyEvent km_dokey(const struct MenuDefinition *md, GetChFlags flags)
438{
439 struct KeyEvent event = { 0, OP_NULL };
440 int pos = 0;
441 keycode_t keys[MAX_SEQ] = { 0 };
442
443 if (!md)
444 return event;
445
446 for (int n = 0; n < MaxKeyLoop; n++)
447 {
448 event = mutt_getch(flags);
449 mutt_debug(LL_DEBUG1, "KEY: \n");
450
451 // abort, timeout, repaint
452 if (event.op < OP_NULL)
453 {
454 mutt_debug(LL_DEBUG1, "KEY: getch() %s\n", opcodes_get_name(event.op));
455 return event;
456 }
457
458 mutt_debug(LL_DEBUG1, "KEY: getch() '%c'\n", isprint(event.ch) ? event.ch : '?');
459
460 keys[pos] = event.ch;
461 struct KeymapMatchArray kma = ARRAY_HEAD_INITIALIZER;
462 KeyGatherFlags kfg = gather_functions(md, keys, pos + 1, &kma);
463
464 mutt_debug(LL_DEBUG1, "KEY: flags = %x\n", kfg);
465
466 if (kfg == KEY_GATHER_NO_MATCH)
467 {
468 mutt_debug(LL_DEBUG1, "KEY: \033[1;31mFAIL1: ('%c', %s)\033[0m\n",
469 isprint(event.ch) ? event.ch : '?', opcodes_get_name(event.op));
470 return event;
471 }
472
473 if ((kfg & KEY_GATHER_MATCH) == KEY_GATHER_MATCH)
474 {
475 struct KeymapMatch *kmatch = NULL;
476
477 ARRAY_FOREACH(kmatch, &kma)
478 {
479 if (kmatch->flags == KEY_GATHER_MATCH)
480 {
481 struct Keymap *map = kmatch->keymap;
482
483 if (map->op != OP_MACRO)
484 {
485 mutt_debug(LL_DEBUG1, "KEY: \033[1;32mSUCCESS: ('%c', %s)\033[0m\n",
486 isprint(event.ch) ? event.ch : '?', opcodes_get_name(map->op));
487 ARRAY_FREE(&kma);
488 return (struct KeyEvent) { event.ch, map->op };
489 }
490
491 /* #GETCH_IGNORE_MACRO turns off processing the MacroEvents buffer
492 * in mutt_getch(). Generating new macro events during that time would
493 * result in undesired behavior once the option is turned off.
494 *
495 * Originally this returned -1, however that results in an unbuffered
496 * username or password prompt being aborted. Returning OP_NULL allows
497 * mw_get_field() to display the keybinding pressed instead.
498 *
499 * It may be unexpected for a macro's keybinding to be returned,
500 * but less so than aborting the prompt. */
501 if (flags & GETCH_IGNORE_MACRO)
502 {
503 ARRAY_FREE(&kma);
504 return (struct KeyEvent) { event.ch, OP_NULL };
505 }
506
508 pos = 0;
509 ARRAY_FREE(&kma);
510 break;
511 }
512 }
513 }
514 else
515 {
516 mutt_debug(LL_DEBUG1, "KEY: \033[1;33mLONGER: getch() '%c'\033[0m\n",
517 isprint(event.ch) ? event.ch : '?');
518 pos++;
519 }
520
521 ARRAY_FREE(&kma);
522 }
523
525 mutt_error(_("Macro loop detected"));
526 return (struct KeyEvent) { '\0', OP_ABORT };
527}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_LAST(head)
Convenience method to get the last element.
Definition array.h:145
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition array.h:74
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:209
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition array.h:58
#define ARRAY_SHRINK(head, n)
Mark a number of slots at the end of the array as unused.
Definition array.h:174
size_t buf_strcpy_n(struct Buffer *buf, const char *s, size_t len)
Copy a string into a Buffer.
Definition buffer.c:416
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
void mutt_query_exit(void)
Ask the user if they want to leave NeoMutt.
Definition curs_lib.c:139
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition exit.c:41
KeyGatherFlags gather_functions(const struct MenuDefinition *md, const keycode_t *keys, int key_len, struct KeymapMatchArray *kma)
Find functions whose keybindings match.
Definition get.c:386
void generic_tokenize_push_string(char *s)
Parse and queue a 'push' command.
Definition get.c:311
void mutt_flushinp(void)
MacroEvents moved to KeyModuleData UngetKeyEvents moved to KeyModuleData.
Definition get.c:60
static const int MaxKeyLoop
XXX.
Definition get.c:49
void array_add(struct KeyEventArray *a, int ch, int op)
Add an event to the end of the array.
Definition get.c:91
void array_to_endcond(struct KeyEventArray *a)
Clear the array until an OP_END_COND.
Definition get.c:101
void mutt_push_macro_event(int ch, int op)
Add the character/operation to the macro buffer.
Definition get.c:144
struct KeyEvent mutt_getch(GetChFlags flags)
Read a character from the input buffer.
Definition get.c:201
struct KeyEvent km_dokey(const struct MenuDefinition *md, GetChFlags flags)
Determine what a keypress should do.
Definition get.c:437
void mutt_unget_op(int op)
Return an operation to the input buffer.
Definition get.c:130
void km_error_key(const struct MenuDefinition *md)
Handle an unbound key sequence.
Definition get.c:287
int mutt_monitor_getch(void)
Get a character and poll the filesystem monitor.
Definition get.c:168
void mutt_flush_macro_to_endcond(void)
Drop a macro from the input buffer.
Definition get.c:156
struct KeyEvent * array_pop(struct KeyEventArray *a)
Remove an event from the array.
Definition get.c:73
void mutt_unget_ch(int ch)
Return a keystroke to the input buffer.
Definition get.c:118
Get a key from the user.
uint8_t GetChFlags
Flags for mutt_getch(), e.g. GETCH_NO_FLAGS.
Definition get.h:33
#define GETCH_IGNORE_MACRO
Don't use MacroEvents.
Definition get.h:35
#define KEY_GATHER_LONGER
No bindings match, but longer strings might.
Definition get.h:40
#define KEY_GATHER_NO_MATCH
No bindings match the search string.
Definition get.h:38
int mutt_monitor_getch(void)
Get a character and poll the filesystem monitor.
Definition get.c:168
uint8_t KeyGatherFlags
Flags for gather_functions(), e.g. KEY_GATHER_NO_MATCH.
Definition get.h:37
#define KEY_GATHER_MATCH
Binding matches the search string.
Definition get.h:39
struct KeyEvent * array_pop(struct KeyEventArray *a)
Remove an event from the array.
Definition get.c:73
void mutt_unget_ch(int ch)
Return a keystroke to the input buffer.
Definition get.c:118
bool OptGui
(pseudo) when the gui (and curses) are started
Definition globals.c:48
Global variables.
#define mutt_error(...)
Definition logging2.h:94
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
Convenience wrapper for the gui headers.
bool keymap_expand_key(struct Keymap *km, struct Buffer *buf)
Get the key string bound to a Keymap.
Definition keymap.c:239
int parse_fkey(char *str)
Parse a function key string.
Definition keymap.c:276
int km_get_op_menu(int mtype, const char *func)
Get the OpCode for a Function from a Menu.
Definition menu.c:214
struct Keymap * km_find_func(const struct MenuDefinition *md, int func)
Find a function's mapping in a Menu.
Definition menu.c:157
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
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
GUI present the user with a selectable list.
Maniplate Menus and SubMenus.
#define MAX_SEQ
Maximum length of a key binding sequence used for buffer in km_bind.
Definition menu.h:32
@ MODULE_ID_KEY
ModuleKey, Key mappings
Definition module_api.h:73
int mutt_monitor_poll(void)
Check for filesystem changes.
Definition monitor.c:401
Monitor files for changes.
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition notify.c:173
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
bool mutt_istrn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings ignoring case (to a maximum), safely.
Definition string.c:457
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:665
@ NT_TIMEOUT
Timeout has occurred.
Definition notify_type.h:56
@ NT_RESIZE
Window has been resized.
Definition notify_type.h:52
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition opcodes.c:48
#define OP_TIMEOUT
1 second with no events
Definition opcodes.h:35
#define OP_REPAINT
Repaint is needed.
Definition opcodes.h:34
#define OP_ABORT
$abort_key pressed (Ctrl-G)
Definition opcodes.h:36
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
volatile sig_atomic_t SigWinch
true after SIGWINCH is received
Definition signal.c:69
volatile sig_atomic_t SigInt
true after SIGINT is received
Definition signal.c:68
void mutt_sig_allow_interrupt(bool allow)
Allow/disallow Ctrl-C (SIGINT)
Definition signal.c:315
String manipulation buffer.
Definition buffer.h:36
An event such as a keypress.
Definition get.h:50
int op
Function opcode, e.g. OP_HELP.
Definition get.h:52
int ch
Raw key pressed.
Definition get.h:51
Key private Module data.
Definition module_data.h:34
struct KeyEventArray macro_events
Macro event buffer.
Definition module_data.h:36
keycode_t abort_key
Key to abort prompts, normally Ctrl-G.
Definition module_data.h:38
struct Mapping * key_names
Key name lookup table.
Definition module_data.h:41
struct KeyEventArray unget_key_events
Unget key event buffer.
Definition module_data.h:37
Result of Matching Keybinding.
Definition get.h:62
KeyGatherFlags flags
Flags, e.g. KEY_GATHER_MATCH.
Definition get.h:64
struct Keymap * keymap
Keymap defining bind or `macro.
Definition get.h:65
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
short len
Length of key sequence (unit: sizeof (keycode_t))
Definition keymap.h:48
short op
Operation to perform.
Definition keymap.h:46
int value
Integer value.
Definition mapping.h:35
const char * name
String value.
Definition mapping.h:34
Functions for a Dialog or Window.
Definition menu.h:80
int id
Menu ID, e.g. MENU_ALIAS.
Definition menu.h:81
struct SubMenuPArray submenus
Parts making up the Menu.
Definition menu.h:83
Container for Accounts, Notifications.
Definition neomutt.h:41
struct Notify * notify_timeout
Timeout notifications handler.
Definition neomutt.h:47
struct Notify * notify_resize
Window resize notifications handler.
Definition neomutt.h:46
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
Collection of related functions.
Definition menu.h:68
MenuType
Types of GUI selections.
Definition type.h:33
@ MENU_MAX
Definition type.h:51