27static sig_atomic_t cont_seen;
28static sig_atomic_t resize_seen;
32 if(signo == SIGWINCH){
35 }
else if(signo == SIGCONT){
55 unsigned char tbuf[BUFSIZ];
56 unsigned char ibuf[BUFSIZ];
119 pthread_mutex_unlock(&ictx->
stats->
lock);
126 pthread_mutex_unlock(&ictx->
stats->
lock);
134 static const struct {
165 { .esc =
NULL, .key = 0, },
167 for(k = keys ; k->esc ; ++k){
174 loginfo(
"added all xtmodkeys");
182 static const struct {
185 bool shift, ctrl, alt;
189 { .tinfo =
"kcbt", .key =
'\t', .shift =
true, },
192 { .tinfo =
"kcuu1", .key =
NCKEY_UP, },
276 { .tinfo =
"kBEG", .key =
NCKEY_BEGIN, .shift = 1, },
277 { .tinfo =
"kBEG3", .key =
NCKEY_BEGIN, .alt = 1, },
278 { .tinfo =
"kBEG4", .key =
NCKEY_BEGIN, .alt = 1, .shift = 1, },
279 { .tinfo =
"kBEG5", .key =
NCKEY_BEGIN, .ctrl = 1, },
280 { .tinfo =
"kBEG6", .key =
NCKEY_BEGIN, .ctrl = 1, .shift = 1, },
281 { .tinfo =
"kBEG7", .key =
NCKEY_BEGIN, .alt = 1, .ctrl = 1, },
282 { .tinfo =
"kDC", .key =
NCKEY_DEL, .shift = 1, },
283 { .tinfo =
"kDC3", .key =
NCKEY_DEL, .alt = 1, },
284 { .tinfo =
"kDC4", .key =
NCKEY_DEL, .alt = 1, .shift = 1, },
285 { .tinfo =
"kDC5", .key =
NCKEY_DEL, .ctrl = 1, },
286 { .tinfo =
"kDC6", .key =
NCKEY_DEL, .ctrl = 1, .shift = 1, },
287 { .tinfo =
"kDC7", .key =
NCKEY_DEL, .alt = 1, .ctrl = 1, },
288 { .tinfo =
"kDN", .key =
NCKEY_DOWN, .shift = 1, },
289 { .tinfo =
"kDN3", .key =
NCKEY_DOWN, .alt = 1, },
290 { .tinfo =
"kDN4", .key =
NCKEY_DOWN, .alt = 1, .shift = 1, },
291 { .tinfo =
"kDN5", .key =
NCKEY_DOWN, .ctrl = 1, },
292 { .tinfo =
"kDN6", .key =
NCKEY_DOWN, .ctrl = 1, .shift = 1, },
293 { .tinfo =
"kDN7", .key =
NCKEY_DOWN, .alt = 1, .ctrl = 1, },
294 { .tinfo =
"kEND", .key =
NCKEY_END, .shift = 1, },
295 { .tinfo =
"kEND3", .key =
NCKEY_END, .alt = 1, },
296 { .tinfo =
"kEND4", .key =
NCKEY_END, .alt = 1, .shift = 1, },
297 { .tinfo =
"kEND5", .key =
NCKEY_END, .ctrl = 1, },
298 { .tinfo =
"kEND6", .key =
NCKEY_END, .ctrl = 1, .shift = 1, },
299 { .tinfo =
"kEND7", .key =
NCKEY_END, .alt = 1, .ctrl = 1, },
300 { .tinfo =
"kHOM", .key =
NCKEY_HOME, .shift = 1, },
301 { .tinfo =
"kHOM3", .key =
NCKEY_HOME, .alt = 1, },
302 { .tinfo =
"kHOM4", .key =
NCKEY_HOME, .alt = 1, .shift = 1, },
303 { .tinfo =
"kHOM5", .key =
NCKEY_HOME, .ctrl = 1, },
304 { .tinfo =
"kHOM6", .key =
NCKEY_HOME, .ctrl = 1, .shift = 1, },
305 { .tinfo =
"kHOM7", .key =
NCKEY_HOME, .alt = 1, .ctrl = 1, },
306 { .tinfo =
"kIC", .key =
NCKEY_INS, .shift = 1, },
307 { .tinfo =
"kIC3", .key =
NCKEY_INS, .alt = 1, },
308 { .tinfo =
"kIC4", .key =
NCKEY_INS, .alt = 1, .shift = 1, },
309 { .tinfo =
"kIC5", .key =
NCKEY_INS, .ctrl = 1, },
310 { .tinfo =
"kIC6", .key =
NCKEY_INS, .ctrl = 1, .shift = 1, },
311 { .tinfo =
"kIC7", .key =
NCKEY_INS, .alt = 1, .ctrl = 1, },
312 { .tinfo =
"kLFT", .key =
NCKEY_LEFT, .shift = 1, },
313 { .tinfo =
"kLFT3", .key =
NCKEY_LEFT, .alt = 1, },
314 { .tinfo =
"kLFT4", .key =
NCKEY_LEFT, .alt = 1, .shift = 1, },
315 { .tinfo =
"kLFT5", .key =
NCKEY_LEFT, .ctrl = 1, },
316 { .tinfo =
"kLFT6", .key =
NCKEY_LEFT, .ctrl = 1, .shift = 1, },
317 { .tinfo =
"kLFT7", .key =
NCKEY_LEFT, .alt = 1, .ctrl = 1, },
320 { .tinfo =
"kNXT4", .key =
NCKEY_PGDOWN, .alt = 1, .shift = 1, },
322 { .tinfo =
"kNXT6", .key =
NCKEY_PGDOWN, .ctrl = 1, .shift = 1, },
323 { .tinfo =
"kNXT7", .key =
NCKEY_PGDOWN, .alt = 1, .ctrl = 1, },
324 { .tinfo =
"kPRV", .key =
NCKEY_PGUP, .shift = 1, },
325 { .tinfo =
"kPRV3", .key =
NCKEY_PGUP, .alt = 1, },
326 { .tinfo =
"kPRV4", .key =
NCKEY_PGUP, .alt = 1, .shift = 1, },
327 { .tinfo =
"kPRV5", .key =
NCKEY_PGUP, .ctrl = 1, },
328 { .tinfo =
"kPRV6", .key =
NCKEY_PGUP, .ctrl = 1, .shift = 1, },
329 { .tinfo =
"kPRV7", .key =
NCKEY_PGUP, .alt = 1, .ctrl = 1, },
330 { .tinfo =
"kRIT", .key =
NCKEY_RIGHT, .shift = 1, },
331 { .tinfo =
"kRIT3", .key =
NCKEY_RIGHT, .alt = 1, },
332 { .tinfo =
"kRIT4", .key =
NCKEY_RIGHT, .alt = 1, .shift = 1, },
333 { .tinfo =
"kRIT5", .key =
NCKEY_RIGHT, .ctrl = 1, },
334 { .tinfo =
"kRIT6", .key =
NCKEY_RIGHT, .ctrl = 1, .shift = 1, },
335 { .tinfo =
"kRIT7", .key =
NCKEY_RIGHT, .alt = 1, .ctrl = 1, },
336 { .tinfo =
"kUP", .key =
NCKEY_UP, .shift = 1, },
337 { .tinfo =
"kUP3", .key =
NCKEY_UP, .alt = 1, },
338 { .tinfo =
"kUP4", .key =
NCKEY_UP, .alt = 1, .shift = 1, },
339 { .tinfo =
"kUP5", .key =
NCKEY_UP, .ctrl = 1, },
340 { .tinfo =
"kUP6", .key =
NCKEY_UP, .ctrl = 1, .shift = 1, },
341 { .tinfo =
"kUP7", .key =
NCKEY_UP, .alt = 1, .ctrl = 1, },
342 { .tinfo =
NULL, .key = 0, }
344 for(k = keys ; k->tinfo ; ++k){
345 char* seq = tigetstr(k->tinfo);
346 if(seq ==
NULL || seq == (
char*)-1){
347 loginfo(
"no terminfo declaration for %s", k->tinfo);
350 if(seq[0] !=
NCKEY_ESC || strlen(seq) < 2){
351 logwarn(
"invalid escape: %s (0x%x)", k->tinfo, k->key);
360 logdebug(
"support for terminfo's %s: %s", k->tinfo, seq);
362 const char* bs = tigetstr(
"kbs");
364 logwarn(
"no backspace key was defined");
388amata_next_kleene(
automaton* amata,
const char* prefix,
char follow){
390 while( (
c = *prefix++) ){
398 const unsigned char* start = amata->
matchstart;
402 char* ret = malloc(amata->
matchstart - start + 1);
404 memcpy(ret, start, amata->
matchstart - start);
418amata_next_numeric(
automaton* amata,
const char* prefix,
char follow){
420 while( (
c = *prefix++) ){
431 if((UINT_MAX - addend) / 10 < ret){
432 logerror(
"overflow: %u * 10 + %u > %u", ret, addend, UINT_MAX);
439 if(candidate != follow){
440 logerror(
"didn't see follow (%c vs %c)", candidate, follow);
450amata_next_string(
automaton* amata,
const char* prefix){
451 return amata_next_kleene(amata, prefix,
'\x1b');
455send_synth_signal(
int sig){
464mark_pipe_ready(
ipipe pipes[
static 2]){
467 if(write(pipes[1], &sig,
sizeof(sig)) != 1){
468 logwarn(
"error writing to pipe (%d) (%s)", pipes[1], strerror(errno));
471 if(!WriteFile(pipes[1], &sig,
sizeof(sig), &wrote,
NULL) || wrote !=
sizeof(sig)){
472 logwarn(
"error writing to pipe");
475 loginfo(
"wrote to readiness pipe");
494 if(islower(tni->
id)){
495 tni->
id = toupper(tni->
id);
510 }
else if(tni->
id ==
'Z'){
512 }
else if(tni->
id ==
'\\'){
517 inc_input_events(ictx);
519 send_synth_signal(synth);
522 pthread_mutex_lock(&ictx->
ilock);
524 pthread_mutex_unlock(&ictx->
ilock);
525 logwarn(
"dropping input 0x%08x", tni->
id);
526 inc_input_errors(ictx);
527 send_synth_signal(synth);
531 memcpy(ni, tni,
sizeof(*tni));
533 if(ni->
id == 0x7f || ni->
id == 0x8){
535 }
else if(ni->
id ==
'\n' || ni->
id ==
'\r'){
539 }
else if(ni->
id > 0 && ni->
id <= 26 && ni->
id !=
'\t'){
540 ni->
id = ni->
id +
'A' - 1;
550 pthread_mutex_unlock(&ictx->
ilock);
551 pthread_cond_broadcast(&ictx->
icond);
552 send_synth_signal(synth);
560 logerror(
"pixelmouse event without pixel info (%ld/%ld)",
y,
x);
561 inc_input_errors(ictx);
572 logwarn(
"dropping click in margins %ld/%ld",
y,
x);
576 logwarn(
"dropping click in margins %ld/%ld",
y,
x);
580 logwarn(
"dropping click in margins %ld/%ld",
y,
x);
585 load_ncinput(ictx, ni);
592mouse_click(
inputctx* ictx,
unsigned release,
char follow){
593 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[<",
';');
594 long x = amata_next_numeric(&ictx->
amata,
"",
';');
595 long y = amata_next_numeric(&ictx->
amata,
"", follow);
599 .shift = mods & 0x04,
620 }
else if(mods >= 64 && mods < 128){
622 }
else if(mods >= 128 && mods < 192){
628 logerror(
"pixelmouse but no pixel info");
630 return pixelmouse_click(ictx, &tni,
y,
x);
636 logwarn(
"dropping click in margins %ld/%ld",
y,
x);
640 logwarn(
"dropping click in margins %ld/%ld",
y,
x);
644 logwarn(
"dropping click in margins %ld/%ld",
y,
x);
651 load_ncinput(ictx, &tni);
656 mouse_click(ictx, 0,
'M');
662 mouse_click(ictx, 1,
'm');
668 unsigned y = amata_next_numeric(&ictx->
amata,
"\x1b[",
';') - 1;
669 unsigned x = amata_next_numeric(&ictx->
amata,
"",
'R') - 1;
671 pthread_mutex_lock(&ictx->
clock);
674 pthread_mutex_unlock(&ictx->
clock);
680 pthread_mutex_unlock(&ictx->
clock);
681 logwarn(
"dropping cursor location report %u/%u",
y,
x);
682 inc_input_errors(ictx);
691 pthread_mutex_unlock(&ictx->
clock);
692 pthread_cond_broadcast(&ictx->
ccond);
700 unsigned kind = amata_next_numeric(&ictx->
amata,
"\x1b[",
';');
701 unsigned y = amata_next_numeric(&ictx->
amata,
"",
';');
702 unsigned x = amata_next_numeric(&ictx->
amata,
"",
't');
708 loginfo(
"pixel geom report %d/%d",
y,
x);
716 logerror(
"invalid geom report type: %d", kind);
723xtmodkey(
inputctx* ictx,
int val,
int mods){
731 if(mods == 2 || mods == 4 || mods == 6 || mods == 8 || mods == 10
732 || mods == 12 || mods == 14 || mods == 16){
736 if(mods == 5 || mods == 6 || mods == 7 || mods == 8 ||
737 (mods >= 13 && mods <= 16)){
741 if(mods == 3 || mods == 4 || mods == 7 || mods == 8 || mods == 11
742 || mods == 12 || mods == 15 || mods == 16){
746 if(mods >= 9 && mods <= 16){
749 load_ncinput(ictx, &tni);
753kitty_functional(uint32_t val){
754 if(val >= 57344 && val <= 63743){
755 if(val >= 57376 && val <= 57398){
757 }
else if(val >= 57428 && val <= 57440){
759 }
else if(val >= 57399 && val <= 57408){
760 val =
'0' + val - 57399;
761 }
else if(val >= 57441 && val <= 57454){
765 case 57400: val =
'1';
break;
771 case 57409: val =
'.';
break;
772 case 57410: val =
'/';
break;
773 case 57411: val =
'*';
break;
774 case 57412: val =
'-';
break;
775 case 57413: val =
'+';
break;
777 case 57415: val =
'=';
break;
800kitty_kbd_txt(
inputctx* ictx,
int val,
int mods, uint32_t *txt,
int evtype){
804 logdebug(
"v/m/e %d %d %d", val, mods, evtype);
811 .
id = kitty_functional(val),
812 .shift = mods && !!((mods - 1) & 0x1),
813 .alt = mods && !!((mods - 1) & 0x2),
814 .ctrl = mods && !!((mods - 1) & 0x4),
815 .modifiers = mods - 1,
834 if(txt && txt[0]!=0){
839 load_ncinput(ictx, &tni);
843kitty_kbd(
inputctx* ictx,
int val,
int mods,
int evtype){
844 kitty_kbd_txt(ictx, val, mods,
NULL, evtype);
849 unsigned val = amata_next_numeric(&ictx->
amata,
"\x1b[",
'u');
850 val = kitty_functional(val);
851 kitty_kbd(ictx, val, 0, 0);
857 unsigned val = amata_next_numeric(&ictx->
amata,
"\x1b[",
';');
858 unsigned mods = amata_next_numeric(&ictx->
amata,
"",
'u');
859 kitty_kbd(ictx, val, mods, 0);
864kitty_cb_atxtn(
inputctx* ictx,
int n,
int with_event){
866 unsigned val = amata_next_numeric(&ictx->
amata,
"\x1b[",
';');
870 mods = amata_next_numeric(&ictx->
amata,
"",
':');
871 ev = amata_next_numeric(&ictx->
amata,
"",
';');
873 mods = amata_next_numeric(&ictx->
amata,
"",
';');
875 for (
int i = 0; i<
n; i++) {
876 txt[i] = amata_next_numeric(&ictx->
amata,
"", (i==
n-1)?
'u':
';');
878 kitty_kbd_txt(ictx, val, mods, txt, ev);
884 return kitty_cb_atxtn(ictx, 1, 0);
889 return kitty_cb_atxtn(ictx, 2, 0);
894 return kitty_cb_atxtn(ictx, 3, 0);
899 return kitty_cb_atxtn(ictx, 4, 0);
904kitty_cb_complex_atxt1(
inputctx* ictx){
905 return kitty_cb_atxtn(ictx, 1, 1);
909kitty_cb_complex_atxt2(
inputctx* ictx){
910 return kitty_cb_atxtn(ictx, 2, 1);
914kitty_cb_complex_atxt3(
inputctx* ictx){
915 return kitty_cb_atxtn(ictx, 3, 1);
919kitty_cb_complex_atxt4(
inputctx* ictx){
920 return kitty_cb_atxtn(ictx, 4, 1);
924legacy_functional(uint32_t
id){
956 unsigned val = amata_next_numeric(&ictx->
amata,
"\x1b[",
';');
957 unsigned mods = amata_next_numeric(&ictx->
amata,
"",
':');
958 unsigned ev = amata_next_numeric(&ictx->
amata,
"",
'~');
963 uint32_t kval = kitty_functional(val);
965 kval = legacy_functional(val);
967 kitty_kbd(ictx, kval, mods, ev);
973 unsigned val = amata_next_numeric(&ictx->
amata,
"\x1b[",
';');
974 unsigned mods = amata_next_numeric(&ictx->
amata,
"",
'~');
975 uint32_t kval = legacy_functional(val);
976 kitty_kbd(ictx, kval, mods, 0);
982 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
'P');
989 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
'Q');
996 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
'S');
1003 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
':');
1004 unsigned ev = amata_next_numeric(&ictx->
amata,
"",
'P');
1011 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
':');
1012 unsigned ev = amata_next_numeric(&ictx->
amata,
"",
'Q');
1019 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
':');
1020 unsigned ev = amata_next_numeric(&ictx->
amata,
"",
'R');
1026kitty_cb_f3_alternate(
inputctx* ictx){
1027 amata_next_numeric(&ictx->
amata,
"\x1b[",
'~');
1034 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
':');
1035 unsigned ev = amata_next_numeric(&ictx->
amata,
"",
'S');
1042 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
'C');
1049 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
'D');
1056 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
'B');
1063 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
'A');
1064 kitty_kbd(ictx,
NCKEY_UP, mods, 0);
1070 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
':');
1071 unsigned ev = amata_next_numeric(&ictx->
amata,
"",
'C');
1078 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
':');
1079 unsigned ev = amata_next_numeric(&ictx->
amata,
"",
'D');
1086 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
':');
1087 unsigned ev = amata_next_numeric(&ictx->
amata,
"",
'B');
1094 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
':');
1095 unsigned ev = amata_next_numeric(&ictx->
amata,
"",
'A');
1096 kitty_kbd(ictx,
NCKEY_UP, mods, ev);
1102 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
'E');
1109 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
'F');
1116 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
'H');
1123 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
':');
1124 unsigned ev = amata_next_numeric(&ictx->
amata,
"",
'E');
1131 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
':');
1132 unsigned ev = amata_next_numeric(&ictx->
amata,
"",
'F');
1139 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[1;",
':');
1140 unsigned ev = amata_next_numeric(&ictx->
amata,
"",
'H');
1147 unsigned val = amata_next_numeric(&ictx->
amata,
"\x1b[",
';');
1148 unsigned mods = amata_next_numeric(&ictx->
amata,
"",
':');
1149 unsigned ev = amata_next_numeric(&ictx->
amata,
"",
'u');
1150 val = kitty_functional(val);
1151 kitty_kbd(ictx, val, mods, ev);
1157 unsigned level = amata_next_numeric(&ictx->
amata,
"\x1b[?",
'u');
1168 unsigned mods = amata_next_numeric(&ictx->
amata,
"\x1b[27;",
';');
1169 unsigned val = amata_next_numeric(&ictx->
amata,
"",
'~');
1170 xtmodkey(ictx, val, mods);
1176xtsmgraphics_cregs_cb(
inputctx* ictx){
1177 unsigned pv = amata_next_numeric(&ictx->
amata,
"\x1b[?1;0;",
'S');
1181 loginfo(
"sixel color registers: %d", pv);
1187xtsmgraphics_sixel_cb(
inputctx* ictx){
1188 unsigned width = amata_next_numeric(&ictx->
amata,
"\x1b[?2;0;",
';');
1189 unsigned height = amata_next_numeric(&ictx->
amata,
"",
'S');
1194 loginfo(
"max sixel geometry: %dx%d", height, width);
1199handoff_initial_responses_late(
inputctx* ictx){
1201 pthread_mutex_lock(&ictx->
ilock);
1206 pthread_mutex_unlock(&ictx->
ilock);
1208 pthread_cond_broadcast(&ictx->
icond);
1209 loginfo(
"handing off initial responses");
1216handoff_initial_responses_early(
inputctx* ictx){
1217 pthread_mutex_lock(&ictx->
ilock);
1220 pthread_mutex_unlock(&ictx->
ilock);
1228 logwarn(
"answered XTSMGRAPHICS, but no sixel in DA1");
1240 loginfo(
"read primary device attributes");
1245 scrub_sixel_responses(ictx->
initdata);
1246 handoff_initial_responses_early(ictx);
1257 loginfo(
"read primary device attributes");
1260 scrub_sixel_responses(ictx->
initdata);
1262 handoff_initial_responses_early(ictx);
1269 loginfo(
"read primary device attributes");
1271 scrub_sixel_responses(ictx->
initdata);
1272 handoff_initial_responses_early(ictx);
1279 loginfo(
"read primary device attributes");
1280 unsigned val = amata_next_numeric(&ictx->
amata,
"\x1b[?",
';');
1281 char* attrlist = amata_next_kleene(&ictx->
amata,
"",
'c');
1282 logdebug(
"DA1: %u [%s]", val, attrlist);
1285 unsigned curattr = 0;
1286 for(
const char* a = attrlist ; *a ; ++a){
1289 curattr += *a -
'0';
1290 }
else if(*a ==
';'){
1296 }
else if(curattr == 28){
1307 }
else if(curattr == 28){
1311 scrub_sixel_responses(ictx->
initdata);
1313 handoff_initial_responses_early(ictx);
1330 unsigned ver = amata_next_numeric(&ictx->
amata,
"\x1b[>83;",
';');
1332 logwarn(
"version %u doesn't look like GNU screen", ver);
1336 int s = snprintf(verstr,
sizeof(verstr),
"%u.%02u.%02u",
1337 ver / 10000, ver / 100 % 100, ver % 100);
1338 if(s < 0 || (
unsigned)s >=
sizeof(verstr)){
1339 logwarn(
"bad screen version %u", ver);
1351 loginfo(
"read secondary device attributes");
1355 amata_next_numeric(&ictx->
amata,
"\x1b[>",
';');
1356 unsigned pv = amata_next_numeric(&ictx->
amata,
"",
';');
1357 int maj, min, patch;
1366 int s = snprintf(ver,
sizeof(ver),
"%u", pv);
1367 if(s < 0 || (
unsigned)s >=
sizeof(ver)){
1384 const char* termname = getenv(
"TERM");
1385 if(termname ==
NULL || strstr(termname,
"alacritty") ==
NULL){
1386 loginfo(
"termname was [%s], probably not alacritty",
1387 termname ? termname :
"unset");
1391 min = (pv % 10000) / 100;
1393 if(maj >= 100 || min >= 100 || patch >= 100){
1398 char* buf = malloc(13);
1400 sprintf(buf,
"%d.%d.%d", maj, min, patch);
1401 loginfo(
"might be alacritty %s", buf);
1410 loginfo(
"kitty graphics message");
1419 unsigned ps = amata_next_numeric(&ictx->
amata,
"\x1b[?1016;",
'$');
1420 loginfo(
"received decrpm 1016 %u", ps);
1431 unsigned ps = amata_next_numeric(&ictx->
amata,
"\x1b[?2026;",
'$');
1432 loginfo(
"received decrpm 2026 %u", ps);
1442get_default_color(
const char* str, uint32_t* color){
1444 if(sscanf(str,
"%02x/%02x/%02x", &
r, &g, &b) == 3){
1446 }
else if(sscanf(str,
"%04x/%04x/%04x", &
r, &g, &b) == 3){
1451 logerror(
"couldn't extract rgb from %s", str);
1454 if(
r < 0 || g < 0 || b < 0){
1455 logerror(
"invalid colors %d %d %d",
r, g, b);
1458 *color = (
r << 16u) | (g << 8u) | b;
1465 char* str = amata_next_string(&ictx->
amata,
"\x1b]11;rgb:");
1469 if(get_default_color(str, &ictx->
initdata->
bg) == 0){
1482 char* str = amata_next_string(&ictx->
amata,
"\x1b]10;rgb:");
1486 if(get_default_color(str, &ictx->
initdata->
fg) == 0){
1499 unsigned idx = amata_next_numeric(&ictx->
amata,
"\x1b]4;",
';');
1500 char* str = amata_next_string(&ictx->
amata,
"rgb:");
1503 }
else if(str ==
NULL){
1519extract_xtversion(
inputctx* ictx,
const char* str,
char suffix){
1520 size_t slen = strlen(str);
1522 logwarn(
"empty version in xtversion");
1526 if(str[slen - 1] != suffix){
1532 logwarn(
"empty version in xtversion");
1544 char* xtversion = amata_next_string(&ictx->
amata,
"\x1bP>|");
1545 if(xtversion ==
NULL){
1549 static const struct {
1558 { .prefix =
"foot(", .suffix =
')', .term =
TERMINAL_FOOT, },
1566 for(xtv = xtvers ; xtv->prefix ; ++xtv){
1567 if(strncmp(xtversion, xtv->prefix, strlen(xtv->prefix)) == 0){
1568 if(extract_xtversion(ictx, xtversion + strlen(xtv->prefix), xtv->suffix) == 0){
1578 if(xtv->prefix ==
NULL){
1579 logwarn(
"unknown xtversion [%s]", xtversion);
1588toxdigit(
const char* s){
1589 char c = isalpha(*s) ? tolower(*s) -
'a' + 10 : *s -
'0';
1592 c += isalpha(*s) ? tolower(*s) -
'a' + 10 : *s -
'0';
1599gettcap(
const char* s,
char** key,
char** val){
1600 const char* equals = s;
1602 unsigned firstnibble =
true;
1603 while(*equals !=
'='){
1604 if(!isxdigit(*equals)){
1608 if(firstnibble && (!isdigit(*equals) || *equals -
'0' >= 8)){
1612 firstnibble = !firstnibble;
1615 if(equals - s == 0 || !firstnibble){
1619 if((*key = malloc((equals - s) / 2 + 1)) ==
NULL){
1622 char* keytarg = *key;
1624 *keytarg = toxdigit(s);
1630 const char *end = equals;
1632 while(*end !=
';' && *end){
1633 if(!isxdigit(*end)){
1637 if(firstnibble && (!isdigit(*end) || *end -
'0' >= 8)){
1641 firstnibble = !firstnibble;
1644 if(end - equals == 0 || !firstnibble){
1648 if((*val = malloc((end - equals) / 2 + 1)) ==
NULL){
1651 char* valtarg = *val;
1654 *valtarg = toxdigit(s);
1659 loginfo(
"key: %s val: %s", *key, *val);
1672determinfo(
char* old){
1673 bool escaped =
false;
1675 for(
char* o = old ; *o ; ++o){
1687 }
else if(*o ==
'\\'){
1701 char* str = amata_next_string(&ictx->
amata,
"\x1bP1+r");
1705 loginfo(
"xtgettcap [%s]", str);
1710 const char* s = str;
1714 while(*s && (s = gettcap(s, &val, &key)) ){
1715 if(strcmp(val,
"TN") == 0){
1717 if(strcmp(key,
"xterm") == 0){
1719 }
else if(strcmp(key,
"mlterm") == 0){
1721 }
else if(strcmp(key,
"xterm-kitty") == 0){
1723 }
else if(strcmp(key,
"xterm-256color") == 0){
1726 logdebug(
"unknown terminal name %s", key);
1729 }
else if(strcmp(val,
"RGB") == 0){
1732 }
else if(strcmp(val,
"hpa") == 0){
1737 logwarn(
"unknown capability: %s", str);
1755 char* str = amata_next_string(&ictx->
amata,
"\x1bP!|");
1757 logwarn(
"empty ternary device attribute");
1761 if(strcmp(str,
"7E565445") == 0){
1763 }
else if(strcmp(str,
"7E7E5459") == 0){
1765 }
else if(strcmp(str,
"464F4F54") == 0){
1767 }
else if(strcmp(str,
"7E4B4445") == 0){
1777build_cflow_automaton(
inputctx* ictx){
1786 {
"[E", simple_cb_begin, },
1787 {
"[<\\N;\\N;\\NM", mouse_press_cb, },
1788 {
"[<\\N;\\N;\\Nm", mouse_release_cb, },
1790 {
"[\\N;\\N;\\Nt", geom_cb, },
1791 {
"[\\Nu", kitty_cb_simple, },
1792 {
"[13~", kitty_cb_f3_alternate, },
1793 {
"[\\N;\\N~", wezterm_cb, },
1794 {
"[\\N;\\Nu", kitty_cb, },
1795 {
"[\\N;\\N;\\Nu", kitty_cb_atxt1, },
1796 {
"[\\N;\\N;\\N;\\Nu", kitty_cb_atxt2, },
1797 {
"[\\N;\\N;\\N;\\N;\\Nu", kitty_cb_atxt3, },
1798 {
"[\\N;\\N;\\N;\\N;\\N;\\Nu", kitty_cb_atxt4, },
1799 {
"[\\N;\\N:\\Nu", kitty_cb_complex, },
1800 {
"[\\N;\\N:\\N;\\Nu", kitty_cb_complex_atxt1, },
1801 {
"[\\N;\\N:\\N;\\N;\\Nu", kitty_cb_complex_atxt2, },
1802 {
"[\\N;\\N:\\N;\\N;\\N;\\Nu", kitty_cb_complex_atxt3, },
1803 {
"[\\N;\\N:\\N;\\N;\\N;\\N;\\Nu", kitty_cb_complex_atxt4, },
1804 {
"[\\N;\\N;\\N~", xtmodkey_cb, },
1805 {
"[\\N;\\N:\\N~", kitty_cb_functional, },
1806 {
"[1;\\NP", legacy_cb_f1, },
1807 {
"[1;\\NQ", legacy_cb_f2, },
1808 {
"[1;\\NS", legacy_cb_f4, },
1809 {
"[1;\\ND", legacy_cb_left, },
1810 {
"[1;\\NC", legacy_cb_right, },
1811 {
"[1;\\NB", legacy_cb_down, },
1812 {
"[1;\\NA", legacy_cb_up, },
1813 {
"[1;\\NE", legacy_cb_begin, },
1814 {
"[1;\\NF", legacy_cb_end, },
1815 {
"[1;\\NH", legacy_cb_home, },
1816 {
"[1;\\N:\\NP", kitty_cb_f1, },
1817 {
"[1;\\N:\\NQ", kitty_cb_f2, },
1818 {
"[1;\\N:\\NR", kitty_cb_f3, },
1819 {
"[1;\\N:\\NS", kitty_cb_f4, },
1820 {
"[1;\\N:\\ND", kitty_cb_left, },
1821 {
"[1;\\N:\\NC", kitty_cb_right, },
1822 {
"[1;\\N:\\NB", kitty_cb_down, },
1823 {
"[1;\\N:\\NA", kitty_cb_up, },
1824 {
"[1;\\N:\\NE", kitty_cb_begin, },
1825 {
"[1;\\N:\\NF", kitty_cb_end, },
1826 {
"[1;\\N:\\NH", kitty_cb_home, },
1827 {
"[?\\Nu", kitty_keyboard_cb, },
1828 {
"[?1016;\\N$y", decrpm_pixelmice, },
1829 {
"[?2026;\\N$y", decrpm_asu_cb, },
1830 {
"[\\N;\\NR", cursor_location_cb, },
1831 {
"[?1;1S",
NULL, },
1832 {
"[?1;2S",
NULL, },
1833 {
"[?1;3S",
NULL, },
1834 {
"[?1;3;S",
NULL, },
1835 {
"[?1;3;0S",
NULL, },
1836 {
"[?2;1S",
NULL, },
1837 {
"[?2;2S",
NULL, },
1838 {
"[?2;3S",
NULL, },
1839 {
"[?2;3;S",
NULL, },
1840 {
"[?2;3;0S",
NULL, },
1841 {
"[?6c", da1_vt102_cb, },
1842 {
"[?7c", da1_cb, },
1843 {
"[?1;0c", da1_cb, },
1844 {
"[?1;2c", da1_cb, },
1845 {
"[?4;6c", da1_cb, },
1852 {
"[?\\N;\\Dc", da1_attrs_cb, },
1853 {
"[?1;0;\\NS", xtsmgraphics_cregs_cb, },
1854 {
"[?2;0;\\N;\\NS", xtsmgraphics_sixel_cb, },
1855 {
"[>83;\\N;0c", da2_screen_cb, },
1856 {
"[>\\N;\\N;\\Nc", da2_cb, },
1857 {
"[=67;84;101;114;109;\\Dc", da1_syncterm_cb, },
1859 {
"P0+\\S",
NULL, },
1860 {
"P1+r\\S", tcap_cb, },
1861 {
"P!|\\S", tda_cb, },
1862 {
"P>|\\S", xtversion_cb, },
1864 {
"_G\\S", kittygraph_cb, },
1866 {
"]10;rgb:\\S", fgdef_cb, },
1867 {
"]11;rgb:\\S", bgdef_cb, },
1870 for(csi = csis ; csi->cflow ; ++csi){
1872 logerror(
"failed adding %p via %s", csi->fxn, csi->cflow);
1875 loginfo(
"added %p via %s", csi->fxn, csi->cflow);
1879 logerror(
"failed adding palette_cb");
1884 logerror(
"failed adding palette_cb");
1889 logerror(
"failed adding palette_cb");
1910endpipes(
ipipe pipes[
static 2]){
1911 closepipe(pipes[0]);
1912 closepipe(pipes[1]);
1917getpipes(
ipipe pipes[
static 2]){
1920 if(pipe2(pipes, O_CLOEXEC | O_NONBLOCK)){
1921 logerror(
"couldn't get pipes (%s)", strerror(errno));
1926 logerror(
"couldn't get pipes (%s)", strerror(errno));
1930 logerror(
"couldn't prep pipe[0] (%s)", strerror(errno));
1935 logerror(
"couldn't prep pipe[1] (%s)", strerror(errno));
1941 if(!CreatePipe(&pipes[0], &pipes[1],
NULL, BUFSIZ)){
1950create_inputctx(
tinfo* ti, FILE* infp,
int lmargin,
int tmargin,
int rmargin,
1952 int linesigs_enabled){
1953 bool sent_queries = (ti->
ttyfd >= 0) ?
true : false;
1960 if(pthread_mutex_init(&i->
ilock,
NULL) == 0){
1961 if(pthread_condmonotonic_init(&i->
icond) == 0){
1962 if(pthread_mutex_init(&i->
clock,
NULL) == 0){
1963 if(pthread_condmonotonic_init(&i->
ccond) == 0){
1964 if((i->
stdinfd = fileno(infp)) >= 0){
1967 if(getpipes(i->
ipipes) == 0){
1969 if(prep_special_keys(i) == 0){
1993 i->stdinhandle = ti->inhandle;
2017 pthread_cond_destroy(&i->
ccond);
2019 pthread_mutex_destroy(&i->
clock);
2021 pthread_cond_destroy(&i->
icond);
2023 pthread_mutex_destroy(&i->
ilock);
2041 pthread_mutex_destroy(&i->
ilock);
2042 pthread_cond_destroy(&i->
icond);
2043 pthread_mutex_destroy(&i->
clock);
2044 pthread_cond_destroy(&i->
ccond);
2064prep_kitty_special_keys(
inputctx* ictx){
2066 static const struct {
2074 { .esc =
"\x1b[13~", .key =
NCKEY_F03, },
2082 { .esc =
NULL, .key = 0, },
2084 for(k = keys ; k->esc ; ++k){
2089 loginfo(
"added all kitty special keys");
2096prep_windows_special_keys(
inputctx* ictx){
2100 static const struct {
2105 { .esc =
"\x1b[A", .key =
NCKEY_UP, },
2109 { .esc =
"\x1b[1;5A", .key =
NCKEY_UP,
2119 { .esc =
"\x1b[2~", .key =
NCKEY_INS, },
2120 { .esc =
"\x1b[3~", .key =
NCKEY_DEL, },
2127 { .esc =
"\x1b[15~", .key =
NCKEY_F05, },
2128 { .esc =
"\x1b[17~", .key =
NCKEY_F06, },
2129 { .esc =
"\x1b[18~", .key =
NCKEY_F07, },
2130 { .esc =
"\x1b[19~", .key =
NCKEY_F08, },
2131 { .esc =
"\x1b[20~", .key =
NCKEY_F09, },
2132 { .esc =
"\x1b[21~", .key =
NCKEY_F10, },
2133 { .esc =
"\x1b[23~", .key =
NCKEY_F11, },
2134 { .esc =
"\x1b[24~", .key =
NCKEY_F12, },
2135 { .esc =
NULL, .key = 0, },
2137 for(k = keys ; k->esc ; ++k){
2141 logdebug(
"added %s %u", k->esc, k->key);
2143 loginfo(
"added all windows special keys");
2149 if(prep_windows_special_keys(ictx)){
2152 if(prep_kitty_special_keys(ictx)){
2155 if(prep_xtmodkeys(ictx)){
2163read_input_nblock(
int fd,
unsigned char* buf,
size_t buflen,
int *bufused,
2168 size_t space = buflen - *bufused;
2172 ssize_t
r = read(fd, buf + *bufused, space);
2174 if(
r < 0 && (errno != EAGAIN && errno != EBUSY && errno == EWOULDBLOCK)){
2175 logwarn(
"couldn't read from %d (%s)", fd, strerror(errno));
2178 logerror(
"error reading from %d (%s)", fd, strerror(errno));
2190 loginfo(
"read %" PRIdPTR
"B from %d (%" PRIuPTR
"B left)",
r, fd, space);
2195ictx_independent_p(
const inputctx* ictx){
2196 return ictx->
termfd >= 0;
2213process_escape(
inputctx* ictx,
const unsigned char* buf,
int buflen){
2216 unsigned char candidate = buf[ictx->
amata.
used++];
2218 if(candidate >= 0x80){
2239 logdebug(
"walk result on %u (%c): %d %u", candidate,
2240 isprint(candidate) ? candidate :
' ', w, ictx->amata.state);
2243 load_ncinput(ictx, &ni);
2265process_escapes(
inputctx* ictx,
unsigned char* buf,
int* bufused){
2268 int consumed = process_escape(ictx, buf + offset, *bufused);
2275 consumed = -consumed;
2278 if(available > consumed){
2279 available = consumed;
2281 logwarn(
"replaying %dB of %dB to ibuf", available, consumed);
2282 memcpy(ictx->
ibuf + ictx->
ibufvalid, buf + offset, available);
2287 *bufused -= consumed;
2293 *bufused -= consumed;
2301 memmove(buf, buf + offset, *bufused);
2311process_input(
const unsigned char* buf,
int buflen,
ncinput* ni){
2313 memset(ni, 0,
sizeof(*ni));
2314 const int cpointlen = utf8_codepoint_length(*buf);
2316 logwarn(
"invalid UTF8 initiator on input (0x%02x)", *buf);
2318 }
else if(cpointlen == 1){
2322 if(cpointlen > buflen){
2323 logwarn(
"utf8 character (%dB) broken across read", cpointlen);
2327 mbstate_t mbstate = {0};
2330 size_t r = mbrtowc(&w, (
const char*)buf, cpointlen, &mbstate);
2331 if(
r == (
size_t)-1 ||
r == (
size_t)-2){
2332 logerror(
"invalid utf8 prefix (%dB) on input", cpointlen);
2342process_ncinput(
inputctx* ictx,
const unsigned char* buf,
int buflen){
2344 int r = process_input(buf, buflen, &ni);
2346 load_ncinput(ictx, &ni);
2348 inc_input_errors(ictx);
2358process_bulk(
inputctx* ictx,
unsigned char* buf,
int* bufused){
2361 bool noroom =
false;
2362 pthread_mutex_lock(&ictx->
ilock);
2366 pthread_mutex_unlock(&ictx->
ilock);
2370 int consumed = process_ncinput(ictx, buf + offset, *bufused);
2374 *bufused -= consumed;
2379 memmove(buf, buf + offset, *bufused);
2389process_melange(
inputctx* ictx,
const unsigned char* buf,
int* bufused){
2391 int origlen = *bufused;
2394 *bufused, buf[offset], isprint(buf[offset]) ? buf[offset] :
' ');
2396 if(buf[offset] ==
'\x1b'){
2397 consumed = process_escape(ictx, buf + offset, *bufused);
2400 if(*bufused != -consumed || *bufused == origlen){
2411 if(consumed <= 0 && !ictx->midescape){
2412 consumed = process_ncinput(ictx, buf + offset, *bufused);
2417 *bufused -= consumed;
2420 handoff_initial_responses_late(ictx);
2430 load_ncinput(ictx, &tni);
2437 load_ncinput(ictx, &tni);
2444 handoff_initial_responses_late(ictx);
2447 if(ictx_independent_p(ictx)){
2464 process_melange(ictx, buf, &
len);
2467 inc_input_errors(ictx);
2476block_on_input(
inputctx* ictx,
unsigned* rtfd,
unsigned* rifd){
2477 logtrace(
"blocking on input availability");
2481 loginfo(
"nonblocking read to check for completion");
2485 int timeoutms = nonblock ? 0 : -1;
2490 handles[ncount++] = ictx->stdinhandle;
2494 handles[ncount++] = ictx->
ipipes[0];
2496 DWORD d = WaitForMultipleObjects(ncount, handles,
false, timeoutms);
2497 if(d == WAIT_TIMEOUT){
2499 }
else if(d == WAIT_FAILED){
2501 }
else if(d - WAIT_OBJECT_0 == 0){
2507 int inevents = POLLIN;
2509 inevents |= POLLRDHUP;
2511 struct pollfd pfds[2];
2515 pfds[pfdcount].fd = ictx->
stdinfd;
2516 pfds[pfdcount].events = inevents;
2517 pfds[pfdcount].revents = 0;
2522 loginfo(
"output queues full; blocking on ipipes");
2523 pfds[pfdcount].fd = ictx->
ipipes[0];
2524 pfds[pfdcount].events = inevents;
2525 pfds[pfdcount].revents = 0;
2529 pfds[pfdcount].fd = ictx->
termfd;
2530 pfds[pfdcount].events = inevents;
2531 pfds[pfdcount].revents = 0;
2537 sigdelset(&smask, SIGCONT);
2538 sigdelset(&smask, SIGWINCH);
2542 sigdelset(&smask, SIGTHR);
2545#if defined(__APPLE__) || defined(__MINGW32__)
2546 int timeoutms = nonblock ? 0 : -1;
2547 while((events = poll(pfds, pfdcount, timeoutms)) < 0){
2549 struct timespec ts = { .tv_sec = 0, .tv_nsec = 0, };
2550 struct timespec* pts = nonblock ? &ts :
NULL;
2551 while((events = ppoll(pfds, pfdcount, pts, &smask)) < 0){
2554 loginfo(
"interrupted by signal");
2556 }
else if(errno != EAGAIN && errno != EBUSY && errno != EWOULDBLOCK){
2557 logerror(
"error polling (%s)", strerror(errno));
2561 loginfo(
"poll returned %d", events);
2564 if(pfds[pfdcount].revents){
2565 if(pfds[pfdcount].fd == ictx->
stdinfd){
2567 }
else if(pfds[pfdcount].fd == ictx->
termfd){
2569 }
else if(pfds[pfdcount].fd == ictx->
ipipes[0]){
2571 while(read(ictx->
ipipes[0], &
c,
sizeof(
c)) == 1){
2579 loginfo(
"got events: %c%c", *rtfd ?
'T' :
't', *rifd ?
'I' :
'i');
2588 unsigned rtfd, rifd;
2589 block_on_input(ictx, &rtfd, &rifd);
2605 pthread_cond_broadcast(&ictx->
icond);
2611input_thread(
void* vmarshall){
2614 if(prep_all_keys(ictx) || build_cflow_automaton(ictx)){
2616 handoff_initial_responses_early(ictx);
2617 handoff_initial_responses_late(ictx);
2620 read_inputs_nblock(ictx);
2629 unsigned drain,
int linesigs_enabled){
2630 inputctx* ictx = create_inputctx(ti, infp, lmargin, tmargin, rmargin,
2631 bmargin, stats, drain, linesigs_enabled);
2635 if(pthread_create(&ictx->
tid,
NULL, input_thread, ictx)){
2636 free_inputctx(ictx);
2640 loginfo(
"spun up input thread");
2650 loginfo(
"tearing down input thread");
2651 ret |= cancel_and_join(
"input", ti->
ictx->
tid,
NULL);
2653 free_inputctx(ti->
ictx);
2666 logerror(
"readiness descriptor unavailable on windows");
2671static inline uint32_t
2675 logerror(
"input is being drained");
2677 memset(ni, 0,
sizeof(*ni));
2678 ni->
id = (uint32_t)-1;
2680 return (uint32_t)-1;
2682 pthread_mutex_lock(&ictx->
ilock);
2685 pthread_mutex_unlock(&ictx->
ilock);
2688 memset(ni, 0,
sizeof(*ni));
2694 pthread_cond_wait(&ictx->
icond, &ictx->
ilock);
2696 int r = pthread_cond_timedwait(&ictx->
icond, &ictx->
ilock, ts);
2698 pthread_mutex_unlock(&ictx->
ilock);
2700 memset(ni, 0,
sizeof(*ni));
2704 inc_input_errors(ictx);
2706 memset(ni, 0,
sizeof(*ni));
2707 ni->
id = (uint32_t)-1;
2709 return (uint32_t)-1;
2715 memcpy(ni, &ictx->
inputs[ictx->
iread],
sizeof(*ni));
2724 bool sendsignal =
false;
2743 pthread_mutex_unlock(&ictx->
ilock);
2745 mark_pipe_ready(ictx->
ipipes);
2752 uint32_t ret = internal_get(nc->
tcache.
ictx, absdl, ni);
2759 for(
int v = 0 ;
v < vcount ; ++
v){
2761 if(u == (uint32_t)-1){
2778 uint32_t
r = internal_get(
n->tcache.ictx, absdl, ni);
2786 pthread_mutex_lock(&ictx->
clock);
2787 while(ictx->
cvalid == 0){
2789 if(tty_emit(u7, ictx->
ti->
ttyfd)){
2790 pthread_mutex_unlock(&ictx->
clock);
2795 pthread_cond_wait(&ictx->
ccond, &ictx->
clock);
2808 pthread_mutex_unlock(&ictx->
clock);
2815linesigs_disable(
tinfo* ti){
2817 logwarn(
"linedisc signals already disabled");
2823 struct termios tios;
2824 if(tcgetattr(ti->
ttyfd, &tios)){
2825 logerror(
"Couldn't preserve terminal state for %d (%s)", ti->
ttyfd, strerror(errno));
2828 tios.c_lflag &= ~ISIG;
2829 if(tcsetattr(ti->
ttyfd, TCSANOW, &tios)){
2830 logerror(
"Error disabling signals on %d (%s)", ti->
ttyfd, strerror(errno));
2835 if(!GetConsoleMode(ti->inhandle, &mode)){
2836 logerror(
"error acquiring input mode");
2839 mode &= ~ENABLE_PROCESSED_INPUT;
2840 if(!SetConsoleMode(ti->inhandle, mode)){
2841 logerror(
"error setting input mode");
2846 loginfo(
"disabled line discipline signals");
2851 return linesigs_disable(&nc->
tcache);
2855linesigs_enable(
tinfo* ti){
2857 logwarn(
"linedisc signals already enabled");
2863 struct termios tios;
2864 if(tcgetattr(ti->
ttyfd, &tios)){
2865 logerror(
"couldn't preserve terminal state for %d (%s)", ti->
ttyfd, strerror(errno));
2868 tios.c_lflag |= ISIG;
2869 if(tcsetattr(ti->
ttyfd, TCSANOW, &tios)){
2870 logerror(
"error disabling signals on %d (%s)", ti->
ttyfd, strerror(errno));
2875 if(!GetConsoleMode(ti->inhandle, &mode)){
2876 logerror(
"error acquiring input mode");
2879 mode |= ENABLE_PROCESSED_INPUT;
2880 if(!SetConsoleMode(ti->inhandle, mode)){
2881 logerror(
"error setting input mode");
2886 loginfo(
"enabled line discipline signals");
2893 return linesigs_enable(&
n->tcache);
2898 pthread_mutex_lock(&ictx->
ilock);
2900 pthread_cond_wait(&ictx->
icond, &ictx->
ilock);
2904 pthread_mutex_unlock(&ictx->
ilock);
2906 logpanic(
"aborting after automaton construction failure");
int walk_automaton(automaton *a, struct inputctx *ictx, unsigned candidate, ncinput *ni)
int inputctx_add_input_escape(automaton *a, const char *esc, uint32_t special, unsigned modifiers)
void input_free_esctrie(automaton *a)
int inputctx_add_cflow(automaton *a, const char *seq, triefunc fxn)
int(* triefunc)(struct inputctx *)
__attribute__((nonnull(1, 2))) static inline int egcpool_stash(egcpool *pool
int get_tty_fd(FILE *ttyfp)
int init_inputlayer(tinfo *ti, FILE *infp, int lmargin, int tmargin, int rmargin, int bmargin, ncsharedstats *stats, unsigned drain, int linesigs_enabled)
int ncinput_shovel(inputctx *ictx, const void *buf, int len)
uint32_t notcurses_get(notcurses *nc, const struct timespec *absdl, ncinput *ni)
struct initial_responses * inputlayer_get_responses(inputctx *ictx)
int notcurses_linesigs_enable(notcurses *n)
int notcurses_linesigs_disable(notcurses *nc)
int inputready_fd(const inputctx *ictx)
int notcurses_getvec(notcurses *n, const struct timespec *absdl, ncinput *ni, int vcount)
void sigwinch_handler(int signo)
int get_cursor_location(inputctx *ictx, const char *u7, unsigned *y, unsigned *x)
int stop_inputlayer(tinfo *ti)
uint32_t ncdirect_get(ncdirect *n, const struct timespec *absdl, ncinput *ni)
int set_fd_nonblocking(int fd, unsigned state, unsigned *oldstate)
#define logerror(fmt,...)
#define logtrace(fmt,...)
#define logdebug(fmt,...)
#define logverbose(fmt,...)
#define logpanic(fmt,...)
#define NCKEY_SCROLL_LOCK
#define NCKEY_PRINT_SCREEN
#define NCKEY_MOD_CAPSLOCK
int notcurses_ucs32_to_utf8(const uint32_t *ucs32, unsigned ucs32count, unsigned char *resultbuf, size_t buflen)
#define NCINPUT_MAX_EFF_TEXT_CODEPOINTS
struct ncvisual_options v
API int API int const nccell unsigned len
sig_atomic_t sigcont_seen_for_render
const unsigned char * matchstart
queried_terminals_e qterm
unsigned appsync_supported
uint32_t chans[NCPALETTESIZE]
queried_terminals_e qterm
unsigned stdio_blocking_save
void setup_alt_sig_stack(void)