Skip to content
This repository was archived by the owner on Dec 13, 2023. It is now read-only.

Commit 3b18e63

Browse files
committed
Add TERMKEY_TYPE_DCS/OSC
1 parent c3e3e30 commit 3b18e63

File tree

6 files changed

+192
-0
lines changed

6 files changed

+192
-0
lines changed

driver-csi.c

+85
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ static char ss3_kpalts[64];
1111

1212
typedef struct {
1313
TermKey *tk;
14+
int saved_string_id;
15+
char *saved_string;
1416
} TermKeyCsi;
1517

1618
typedef TermKeyResult CsiHandler(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args);
@@ -508,6 +510,8 @@ static void *new_driver(TermKey *tk, const char *term)
508510
return NULL;
509511

510512
csi->tk = tk;
513+
csi->saved_string_id = 0;
514+
csi->saved_string = NULL;
511515

512516
return csi;
513517
}
@@ -516,6 +520,9 @@ static void free_driver(void *info)
516520
{
517521
TermKeyCsi *csi = info;
518522

523+
if(csi->saved_string)
524+
free(csi->saved_string);
525+
519526
free(csi);
520527
}
521528

@@ -637,6 +644,52 @@ static TermKeyResult peekkey_ss3(TermKey *tk, TermKeyCsi *csi, size_t introlen,
637644
return TERMKEY_RES_KEY;
638645
}
639646

647+
static TermKeyResult peekkey_ctrlstring(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key, int force, size_t *nbytep)
648+
{
649+
size_t str_end = introlen;
650+
651+
while(str_end < tk->buffcount) {
652+
if(CHARAT(str_end) == 0x9c) // ST
653+
break;
654+
if(CHARAT(str_end) == 0x1b &&
655+
(str_end + 1) < tk->buffcount &&
656+
CHARAT(str_end+1) == 0x5c) // ESC-prefixed ST
657+
break;
658+
659+
str_end++;
660+
}
661+
662+
if(str_end >= tk->buffcount)
663+
return TERMKEY_RES_AGAIN;
664+
665+
#ifdef DEBUG
666+
fprintf(stderr, "Found a control string: %*s",
667+
str_end - introlen, tk->buffer + introlen);
668+
#endif
669+
670+
*nbytep = str_end + 1;
671+
if(CHARAT(str_end) == 0x1b)
672+
(*nbytep)++;
673+
674+
if(csi->saved_string)
675+
free(csi->saved_string);
676+
677+
size_t len = str_end - introlen;
678+
679+
csi->saved_string_id++;
680+
csi->saved_string = malloc(len + 1);
681+
682+
strncpy(csi->saved_string, (char *)tk->buffer + introlen, len);
683+
csi->saved_string[len] = 0;
684+
685+
key->type = (CHARAT(introlen-1) & 0x1f) == 0x10 ?
686+
TERMKEY_TYPE_DCS : TERMKEY_TYPE_OSC;
687+
key->code.number = csi->saved_string_id;
688+
key->modifiers = 0;
689+
690+
return TERMKEY_RES_KEY;
691+
}
692+
640693
static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force, size_t *nbytep)
641694
{
642695
if(tk->buffcount == 0)
@@ -653,6 +706,10 @@ static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force
653706
case 0x4f: // ESC-prefixed SS3
654707
return peekkey_ss3(tk, csi, 2, key, force, nbytep);
655708

709+
case 0x50: // ESC-prefixed DCS
710+
case 0x5d: // ESC-prefixed OSC
711+
return peekkey_ctrlstring(tk, csi, 2, key, force, nbytep);
712+
656713
case 0x5b: // ESC-prefixed CSI
657714
return peekkey_csi(tk, csi, 2, key, force, nbytep);
658715
}
@@ -662,6 +719,10 @@ static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force
662719
case 0x8f: // SS3
663720
return peekkey_ss3(tk, csi, 1, key, force, nbytep);
664721

722+
case 0x90: // DCS
723+
case 0x9d: // OSC
724+
return peekkey_ctrlstring(tk, csi, 1, key, force, nbytep);
725+
665726
case 0x9b: // CSI
666727
return peekkey_csi(tk, csi, 1, key, force, nbytep);
667728
}
@@ -677,3 +738,27 @@ struct TermKeyDriver termkey_driver_csi = {
677738

678739
.peekkey = peekkey,
679740
};
741+
742+
TermKeyResult termkey_interpret_string(TermKey *tk, const TermKeyKey *key, const char **strp)
743+
{
744+
struct TermKeyDriverNode *p;
745+
for(p = tk->drivers; p; p = p->next)
746+
if(p->driver == &termkey_driver_csi)
747+
break;
748+
749+
if(!p)
750+
return TERMKEY_RES_NONE;
751+
752+
if(key->type != TERMKEY_TYPE_DCS &&
753+
key->type != TERMKEY_TYPE_OSC)
754+
return TERMKEY_RES_NONE;
755+
756+
TermKeyCsi *csi = p->info;
757+
758+
if(csi->saved_string_id != key->code.number)
759+
return TERMKEY_RES_NONE;
760+
761+
*strp = csi->saved_string;
762+
763+
return TERMKEY_RES_KEY;
764+
}

