NeoMutt  2024-02-01-23-g345d7b
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
get.c File Reference

Get a key from the user. More...

#include "config.h"
#include <stdbool.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "core/lib.h"
#include "gui/lib.h"
#include "key/lib.h"
#include "menu/lib.h"
#include "globals.h"
#include "monitor.h"
+ Include dependency graph for get.c:

Go to the source code of this file.

Functions

void mutt_flushinp (void)
 Empty all the keyboard buffers.
 
static struct KeyEventarray_pop (struct KeyEventArray *a)
 Remove an event from the array.
 
static void array_add (struct KeyEventArray *a, int ch, int op)
 Add an event to the end of the array.
 
static void array_to_endcond (struct KeyEventArray *a)
 Clear the array until an OP_END_COND.
 
void mutt_unget_ch (int ch)
 Return a keystroke to the input buffer.
 
void mutt_unget_op (int op)
 Return an operation to the input buffer.
 
void mutt_unget_string (const char *s)
 Return a string to the input buffer.
 
void mutt_push_macro_event (int ch, int op)
 Add the character/operation to the macro buffer.
 
void mutt_flush_macro_to_endcond (void)
 Drop a macro from the input buffer.
 
static int mutt_monitor_getch (void)
 Get a character and poll the filesystem monitor.
 
struct KeyEvent mutt_getch (GetChFlags flags)
 Read a character from the input buffer.
 
void km_error_key (enum MenuType mtype)
 Handle an unbound key sequence.
 
static struct KeyEvent retry_generic (enum MenuType mtype, keycode_t *keys, int keyslen, int lastkey, GetChFlags flags)
 Try to find the key in the generic menu bindings.
 
struct KeyEvent km_dokey_event (enum MenuType mtype, GetChFlags flags)
 Determine what a keypress should do.
 
int km_dokey (enum MenuType mtype, GetChFlags flags)
 Determine what a keypress should do.
 

Variables

struct KeyEventArray MacroEvents = ARRAY_HEAD_INITIALIZER
 These are used for macros and exec/push commands.
 
static struct KeyEventArray UngetKeyEvents = ARRAY_HEAD_INITIALIZER
 These are used in all other "normal" situations, and are not ignored when passing GETCH_IGNORE_MACRO.
 

Detailed Description

Get a key from the user.

Authors
  • Richard Russon

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file get.c.

Function Documentation

◆ mutt_flushinp()

void mutt_flushinp ( void  )

Empty all the keyboard buffers.

Definition at line 57 of file get.c.

58{
61 flushinp();
62}
#define ARRAY_SHRINK(head, num)
Mark a number of slots at the end of the array as unused.
Definition: array.h:172
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:87
struct KeyEventArray MacroEvents
These are used for macros and exec/push commands.
Definition: get.c:48
static struct KeyEventArray UngetKeyEvents
These are used in all other "normal" situations, and are not ignored when passing GETCH_IGNORE_MACRO.
Definition: get.c:52
+ Here is the caller graph for this function:

◆ array_pop()

static struct KeyEvent * array_pop ( struct KeyEventArray *  a)
static

Remove an event from the array.

Parameters
aArray
Return values
ptrEvent

Definition at line 69 of file get.c.

70{
71 if (ARRAY_EMPTY(a))
72 {
73 return NULL;
74 }
75
76 struct KeyEvent *event = ARRAY_LAST(a);
77 ARRAY_SHRINK(a, 1);
78 return event;
79}
#define ARRAY_LAST(head)
Convenience method to get the last element.
Definition: array.h:144
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition: array.h:74
An event such as a keypress.
Definition: lib.h:81
+ Here is the caller graph for this function:

◆ array_add()

static void array_add ( struct KeyEventArray *  a,
int  ch,
int  op 
)
static

Add an event to the end of the array.

Parameters
aArray
chCharacter
opOperation, e.g. OP_DELETE

Definition at line 87 of file get.c.

88{
89 struct KeyEvent event = { ch, op };
90 ARRAY_ADD(a, event);
91}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:156
int op
Function opcode, e.g. OP_HELP.
Definition: lib.h:83
int ch
Raw key pressed.
Definition: lib.h:82
+ Here is the caller graph for this function:

