Return a real key type for unrecognised CSI sequences; allow accessing them by termkey_interpret_csi()

This commit is contained in:
Paul LeoNerd Evans 2012-11-30 14:35:23 +00:00
parent d241d6216a
commit 7b3dc4be71
7 changed files with 101 additions and 4 deletions

View File

@ -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",

View File

@ -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),

View File

@ -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)

32
t/39csi.c Normal file
View File

@ -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();
}

View File

@ -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;

View File

@ -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;

View File

@ -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 */