Handle ANSI and DEC mode report CSIs

This commit is contained in:
Paul LeoNerd Evans 2012-11-30 16:34:47 +00:00
parent c00f6cd3c6
commit 0be6f18019
7 changed files with 152 additions and 1 deletions

15
demo.c
View File

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

View File

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

View File

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

View File

@ -0,0 +1,26 @@
.TH TERMKEY_INTERPRET_MODEREPORT 3
.SH NAME
termkey_interpret_modereport \- interpret opaque mode report data
.SH SYNOPSIS
.nf
.B #include <termkey.h>
.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)

41
t/32modereport.c Normal file
View File

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

View File

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

View File

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