Rewrite Windows console input handling

This change removes our use of ENABLE_VIRTUAL_TERMINAL_INPUT (which
isn't very good) in favor of having read() translate Windows Console
input events to ANSI/XTERM sequences by hand. This makes it possible to
capture important keystrokes (e.g. ctrl-space) that weren't possible
before. Most importantly this change also removes the stdin/sigwinch
worker threads, which never really worked that well. Interactive TTY
sessions will now work reliably when a Cosmo process spawns or forks
another Cosmo process, e.g. unbourne.com launching emacs.com.
This commit is contained in:
Justine Tunney 2023-09-19 11:42:38 -07:00
parent ececec4c94
commit d6c2830850
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
27 changed files with 635 additions and 464 deletions

View file

@ -23,9 +23,12 @@
#include "libc/calls/struct/iovec.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/errno.h"
#include "libc/intrin/nomultics.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h"
#include "libc/macros.internal.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/consolemodeflags.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/enum/wait.h"
#include "libc/nt/errors.h"
@ -46,6 +49,13 @@
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
static bool IsMouseModeCommand(int x) {
return x == 1000 || // SET_VT200_MOUSE
x == 1002 || // SET_BTN_EVENT_MOUSE
x == 1006 || // SET_SGR_EXT_MODE_MOUSE
x == 1015; // SET_URXVT_EXT_MODE_MOUSE
}
static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size,
ssize_t offset) {
@ -81,6 +91,76 @@ static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size,
offset = f->pointer;
}
// To use the tty mouse events feature:
// - write(1, "\e[?1000;1002;1015;1006h") to enable
// - write(1, "\e[?1000;1002;1015;1006l") to disable
// See o//examples/ttyinfo.com and o//tool/viz/life.com
uint32_t cm;
if (!seekable && (f->kind == kFdConsole || GetConsoleMode(handle, &cm))) {
int64_t hin;
if (f->kind == kFdConsole) {
hin = f->handle;
} else {
hin = GetStdHandle(kNtStdInputHandle);
}
if (GetConsoleMode(hin, &cm)) {
int t = 0;
unsigned x;
bool m = false;
char *p = data;
uint32_t cm2 = cm;
for (int i = 0; i < size; ++i) {
switch (t) {
case 0:
if (p[i] == 033) {
t = 1;
}
break;
case 1:
if (p[i] == '[') {
t = 2;
} else {
t = 0;
}
break;
case 2:
if (p[i] == '?') {
t = 3;
x = 0;
} else {
t = 0;
}
break;
case 3:
if ('0' <= p[i] && p[i] <= '9') {
x *= 10;
x += p[i] - '0';
} else if (p[i] == ';') {
m |= IsMouseModeCommand(x);
x = 0;
} else {
m |= IsMouseModeCommand(x);
if (p[i] == 'h') {
__ttymagic |= kFdTtyXtMouse;
cm2 |= kNtEnableMouseInput;
cm2 &= kNtEnableQuickEditMode; // precludes mouse events
} else if (p[i] == 'l') {
__ttymagic &= ~kFdTtyXtMouse;
cm2 |= kNtEnableQuickEditMode; // disables mouse too
}
t = 0;
}
break;
default:
__builtin_unreachable();
}
}
if (cm2 != cm) {
SetConsoleMode(hin, cm2);
}
}
}
struct NtOverlapped overlap = {.hEvent = CreateEvent(0, 0, 0, 0),
.Pointer = offset};
ok = WriteFile(handle, data, size, 0, &overlap);
@ -143,7 +223,6 @@ static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size,
_weaken(__sig_raise)(SIGPIPE, SI_KERNEL);
return epipe();
} else {
STRACE("broken pipe");
TerminateThisProcess(SIGPIPE);
}
case kNtErrorAccessDenied: // write doesn't return EACCESS