diff --git a/demo.c b/demo.c index 2cd8ebc..7d697cd 100644 --- a/demo.c +++ b/demo.c @@ -68,6 +68,18 @@ int main(int argc, char *argv[]) termkey_interpret_position(tk, &key, &line, &col); printf("Cursor position report at line=%d, col=%d\n", line, col); } + else if(key.type == TERMKEY_TYPE_MODEREPORT) { + int initial, mode, value; + termkey_interpret_modereport(tk, &key, &initial, &mode, &value); + printf("Mode report %s mode %d = %d\n", initial ? "DEC" : "ANSI", mode, value); + } + else if(key.type == TERMKEY_TYPE_UNKNOWN_CSI) { + long args[16]; + size_t nargs = 16; + unsigned long command; + termkey_interpret_csi(tk, &key, args, &nargs, &command); + printf("Unrecognised CSI %c %ld;%ld %c%c\n", (char)(command >> 8), args[0], args[1], (char)(command >> 16), (char)command); + } else { printf("%s\n", buffer); } @@ -80,7 +92,8 @@ int main(int argc, char *argv[]) if(key.type == TERMKEY_TYPE_UNICODE && key.modifiers == 0 && key.code.codepoint == '?') { - printf("\033[?6n"); + // printf("\033[?6n"); // DECDSR 6 == request cursor position + printf("\033[?1$p"); // DECRQM == request mode, DEC origin mode fflush(stdout); } } diff --git a/driver-csi.c b/driver-csi.c index 3ff41e0..45e6dcf 100644 --- a/driver-csi.c +++ b/driver-csi.c @@ -287,6 +287,47 @@ TermKeyResult termkey_interpret_position(TermKey *tk, const TermKeyKey *key, int return TERMKEY_RES_KEY; } +/* + * Handler for CSI $y mode status reports + */ + +static TermKeyResult handle_csi_y(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args) +{ + switch(cmd) { + case 'y'|'$'<<16: + case 'y'|'$'<<16 | '?'<<8: + if(args < 2) + return TERMKEY_RES_NONE; + + key->type = TERMKEY_TYPE_MODEREPORT; + key->code.mouse[0] = (cmd >> 8); + key->code.mouse[1] = arg[0] >> 8; + key->code.mouse[2] = arg[0] & 0xff; + key->code.mouse[3] = arg[1]; + return TERMKEY_RES_KEY; + + default: + return TERMKEY_RES_NONE; + } +} + +TermKeyResult termkey_interpret_modereport(TermKey *tk, const TermKeyKey *key, int *initial, int *mode, int *value) +{ + if(key->type != TERMKEY_TYPE_MODEREPORT) + return TERMKEY_RES_NONE; + + if(initial) + *initial = key->code.mouse[0]; + + if(mode) + *mode = (key->code.mouse[1] << 8) | key->code.mouse[2]; + + if(value) + *value = key->code.mouse[3]; + + return TERMKEY_RES_KEY; +} + #define CHARAT(i) (tk->buffer[tk->buffstart + (i)]) static TermKeyResult parse_csi(TermKey *tk, size_t introlen, size_t *csi_len, long args[], size_t *nargs, unsigned long *commandp) @@ -450,6 +491,8 @@ static int register_keys(void) csi_handlers['R' - 0x40] = &handle_csi_R; + csi_handlers['y' - 0x40] = &handle_csi_y; + keyinfo_initialised = 1; return 1; } diff --git a/man/termkey.7 b/man/termkey.7 index 2313fb5..01ad69c 100644 --- a/man/termkey.7 +++ b/man/termkey.7 @@ -53,6 +53,9 @@ a mouse button press, release, or movement. The \fIcode.mouse\fP array should be .B TERMKEY_TYPE_POSITION 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_MODEREPORT +an ANSI or DEC mode value report. The structure should be considered opaque; \fBtermkey_interpret_modereport\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 @@ -133,6 +136,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. Note that only a DEC CPR sequence (\f(CWCSI ? R\fP) is recognised, and not the non-DEC prefixed \f(CWCSI R\fP because the latter could be interpreted as the \f(CWF3\fP function key instead. +.SS Mode Reports +The \fBTERMKEY_TYPE_MODEREPORT\fP event type indicates an ANSI or DEC mode report. This is typically sent by a terminal in response to the Request Mode command (\f(CWCSI $p\fP or \f(CWCSI ? $p\fP). The event bytes are opaque, but can be obtained by calling \fBtermkey_interpret_modereport\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" diff --git a/man/termkey_interpret_modereport.3 b/man/termkey_interpret_modereport.3 new file mode 100644 index 0000000..d778655 --- /dev/null +++ b/man/termkey_interpret_modereport.3 @@ -0,0 +1,26 @@ +.TH TERMKEY_INTERPRET_MODEREPORT 3 +.SH NAME +termkey_interpret_modereport \- interpret opaque mode report data +.SH SYNOPSIS +.nf +.B #include +.sp +.BI "TermKeyResult termkey_interpret_modereport(TermKey *" tk ", const TermKeyKey *" key ", " +.BI " int *" initial ", int *" mode ", int *" value ); +.fi +.sp +Link with \fI-ltermkey\fP. +.SH DESCRIPTION +\fBtermkey_interpret_modereport\fP() fills in variables in the passed pointers according to the mode report 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_MODEREPORT\fP. +.PP +Any pointer may instead be given as \fBNULL\fP to not return that value. +.PP +The \fIinitial\fP variable will be filled with 0 for an ANSI mode report, or \f(CW'?'\fP for a DEC mode report. The \fImode\fP variable will be filled with the number of the mode, and \fIvalue\fP will be filled with the value from the report. +.SH "RETURN VALUE" +If passed a \fIkey\fP event of the type \fBTERMKEY_TYPE_MODEREPORT\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/32modereport.c b/t/32modereport.c new file mode 100644 index 0000000..31de400 --- /dev/null +++ b/t/32modereport.c @@ -0,0 +1,41 @@ +#include "../termkey.h" +#include "taplib.h" + +int main(int argc, char *argv[]) +{ + TermKey *tk; + TermKeyKey key; + int initial, mode, value; + + plan_tests(12); + + tk = termkey_new_abstract("vt100", 0); + + termkey_push_bytes(tk, "\e[?1;2$y", 8); + + is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for mode report"); + + is_int(key.type, TERMKEY_TYPE_MODEREPORT, "key.type for mode report"); + + is_int(termkey_interpret_modereport(tk, &key, &initial, &mode, &value), TERMKEY_RES_KEY, "interpret_modereoprt yields RES_KEY"); + + is_int(initial, '?', "initial indicator from mode report"); + is_int(mode, 1, "mode number from mode report"); + is_int(value, 2, "mode value from mode report"); + + termkey_push_bytes(tk, "\e[4;1$y", 7); + + is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for mode report"); + + is_int(key.type, TERMKEY_TYPE_MODEREPORT, "key.type for mode report"); + + is_int(termkey_interpret_modereport(tk, &key, &initial, &mode, &value), TERMKEY_RES_KEY, "interpret_modereoprt yields RES_KEY"); + + is_int(initial, 0, "initial indicator from mode report"); + is_int(mode, 4, "mode number from mode report"); + is_int(value, 1, "mode value from mode report"); + + termkey_destroy(tk); + + return exit_status(); +} diff --git a/termkey.c b/termkey.c index a366636..c3f8060 100644 --- a/termkey.c +++ b/termkey.c @@ -1254,6 +1254,15 @@ 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_MODEREPORT: + { + int initial, mode, value; + termkey_interpret_modereport(tk, key, &initial, &mode, &value); + if(initial) + l = snprintf(buffer + pos, len - pos, "Mode(%c%d=%d)", initial, mode, value); + else + l = snprintf(buffer + pos, len - pos, "Mode(%d=%d)", mode, value); + } case TERMKEY_TYPE_UNKNOWN_CSI: l = snprintf(buffer + pos, len - pos, "CSI %c", key->code.number & 0xff); break; @@ -1381,6 +1390,17 @@ int termkey_keycmp(TermKey *tk, const TermKeyKey *key1p, const TermKeyKey *key2p return col1 - col2; } break; + case TERMKEY_TYPE_MODEREPORT: + { + int initial1, initial2, mode1, mode2, value1, value2; + termkey_interpret_modereport(tk, &key1, &initial1, &mode1, &value1); + termkey_interpret_modereport(tk, &key2, &initial2, &mode2, &value2); + if(initial1 != initial2) + return initial1 - initial2; + if(mode1 != mode2) + return mode1 - mode2; + return value1 - value2; + } } return key1.modifiers - key2.modifiers; diff --git a/termkey.h.in b/termkey.h.in index 754700f..95f315b 100644 --- a/termkey.h.in +++ b/termkey.h.in @@ -97,6 +97,7 @@ typedef enum { TERMKEY_TYPE_KEYSYM, TERMKEY_TYPE_MOUSE, TERMKEY_TYPE_POSITION, + TERMKEY_TYPE_MODEREPORT, /* add other recognised types here */ TERMKEY_TYPE_UNKNOWN_CSI = -1 @@ -205,6 +206,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_modereport(TermKey *tk, const TermKeyKey *key, int *initial, int *mode, int *value); + TermKeyResult termkey_interpret_csi(TermKey *tk, const TermKeyKey *key, long args[], size_t *nargs, unsigned long *cmd); typedef enum {