1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
|
/* See LICENSE file for copyright and license details. */
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "libterminput.h"
static volatile sig_atomic_t interrupted = 0;
static void
sigint_handler(int signo)
{
(void) signo;
interrupted = 1;
}
int
main(void)
{
struct libterminput_state ctx;
union libterminput_input input;
struct termios stty, saved_stty;
int r, print_state, flags;
struct sigaction sa;
memset(&ctx, 0, sizeof(ctx));
if (libterminput_init(&ctx, STDIN_FILENO)) {
perror("libterminput_init STDIN_FILENO");
return 1;
}
memset(&sa, 0, sizeof(sa)); /* importantly, SA_RESTART is cleared from sa.sa_flags */
sa.sa_handler = &sigint_handler;
sigaction(SIGINT, &sa, NULL);
if (getenv("TEST_LIBTERMINPUT_DECSET_1005")) {
fprintf(stderr, "LIBTERMINPUT_DECSET_1005 set\n");
libterminput_set_flags(&ctx, LIBTERMINPUT_DECSET_1005);
}
if (getenv("TEST_LIBTERMINPUT_MACRO_ON_CSI_M")) {
fprintf(stderr, "LIBTERMINPUT_MACRO_ON_CSI_M set\n");
libterminput_set_flags(&ctx, LIBTERMINPUT_MACRO_ON_CSI_M);
}
if (getenv("TEST_LIBTERMINPUT_PAUSE_ON_CSI_P")) {
fprintf(stderr, "LIBTERMINPUT_PAUSE_ON_CSI_P set\n");
libterminput_set_flags(&ctx, LIBTERMINPUT_PAUSE_ON_CSI_P);
}
if (getenv("TEST_LIBTERMINPUT_INS_ON_CSI_AT")) {
fprintf(stderr, "LIBTERMINPUT_INS_ON_CSI_AT set\n");
libterminput_set_flags(&ctx, LIBTERMINPUT_INS_ON_CSI_AT);
}
if (getenv("TEST_LIBTERMINPUT_SEPARATE_BACKTAB")) {
fprintf(stderr, "LIBTERMINPUT_SEPARATE_BACKTAB set\n");
libterminput_set_flags(&ctx, LIBTERMINPUT_SEPARATE_BACKTAB);
}
if (getenv("TEST_LIBTERMINPUT_ESC_ON_BLOCK")) {
fprintf(stderr, "LIBTERMINPUT_ESC_ON_BLOCK set\n");
libterminput_set_flags(&ctx, LIBTERMINPUT_ESC_ON_BLOCK);
}
if (getenv("TEST_LIBTERMINPUT_AWAITING_CURSOR_POSITION")) {
fprintf(stderr, "LIBTERMINPUT_AWAITING_CURSOR_POSITION set\n");
libterminput_set_flags(&ctx, LIBTERMINPUT_AWAITING_CURSOR_POSITION);
}
print_state = !!getenv("TEST_LIBTERMINPUT_PRINT_STATE");
if (tcgetattr(STDERR_FILENO, &stty)) {
perror("tcgetattr STDERR_FILENO");
return 1;
}
saved_stty = stty;
stty.c_lflag &= (tcflag_t)~(ECHO | ICANON);
if (tcsetattr(STDERR_FILENO, TCSAFLUSH, &stty)) {
perror("tcsetattr STDERR_FILENO TCSAFLUSH");
return 1;
}
flags = fcntl(STDIN_FILENO, F_GETFL);
if (flags < 0) {
perror("fcntl STDIN_FILENO F_GETFL");
return 1;
} else if (!(flags & O_NONBLOCK)) {
if (fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK) < 0) {
perror("fcntl STDIN_FILENO F_SETFL <old>|O_NONBLOCK");
return 1;
}
}
again:
while ((r = libterminput_read(STDIN_FILENO, &input, &ctx)) > 0) {
if (input.type == LIBTERMINPUT_NONE) {
printf("none\n");
} else if (input.type == LIBTERMINPUT_KEYPRESS) {
printf("keypress:\n");
switch (input.keypress.key) {
case LIBTERMINPUT_SYMBOL:
printf("\t%s: %s\n", "key: symbol", input.keypress.symbol);
break;
case LIBTERMINPUT_UP: printf("\t%s: %s\n", "key", "up"); break;
case LIBTERMINPUT_DOWN: printf("\t%s: %s\n", "key", "down"); break;
case LIBTERMINPUT_RIGHT: printf("\t%s: %s\n", "key", "right"); break;
case LIBTERMINPUT_LEFT: printf("\t%s: %s\n", "key", "left"); break;
case LIBTERMINPUT_BEGIN: printf("\t%s: %s\n", "key", "begin"); break;
case LIBTERMINPUT_TAB: printf("\t%s: %s\n", "key", "tab"); break;
case LIBTERMINPUT_BACKTAB: printf("\t%s: %s\n", "key", "backtab"); break;
case LIBTERMINPUT_F1: printf("\t%s: %s\n", "key", "f1"); break;
case LIBTERMINPUT_F2: printf("\t%s: %s\n", "key", "f2"); break;
case LIBTERMINPUT_F3: printf("\t%s: %s\n", "key", "f3"); break;
case LIBTERMINPUT_F4: printf("\t%s: %s\n", "key", "f4"); break;
case LIBTERMINPUT_F5: printf("\t%s: %s\n", "key", "f5"); break;
case LIBTERMINPUT_F6: printf("\t%s: %s\n", "key", "f6"); break;
case LIBTERMINPUT_F7: printf("\t%s: %s\n", "key", "f7"); break;
case LIBTERMINPUT_F8: printf("\t%s: %s\n", "key", "f8"); break;
case LIBTERMINPUT_F9: printf("\t%s: %s\n", "key", "f9"); break;
case LIBTERMINPUT_F10: printf("\t%s: %s\n", "key", "f10"); break;
case LIBTERMINPUT_F11: printf("\t%s: %s\n", "key", "f11"); break;
case LIBTERMINPUT_F12: printf("\t%s: %s\n", "key", "f12"); break;
case LIBTERMINPUT_HOME: printf("\t%s: %s\n", "key", "home"); break;
case LIBTERMINPUT_INS: printf("\t%s: %s\n", "key", "ins"); break;
case LIBTERMINPUT_DEL: printf("\t%s: %s\n", "key", "del"); break;
case LIBTERMINPUT_END: printf("\t%s: %s\n", "key", "end"); break;
case LIBTERMINPUT_PRIOR: printf("\t%s: %s\n", "key", "prior"); break;
case LIBTERMINPUT_NEXT: printf("\t%s: %s\n", "key", "next"); break;
case LIBTERMINPUT_ERASE: printf("\t%s: %s\n", "key", "erase"); break;
case LIBTERMINPUT_ENTER: printf("\t%s: %s\n", "key", "enter"); break;
case LIBTERMINPUT_ESC: printf("\t%s: %s\n", "key", "esc"); break;
case LIBTERMINPUT_KEYPAD_0: printf("\t%s: %s\n", "key", "keypad 0"); break;
case LIBTERMINPUT_KEYPAD_1: printf("\t%s: %s\n", "key", "keypad 1"); break;
case LIBTERMINPUT_KEYPAD_2: printf("\t%s: %s\n", "key", "keypad 2"); break;
case LIBTERMINPUT_KEYPAD_3: printf("\t%s: %s\n", "key", "keypad 3"); break;
case LIBTERMINPUT_KEYPAD_4: printf("\t%s: %s\n", "key", "keypad 4"); break;
case LIBTERMINPUT_KEYPAD_5: printf("\t%s: %s\n", "key", "keypad 5"); break;
case LIBTERMINPUT_KEYPAD_6: printf("\t%s: %s\n", "key", "keypad 6"); break;
case LIBTERMINPUT_KEYPAD_7: printf("\t%s: %s\n", "key", "keypad 7"); break;
case LIBTERMINPUT_KEYPAD_8: printf("\t%s: %s\n", "key", "keypad 8"); break;
case LIBTERMINPUT_KEYPAD_9: printf("\t%s: %s\n", "key", "keypad 9"); break;
case LIBTERMINPUT_KEYPAD_PLUS: printf("\t%s: %s\n", "key", "keypad plus"); break;
case LIBTERMINPUT_KEYPAD_MINUS: printf("\t%s: %s\n", "key", "keypad minus"); break;
case LIBTERMINPUT_KEYPAD_TIMES: printf("\t%s: %s\n", "key", "keypad times"); break;
case LIBTERMINPUT_KEYPAD_DIVISION: printf("\t%s: %s\n", "key", "keypad division"); break;
case LIBTERMINPUT_KEYPAD_DECIMAL: printf("\t%s: %s\n", "key", "keypad decimal"); break;
case LIBTERMINPUT_KEYPAD_COMMA: printf("\t%s: %s\n", "key", "keypad comma"); break;
case LIBTERMINPUT_KEYPAD_POINT: printf("\t%s: %s\n", "key", "keypad point"); break;
case LIBTERMINPUT_KEYPAD_ENTER: printf("\t%s: %s\n", "key", "keypad enter"); break;
case LIBTERMINPUT_MACRO: printf("\t%s: %s\n", "key", "macro"); break;
case LIBTERMINPUT_PAUSE: printf("\t%s: %s\n", "key", "pause"); break;
default:
printf("\t%s: %s\n", "key", "other");
break;
}
printf("\t%s: %s\n", "shift", (input.keypress.mods & LIBTERMINPUT_SHIFT) ? "yes" : "no");
printf("\t%s: %s\n", "meta", (input.keypress.mods & LIBTERMINPUT_META) ? "yes" : "no");
printf("\t%s: %s\n", "ctrl", (input.keypress.mods & LIBTERMINPUT_CTRL) ? "yes" : "no");
printf("\t%s: %s (%llu)\n", "will repeat", input.keypress.times > 1 ? "yes" : "no", input.keypress.times);
} else if (input.type == LIBTERMINPUT_BRACKETED_PASTE_START) {
printf("bracketed paste start\n");
} else if (input.type == LIBTERMINPUT_BRACKETED_PASTE_END) {
printf("bracketed paste end\n");
} else if (input.type == LIBTERMINPUT_TEXT) {
printf("text:\n");
printf("\tlength: %zu\n", input.text.nbytes);
printf("\tdata: %.512s\n", input.text.bytes);
} else if (input.type == LIBTERMINPUT_MOUSEEVENT) {
printf("mouseevent:\n");
switch (input.mouseevent.event) {
case LIBTERMINPUT_PRESS: printf("\t%s: %s\n", "event", "press"); break;
case LIBTERMINPUT_RELEASE: printf("\t%s: %s\n", "event", "release"); break;
case LIBTERMINPUT_MOTION: printf("\t%s: %s\n", "event", "motion"); break;
case LIBTERMINPUT_HIGHLIGHT_INSIDE: printf("\t%s: %s\n", "event", "highlight inside"); goto was_highlight;
case LIBTERMINPUT_HIGHLIGHT_OUTSIDE: printf("\t%s: %s\n", "event", "highlight outside"); goto was_highlight;
default:
printf("\t%s: %s\n", "event", "other");
break;
}
switch (input.mouseevent.button) {
case LIBTERMINPUT_NO_BUTTON: printf("\t%s: %s\n", "button", "none"); break;
case LIBTERMINPUT_BUTTON1: printf("\t%s: %s\n", "button", "button 1 (left)"); break;
case LIBTERMINPUT_BUTTON2: printf("\t%s: %s\n", "button", "button 2 (middle)"); break;
case LIBTERMINPUT_BUTTON3: printf("\t%s: %s\n", "button", "button 3 (right)"); break;
case LIBTERMINPUT_SCROLL_UP: printf("\t%s: %s\n", "button", "scroll up"); break;
case LIBTERMINPUT_SCROLL_DOWN: printf("\t%s: %s\n", "button", "scroll down"); break;
case LIBTERMINPUT_SCROLL_LEFT: printf("\t%s: %s\n", "button", "scroll left"); break;
case LIBTERMINPUT_SCROLL_RIGHT: printf("\t%s: %s\n", "button", "scroll right"); break;
case LIBTERMINPUT_XBUTTON1: printf("\t%s: %s\n", "button", "extended button 1 (X1; backward)"); break;
case LIBTERMINPUT_XBUTTON2: printf("\t%s: %s\n", "button", "extended button 2 (X2; forward)"); break;
case LIBTERMINPUT_XBUTTON3: printf("\t%s: %s\n", "button", "extended button 3 (X3)"); break;
case LIBTERMINPUT_XBUTTON4: printf("\t%s: %s\n", "button", "extended button 4 (X4)"); break;
default:
printf("\t%s: %s\n", "button", "other");
break;
}
printf("\t%s: %s\n", "shift", (input.mouseevent.mods & LIBTERMINPUT_SHIFT) ? "yes" : "no");
printf("\t%s: %s\n", "meta", (input.mouseevent.mods & LIBTERMINPUT_META) ? "yes" : "no");
printf("\t%s: %s\n", "ctrl", (input.mouseevent.mods & LIBTERMINPUT_CTRL) ? "yes" : "no");
was_highlight:
printf("\t%s: x=%zu, y=%zu\n", "position", input.mouseevent.x, input.mouseevent.y);
if (LIBTERMINPUT_HIGHLIGHT_OUTSIDE) {
printf("\t%s: x=%zu, y=%zu\n", "start", input.mouseevent.start_x, input.mouseevent.start_y);
printf("\t%s: x=%zu, y=%zu\n", "end", input.mouseevent.end_x, input.mouseevent.end_y);
}
if (input.mouseevent.event == LIBTERMINPUT_PRESS) {
printf("\033[1;4;4;10;10T");
fflush(stdout);
}
} else if (input.type == LIBTERMINPUT_TERMINAL_IS_OK) {
printf("terminal ok\n");
} else if (input.type == LIBTERMINPUT_TERMINAL_IS_NOT_OK) {
printf("terminal not ok\n");
} else if (input.type == LIBTERMINPUT_CURSOR_POSITION) {
printf("cursor position:\n");
printf("\tx: %zu\n", input.position.x);
printf("\ty: %zu\n", input.position.y);
} else {
printf("other\n");
}
if (print_state) {
printf("(state):\n"
"\tinited=%i, mods=%#x, flags=%#x, bracketed_paste=%i, mouse_tracking=%i, meta=%i,\n"
"\tn=%i, stored_head=%zu, stored_tail=%zu, paused=%i, npartial=%i, partial=\"%.*s\",\n"
"\tkey=\"%s\", stored=\"%.*s\"\n",
(int)ctx.inited, (unsigned)ctx.mods, (unsigned)ctx.flags, (int)ctx.bracketed_paste,
(int)ctx.mouse_tracking, (int)ctx.meta, (int)ctx.n, ctx.stored_head, ctx.stored_tail,
(int)ctx.paused, (int)ctx.npartial, (int)ctx.npartial, ctx.partial, ctx.key,
(int)(ctx.stored_tail - ctx.stored_head), &ctx.stored[ctx.stored_head]);
}
}
if (r < 0 && !interrupted) {
if (errno == EAGAIN) {
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(STDIN_FILENO, &fdset);
select(1, &fdset, NULL, NULL, NULL);
goto again;
}
perror("libterminput_read STDIN_FILENO");
}
if (!(flags & O_NONBLOCK))
fcntl(STDIN_FILENO, F_SETFL, flags);
tcsetattr(STDERR_FILENO, TCSAFLUSH, &saved_stty);
libterminput_destroy(&ctx);
return -r && !interrupted;
}
|