/* See LICENSE file for copyright and license details. */ #ifndef LIBTERMINPUT_H #define LIBTERMINPUT_H #include /** * Flags for supporting incompatible input; the user must * set or clear his flag after setting or clearing it on * the terminal, and the user must make sure that the * terminal support this flag if set. */ enum libterminput_flags { LIBTERMINPUT_DECSET_1005 = 0x0001, LIBTERMINPUT_MACRO_ON_CSI_M = 0x0002, LIBTERMINPUT_PAUSE_ON_CSI_P = 0x0004, LIBTERMINPUT_INS_ON_CSI_AT = 0x0008, LIBTERMINPUT_SEPARATE_BACKTAB = 0x0010, /** * If an ESC is received without anything after it, * return ESC keypress. This is not always desirable * behaviour as the user may manually press ESC to * simulate a keypress that terminal does not support * (yes, this is a real world issue). */ LIBTERMINPUT_ESC_ON_BLOCK = 0x0020 }; enum libterminput_mod { LIBTERMINPUT_SHIFT = 0x01, LIBTERMINPUT_META = 0x02, LIBTERMINPUT_CTRL = 0x04 }; enum libterminput_key { LIBTERMINPUT_SYMBOL, LIBTERMINPUT_UP, LIBTERMINPUT_DOWN, LIBTERMINPUT_RIGHT, LIBTERMINPUT_LEFT, LIBTERMINPUT_BEGIN, /* keypad 5 without numlock */ LIBTERMINPUT_TAB, /* backtab is interpreted as shift+tab by default */ LIBTERMINPUT_BACKTAB, /* requires LIBTERMINPUT_SEPARATE_BACKTAB */ LIBTERMINPUT_F1, LIBTERMINPUT_F2, LIBTERMINPUT_F3, LIBTERMINPUT_F4, LIBTERMINPUT_F5, LIBTERMINPUT_F6, LIBTERMINPUT_F7, LIBTERMINPUT_F8, LIBTERMINPUT_F9, LIBTERMINPUT_F10, LIBTERMINPUT_F11, LIBTERMINPUT_F12, LIBTERMINPUT_HOME, /* = find */ LIBTERMINPUT_INS, LIBTERMINPUT_DEL, /* = remove */ LIBTERMINPUT_END, /* = select */ LIBTERMINPUT_PRIOR, /* page up */ LIBTERMINPUT_NEXT, /* page down */ LIBTERMINPUT_ERASE, /* backspace */ LIBTERMINPUT_ENTER, /* return */ LIBTERMINPUT_ESC, LIBTERMINPUT_MACRO, LIBTERMINPUT_PAUSE, LIBTERMINPUT_KEYPAD_0, LIBTERMINPUT_KEYPAD_1, LIBTERMINPUT_KEYPAD_2, LIBTERMINPUT_KEYPAD_3, LIBTERMINPUT_KEYPAD_4, LIBTERMINPUT_KEYPAD_5, LIBTERMINPUT_KEYPAD_6, LIBTERMINPUT_KEYPAD_7, LIBTERMINPUT_KEYPAD_8, LIBTERMINPUT_KEYPAD_9, LIBTERMINPUT_KEYPAD_PLUS, LIBTERMINPUT_KEYPAD_MINUS, LIBTERMINPUT_KEYPAD_TIMES, LIBTERMINPUT_KEYPAD_DIVISION, LIBTERMINPUT_KEYPAD_DECIMAL, LIBTERMINPUT_KEYPAD_COMMA, LIBTERMINPUT_KEYPAD_POINT, LIBTERMINPUT_KEYPAD_ENTER, }; enum libterminput_button { LIBTERMINPUT_NO_BUTTON, LIBTERMINPUT_BUTTON1, /* left (assuming right-handed) */ LIBTERMINPUT_BUTTON2, /* middle */ LIBTERMINPUT_BUTTON3, /* right (assuming right-handed) */ LIBTERMINPUT_SCROLL_UP, /* no corresponding release event shall be generated */ LIBTERMINPUT_SCROLL_DOWN, /* no corresponding release event shall be generated */ LIBTERMINPUT_SCROLL_LEFT, /* may or may not have a corresponding release event */ LIBTERMINPUT_SCROLL_RIGHT, /* may or may not have a corresponding release event */ LIBTERMINPUT_XBUTTON1, /* extended button 1, also known as backward */ LIBTERMINPUT_XBUTTON2, /* extended button 2, also known as forward */ LIBTERMINPUT_XBUTTON3, /* extended button 3, you probably don't have this button */ LIBTERMINPUT_XBUTTON4 /* extended button 4, you probably don't have this button */ }; enum libterminput_type { LIBTERMINPUT_NONE, LIBTERMINPUT_KEYPRESS, LIBTERMINPUT_BRACKETED_PASTE_START, LIBTERMINPUT_BRACKETED_PASTE_END, LIBTERMINPUT_TEXT, LIBTERMINPUT_MOUSEEVENT }; enum libterminput_event { LIBTERMINPUT_PRESS, LIBTERMINPUT_RELEASE, LIBTERMINPUT_MOTION, LIBTERMINPUT_HIGHLIGHT_INSIDE, LIBTERMINPUT_HIGHLIGHT_OUTSIDE }; struct libterminput_keypress { enum libterminput_type type; enum libterminput_key key; unsigned long long int times; /* if .times > 1, next will be the same, but will .times -= 1 */ enum libterminput_mod mods; char symbol[7]; /* use if .key == LIBTERMINPUT_SYMBOL */ }; struct libterminput_mouseevent { enum libterminput_type type; enum libterminput_mod mods; /* Set to 0 for LIBTERMINPUT_HIGHLIGHT_INSIDE and LIBTERMINPUT_HIGHLIGHT_OUTSIDE */ enum libterminput_button button; /* Set to 1 for LIBTERMINPUT_HIGHLIGHT_INSIDE and LIBTERMINPUT_HIGHLIGHT_OUTSIDE */ enum libterminput_event event; size_t x; size_t y; size_t start_x; /* Only set for LIBTERMINPUT_HIGHLIGHT_OUTSIDE */ size_t start_y; /* Only set for LIBTERMINPUT_HIGHLIGHT_OUTSIDE */ size_t end_x; /* Only set for LIBTERMINPUT_HIGHLIGHT_OUTSIDE */ size_t end_y; /* Only set for LIBTERMINPUT_HIGHLIGHT_OUTSIDE */ }; struct libterminput_text { enum libterminput_type type; size_t nbytes; char bytes[512]; }; union libterminput_input { enum libterminput_type type; struct libterminput_keypress keypress; /* use if .type == LIBTERMINPUT_KEYPRESS */ struct libterminput_text text; /* use if .type == LIBTERMINPUT_TEXT */ struct libterminput_mouseevent mouseevent; /* use if .type == LIBTERMINPUT_MOUSEEVENT */ }; /** * This struct should be considered opaque */ struct libterminput_state { int inited; /* whether the input in initialised, not this struct */ enum libterminput_mod mods; enum libterminput_flags flags; size_t stored_head; size_t stored_tail; char bracketed_paste; char mouse_tracking; char meta; char n; char npartial; char partial[7]; char key[44]; char stored[512]; }; /** * Get input from the terminal * * @param fd The file descriptor to the terminal * @param input Output parameter for input * @param ctx State for the terminal, parts of the state may be stored in `input` * @return 1 normally, 0 on end of input, -1 on error */ int libterminput_read(int fd, union libterminput_input *input, struct libterminput_state *ctx); inline int libterminput_is_ready(union libterminput_input *input, struct libterminput_state *ctx) { if (!ctx->inited) return 0; if (input->type == LIBTERMINPUT_KEYPRESS && input->keypress.times > 1) return 1; return ctx->stored_head > ctx->stored_tail; } int libterminput_set_flags(struct libterminput_state *ctx, enum libterminput_flags flags); int libterminput_clear_flags(struct libterminput_state *ctx, enum libterminput_flags flags); #endif