◆ array_to_endcond()

static void array_to_endcond ( struct KeyEventArray *  a)
static

Clear the array until an OP_END_COND.

Parameters
aArray

Definition at line 97 of file get.c.

98{
99 while (!ARRAY_EMPTY(a))
100 {
101 if (array_pop(a)->op == OP_END_COND)
102 {
103 return;
104 }
105 }
106}
static struct KeyEvent * array_pop(struct KeyEventArray *a)
Remove an event from the array.
Definition: get.c:69
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_unget_ch()

void mutt_unget_ch ( int  ch)

Return a keystroke to the input buffer.

Parameters
chKey press

This puts events into the UngetKeyEvents buffer

Definition at line 114 of file get.c.

115{
116 array_add(&UngetKeyEvents, ch, OP_NULL);
117}
static void array_add(struct KeyEventArray *a, int ch, int op)
Add an event to the end of the array.
Definition: get.c:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_unget_op()

void mutt_unget_op ( int  op)

Return an operation to the input buffer.

Parameters
opOperation, e.g. OP_DELETE

This puts events into the UngetKeyEvents buffer

Definition at line 125 of file get.c.

126{
127 array_add(&UngetKeyEvents, 0, op);
128}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_unget_string()

void mutt_unget_string ( const char *  s)

Return a string to the input buffer.

Parameters
sString to return

This puts events into the UngetKeyEvents buffer

Definition at line 136 of file get.c.

137{
138 const char *p = s + mutt_str_len(s) - 1;
139
140 while (p >= s)
141 {
142 mutt_unget_ch((unsigned char) *p--);
143 }
144}
void mutt_unget_ch(int ch)
Return a keystroke to the input buffer.
Definition: get.c:114
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:545
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_push_macro_event()

void mutt_push_macro_event ( int  ch,
int  op 
)

Add the character/operation to the macro buffer.

Parameters
chCharacter to add
opOperation to add

Adds the ch/op to the macro buffer. This should be used for macros, push, and exec commands only.

Definition at line 154 of file get.c.

155{
156 array_add(&MacroEvents, ch, op);
157}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_flush_macro_to_endcond()

void mutt_flush_macro_to_endcond ( void  )

Drop a macro from the input buffer.

All the macro text is deleted until an OP_END_COND command, or the buffer is empty.

Definition at line 165 of file get.c.

166{
168}
static void array_to_endcond(struct KeyEventArray *a)
Clear the array until an OP_END_COND.
Definition: get.c:97
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_monitor_getch()

static int mutt_monitor_getch ( void  )
static

Get a character and poll the filesystem monitor.

Return values
numCharacter pressed
ERRTimeout

Definition at line 176 of file get.c.

177{
178 /* ncurses has its own internal buffer, so before we perform a poll,
179 * we need to make sure there isn't a character waiting */
180 timeout(0);
181 int ch = getch();
182 timeout(1000); // 1 second
183 if (ch == ERR)
184 {
185 if (mutt_monitor_poll() != 0)
186 ch = ERR;
187 else
188 ch = getch();
189 }
190 return ch;
191}
int mutt_monitor_poll(void)
Check for filesystem changes.
Definition: monitor.c:400
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_getch()

struct KeyEvent mutt_getch ( GetChFlags  flags)

Read a character from the input buffer.

Parameters
flagsFlags, e.g. GETCH_IGNORE_MACRO
Return values
objKeyEvent to process

The priority for reading events is:

  1. UngetKeyEvents buffer
  2. MacroEvents buffer
  3. Keyboard

This function can return:

  • Abort { 0, OP_ABORT }
  • Repaint { 0, OP_REPAINT }
  • Timeout { 0, OP_TIMEOUT }

Definition at line 209 of file get.c.

