mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-12 22:19:10 +00:00
Improve Windows Console I/O
- Blocking read operations on the Windows Console can now EINTR - Blocking read operations on Windows pipes now EINTR more reliably - setitimer() will no longer be inherited across fork() on Windows - It's now possible to use ECHO when the console is in raw mode - The ECHOCTL flag now works correctly on the Windows Console - The ICRNL flag now works correctly on the Windows Console - pread() and pwrite() will now raise ESPIPE on Windows - Opening /dev/tty on Windows is improved (untested) - Overlapped I/O is now implemented in a better way
This commit is contained in:
parent
decf216655
commit
33d280c8ba
34 changed files with 580 additions and 376 deletions
|
@ -29,57 +29,86 @@
|
|||
#include "libc/sysv/consts/termios.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int tcsetattr_nt(int ignored, int opt, const struct termios *tio) {
|
||||
int64_t in, out;
|
||||
bool32 ok, inok, outok;
|
||||
textwindows int tcsetattr_nt(int fd, int opt, const struct termios *tio) {
|
||||
bool32 ok;
|
||||
int ttymagic;
|
||||
int64_t hInput, hOutput;
|
||||
uint32_t inmode, outmode;
|
||||
inok = GetConsoleMode((in = __getfdhandleactual(0)), &inmode);
|
||||
outok = GetConsoleMode((out = __getfdhandleactual(1)), &outmode);
|
||||
if (inok | outok) {
|
||||
if (__isfdkind(fd, kFdConsole)) {
|
||||
// program manually opened /dev/tty in O_RDWR mode for cmd.exe
|
||||
hInput = g_fds.p[fd].handle;
|
||||
hOutput = g_fds.p[fd].extra;
|
||||
} else if (fd == 0 || fd == 1) {
|
||||
// otherwise just assume cmd.exe console stdio
|
||||
// there's no serial port support yet
|
||||
hInput = g_fds.p[0].handle;
|
||||
hOutput = g_fds.p[1].handle;
|
||||
fd = 0;
|
||||
} else {
|
||||
STRACE("tcsetattr(fd) must be 0, 1, or open'd /dev/tty");
|
||||
return enotty();
|
||||
}
|
||||
if (GetConsoleMode(hInput, &inmode) && GetConsoleMode(hOutput, &outmode)) {
|
||||
|
||||
if (inok) {
|
||||
if (opt == TCSAFLUSH) {
|
||||
FlushConsoleInputBuffer(in);
|
||||
if (opt == TCSAFLUSH) {
|
||||
FlushConsoleInputBuffer(hInput);
|
||||
}
|
||||
inmode &=
|
||||
~(kNtEnableLineInput | kNtEnableEchoInput | kNtEnableProcessedInput);
|
||||
inmode |= kNtEnableWindowInput;
|
||||
ttymagic = 0;
|
||||
if (tio->c_lflag & ICANON) {
|
||||
inmode |= kNtEnableLineInput;
|
||||
} else {
|
||||
ttymagic |= kFdTtyMunging;
|
||||
if (tio->c_cc[VMIN] != 1) {
|
||||
STRACE("tcsetattr c_cc[VMIN] must be 1 on Windows");
|
||||
return einval();
|
||||
}
|
||||
inmode &=
|
||||
~(kNtEnableLineInput | kNtEnableEchoInput | kNtEnableProcessedInput);
|
||||
inmode |= kNtEnableWindowInput;
|
||||
}
|
||||
if (!(tio->c_iflag & ICRNL)) {
|
||||
ttymagic |= kFdTtyNoCr2Nl;
|
||||
}
|
||||
if (!(tio->c_lflag & ECHOCTL)) {
|
||||
ttymagic |= kFdTtyEchoRaw;
|
||||
}
|
||||
if (tio->c_lflag & ECHO) {
|
||||
// "kNtEnableEchoInput can be used only if the
|
||||
// kNtEnableLineInput mode is also enabled." -MSDN
|
||||
if (tio->c_lflag & ICANON) {
|
||||
inmode |= kNtEnableLineInput;
|
||||
inmode |= kNtEnableEchoInput;
|
||||
} else {
|
||||
// If ECHO is enabled in raw mode, then read(0) needs to
|
||||
// magically write(1) to simulate echoing. This normally
|
||||
// visualizes control codes, e.g. \r → ^M unless ECHOCTL
|
||||
// hasn't been specified.
|
||||
ttymagic |= kFdTtyEchoing;
|
||||
}
|
||||
if (tio->c_lflag & ECHO) {
|
||||
/*
|
||||
* kNtEnableEchoInput can be used only if the ENABLE_LINE_INPUT mode
|
||||
* is also enabled. --Quoth MSDN
|
||||
*/
|
||||
inmode |= kNtEnableEchoInput | kNtEnableLineInput;
|
||||
}
|
||||
if (tio->c_lflag & (IEXTEN | ISIG)) {
|
||||
inmode |= kNtEnableProcessedInput;
|
||||
}
|
||||
if (IsAtLeastWindows10()) {
|
||||
inmode |= kNtEnableVirtualTerminalInput;
|
||||
}
|
||||
ok = SetConsoleMode(in, inmode);
|
||||
(void)ok;
|
||||
NTTRACE("SetConsoleMode(%p, %s) → %hhhd", in,
|
||||
DescribeNtConsoleInFlags(inmode), ok);
|
||||
}
|
||||
if (tio->c_lflag & (IEXTEN | ISIG)) {
|
||||
inmode |= kNtEnableProcessedInput;
|
||||
}
|
||||
if (IsAtLeastWindows10()) {
|
||||
inmode |= kNtEnableVirtualTerminalInput;
|
||||
}
|
||||
g_fds.p[fd].ttymagic = ttymagic;
|
||||
ok = SetConsoleMode(hInput, inmode);
|
||||
(void)ok;
|
||||
NTTRACE("SetConsoleMode(%p, %s) → %hhhd", hInput,
|
||||
DescribeNtConsoleInFlags(inmode), ok);
|
||||
|
||||
if (outok) {
|
||||
outmode &= ~(kNtDisableNewlineAutoReturn);
|
||||
outmode |= kNtEnableProcessedOutput;
|
||||
if (!(tio->c_oflag & ONLCR)) {
|
||||
outmode |= kNtDisableNewlineAutoReturn;
|
||||
}
|
||||
if (IsAtLeastWindows10()) {
|
||||
outmode |= kNtEnableVirtualTerminalProcessing;
|
||||
}
|
||||
ok = SetConsoleMode(out, outmode);
|
||||
(void)ok;
|
||||
NTTRACE("SetConsoleMode(%p, %s) → %hhhd", out,
|
||||
DescribeNtConsoleOutFlags(outmode), ok);
|
||||
outmode &= ~kNtDisableNewlineAutoReturn;
|
||||
outmode |= kNtEnableProcessedOutput;
|
||||
if (!(tio->c_oflag & ONLCR)) {
|
||||
outmode |= kNtDisableNewlineAutoReturn;
|
||||
}
|
||||
if (IsAtLeastWindows10()) {
|
||||
outmode |= kNtEnableVirtualTerminalProcessing;
|
||||
}
|
||||
ok = SetConsoleMode(hOutput, outmode);
|
||||
(void)ok;
|
||||
NTTRACE("SetConsoleMode(%p, %s) → %hhhd", hOutput,
|
||||
DescribeNtConsoleOutFlags(outmode), ok);
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue