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

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/console.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/state.internal.h"
@ -26,6 +27,7 @@
#include "libc/intrin/strace.internal.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/errors.h"
#include "libc/nt/files.h"
@ -47,8 +49,6 @@
#ifdef __x86_64__
__static_yoink("WinMainStdin");
/*
* Polls on the New Technology.
*
@ -59,8 +59,8 @@ __static_yoink("WinMainStdin");
textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
const sigset_t *sigmask) {
bool ok;
uint32_t avail;
sigset_t oldmask;
uint32_t avail, cm;
struct sys_pollfd_nt pipefds[8];
struct sys_pollfd_nt sockfds[64];
int pipeindices[ARRAYLEN(pipefds)];
@ -98,7 +98,7 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
}
} else if (pn < ARRAYLEN(pipefds)) {
pipeindices[pn] = i;
pipefds[pn].handle = __resolve_stdin_handle(g_fds.p[fds[i].fd].handle);
pipefds[pn].handle = g_fds.p[fds[i].fd].handle;
pipefds[pn].events = 0;
pipefds[pn].revents = 0;
switch (g_fds.p[fds[i].fd].flags & O_ACCMODE) {
@ -151,6 +151,19 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms,
} else {
pipefds[i].revents |= POLLERR;
}
} else if (GetConsoleMode(pipefds[i].handle, &cm)) {
int e = errno;
avail = CountConsoleInputBytes(pipefds[i].handle);
if (avail > 0) {
pipefds[i].revents |= POLLIN;
} else if (avail == -1u) {
if (errno == ENODATA) {
pipefds[i].revents |= POLLIN;
} else {
pipefds[i].revents |= POLLERR;
}
errno = e;
}
} else {
// we have no way of polling if a non-socket is readable yet
// therefore we assume that if it can happen it shall happen