diff options
| author | Mattias Andrée <maandree@kth.se> | 2021-04-01 23:39:01 +0200 | 
|---|---|---|
| committer | Mattias Andrée <maandree@kth.se> | 2021-04-01 23:39:01 +0200 | 
| commit | c120520578692ee2448ba057e470ac580fc01de8 (patch) | |
| tree | e1a89a37ff4abe4578edd50c5eff6411cdad3a9b | |
| download | libterminput-c120520578692ee2448ba057e470ac580fc01de8.tar.gz libterminput-c120520578692ee2448ba057e470ac580fc01de8.tar.bz2 libterminput-c120520578692ee2448ba057e470ac580fc01de8.tar.xz | |
First commit
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to '')
| -rw-r--r-- | .gitignore | 9 | ||||
| -rw-r--r-- | LICENSE | 15 | ||||
| -rw-r--r-- | Makefile | 44 | ||||
| -rw-r--r-- | config.mk | 8 | ||||
| -rw-r--r-- | interactive-test.c | 99 | ||||
| -rw-r--r-- | libterminput.c | 345 | ||||
| -rw-r--r-- | libterminput.h | 106 | 
7 files changed, 626 insertions, 0 deletions
| diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e41cec2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*~ +*\#* +*.a +*.o +*.so +*.su +*.out +/test +/interactive-test @@ -0,0 +1,15 @@ +ISC License + +© 2021 Mattias Andrée <maandree@kth.se> + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b6913f6 --- /dev/null +++ b/Makefile @@ -0,0 +1,44 @@ +.POSIX: + +CONFIGFILE = config.mk +include $(CONFIGFILE) + + +OBJ =\ +	interactive-test.o\ +	libterminput.o + +HDR =\ +	libterminput.h + + +all: libterminput.a interactive-test +$(OBJ): $(@:.o=.c) $(HDR) + +.c.o: +	$(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS) + +.o.a: +	$(AR) rc $@ $< +	$(AR) -s $@ + +interactive-test: interactive-test.o libterminput.a +	$(CC) -o $@ interactive-test.o libterminput.a $(LDFLAGS) + +install: libterminput.a +	mkdir -p -- "$(DESTDIR)$(PREFIX)/lib" +	mkdir -p -- "$(DESTDIR)$(PREFIX)/include" +	cp -- libterminput.a "$(DESTDIR)$(PREFIX)/lib/" +	cp -- libterminput.h "$(DESTDIR)$(PREFIX)/include/" + +uninstall: +	rm -- "$(DESTDIR)$(PREFIX)/lib/libterminput.a" +	rm -- "$(DESTDIR)$(PREFIX)/include/libterminput.h" + +clean: +	-rm -f -- *.o *.a interactive-test + +.SUFFIXES: +.SUFFIXES: .a .o .c + +.PHONY: all install uninstall clean diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..9404b9a --- /dev/null +++ b/config.mk @@ -0,0 +1,8 @@ +PREFIX    = /usr +MANPREFIX = $(PREFIX)/share/man + +CC = cc + +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 +CFLAGS   = -std=c99 -O2 +LDFLAGS  = -s diff --git a/interactive-test.c b/interactive-test.c new file mode 100644 index 0000000..cc41231 --- /dev/null +++ b/interactive-test.c @@ -0,0 +1,99 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdio.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "libterminput.h" + + +int +main(void) +{ +	struct libterminput_state ctx; +	union libterminput_input input; +	struct termios stty, saved_stty; +	int r; + +	memset(&ctx, 0, sizeof(ctx)); + +	if (tcgetattr(STDIN_FILENO, &stty)) { +		perror("tcgetattr STDIN_FILENO"); +		return 1; +	} +	saved_stty = stty; +	stty.c_lflag &= (tcflag_t)~(ECHO | ICANON); +	if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &stty)) { +		perror("tcsetattr STDIN_FILENO TCSAFLUSH"); +		return 1; +	} + +	while ((r = libterminput_read(STDIN_FILENO, &input, &ctx)) > 0) { +		if (input.type == LIBTERMINPUT_NONE) { +			printf("none\n"); +		} else if (input.type == LIBTERMINPUT_KEYPRESS) { +			printf("keypress:\n"); +			switch (input.keypress.key) { +			case LIBTERMINPUT_SYMBOL: +				printf("\t%s: %s\n", "key: symbol", input.keypress.symbol); +				break; +			case LIBTERMINPUT_UP:           printf("\t%s: %s\n", "key", "up");           break; +			case LIBTERMINPUT_DOWN:         printf("\t%s: %s\n", "key", "down");         break; +			case LIBTERMINPUT_RIGHT:        printf("\t%s: %s\n", "key", "right");        break; +			case LIBTERMINPUT_BEGIN:        printf("\t%s: %s\n", "key", "begin");        break; +			case LIBTERMINPUT_PAUSE:        printf("\t%s: %s\n", "key", "pause");        break; +			case LIBTERMINPUT_TAB:          printf("\t%s: %s\n", "key", "tab");          break; +			case LIBTERMINPUT_F1:           printf("\t%s: %s\n", "key", "f1");           break; +			case LIBTERMINPUT_F2:           printf("\t%s: %s\n", "key", "f2");           break; +			case LIBTERMINPUT_F3:           printf("\t%s: %s\n", "key", "f3");           break; +			case LIBTERMINPUT_F4:           printf("\t%s: %s\n", "key", "f4");           break; +			case LIBTERMINPUT_F5:           printf("\t%s: %s\n", "key", "f5");           break; +			case LIBTERMINPUT_F6:           printf("\t%s: %s\n", "key", "f6");           break; +			case LIBTERMINPUT_F7:           printf("\t%s: %s\n", "key", "f7");           break; +			case LIBTERMINPUT_F8:           printf("\t%s: %s\n", "key", "f8");           break; +			case LIBTERMINPUT_F9:           printf("\t%s: %s\n", "key", "f9");           break; +			case LIBTERMINPUT_F10:          printf("\t%s: %s\n", "key", "f10");          break; +			case LIBTERMINPUT_F11:          printf("\t%s: %s\n", "key", "f11");          break; +			case LIBTERMINPUT_F12:          printf("\t%s: %s\n", "key", "f12");          break; +			case LIBTERMINPUT_HOME:         printf("\t%s: %s\n", "key", "home");         break; +			case LIBTERMINPUT_INS:          printf("\t%s: %s\n", "key", "ins");          break; +			case LIBTERMINPUT_DEL:          printf("\t%s: %s\n", "key", "del");          break; +			case LIBTERMINPUT_END:          printf("\t%s: %s\n", "key", "end");          break; +			case LIBTERMINPUT_PRIOR:        printf("\t%s: %s\n", "key", "prior");        break; +			case LIBTERMINPUT_NEXT:         printf("\t%s: %s\n", "key", "next");         break; +			case LIBTERMINPUT_ERASE:        printf("\t%s: %s\n", "key", "erase");        break; +			case LIBTERMINPUT_ENTER:        printf("\t%s: %s\n", "key", "enter");        break; +			case LIBTERMINPUT_ESC:          printf("\t%s: %s\n", "key", "esc");          break; +			case LIBTERMINPUT_KEYPAD_0:     printf("\t%s: %s\n", "key", "keypad 0");     break; +			case LIBTERMINPUT_KEYPAD_1:     printf("\t%s: %s\n", "key", "keypad 1");     break; +			case LIBTERMINPUT_KEYPAD_2:     printf("\t%s: %s\n", "key", "keypad 2");     break; +			case LIBTERMINPUT_KEYPAD_3:     printf("\t%s: %s\n", "key", "keypad 3");     break; +			case LIBTERMINPUT_KEYPAD_4:     printf("\t%s: %s\n", "key", "keypad 4");     break; +			case LIBTERMINPUT_KEYPAD_5:     printf("\t%s: %s\n", "key", "keypad 5");     break; +			case LIBTERMINPUT_KEYPAD_6:     printf("\t%s: %s\n", "key", "keypad 6");     break; +			case LIBTERMINPUT_KEYPAD_7:     printf("\t%s: %s\n", "key", "keypad 7");     break; +			case LIBTERMINPUT_KEYPAD_8:     printf("\t%s: %s\n", "key", "keypad 8");     break; +			case LIBTERMINPUT_KEYPAD_9:     printf("\t%s: %s\n", "key", "keypad 9");     break; +			case LIBTERMINPUT_KEYPAD_MINUS: printf("\t%s: %s\n", "key", "keypad minus"); break; +			case LIBTERMINPUT_KEYPAD_COMMA: printf("\t%s: %s\n", "key", "keypad comma"); break; +			case LIBTERMINPUT_KEYPAD_POINT: printf("\t%s: %s\n", "key", "keypad point"); break; +			case LIBTERMINPUT_KEYPAD_ENTER: printf("\t%s: %s\n", "key", "keypad enter"); break; +			default: +				printf("\t%s: %s\n", "key", "other"); +				break; +			} +			printf("\t%s: %s\n", "shift", (input.keypress.mods & LIBTERMINPUT_SHIFT) ? "yes" : "no"); +			printf("\t%s: %s\n", "meta",  (input.keypress.mods & LIBTERMINPUT_META)  ? "yes" : "no"); +			printf("\t%s: %s\n", "ctrl",  (input.keypress.mods & LIBTERMINPUT_CTRL)  ? "yes" : "no"); +			printf("\t%s: %s (%llu)\n", "will repeat", input.keypress.times > 1 ? "yes" : "no", input.keypress.times); +		} else { +			printf("other\n"); +		} +	} + +	if (r < 0) +		perror("libterminput_read STDIN_FILENO"); + +	tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_stty); +	return -r; +} diff --git a/libterminput.c b/libterminput.c new file mode 100644 index 0000000..a255373 --- /dev/null +++ b/libterminput.c @@ -0,0 +1,345 @@ +/* See LICENSE file for copyright and license details. */ +#include "libterminput.h" + +#include <alloca.h> +#include <ctype.h> +#include <limits.h> +#include <string.h> +#include <unistd.h> + + +struct input { +	enum libterminput_mod mods; +	char symbol[7]; +}; + + +static int +read_input(int fd, struct input *input, struct libterminput_state *ctx) +{ +	unsigned char c, tc; +	int r; + +	/* Get next byte from input */ +	if (ctx->have_stored) { +		ctx->have_stored = 0; +		c = (unsigned char)ctx->stored; +	} else { +		r = read(fd, &c, 1); +		if (r <= 0) +			return r; +	} + +	if (ctx->n) { +		/* Continuation of multibyte-character */ +		if ((c & 0xC0) != 0x80) { +			/* Short multibyte-character: return short and store read byte from next input */ +			input->mods = ctx->mods; +			ctx->partial[ctx->npartial] = '\0'; +			ctx->n = 0; +			ctx->npartial = 0; +			ctx->mods = 0; +			ctx->have_stored = 1; +			ctx->stored = (char)c; +			strcpy(input->symbol, ctx->partial); +			return 1; +		} else { +			/* Store byte, and if done, return */ +			ctx->partial[ctx->npartial++] = c; +			if (ctx->npartial == ctx->n) { +				ctx->partial[ctx->npartial] = '\0'; +				input->mods = ctx->mods; +				ctx->npartial = 0; +				ctx->mods = 0; +				ctx->n = 0; +				strcpy(input->symbol, ctx->partial); +				return 1; +			} +		} +	} else if (c == 033 && !*ctx->key) { +		/* ESC at the beginning, save as a Meta/ESC */ +		ctx->meta += 1; +	} else if (c == 0) { +		/* CTRL on Space */ +		input->symbol[0] = ' '; +		input->symbol[1] = '\0'; +		input->mods = ctx->mods | LIBTERMINPUT_CTRL; +		ctx->mods = 0; +		return 1; +	} else if (c < (unsigned char)' ' && (char)c != '\t' && (char)c != '\b' && (char)c != '\n') { +		/* CTRL on some some character key */ +		input->symbol[0] = (char)c + '@'; +		input->symbol[1] = '\0'; +		input->mods = ctx->mods | LIBTERMINPUT_CTRL; +		ctx->mods = 0; +		return 1; +	} else if ((c & 0xC0) == 0xC0) { +		/* Beginning of multibyte-character */ +		ctx->n = 0; +		for (tc = c; tc & 0x80; tc <<= 1) +			ctx->n++; +		if (ctx->n > 6) { +			/* If overlong, return first byte a single-byte-character */ +			input->symbol[0] = c; +			input->symbol[1] = '\0'; +			input->mods = ctx->mods; +			ctx->mods = 0; +			return 1; +		} +		ctx->partial[0] = c; +		ctx->npartial = 1; +	} else { +		/* Single-byte-character or stray multi-byte continuation byte */ +		input->symbol[0] = c; +		input->symbol[1] = '\0'; +		input->mods = ctx->mods; +		ctx->mods = 0; +		return 1; +	} + +	input->symbol[0] = '\0'; +	input->mods = -1; +	return 1; +} + + +static void +parse_sequence(union libterminput_input *input, struct libterminput_state *ctx) +{ +	unsigned long long int *nums; +	size_t keylen, n; +	char *p; + +	/* Get number of numbers in the sequence, and allocate an array of at least 2 */ +	for (n = 2, p = ctx->key; *p; p++) +		n += *p == ';'; +	nums = alloca(n * sizeof(*nums)); +	nums[0] = nums[1] = 0; + +	/* Read numbers and remove numbers and delimiters */ +	for (keylen = 0, n = 0, p = ctx->key; *p; p++) { +		if (*p == ';') { +			nums[++n] = 0; /* We made sure above to allocate one extra */ +		} else if (!isdigit(*p)) { +			ctx->key[keylen++] = *p; +		} else if (n < 3) { +			if (nums[n] < (ULLONG_MAX - (*p & 15)) / 10) +				nums[n] = nums[n] * 10 + (*p & 15); +			else +				nums[n] = ULLONG_MAX; +		} +	} +	ctx->key[keylen] = '\0'; + +	/* Get times and mods, and reset symbol, and more as keypress */ +	input->type = LIBTERMINPUT_KEYPRESS; +	input->keypress.symbol[0] = '\0'; +	input->keypress.times = nums[0] + !nums[0]; +	input->keypress.mods = nums[1] > 1 ? nums[1] - 1 : 0; +	input->keypress.mods |= ctx->meta > 1 ? LIBTERMINPUT_META : 0; + +	switch (ctx->key[0]) { +	case '[': +		switch (keylen) { +		case 2: +			switch (ctx->key[1]) { +			case 'A': input->keypress.key = LIBTERMINPUT_UP;    break; +			case 'B': input->keypress.key = LIBTERMINPUT_DOWN;  break; +			case 'C': input->keypress.key = LIBTERMINPUT_RIGHT; break; +			case 'D': input->keypress.key = LIBTERMINPUT_LEFT;  break; +			case 'E': input->keypress.key = LIBTERMINPUT_BEGIN; break; +			case 'G': input->keypress.key = LIBTERMINPUT_BEGIN; break; +			case 'P': input->keypress.key = LIBTERMINPUT_PAUSE; break; +			case 'Z': +				input->keypress.key = LIBTERMINPUT_TAB; +				input->keypress.mods |= LIBTERMINPUT_SHIFT; +				break; +			case '~': +				input->keypress.times = 1; +				switch (nums[0]) { +				case  1: input->keypress.key = LIBTERMINPUT_HOME;  break; +				case  2: input->keypress.key = LIBTERMINPUT_INS;   break; +				case  3: input->keypress.key = LIBTERMINPUT_DEL;   break; +				case  4: input->keypress.key = LIBTERMINPUT_END;   break; +				case  5: input->keypress.key = LIBTERMINPUT_PRIOR; break; +				case  6: input->keypress.key = LIBTERMINPUT_NEXT;  break; +				case 15: input->keypress.key = LIBTERMINPUT_F5;    break; +				case 17: input->keypress.key = LIBTERMINPUT_F6;    break; +				case 18: input->keypress.key = LIBTERMINPUT_F7;    break; +				case 19: input->keypress.key = LIBTERMINPUT_F8;    break; +				case 20: input->keypress.key = LIBTERMINPUT_F9;    break; +				case 21: input->keypress.key = LIBTERMINPUT_F10;   break; +				case 23: input->keypress.key = LIBTERMINPUT_F11;   break; +				case 24: input->keypress.key = LIBTERMINPUT_F12;   break; +				case 25: input->keypress.key = LIBTERMINPUT_F1;    break; +				case 26: input->keypress.key = LIBTERMINPUT_F2;    break; +				case 28: input->keypress.key = LIBTERMINPUT_F3;    break; +				case 29: input->keypress.key = LIBTERMINPUT_F4;    break; +				case 31: input->keypress.key = LIBTERMINPUT_F5;    break; +				case 32: input->keypress.key = LIBTERMINPUT_F6;    break; +				case 33: input->keypress.key = LIBTERMINPUT_F7;    break; +				case 34: input->keypress.key = LIBTERMINPUT_F8;    break; +				default: +					input->type = LIBTERMINPUT_NONE; +					return; +				} +				if (25 <= nums[0] && nums[0] <= 34) +					input->keypress.mods |= LIBTERMINPUT_SHIFT; +				break; +			default: +				input->type = LIBTERMINPUT_NONE; +				break; +			} +			break; +		case 3: +			switch (ctx->key[1] == '[' ? ctx->key[2] : 0) { +			case 'A': input->keypress.key = LIBTERMINPUT_F1; break; +			case 'B': input->keypress.key = LIBTERMINPUT_F2; break; +			case 'C': input->keypress.key = LIBTERMINPUT_F3; break; +			case 'D': input->keypress.key = LIBTERMINPUT_F4; break; +			case 'E': input->keypress.key = LIBTERMINPUT_F5; break; +			default: +				input->type = LIBTERMINPUT_NONE; +				break; +			} +			break; +		default: +			input->type = LIBTERMINPUT_NONE; +			break; +		} +		break; + +	case 'O': +		switch (!ctx->key[2] ? ctx->key[1] : 0) { +		case 'H': input->keypress.key = LIBTERMINPUT_HOME;         break; +		case 'F': input->keypress.key = LIBTERMINPUT_END;          break; +		case 'P': input->keypress.key = LIBTERMINPUT_F1;           break; +		case 'Q': input->keypress.key = LIBTERMINPUT_F2;           break; +		case 'R': input->keypress.key = LIBTERMINPUT_F3;           break; +		case 'S': input->keypress.key = LIBTERMINPUT_F4;           break; +		case 'p': input->keypress.key = LIBTERMINPUT_KEYPAD_0;     break; +		case 'q': input->keypress.key = LIBTERMINPUT_KEYPAD_1;     break; +		case 'r': input->keypress.key = LIBTERMINPUT_KEYPAD_2;     break; +		case 's': input->keypress.key = LIBTERMINPUT_KEYPAD_3;     break; +		case 't': input->keypress.key = LIBTERMINPUT_KEYPAD_4;     break; +		case 'u': input->keypress.key = LIBTERMINPUT_KEYPAD_5;     break; +		case 'v': input->keypress.key = LIBTERMINPUT_KEYPAD_6;     break; +		case 'w': input->keypress.key = LIBTERMINPUT_KEYPAD_7;     break; +		case 'x': input->keypress.key = LIBTERMINPUT_KEYPAD_8;     break; +		case 'y': input->keypress.key = LIBTERMINPUT_KEYPAD_9;     break; +		case 'm': input->keypress.key = LIBTERMINPUT_KEYPAD_MINUS; break; +		case 'l': input->keypress.key = LIBTERMINPUT_KEYPAD_COMMA; break; +		case 'b': input->keypress.key = LIBTERMINPUT_KEYPAD_POINT; break; +		case 'M': input->keypress.key = LIBTERMINPUT_KEYPAD_ENTER; break; +		default: +			input->type = LIBTERMINPUT_NONE; +			break; +		} +		break; + +	default: +		/* This shouldn't happen */ +		input->type = LIBTERMINPUT_NONE; +		break; +	}		 +} + + +int +libterminput_read(int fd, union libterminput_input *input, struct libterminput_state *ctx) +{ +	struct input ret; +	size_t n, m; +	char *p; +	int r; + +	if (!ctx->inited) { +		ctx->inited = 1; +		memset(input, 0, sizeof(*input)); +	} else if (input->type == LIBTERMINPUT_KEYPRESS && input->keypress.times > 1) { +		input->keypress.times -= 1; +		return 1; +	} + +	r = read_input(fd, &ret, ctx); +	if (r <= 0) +		return r; + +again: +	if (!*ret.symbol) { +		/* Incomplete input */ +		if (ctx->meta < 3) { +			/* Up to two Meta/ESC, wait until a third or something else is read */ +			input->type = LIBTERMINPUT_NONE; +			return 1; +		} +		/* Three ESC's */ +		input->type = LIBTERMINPUT_KEYPRESS; +		input->keypress.key = LIBTERMINPUT_ESC; +		input->keypress.times = 3; +		input->keypress.mods = ret.mods; +		input->keypress.symbol[0] = '\0'; +		ctx->meta -= 3; +	} else if (*ctx->key) { +		/* Special keys */ +		if (ret.mods) { +			/* Special key was aborted, restart */ +			*ctx->key = '\0'; +			goto again; +		} +		/* Add new input to sequence */ +		n = strlen(ctx->key); +		m = strlen(ret.symbol); +		if (n + m >= sizeof(ctx->key)) { +			/* Abort if too long */ +			input->type = LIBTERMINPUT_NONE; +			return 1; +		} +		p = stpcpy(&ctx->key[n], ret.symbol); +		/* Check if sequence is complete */ +		if (!isalpha(p[-1]) && p[-1] != '~') { +			input->type = LIBTERMINPUT_NONE; +			return 1; +		} +		/* Parse the complete sequence */ +		parse_sequence(input, ctx); +		/* Reset */ +		ctx->meta = 0; +		ctx->key[0] = '\0'; +	} else if (ctx->meta && (!strcmp(ret.symbol, "[") || !strcmp(ret.symbol, "O"))) { +		/* ESC [ or ESC 0 is used as the beginning of most special keys */ +		strcpy(ctx->key, ret.symbol); +		input->type == LIBTERMINPUT_NONE; +	} else { +		/* Character input and single-byte special keys */ +		input->type = LIBTERMINPUT_KEYPRESS; +		input->keypress.mods = ret.mods; +		input->keypress.times = 1; +		if (ctx->meta) { +			/* Transfer meta modifier from state to input */ +			input->keypress.mods |= LIBTERMINPUT_META; +			ctx->meta = 0; +		} +		switch (ret.symbol[1] ? 0 : ret.symbol[0]) { +		case 127: +		case '\b': +			input->keypress.key = LIBTERMINPUT_ERASE; +			input->keypress.symbol[0] = '\0'; +			break; +		case '\t': +			input->keypress.key = LIBTERMINPUT_TAB; +			input->keypress.symbol[0] = '\0'; +			break; +		case '\n': +			input->keypress.key = LIBTERMINPUT_ENTER; +			input->keypress.symbol[0] = '\0'; +			break; +		default: +			input->keypress.key = LIBTERMINPUT_SYMBOL; +			strcpy(input->keypress.symbol, ret.symbol); +			break; +		} +	} + +	return 1; +} diff --git a/libterminput.h b/libterminput.h new file mode 100644 index 0000000..b86a2bd --- /dev/null +++ b/libterminput.h @@ -0,0 +1,106 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBTERMINPUT_H +#define LIBTERMINPUT_H + +#include <stddef.h> + + +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_PAUSE, +	LIBTERMINPUT_TAB,   /* backtab if with shift */ +	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, +	LIBTERMINPUT_INS, +	LIBTERMINPUT_DEL, +	LIBTERMINPUT_END, +	LIBTERMINPUT_PRIOR, /* page up   */ +	LIBTERMINPUT_NEXT,  /* page down */ +	LIBTERMINPUT_ERASE, /* backspace */ +	LIBTERMINPUT_ENTER, /* return    */ +	LIBTERMINPUT_ESC, +	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_MINUS, +	LIBTERMINPUT_KEYPAD_COMMA, +	LIBTERMINPUT_KEYPAD_POINT, +	LIBTERMINPUT_KEYPAD_ENTER +}; + +enum libterminput_type { +	LIBTERMINPUT_NONE, +	LIBTERMINPUT_KEYPRESS +}; + +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 */ +}; + +union libterminput_input { +	enum libterminput_type type; +	struct libterminput_keypress keypress; +}; + + +/** + * This struct should be considered opaque + */ +struct libterminput_state { +	int inited; /* whether the input in initialised, not this struct */ +	enum libterminput_mod mods; +	char meta; +	char n; +	char have_stored; +	char npartial; +	char stored; +	char partial[7]; +	char key[44]; +}; + + +/** + * 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); + + +#endif | 
