From 24ebd3c309c5d6cad63bbf1b40de8c17aead0366 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Wed, 19 Feb 2025 23:06:02 +0100 Subject: Add state marshalling and unmarshalling functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- Makefile | 31 ++++++++++++------- common.h | 23 +++++++++++++++ libterminput.h | 46 ++++++++++++++++++++++++++++- libterminput_clear_flags.3 | 1 + libterminput_marshal_input.c | 27 +++++++++++++++++ libterminput_marshal_keypress__.c | 16 ++++++++++ libterminput_marshal_mouseevent__.c | 20 +++++++++++++ libterminput_marshal_position__.c | 9 ++++++ libterminput_marshal_state.c | 9 ++++++ libterminput_marshal_text__.c | 12 ++++++++ libterminput_parse_csi_m_mouse_tracking__.c | 2 +- libterminput_parse_sequence__.c | 4 +-- libterminput_read.c | 7 +++-- libterminput_read_bracketed_paste__.c | 2 +- libterminput_unmarshal_input.c | 30 +++++++++++++++++++ libterminput_unmarshal_keypress__.c | 19 ++++++++++++ libterminput_unmarshal_mouseevent__.c | 23 +++++++++++++++ libterminput_unmarshal_position__.c | 10 +++++++ libterminput_unmarshal_state.c | 9 ++++++ libterminput_unmarshal_text__.c | 13 ++++++++ 20 files changed, 296 insertions(+), 17 deletions(-) create mode 120000 libterminput_clear_flags.3 create mode 100644 libterminput_marshal_input.c create mode 100644 libterminput_marshal_keypress__.c create mode 100644 libterminput_marshal_mouseevent__.c create mode 100644 libterminput_marshal_position__.c create mode 100644 libterminput_marshal_state.c create mode 100644 libterminput_marshal_text__.c create mode 100644 libterminput_unmarshal_input.c create mode 100644 libterminput_unmarshal_keypress__.c create mode 100644 libterminput_unmarshal_mouseevent__.c create mode 100644 libterminput_unmarshal_position__.c create mode 100644 libterminput_unmarshal_state.c create mode 100644 libterminput_unmarshal_text__.c diff --git a/Makefile b/Makefile index 552a2e3..a6c1472 100644 --- a/Makefile +++ b/Makefile @@ -15,11 +15,26 @@ LIB_MINOR = 0 LIB_VERSION = $(LIB_MAJOR).$(LIB_MINOR) +MAN3 =\ + libterminput_read.3\ + libterminput_is_ready.3\ + libterminput_set_flags.3\ + libterminput_clear_flags.3 + OBJ =\ - libterminput_read.o\ - libterminput_is_ready.o\ - libterminput_set_flags.o\ - libterminput_clear_flags.o\ + $(MAN3:.3=.o)\ + libterminput_marshal_input.o\ + libterminput_marshal_state.o\ + libterminput_unmarshal_input.o\ + libterminput_unmarshal_state.o\ + libterminput_marshal_keypress__.o\ + libterminput_marshal_text__.o\ + libterminput_marshal_mouseevent__.o\ + libterminput_marshal_position__.o\ + libterminput_unmarshal_keypress__.o\ + libterminput_unmarshal_text__.o\ + libterminput_unmarshal_mouseevent__.o\ + libterminput_unmarshal_position__.o\ libterminput_encode_utf8__.o\ libterminput_check_utf8_char__.o\ libterminput_utf8_decode__.o\ @@ -81,8 +96,7 @@ install: libterminput.a libterminput.$(LIBEXT) $(FIX_INSTALL_NAME) "$(DESTDIR)$(PREFIX)/lib/libterminput.$(LIBMINOREXT)" ln -sf -- libterminput.$(LIBMINOREXT) "$(DESTDIR)$(PREFIX)/lib/libterminput.$(LIBMAJOREXT)" ln -sf -- libterminput.$(LIBMAJOREXT) "$(DESTDIR)$(PREFIX)/lib/libterminput.$(LIBEXT)" - cp -- libterminput_read.3 libterminput_set_flags.3 libterminput_is_ready.3 "$(DESTDIR)$(MANPREFIX)/man3" - ln -sf -- libterminput_set_flags.3 "$(DESTDIR)$(MANPREFIX)/man3/libterminput_clear_flags.3" + cp -P -- $(MAN3) "$(DESTDIR)$(MANPREFIX)/man3" cp -- libterminput.7 "$(DESTDIR)$(MANPREFIX)/man7" uninstall: @@ -91,10 +105,7 @@ uninstall: -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libterminput.$(LIBEXT)" -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libterminput.a" -rm -f -- "$(DESTDIR)$(PREFIX)/include/libterminput.h" - -rm -f -- "$(DESTDIR)$(MANPREFIX)/man3/libterminput_read.3" - -rm -f -- "$(DESTDIR)$(MANPREFIX)/man3/libterminput_set_flags.3" - -rm -f -- "$(DESTDIR)$(MANPREFIX)/man3/libterminput_clear_flags.3" - -rm -f -- "$(DESTDIR)$(MANPREFIX)/man3/libterminput_is_ready.3" + -cd -- "$(DESTDIR)$(MANPREFIX)/man3/" && rm -f -- $(MAN3) -rm -f -- "$(DESTDIR)$(MANPREFIX)/man7/libterminput.7" clean: diff --git a/common.h b/common.h index ba96f50..a1c385f 100644 --- a/common.h +++ b/common.h @@ -16,6 +16,19 @@ #endif +/** + * Mark that there is no input available or pending + * + * @param INPUT_OUT:union libterminput_input *input The input output + */ +#define NOTHING(INPUT_OUT)\ + do {\ + union libterminput_input *input__ = (INPUT_OUT);\ + input__->type = LIBTERMINPUT_NONE;\ + input__->keypress.key = LIBTERMINPUT_SYMBOL;\ + } while (0); + + /** * Singlar read symbol */ @@ -130,5 +143,15 @@ HIDDEN void libterminput_parse_sequence__(union libterminput_input *input, struc */ HIDDEN int libterminput_read_symbol__(int fd, struct input *input, struct libterminput_state *ctx); +/* TODO doc, test */ +HIDDEN int libterminput_marshal_keypress__(struct libterminput_marshaller *how, const struct libterminput_keypress *what); +HIDDEN int libterminput_marshal_text__(struct libterminput_marshaller *how, const struct libterminput_text *what); +HIDDEN int libterminput_marshal_mouseevent__(struct libterminput_marshaller *how, const struct libterminput_mouseevent *what); +HIDDEN int libterminput_marshal_position__(struct libterminput_marshaller *how, const struct libterminput_position *what); +HIDDEN int libterminput_unmarshal_keypress__(struct libterminput_unmarshaller *how, struct libterminput_keypress *what); +HIDDEN int libterminput_unmarshal_text__(struct libterminput_unmarshaller *how, struct libterminput_text *what); +HIDDEN int libterminput_unmarshal_mouseevent__(struct libterminput_unmarshaller *how, struct libterminput_mouseevent *what); +HIDDEN int libterminput_unmarshal_position__(struct libterminput_unmarshaller *how, struct libterminput_position *what); + #undef HIDDEN diff --git a/libterminput.h b/libterminput.h index 46d47e2..d69cb0d 100644 --- a/libterminput.h +++ b/libterminput.h @@ -85,6 +85,7 @@ enum libterminput_flags { LIBTERMINPUT_MACRO_ON_BLOCK = 0x0080 }; + /** * Modifier keys * @@ -108,6 +109,7 @@ enum libterminput_mod { LIBTERMINPUT_CTRL = 0x04 }; + /** * Keyboard buttons * @@ -178,6 +180,7 @@ enum libterminput_key { LIBTERMINPUT_KEYPAD_ENTER }; + /** * Mouse buttons * @@ -264,6 +267,7 @@ enum libterminput_button { LIBTERMINPUT_XBUTTON4 }; + /** * Input event type */ @@ -316,6 +320,7 @@ enum libterminput_type { LIBTERMINPUT_CURSOR_POSITION /* response to CSI 6 n */ }; + /** * Mouse event subtype */ @@ -346,6 +351,7 @@ enum libterminput_event { LIBTERMINPUT_HIGHLIGHT_OUTSIDE }; + /** * Keypress event * @@ -395,6 +401,7 @@ struct libterminput_keypress { char symbol[7]; }; + /** * Text from a bracketed paste */ @@ -424,6 +431,7 @@ struct libterminput_text { char bytes[512]; }; + /** * Mouse event */ @@ -498,6 +506,7 @@ struct libterminput_mouseevent { size_t end_y; }; + /** * Cursor position response */ @@ -522,6 +531,7 @@ struct libterminput_position { size_t y; }; + /** * Input event */ @@ -529,7 +539,7 @@ union libterminput_input { /** * Input event type, used to determine which * other member to read - * + * * The following values have no corresponding * member to read data from: * `LIBTERMINPUT_NONE`, @@ -537,6 +547,12 @@ union libterminput_input { * `LIBTERMINPUT_BRACKETED_PASTE_END`, * `LIBTERMINPUT_TERMINAL_IS_OK`, * `LIBTERMINPUT_TERMINAL_IS_NOT_OK` + * + * Internal comment: + * When `.type == LIBTERMINPUT_NONE`, `.keypress.key` + * is normally set to `LIBTERMINPUT_SYMBOL`, however + * if it is set to anything else, there is a queued + * keypress */ enum libterminput_type type; @@ -590,6 +606,28 @@ struct libterminput_state { }; +/* TODO doc */ +struct libterminput_marshaller { + int (*store)(struct libterminput_marshaller *this, const void *data, size_t size); + union { + void *ptr; + int i; + size_t zu; + } user; +}; + + +/* TODO doc */ +struct libterminput_unmarshaller { + int (*load)(struct libterminput_unmarshaller *this, void *data, size_t size); + union { + void *ptr; + int i; + size_t zu; + } user; +}; + + /** * Get input from the terminal * @@ -652,5 +690,11 @@ int libterminput_set_flags(struct libterminput_state *ctx, enum libterminput_fla */ int libterminput_clear_flags(struct libterminput_state *ctx, enum libterminput_flags flags); +/* TODO doc, man */ +int libterminput_marshal_input(struct libterminput_marshaller *how, const union libterminput_input *what); +int libterminput_marshal_state(struct libterminput_marshaller *how, const struct libterminput_state *what); +int libterminput_unmarshal_input(struct libterminput_unmarshaller *how, union libterminput_input *what); +int libterminput_unmarshal_state(struct libterminput_unmarshaller *how, struct libterminput_state *what); + #endif diff --git a/libterminput_clear_flags.3 b/libterminput_clear_flags.3 new file mode 120000 index 0000000..62881e4 --- /dev/null +++ b/libterminput_clear_flags.3 @@ -0,0 +1 @@ +libterminput_set_flags.3 \ No newline at end of file diff --git a/libterminput_marshal_input.c b/libterminput_marshal_input.c new file mode 100644 index 0000000..9949838 --- /dev/null +++ b/libterminput_marshal_input.c @@ -0,0 +1,27 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +int +libterminput_marshal_input(struct libterminput_marshaller *how, const union libterminput_input *what) /* TODO test */ +{ + enum libterminput_type type = what->type; + if (how->store(how, &type, sizeof(type))) + return -1; + if (type == LIBTERMINPUT_NONE) { + if (what->keypress.key == LIBTERMINPUT_SYMBOL) + type = LIBTERMINPUT_KEYPRESS; + if (how->store(how, &type, sizeof(type))) + return -1; + } + if (type == LIBTERMINPUT_KEYPRESS) + return libterminput_marshal_keypress__(how, &what->keypress); + else if (type == LIBTERMINPUT_TEXT) + return libterminput_marshal_text__(how, &what->text); + else if (type == LIBTERMINPUT_MOUSEEVENT) + return libterminput_marshal_mouseevent__(how, &what->mouseevent); + else if (type == LIBTERMINPUT_CURSOR_POSITION) + return libterminput_marshal_position__(how, &what->position); + else + return 0; +} diff --git a/libterminput_marshal_keypress__.c b/libterminput_marshal_keypress__.c new file mode 100644 index 0000000..1ffba01 --- /dev/null +++ b/libterminput_marshal_keypress__.c @@ -0,0 +1,16 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +int +libterminput_marshal_keypress__(struct libterminput_marshaller *how, const struct libterminput_keypress *what) +{ + if (how->store(how, &what->key, sizeof(what->key)) || + how->store(how, &what->times, sizeof(what->times)) || + how->store(how, &what->mods, sizeof(what->mods))) + return -1; + if (what->key == LIBTERMINPUT_SYMBOL) + return how->store(how, what->symbol, sizeof(what->symbol)); + else + return 0; +} diff --git a/libterminput_marshal_mouseevent__.c b/libterminput_marshal_mouseevent__.c new file mode 100644 index 0000000..8fe64c7 --- /dev/null +++ b/libterminput_marshal_mouseevent__.c @@ -0,0 +1,20 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +int +libterminput_marshal_mouseevent__(struct libterminput_marshaller *how, const struct libterminput_mouseevent *what) +{ + if (how->store(how, &what->event, sizeof(what->event)) || + how->store(how, &what->x, sizeof(size_t) * 2U)) + return -1; + if (what->event == LIBTERMINPUT_HIGHLIGHT_OUTSIDE) { + if (how->store(how, &what->start_x, sizeof(size_t) * 4U)) + return -1; + } else if (what->event != LIBTERMINPUT_HIGHLIGHT_INSIDE) { + if (how->store(how, &what->mods, sizeof(what->mods)) || + how->store(how, &what->button, sizeof(what->button))) + return -1; + } + return 0; +} diff --git a/libterminput_marshal_position__.c b/libterminput_marshal_position__.c new file mode 100644 index 0000000..59fc20e --- /dev/null +++ b/libterminput_marshal_position__.c @@ -0,0 +1,9 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +int +libterminput_marshal_position__(struct libterminput_marshaller *how, const struct libterminput_position *what) +{ + return how->store(how, &what->x, sizeof(size_t) * 2U); +} diff --git a/libterminput_marshal_state.c b/libterminput_marshal_state.c new file mode 100644 index 0000000..8c0c79c --- /dev/null +++ b/libterminput_marshal_state.c @@ -0,0 +1,9 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +int +libterminput_marshal_state(struct libterminput_marshaller *how, const struct libterminput_state *what) /* TODO test */ +{ + return how->store(how, what, sizeof(*what)); +} diff --git a/libterminput_marshal_text__.c b/libterminput_marshal_text__.c new file mode 100644 index 0000000..fa9b542 --- /dev/null +++ b/libterminput_marshal_text__.c @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +int +libterminput_marshal_text__(struct libterminput_marshaller *how, const struct libterminput_text *what) +{ + if (how->store(how, &what->nbytes, sizeof(what->nbytes)) || + how->store(how, what->bytes, sizeof(what->nbytes))) + return -1; + return 0; +} diff --git a/libterminput_parse_csi_m_mouse_tracking__.c b/libterminput_parse_csi_m_mouse_tracking__.c index f943c04..988a665 100644 --- a/libterminput_parse_csi_m_mouse_tracking__.c +++ b/libterminput_parse_csi_m_mouse_tracking__.c @@ -45,7 +45,7 @@ libterminput_parse_csi_m_mouse_tracking__(union libterminput_input *input, struc ctx->stored_head = ctx->stored_tail = 0; } else { - input->type = LIBTERMINPUT_NONE; + NOTHING(input); return; } diff --git a/libterminput_parse_sequence__.c b/libterminput_parse_sequence__.c index aaf0fb4..78f0161 100644 --- a/libterminput_parse_sequence__.c +++ b/libterminput_parse_sequence__.c @@ -112,7 +112,7 @@ libterminput_parse_sequence__(union libterminput_input *input, struct libterminp break; case 'u': if (nums[0] > 0x10FFFFULL || (nums[0] & 0xFFF800ULL) == 0xD800ULL) { - input->type = LIBTERMINPUT_NONE; + NOTHING(input); break; } libterminput_encode_utf8__(nums[0], input->keypress.symbol); @@ -268,7 +268,7 @@ libterminput_parse_sequence__(union libterminput_input *input, struct libterminp default: /* This shouldn't happen (without goto) */ suppress: - input->type = LIBTERMINPUT_NONE; + NOTHING(input); break; } } diff --git a/libterminput_read.c b/libterminput_read.c index 42bb710..9324573 100644 --- a/libterminput_read.c +++ b/libterminput_read.c @@ -74,6 +74,8 @@ again: if (ctx->meta > 1) input->keypress.mods |= LIBTERMINPUT_META; ctx->queued = 1; + input->type = LIBTERMINPUT_NONE; + return 1; } goto none; } @@ -117,7 +119,8 @@ again: if (ctx->meta > 1) input->keypress.mods |= LIBTERMINPUT_META; ctx->queued = 1; - goto none; + input->type = LIBTERMINPUT_NONE; + return 1; } else if (ctx->key[0] == '[' && ctx->key[1] == 'M' && (ctx->flags & LIBTERMINPUT_DECSET_1005)) { ctx->mouse_tracking = 1; n = ctx->stored_tail; @@ -188,6 +191,6 @@ again: return 1; none: - input->type = LIBTERMINPUT_NONE; + NOTHING(input); return 1; } diff --git a/libterminput_read_bracketed_paste__.c b/libterminput_read_bracketed_paste__.c index 02fecc5..b580b70 100644 --- a/libterminput_read_bracketed_paste__.c +++ b/libterminput_read_bracketed_paste__.c @@ -87,11 +87,11 @@ libterminput_read_bracketed_paste__(int fd, union libterminput_input *input, str * end marker, output that we do not have any complete input, * and pause as the available buffered input is incomplete */ if (input->text.nbytes < 6U) { - input->text.type = LIBTERMINPUT_NONE; memcpy(ctx->stored, input->text.bytes, input->text.nbytes); ctx->stored_tail = 0; ctx->stored_head = input->text.nbytes; ctx->paused = 1; + NOTHING(input); return 1; } diff --git a/libterminput_unmarshal_input.c b/libterminput_unmarshal_input.c new file mode 100644 index 0000000..ef8606c --- /dev/null +++ b/libterminput_unmarshal_input.c @@ -0,0 +1,30 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +int +libterminput_unmarshal_input(struct libterminput_unmarshaller *how, union libterminput_input *what) /* TODO test */ +{ + enum libterminput_type type; + int r; + if (how->load(how, &what->type, sizeof(what->type))) + return -1; + type = what->type; + if (what->type == LIBTERMINPUT_NONE) { + what->keypress.key = LIBTERMINPUT_SYMBOL; + if (how->load(how, &what->type, sizeof(what->type))) + return -1; + } + if (what->type == LIBTERMINPUT_KEYPRESS) + r = libterminput_unmarshal_keypress__(how, &what->keypress); + else if (what->type == LIBTERMINPUT_TEXT) + r = libterminput_unmarshal_text__(how, &what->text); + else if (what->type == LIBTERMINPUT_MOUSEEVENT) + r = libterminput_unmarshal_mouseevent__(how, &what->mouseevent); + else if (what->type == LIBTERMINPUT_CURSOR_POSITION) + r = libterminput_unmarshal_position__(how, &what->position); + else + r = 0; + what->type = type; + return r; +} diff --git a/libterminput_unmarshal_keypress__.c b/libterminput_unmarshal_keypress__.c new file mode 100644 index 0000000..68a622d --- /dev/null +++ b/libterminput_unmarshal_keypress__.c @@ -0,0 +1,19 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +int +libterminput_unmarshal_keypress__(struct libterminput_unmarshaller *how, struct libterminput_keypress *what) +{ + what->type = LIBTERMINPUT_KEYPRESS; + if (how->load(how, &what->key, sizeof(what->key)) || + how->load(how, &what->times, sizeof(what->times)) || + how->load(how, &what->mods, sizeof(what->mods))) + return -1; + if (what->key == LIBTERMINPUT_SYMBOL) { + return how->load(how, what->symbol, sizeof(what->symbol)); + } else { + memset(what->symbol, 0, sizeof(what->symbol)); + return 0; + } +} diff --git a/libterminput_unmarshal_mouseevent__.c b/libterminput_unmarshal_mouseevent__.c new file mode 100644 index 0000000..55f72ea --- /dev/null +++ b/libterminput_unmarshal_mouseevent__.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +int +libterminput_unmarshal_mouseevent__(struct libterminput_unmarshaller *how, struct libterminput_mouseevent *what) +{ + what->type = LIBTERMINPUT_MOUSEEVENT; + if (how->load(how, &what->event, sizeof(what->event)) || + how->load(how, &what->x, sizeof(size_t) * 2U)) + return -1; + what->mods = 0; + what->button = LIBTERMINPUT_BUTTON1; + if (what->event == LIBTERMINPUT_HIGHLIGHT_OUTSIDE) { + if (how->load(how, &what->start_x, sizeof(size_t) * 4U)) + return -1; + } else if (what->event != LIBTERMINPUT_HIGHLIGHT_INSIDE) { + if (how->load(how, &what->mods, sizeof(what->mods)) || + how->load(how, &what->button, sizeof(what->button))) + return -1; + } + return 0; +} diff --git a/libterminput_unmarshal_position__.c b/libterminput_unmarshal_position__.c new file mode 100644 index 0000000..9040c50 --- /dev/null +++ b/libterminput_unmarshal_position__.c @@ -0,0 +1,10 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +int +libterminput_unmarshal_position__(struct libterminput_unmarshaller *how, struct libterminput_position *what) +{ + what->type = LIBTERMINPUT_CURSOR_POSITION; + return how->load(how, &what->x, sizeof(size_t) * 2U); +} diff --git a/libterminput_unmarshal_state.c b/libterminput_unmarshal_state.c new file mode 100644 index 0000000..fd1d6db --- /dev/null +++ b/libterminput_unmarshal_state.c @@ -0,0 +1,9 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +int +libterminput_unmarshal_state(struct libterminput_unmarshaller *how, struct libterminput_state *what) /* TODO test */ +{ + return how->load(how, what, sizeof(*what)); +} diff --git a/libterminput_unmarshal_text__.c b/libterminput_unmarshal_text__.c new file mode 100644 index 0000000..4843db4 --- /dev/null +++ b/libterminput_unmarshal_text__.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +int +libterminput_unmarshal_text__(struct libterminput_unmarshaller *how, struct libterminput_text *what) +{ + what->type = LIBTERMINPUT_TEXT; + if (how->load(how, &what->nbytes, sizeof(what->nbytes)) || + how->load(how, what->bytes, sizeof(what->nbytes))) + return -1; + return 0; +} -- cgit v1.2.3-70-g09d2