man/termkey.7

+8
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ a cursor position report. The \fIcode\fP structure should be considered opaque;
5555
.B TERMKEY_TYPE_MODEREPORT
5656
an ANSI or DEC mode value report. The \fIcode\fP structure should be considered opaque; \fBtermkey_interpret_modereport\fP(3) may be used to interpret it.
5757
.TP
58+
.B TERMKEY_TYPE_DCS
59+
a DCS sequence including its terminator. The \fIcode\fP structure should be considered opaque; \fBtermkey_interpret_string\fP(3) may be used to interpret it.
60+
.TP
61+
.B TERMKEY_TYPE_OSC
62+
a OSC sequence including its terminator. The \fIcode\fP structure should be considered opaque; \fBtermkey_interpret_string\fP(3) may be used to interpret it.
63+
.TP
5864
.B TERMKEY_TYPE_UNKNOWN_CSI
5965
an unrecognised CSI sequence. The \fIcode\fP structure should be considered opaque; \fBtermkey_interpret_csi\fP(3) may be used to interpret it.
6066
.PP
@@ -140,6 +146,8 @@ encoding (\f(CWCSI < ... M\fP, as requested by \f(CWCSI ? 1006 h\fP), and rxvt e
140146
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.
141147
.SS Mode Reports
142148
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.
149+
.SS Control Strings
150+
The \fBTERMKEY_TYPE_DCS\fP and \fBTERMKEY_TYPE_OSC\fP event types indicate a DCS or OSC control string. These are typically sent by the terminal in response of similar kinds of strings being sent as queries by the application. The event bytes are opaque, but the body of the string itself can be obtained by calling \fBtermkey_interpret_string\fP(3) immediately after this event is received. The underlying \fBtermkey\fP instance itself can only store one pending string, so the application should be sure to call this function in a timely manner soon after the event is received; at the very least, before calling any other functions that will insert bytes into or remove key events from the instance.
143151
.SS Unrecognised CSIs
144152
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. Other types of key event do not suffer this limitation as the \fBTermKeyKey\fP structure is sufficient to contain all the information required.
145153
.SH "SEE ALSO"

man/termkey_interpret_string.3

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
.TH TERMKEY_INTERPRET_STRING 3
2+
.SH NAME
3+
termkey_interpret_string \- fetch stored control string
4+
.SH SYNOPSIS
5+
.nf
6+
.B #include <termkey.h>
7+
.sp
8+
.BI "TermKeyResult termkey_interpret_string(TermKey *" tk ", const TermKeyKey *" key ", "
9+
.BI " const char **" strp );
10+
.fi
11+
.sp
12+
Link with \fI-ltermkey\fP.
13+
.SH DESCRIPTION
14+
\fBtermkey_interpret_string\fP() fetches the string stored in the \fBTermKey\fP instance from the most recently received \fBTERMKEY_TYPE_DCS\fP or \fBTERMKEY_TYPE_OSC\fP event. Note that it is important to call this function as soon as possible after obtaining a one of these string 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 string.
15+
.PP
16+
The string pointer whose address is given by \fIstrp\fP will be set to point at the actual stored string in the instance. The caller is free to read this string (which will be correctly NUL-terminated), but should not modify it. It is not necessary to \fBfree\fP() the pointer; the containing \fBTermKey\fP instance will do that.
17+
.SH "RETURN VALUE"
18+
If passed the most recent \fIkey\fP event of the type \fBTERMKEY_TYPE_DCS\fP or \fBTERMKEY_TYPE_OSC\fP, this function will return \fBTERMKEY_RES_KEY\fP and will affect the variables whose pointers were passed in, as described above.
19+
.PP
20+
For other event types, or stale events, it will return \fBTERMKEY_RES_NONE\fP, and its effects on any variables whose pointers were passed in are undefined.
21+
.SH "SEE ALSO"
22+
.BR termkey_waitkey (3),
23+
.BR termkey_getkey (3),
24+
.BR termkey (7)

t/39dcs.c

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#include "../termkey.h"
2+
#include "taplib.h"
3+
4+
int main(int argc, char *argv[])
5+
{
6+
TermKey *tk;
7+
TermKeyKey key;
8+
const char *str;
9+
10+
plan_tests(18);
11+
12+
tk = termkey_new_abstract("xterm", 0);
13+
14+
// 7bit DCS
15+
termkey_push_bytes(tk, "\eP1$r1 q\e\\", 10);
16+
17+
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for DCS");
18+
19+
is_int(key.type, TERMKEY_TYPE_DCS, "key.type for DCS");
20+
is_int(key.modifiers, 0, "key.modifiers for DCS");
21+
22+
is_int(termkey_interpret_string(tk, &key, &str), TERMKEY_RES_KEY, "termkey_interpret_string() gives string");
23+
is_str(str, "1$r1 q", "termkey_interpret_string() yields correct string");
24+
25+
is_int(termkey_getkey(tk, &key), TERMKEY_RES_NONE, "getkey again yields RES_NONE");
26+
27+
// 8bit DCS
28+
termkey_push_bytes(tk, "\x90""1$r2 q""\x9c", 8);
29+
30+
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for DCS");
31+
32+
is_int(key.type, TERMKEY_TYPE_DCS, "key.type for DCS");
33+
is_int(key.modifiers, 0, "key.modifiers for DCS");
34+
35+
is_int(termkey_interpret_string(tk, &key, &str), TERMKEY_RES_KEY, "termkey_interpret_string() gives string");
36+
is_str(str, "1$r2 q", "termkey_interpret_string() yields correct string");
37+
38+
is_int(termkey_getkey(tk, &key), TERMKEY_RES_NONE, "getkey again yields RES_NONE");
39+
40+
// 7bit OSC
41+
termkey_push_bytes(tk, "\e]15;abc\e\\", 10);
42+
43+
is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for OSC");
44+
45+
is_int(key.type, TERMKEY_TYPE_OSC, "key.type for OSC");
46+
is_int(key.modifiers, 0, "key.modifiers for OSC");
47+
48+
is_int(termkey_interpret_string(tk, &key, &str), TERMKEY_RES_KEY, "termkey_interpret_string() gives string");
49+
is_str(str, "15;abc", "termkey_interpret_string() yields correct string");
50+
51+
is_int(termkey_getkey(tk, &key), TERMKEY_RES_NONE, "getkey again yields RES_NONE");
52+
53+
termkey_destroy(tk);
54+
55+
return exit_status();
56+
}

termkey.c

+15
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,12 @@ static void print_key(TermKey *tk, TermKeyKey *key)
159159
fprintf(stderr, "Mode report mode=%s %d val=%d\n", initial == '?' ? "DEC" : "ANSI", mode, value);
160160
}
161161
break;
162+
case TERMKEY_TYPE_DCS:
163+
fprintf(stderr, "Device Control String");
164+
break;
165+
case TERMKEY_TYPE_OSC:
166+
fprintf(stderr, "Operating System Control");
167+
break;
162168
case TERMKEY_TYPE_UNKNOWN_CSI:
163169
fprintf(stderr, "unknown CSI\n");
164170
break;
@@ -1392,6 +1398,12 @@ size_t termkey_strfkey(TermKey *tk, char *buffer, size_t len, TermKeyKey *key, T
13921398
else
13931399
l = snprintf(buffer + pos, len - pos, "Mode(%d=%d)", mode, value);
13941400
}
1401+
case TERMKEY_TYPE_DCS:
1402+
l = snprintf(buffer + pos, len - pos, "DCS");
1403+
break;
1404+
case TERMKEY_TYPE_OSC:
1405+
l = snprintf(buffer + pos, len - pos, "OSC");
1406+
break;
13951407
case TERMKEY_TYPE_UNKNOWN_CSI:
13961408
l = snprintf(buffer + pos, len - pos, "CSI %c", key->code.number & 0xff);
13971409
break;
@@ -1520,6 +1532,9 @@ int termkey_keycmp(TermKey *tk, const TermKeyKey *key1p, const TermKeyKey *key2p
15201532
return col1 - col2;
15211533
}
15221534
break;
1535+
case TERMKEY_TYPE_DCS:
1536+
case TERMKEY_TYPE_OSC:
1537+
return key1p - key2p;
15231538
case TERMKEY_TYPE_MODEREPORT:
15241539
{
15251540
int initial1, initial2, mode1, mode2, value1, value2;

termkey.h.in

+4
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ typedef enum {
9898
TERMKEY_TYPE_MOUSE,
9999
TERMKEY_TYPE_POSITION,
100100
TERMKEY_TYPE_MODEREPORT,
101+
TERMKEY_TYPE_DCS,
102+
TERMKEY_TYPE_OSC,
101103
/* add other recognised types here */
102104

103105
TERMKEY_TYPE_UNKNOWN_CSI = -1
@@ -215,6 +217,8 @@ TermKeyResult termkey_interpret_modereport(TermKey *tk, const TermKeyKey *key, i
215217

216218
TermKeyResult termkey_interpret_csi(TermKey *tk, const TermKeyKey *key, long args[], size_t *nargs, unsigned long *cmd);
217219

220+
TermKeyResult termkey_interpret_string(TermKey *tk, const TermKeyKey *key, const char **strp);
221+
218222
typedef enum {
219223
TERMKEY_FORMAT_LONGMOD = 1 << 0, /* Shift-... instead of S-... */
220224
TERMKEY_FORMAT_CARETCTRL = 1 << 1, /* ^X instead of C-X */

0 commit comments

Comments
 (0)