diff options
-rw-r--r-- | driver-csi.c | 22 | ||||
-rw-r--r-- | man/termkey.7 | 7 | ||||
-rw-r--r-- | man/termkey_interpret_csi.3 | 24 | ||||
-rw-r--r-- | t/39csi.c | 32 | ||||
-rw-r--r-- | termkey-internal.h | 2 | ||||
-rw-r--r-- | termkey.c | 11 | ||||
-rw-r--r-- | termkey.h.in | 7 |
7 files changed, 101 insertions, 4 deletions
diff --git a/driver-csi.c b/driver-csi.c index 80f7eaa..bb699bd 100644 --- a/driver-csi.c +++ b/driver-csi.c @@ -419,7 +419,7 @@ static TermKeyResult peekkey_csi(TermKey *tk, TermKeyCsi *csi, size_t introlen, if(csi_handlers[(cmd & 0xff) - 0x40]) result = (*csi_handlers[(cmd & 0xff) - 0x40])(tk, key, cmd, arg, args); - if(key->code.sym == TERMKEY_SYM_UNKNOWN) { + if(result == TERMKEY_RES_NONE) { #ifdef DEBUG switch(args) { case 1: @@ -436,7 +436,12 @@ static TermKeyResult peekkey_csi(TermKey *tk, TermKeyCsi *csi, size_t introlen, break; } #endif - return TERMKEY_RES_NONE; + key->type = TERMKEY_TYPE_UNKNOWN_CSI; + key->code.number = cmd; + + tk->hightide = csi_len - introlen; + *nbytep = introlen; // Do not yet eat the data bytes + return TERMKEY_RES_KEY; } *nbytep = csi_len; @@ -518,6 +523,19 @@ static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force return TERMKEY_RES_NONE; } +/* non-static */ +TermKeyResult termkey_interpret_csi(TermKey *tk, const TermKeyKey *key, long args[], size_t *nargs, unsigned long *cmd) +{ + size_t dummy; + + if(tk->hightide == 0) + return TERMKEY_RES_NONE; + if(key->type != TERMKEY_TYPE_UNKNOWN_CSI) + return TERMKEY_RES_NONE; + + return parse_csi(tk, 0, &dummy, args, nargs, cmd); +} + struct TermKeyDriver termkey_driver_csi = { .name = "CSI", diff --git a/man/termkey.7 b/man/termkey.7 index bafa0b8..c96c4b4 100644 --- a/man/termkey.7 +++ b/man/termkey.7 @@ -51,7 +51,10 @@ a symbolic key. This value indicates that \fIcode.sym\fP is valid, and contains a mouse button press, release, or movement. The \fIcode.mouse\fP array should be considered opaque. .TP .B TERMKEY_TYPE_POSITION -a cursor position report. +a cursor position report. The structure should be considered opaque; \fBtermkey_interpret_position\fP(3) may be used to interpret it. +.TP +.B TERMKEY_TYPE_UNKNOWN_CSI +an unrecognised CSI sequence. The structure should be considered opaque; \fBtermkey_interpret_csi\fP(3) may be used to interpret it. .PP The \fImodifiers\fP bitmask is composed of a bitwise-or of the constants \fBTERMKEY_KEYMOD_SHIFT\fP, \fBTERMKEY_KEYMOD_CTRL\fP and \fBTERMKEY_KEYMOD_ALT\fP. .PP @@ -130,6 +133,8 @@ protocol (\f(CWCSI M\fP followed by three bytes), encoding (\f(CWCSI < ... M\fP, as requested by \f(CWCSI ? 1006 h\fP), and rxvt encoding (\f(CWCSI ... M\fP, as requested by \f(CWCSI ? 1015 h\fP). Which encoding is in use is inferred automatically by \fBtermkey\fP, and does not need to be specified explicitly. .SS Position Events The \fBTERMKEY_TYPE_POSITION\fP event type indicates a cursor position report. This is typically sent by a terminal in response to the Report Cursor Position command (\f(CWCSI 6 n\fP). The event bytes are opaque, but can be obtained by calling \fBtermkey_interpret_position\fP(3) passing the event structure and pointers to integers to store the result in. +.SS Unrecognised CSIs +The \fBTERMKEY_TYPE_UNKNOWN_CSI\fP event type indicates a CSI sequence that the \fBtermkey\fP does not recognise. It will have been extracted from the stream, but is available to the application to inspect by calling \fBtermkey_interpret_csi\fP(3). It is important that if the application wishes to inspect this sequence it is done immediately, before any other IO operations on the \fBtermkey\fP instance (specifically, before calling \fBtermkey_waitkey\fP() or \fBtermkey_getkey\fP() again), otherwise the buffer space consumed by the sequence will be overwritten. .SH "SEE ALSO" .BR termkey_new (3), .BR termkey_waitkey (3), diff --git a/man/termkey_interpret_csi.3 b/man/termkey_interpret_csi.3 new file mode 100644 index 0000000..fa0444d --- /dev/null +++ b/man/termkey_interpret_csi.3 @@ -0,0 +1,24 @@ +.TH TERMKEY_INTERPRET_CSI 3 +.SH NAME +termkey_interpret_csi \- interpret unrecognised CSI sequence +.SH SYNOPSIS +.nf +.B #include <termkey.h> +.sp +.BI "TermKeyResult termkey_interpret_csi(TermKey *" tk ", const TermKeyKey *" key ", " +.BI " long *" args "[], size_t *" nargs ", unsigned long *" cmd ); +.fi +.sp +Link with \fI-ltermkey\fP. +.SH DESCRIPTION +\fBtermkey_interpret_csi\fP() fills in variables in the passed pointers according to the unrecognised CSI sequence event found in \fIkey\fP. It should be called if \fBtermkey_getkey\fP(3) or similar have returned a key event with the type of \fBTERMKEY_TYPE_UNKNOWN_CSI\fP. Note that it is important to call this function as soon as possible after obtaining a \fBTERMKEY_TYPE_CSI\fP key event; specifically, before calling \fBtermkey_getkey\fP() or \fBtermkey_waitkey\fP() again, as a subsequent call will overwrite the buffer space currently containing this sequence. +.PP +The \fIargs\fP array will be filled with the numerical arguments of the CSI sequence. The number of elements available in this array should be given as the initial value of the value pointed to by \fInargs\fP, which will be adjusted to give the number of arguments actually found when the function returns. The \fIcmd\fP variable will contain the CSI command value. If a leading byte was found (such as '\f(CW$\fP') then it will be bitwise-ored with the command value, shifted up by 8 bits. +.SH "RETURN VALUE" +If passed a \fIkey\fP event of the type \fBTERMKEY_TYPE_UNKNOWN_CSI\fP, this function will return \fBTERMKEY_RES_KEY\fP and will affect the variables whose pointers were passed in, as described above. +.PP +For other event types it will return \fBTERMKEY_RES_NONE\fP, and its effects on any variables whose pointers were passed in, are undefined. +.SH "SEE ALSO" +.BR termkey_waitkey (3), +.BR termkey_getkey (3), +.BR termkey (7) diff --git a/t/39csi.c b/t/39csi.c new file mode 100644 index 0000000..f3bb598 --- /dev/null +++ b/t/39csi.c @@ -0,0 +1,32 @@ +#include "../termkey.h" +#include "taplib.h" + +int main(int argc, char *argv[]) +{ + TermKey *tk; + TermKeyKey key; + long args[16]; + size_t nargs = 16; + unsigned long command; + + plan_tests(7); + + tk = termkey_new_abstract("vt100", 0); + + termkey_push_bytes(tk, "\e[5;25v", 7); + + is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for position report"); + + is_int(key.type, TERMKEY_TYPE_UNKNOWN_CSI, "key.type for unknown CSI"); + + is_int(termkey_interpret_csi(tk, &key, args, &nargs, &command), TERMKEY_RES_KEY, "interpret_csi yields RES_KEY"); + + is_int(nargs, 2, "nargs for unknown CSI"); + is_int(args[0], 5, "args[0] for unknown CSI"); + is_int(args[1], 25, "args[1] for unknown CSI"); + is_int(command, 'v', "command for unknown CSI"); + + termkey_destroy(tk); + + return exit_status(); +} diff --git a/termkey-internal.h b/termkey-internal.h index 1ebdecb..733f148 100644 --- a/termkey-internal.h +++ b/termkey-internal.h @@ -38,6 +38,8 @@ struct TermKey { size_t buffstart; // First offset in buffer size_t buffcount; // NUMBER of entires valid in buffer size_t buffsize; // Total malloc'ed size + size_t hightide; /* Position beyond buffstart at which peekkey() should next start + * normally 0, but see also termkey_interpret_csi */ struct termios restore_termios; char restore_termios_valid; @@ -189,6 +189,7 @@ static TermKey *termkey_alloc(void) tk->buffstart = 0; tk->buffcount = 0; tk->buffsize = 256; /* bytes */ + tk->hightide = 0; tk->restore_termios_valid = 0; @@ -744,6 +745,12 @@ static TermKeyResult peekkey(TermKey *tk, TermKeyKey *key, int force, size_t *nb fprintf(stderr, "\n"); #endif + if(tk->hightide) { + tk->buffstart += tk->hightide; + tk->buffcount -= tk->hightide; + tk->hightide = 0; + } + TermKeyResult ret; struct TermKeyDriverNode *p; for(p = tk->drivers; p; p = p->next) { @@ -1310,6 +1317,9 @@ size_t termkey_strfkey(TermKey *tk, char *buffer, size_t len, TermKeyKey *key, T case TERMKEY_TYPE_POSITION: l = snprintf(buffer + pos, len - pos, "Position"); break; + case TERMKEY_TYPE_UNKNOWN_CSI: + l = snprintf(buffer + pos, len - pos, "CSI %c", key->code.number & 0xff); + break; } if(l <= 0) return pos; @@ -1413,6 +1423,7 @@ int termkey_keycmp(TermKey *tk, const TermKeyKey *key1p, const TermKeyKey *key2p return key1.code.sym - key2.code.sym; break; case TERMKEY_TYPE_FUNCTION: + case TERMKEY_TYPE_UNKNOWN_CSI: if(key1.code.number != key2.code.number) return key1.code.number - key2.code.number; break; diff --git a/termkey.h.in b/termkey.h.in index bd5187c..754700f 100644 --- a/termkey.h.in +++ b/termkey.h.in @@ -96,7 +96,10 @@ typedef enum { TERMKEY_TYPE_FUNCTION, TERMKEY_TYPE_KEYSYM, TERMKEY_TYPE_MOUSE, - TERMKEY_TYPE_POSITION + TERMKEY_TYPE_POSITION, + /* add other recognised types here */ + + TERMKEY_TYPE_UNKNOWN_CSI = -1 } TermKeyType; typedef enum { @@ -202,6 +205,8 @@ TermKeyResult termkey_interpret_mouse(TermKey *tk, const TermKeyKey *key, TermKe TermKeyResult termkey_interpret_position(TermKey *tk, const TermKeyKey *key, int *line, int *col); +TermKeyResult termkey_interpret_csi(TermKey *tk, const TermKeyKey *key, long args[], size_t *nargs, unsigned long *cmd); + typedef enum { TERMKEY_FORMAT_LONGMOD = 1 << 0, /* Shift-... instead of S-... */ TERMKEY_FORMAT_CARETCTRL = 1 << 1, /* ^X instead of C-X */ |