210{
211 static const struct KeyEvent event_abort = { 0, OP_ABORT };
212 static const struct KeyEvent event_repaint = { 0, OP_REPAINT };
213 static const struct KeyEvent event_timeout = { 0, OP_TIMEOUT };
214
215 if (OptNoCurses)
216 return event_abort;
217
218 struct KeyEvent *event_key = array_pop(&UngetKeyEvents);
219 if (event_key)
220 return *event_key;
221
222 if (!(flags & GETCH_IGNORE_MACRO))
223 {
224 event_key = array_pop(&MacroEvents);
225 if (event_key)
226 return *event_key;
227 }
228
229 int ch;
230 SigInt = false;
232 timeout(1000); // 1 second
233#ifdef USE_INOTIFY
235#else
236 ch = getch();
237#endif
239
240 if (SigInt)
241 {
243 return event_abort;
244 }
245
246 if (ch == KEY_RESIZE)
247 {
248 timeout(0);
249 while ((ch = getch()) == KEY_RESIZE)
250 {
251 // do nothing
252 }
253 }
254
255 if (ch == ERR)
256 {
257 if (!isatty(0)) // terminal was lost
258 mutt_exit(1);
259
260 if (SigWinch)
261 {
262 SigWinch = false;
264 return event_repaint;
265 }
266
268 return event_timeout;
269 }
270
271 if (ch == AbortKey)
272 return event_abort;
273
274 if (ch & 0x80)
275 {
276 const bool c_meta_key = cs_subset_bool(NeoMutt->sub, "meta_key");
277 if (c_meta_key)
278 {
279 /* send ALT-x as ESC-x */
280 ch &= ~0x80;
282 return (struct KeyEvent){ '\033', OP_NULL }; // Escape
283 }
284 }
285
286 return (struct KeyEvent){ ch, OP_NULL };
287}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
void mutt_query_exit(void)
Ask the user if they want to leave NeoMutt.
Definition: curs_lib.c:139
static int mutt_monitor_getch(void)
Get a character and poll the filesystem monitor.
Definition: get.c:176
bool OptNoCurses
(pseudo) when sending in batch mode
Definition: globals.c:72
keycode_t AbortKey
code of key to abort prompts, normally Ctrl-G
Definition: lib.c:125
#define GETCH_IGNORE_MACRO
Don't use MacroEvents.
Definition: lib.h:52
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:231
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
@ NT_TIMEOUT
Timeout has occurred.
Definition: notify_type.h:56
@ NT_RESIZE
Window has been resized.
Definition: notify_type.h:52
#define OP_TIMEOUT
1 second with no events
Definition: opcodes.h:36
#define OP_REPAINT
Repaint is needed.
Definition: opcodes.h:34
#define OP_ABORT
$abort_key pressed (Ctrl-G)
Definition: opcodes.h:37
volatile sig_atomic_t SigWinch
true after SIGWINCH is received
Definition: signal.c:64
volatile sig_atomic_t SigInt
true after SIGINT is received
Definition: signal.c:63
void mutt_sig_allow_interrupt(bool allow)
Allow/disallow Ctrl-C (SIGINT)
Definition: signal.c:254
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct Notify * notify_timeout
Timeout notifications handler.
Definition: neomutt.h:44
struct Notify * notify_resize
Window resize notifications handler.
Definition: neomutt.h:43
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ km_error_key()

void km_error_key ( enum MenuType  mtype)

Handle an unbound key sequence.

Parameters
mtypeMenu type, e.g. MENU_PAGER

Definition at line 293 of file get.c.

294{
295 struct Keymap *key = km_find_func(mtype, OP_HELP);
296 if (!key && (mtype != MENU_EDITOR) && (mtype != MENU_PAGER))
297 key = km_find_func(MENU_GENERIC, OP_HELP);
298 if (!key)
299 {
300 mutt_error(_("Key is not bound"));
301 return;
302 }
303
304 char buf[128] = { 0 };
305 km_expand_key(buf, sizeof(buf), key);
306 mutt_error(_("Key is not bound. Press '%s' for help."), buf);
307}
#define mutt_error(...)
Definition: logging2.h:92
struct Keymap * km_find_func(enum MenuType mtype, int func)
Find a function's mapping in a Menu.
Definition: lib.c:512
int km_expand_key(char *s, size_t len, struct Keymap *map)
Get the key string bound to a Keymap.
Definition: lib.c:460
#define _(a)
Definition: message.h:28
A keyboard mapping.
Definition: lib.h:65
@ MENU_GENERIC
Generic selection list.
Definition: type.h:46
@ MENU_PAGER
Pager pager (email viewer)
Definition: type.h:55
@ MENU_EDITOR
Text entry area.
Definition: type.h:44
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ retry_generic()

static struct KeyEvent retry_generic ( enum MenuType  mtype,
keycode_t keys,
int  keyslen,
int  lastkey,
GetChFlags  flags 
)
static

Try to find the key in the generic menu bindings.

Parameters
mtypeMenu type, e.g. MENU_PAGER
keysArray of keys to return to the input queue
keyslenNumber of keys in the array
lastkeyLast key pressed (to return to input queue)
flagsFlags, e.g. GETCH_IGNORE_MACRO
Return values
numOperation, e.g. OP_DELETE

Definition at line 318 of file get.c.

320{
321 if (lastkey)
322 mutt_unget_ch(lastkey);
323 for (; keyslen; keyslen--)
324 mutt_unget_ch(keys[keyslen - 1]);
325
326 if ((mtype != MENU_EDITOR) && (mtype != MENU_GENERIC) && (mtype != MENU_PAGER))
327 {
328 return km_dokey_event(MENU_GENERIC, flags);
329 }
330 if ((mtype != MENU_EDITOR) && (mtype != MENU_GENERIC))
331 {
332 /* probably a good idea to flush input here so we can abort macros */
334 }
335
336 return (struct KeyEvent){ mutt_getch(flags).ch, OP_NULL };
337}
struct KeyEvent km_dokey_event(enum MenuType mtype, GetChFlags flags)
Determine what a keypress should do.
Definition: get.c:345
void mutt_flushinp(void)
Empty all the keyboard buffers.
Definition: get.c:57
struct KeyEvent mutt_getch(GetChFlags flags)
Read a character from the input buffer.
Definition: get.c:209
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ km_dokey_event()

struct KeyEvent km_dokey_event ( enum MenuType  mtype,
GetChFlags  flags 
)

Determine what a keypress should do.

Parameters
mtypeMenu type, e.g. MENU_EDITOR
flagsFlags, e.g. GETCH_IGNORE_MACRO
Return values
ptrEvent

Definition at line 345 of file get.c.

346{
347 struct KeyEvent event = { 0, OP_NULL };
348 struct Keymap *map = STAILQ_FIRST(&Keymaps[mtype]);
349 int pos = 0;
350 int n = 0;
351
352 if (!map && (mtype != MENU_EDITOR))
353 return retry_generic(mtype, NULL, 0, 0, flags);
354
355 while (true)
356 {
357 event = mutt_getch(flags);
358
359 // abort, timeout, repaint
360 if (event.op < OP_NULL)
361 return event;
362
363 /* do we have an op already? */
364 if (event.op != OP_NULL)
365 {
366 const char *func = NULL;
367 const struct MenuFuncOp *funcs = NULL;
368
369 /* is this a valid op for this menu type? */
370 if ((funcs = km_get_table(mtype)) && (func = mutt_get_func(funcs, event.op)))
371 return event;
372
373 if ((mtype != MENU_EDITOR) && (mtype != MENU_PAGER) && (mtype != MENU_GENERIC))
374 {
375 /* check generic menu type */
376 funcs = OpGeneric;
377 func = mutt_get_func(funcs, event.op);
378 if (func)
379 return event;
380 }
381
382 /* Sigh. Valid function but not in this context.
383 * Find the literal string and push it back */
384 for (int i = 0; MenuNames[i].name; i++)
385 {
386 funcs = km_get_table(MenuNames[i].value);
387 if (funcs)
388 {
389 func = mutt_get_func(funcs, event.op);
390 if (func)
391 {
392 mutt_unget_ch('>');
393 mutt_unget_string(func);
394 mutt_unget_ch('<');
395 break;
396 }
397 }
398 }
399 /* continue to chew */
400 if (func)
401 continue;
402 }
403
404 if (!map)
405 return event;
406
407 /* Nope. Business as usual */
408 while (event.ch > map->keys[pos])
409 {
410 if ((pos > map->eq) || !STAILQ_NEXT(map, entries))
411 return retry_generic(mtype, map->keys, pos, event.ch, flags);
412 map = STAILQ_NEXT(map, entries);
413 }
414
415 if (event.ch != map->keys[pos])
416 return retry_generic(mtype, map->keys, pos, event.ch, flags);
417
418 if (++pos == map->len)
419 {
420 if (map->op != OP_MACRO)
421 return (struct KeyEvent){ event.ch, map->op };
422
423 /* #GETCH_IGNORE_MACRO turns off processing the MacroEvents buffer
424 * in mutt_getch(). Generating new macro events during that time would
425 * result in undesired behavior once the option is turned off.
426 *
427 * Originally this returned -1, however that results in an unbuffered
428 * username or password prompt being aborted. Returning OP_NULL allows
429 * mw_get_field() to display the keybinding pressed instead.
430 *
431 * It may be unexpected for a macro's keybinding to be returned,
432 * but less so than aborting the prompt. */
433 if (flags & GETCH_IGNORE_MACRO)
434 {
435 return (struct KeyEvent){ event.ch, OP_NULL };
436 }
437
438 if (n++ == 10)
439 {
441 mutt_error(_("Macro loop detected"));
442 return (struct KeyEvent){ '\0', OP_ABORT };
443 }
444
446 map = STAILQ_FIRST(&Keymaps[mtype]);
447 pos = 0;
448 }
449 }
450
451 /* not reached */
452}
void mutt_unget_string(const char *s)
Return a string to the input buffer.
Definition: get.c:136
static struct KeyEvent retry_generic(enum MenuType mtype, keycode_t *keys, int keyslen, int lastkey, GetChFlags flags)
Try to find the key in the generic menu bindings.
Definition: get.c:318
const struct MenuFuncOp OpGeneric[]
Functions for the Generic Menu.
Definition: functions.c:68
void generic_tokenize_push_string(char *s)
Parse and queue a 'push' command.
Definition: lib.c:341
struct KeymapList Keymaps[MENU_MAX]
Array of key mappings, one for each MenuType.
Definition: lib.c:128
const char * mutt_get_func(const struct MenuFuncOp *funcs, int op)
Get the name of a function.
Definition: lib.c:324
const struct MenuFuncOp * km_get_table(enum MenuType mtype)
Lookup a Menu's functions.
Definition: lib.c:528
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
keycode_t * keys
key sequence
Definition: lib.h:71
char * macro
Macro expansion (op == OP_MACRO)
Definition: lib.h:66
short eq
Number of leading keys equal to next entry.
Definition: lib.h:69
short len
Length of key sequence (unit: sizeof (keycode_t))
Definition: lib.h:70
short op
Operation to perform.
Definition: lib.h:68
const char * name
String value.
Definition: mapping.h:34
Mapping between a function and an operation.
Definition: lib.h:101
const struct Mapping MenuNames[]
Menu name lookup table.
Definition: type.c:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ km_dokey()

int km_dokey ( enum MenuType  mtype,
GetChFlags  flags 
)

Determine what a keypress should do.

Parameters
mtypeMenu type, e.g. MENU_EDITOR
flagsFlags, e.g. GETCH_IGNORE_MACRO
Return values
>0Function to execute
OP_NULLNo function bound to key sequence
-1Error occurred while reading input
-2A timeout or sigwinch occurred

Definition at line 463 of file get.c.

464{
465 return km_dokey_event(mtype, flags).op;
466}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ MacroEvents

struct KeyEventArray MacroEvents = ARRAY_HEAD_INITIALIZER

These are used for macros and exec/push commands.

They can be temporarily ignored by passing GETCH_IGNORE_MACRO

Definition at line 48 of file get.c.

◆ UngetKeyEvents

struct KeyEventArray UngetKeyEvents = ARRAY_HEAD_INITIALIZER
static

These are used in all other "normal" situations, and are not ignored when passing GETCH_IGNORE_MACRO.

Definition at line 52 of file get.c.