Cygwin: console: Fix handling of Ctrl-S in Win7.

- If ENABLE_LINE_INPUT is set, Ctrl-S is handled by Windows if the
  OS is Windows 7. This conflicts with Ctrl-S handling in cygwin
  console code. This patch unsets ENABLE_LINE_INPUT flag in cygwin
  and set it when native app is executed.
This commit is contained in:
Takashi Yano via Cygwin-patches 2021-02-18 18:01:28 +09:00 committed by Corinna Vinschen
parent 2b9219b4a5
commit 48285aa36c
5 changed files with 98 additions and 246 deletions

View File

@ -2135,11 +2135,9 @@ private:
const unsigned char *write_normal (unsigned const char*, unsigned const char *); const unsigned char *write_normal (unsigned const char*, unsigned const char *);
void char_command (char); void char_command (char);
bool set_raw_win32_keyboard_mode (bool); bool set_raw_win32_keyboard_mode (bool);
int output_tcsetattr (int a, const struct termios *t);
/* Input calls */ /* Input calls */
int igncr_enabled (); int igncr_enabled ();
int input_tcsetattr (int a, const struct termios *t);
void set_cursor_maybe (); void set_cursor_maybe ();
static bool create_invisible_console (HWINSTA); static bool create_invisible_console (HWINSTA);
static bool create_invisible_console_workaround (bool force); static bool create_invisible_console_workaround (bool force);
@ -2196,7 +2194,6 @@ private:
void fixup_after_exec () {fixup_after_fork_exec (true);} void fixup_after_exec () {fixup_after_fork_exec (true);}
void fixup_after_fork (HANDLE) {fixup_after_fork_exec (false);} void fixup_after_fork (HANDLE) {fixup_after_fork_exec (false);}
void set_close_on_exec (bool val); void set_close_on_exec (bool val);
void set_input_state ();
bool send_winch_maybe (); bool send_winch_maybe ();
void setup (); void setup ();
bool set_unit (); bool set_unit ();
@ -2245,8 +2242,10 @@ private:
void get_duplicated_handle_set (handle_set_t *p); void get_duplicated_handle_set (handle_set_t *p);
static void close_handle_set (handle_set_t *p); static void close_handle_set (handle_set_t *p);
static void request_xterm_mode_input (bool, const handle_set_t *p); static void set_input_mode (tty::cons_mode m, const termios *t,
static void request_xterm_mode_output (bool, const handle_set_t *p); const handle_set_t *p);
static void set_output_mode (tty::cons_mode m, const termios *t,
const handle_set_t *p);
static void cons_master_thread (handle_set_t *p, tty *ttyp); static void cons_master_thread (handle_set_t *p, tty *ttyp);

View File

@ -299,8 +299,8 @@ fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp)
{ /* Fix tab position */ { /* Fix tab position */
/* Re-setting ENABLE_VIRTUAL_TERMINAL_PROCESSING /* Re-setting ENABLE_VIRTUAL_TERMINAL_PROCESSING
fixes the tab position. */ fixes the tab position. */
request_xterm_mode_output (false, p); set_output_mode (tty::restore, &ti, p);
request_xterm_mode_output (true, p); set_input_mode (tty::cygwin, &ti, p);
} }
ttyp->kill_pgrp (SIGWINCH); ttyp->kill_pgrp (SIGWINCH);
} }
@ -446,64 +446,72 @@ fhandler_console::rabuflen ()
return con_ra.rabuflen; return con_ra.rabuflen;
} }
/* The function request_xterm_mode_{in,out}put() should be static so that /* The function set_{in,out}put_mode() should be static so that they
they can be called even after the fhandler_console instance is deleted. */ can be called even after the fhandler_console instance is deleted. */
void void
fhandler_console::request_xterm_mode_input (bool req, const handle_set_t *p) fhandler_console::set_input_mode (tty::cons_mode m, const termios *t,
const handle_set_t *p)
{ {
if (con_is_legacy) DWORD flags = 0, oflags;
return;
WaitForSingleObject (p->input_mutex, INFINITE); WaitForSingleObject (p->input_mutex, INFINITE);
DWORD dwMode; GetConsoleMode (p->input_handle, &oflags);
GetConsoleMode (p->input_handle, &dwMode); switch (m)
if (req)
{ {
if (!(dwMode & ENABLE_VIRTUAL_TERMINAL_INPUT)) case tty::restore:
{ flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
dwMode |= ENABLE_VIRTUAL_TERMINAL_INPUT; break;
SetConsoleMode (p->input_handle, dwMode); case tty::cygwin:
if (con.cursor_key_app_mode) /* Restore DECCKM */ flags = ENABLE_WINDOW_INPUT;
{ if (wincap.has_con_24bit_colors () && !con_is_legacy)
request_xterm_mode_output (true, p); flags |= ENABLE_VIRTUAL_TERMINAL_INPUT;
WriteConsoleW (p->output_handle, L"\033[?1h", 5, NULL, 0); else
} flags |= ENABLE_MOUSE_INPUT;
} break;
case tty::native:
if (t->c_lflag & ECHO)
flags |= ENABLE_ECHO_INPUT;
if (t->c_lflag & ICANON)
flags |= ENABLE_LINE_INPUT;
if (flags & ENABLE_ECHO_INPUT && !(flags & ENABLE_LINE_INPUT))
/* This is illegal, so turn off the echo here, and fake it
when we read the characters */
flags &= ~ENABLE_ECHO_INPUT;
if ((t->c_lflag & ISIG) && !(t->c_iflag & IGNBRK))
flags |= ENABLE_PROCESSED_INPUT;
break;
} }
else SetConsoleMode (p->input_handle, flags);
{ if (!(oflags & ENABLE_VIRTUAL_TERMINAL_INPUT)
if (dwMode & ENABLE_VIRTUAL_TERMINAL_INPUT) && (flags & ENABLE_VIRTUAL_TERMINAL_INPUT)
{ && con.cursor_key_app_mode)
dwMode &= ~ENABLE_VIRTUAL_TERMINAL_INPUT; { /* Restore DECCKM */
SetConsoleMode (p->input_handle, dwMode); set_output_mode (tty::cygwin, t, p);
} WriteConsoleW (p->output_handle, L"\033[?1h", 5, NULL, 0);
} }
ReleaseMutex (p->input_mutex); ReleaseMutex (p->input_mutex);
} }
void void
fhandler_console::request_xterm_mode_output (bool req, const handle_set_t *p) fhandler_console::set_output_mode (tty::cons_mode m, const termios *t,
const handle_set_t *p)
{ {
if (con_is_legacy) DWORD flags = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
return;
WaitForSingleObject (p->output_mutex, INFINITE); WaitForSingleObject (p->output_mutex, INFINITE);
DWORD dwMode; switch (m)
GetConsoleMode (p->output_handle, &dwMode);
if (req)
{ {
if (!(dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)) case tty::restore:
{ break;
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; case tty::cygwin:
SetConsoleMode (p->output_handle, dwMode); if (wincap.has_con_24bit_colors () && !con_is_legacy)
} flags |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
} fallthrough;
else case tty::native:
{ if (wincap.has_con_24bit_colors () && !con_is_legacy
if (dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) && (!(t->c_oflag & OPOST) || !(t->c_oflag & ONLCR)))
{ flags |= DISABLE_NEWLINE_AUTO_RETURN;
dwMode &= ~ENABLE_VIRTUAL_TERMINAL_PROCESSING; break;
SetConsoleMode (p->output_handle, dwMode);
}
} }
SetConsoleMode (p->output_handle, flags);
ReleaseMutex (p->output_mutex); ReleaseMutex (p->output_mutex);
} }
@ -616,8 +624,8 @@ fhandler_console::fix_tab_position (void)
{ {
/* Re-setting ENABLE_VIRTUAL_TERMINAL_PROCESSING /* Re-setting ENABLE_VIRTUAL_TERMINAL_PROCESSING
fixes the tab position. */ fixes the tab position. */
request_xterm_mode_output (false, &handle_set); set_output_mode (tty::restore, &get_ttyp ()->ti, &handle_set);
request_xterm_mode_output (true, &handle_set); set_output_mode (tty::cygwin, &get_ttyp ()->ti, &handle_set);
} }
bool bool
@ -678,11 +686,7 @@ fhandler_console::read (void *pv, size_t& buflen)
DWORD timeout = is_nonblocking () ? 0 : INFINITE; DWORD timeout = is_nonblocking () ? 0 : INFINITE;
set_input_state (); set_input_mode (tty::cygwin, &get_ttyp ()->ti, &handle_set);
/* if system has 24 bit color capability, use xterm compatible mode. */
if (wincap.has_con_24bit_colors ())
request_xterm_mode_input (true, &handle_set);
while (!input_ready && !get_cons_readahead_valid ()) while (!input_ready && !get_cons_readahead_valid ())
{ {
@ -1165,13 +1169,6 @@ out:
return stat; return stat;
} }
void
fhandler_console::set_input_state ()
{
if (get_ttyp ()->rstcons ())
input_tcsetattr (0, &get_ttyp ()->ti);
}
bool bool
dev_console::fillin (HANDLE h) dev_console::fillin (HANDLE h)
{ {
@ -1313,7 +1310,6 @@ fhandler_console::open (int flags, mode_t)
con.set_default_attr (); con.set_default_attr ();
} }
get_ttyp ()->rstcons (false);
set_open_status (); set_open_status ();
if (myself->pid == con.owner && wincap.has_con_24bit_colors ()) if (myself->pid == con.owner && wincap.has_con_24bit_colors ())
@ -1338,12 +1334,8 @@ fhandler_console::open (int flags, mode_t)
setenv ("TERM", "cygwin", 1); setenv ("TERM", "cygwin", 1);
} }
DWORD cflags; set_input_mode (tty::cygwin, &get_ttyp ()->ti, &handle_set);
if (GetConsoleMode (get_handle (), &cflags)) set_output_mode (tty::cygwin, &get_ttyp ()->ti, &handle_set);
SetConsoleMode (get_handle (), ENABLE_WINDOW_INPUT
| ((wincap.has_con_24bit_colors () && !con_is_legacy) ?
0 : ENABLE_MOUSE_INPUT)
| cflags);
debug_printf ("opened conin$ %p, conout$ %p", get_handle (), debug_printf ("opened conin$ %p, conout$ %p", get_handle (),
get_output_handle ()); get_output_handle ());
@ -1376,7 +1368,7 @@ fhandler_console::close ()
acquire_output_mutex (INFINITE); acquire_output_mutex (INFINITE);
if (shared_console_info && wincap.has_con_24bit_colors ()) if (shared_console_info)
{ {
/* Restore console mode if this is the last closure. */ /* Restore console mode if this is the last closure. */
OBJECT_BASIC_INFORMATION obi; OBJECT_BASIC_INFORMATION obi;
@ -1386,8 +1378,8 @@ fhandler_console::close ()
if ((NT_SUCCESS (status) && obi.HandleCount == 1) if ((NT_SUCCESS (status) && obi.HandleCount == 1)
|| myself->pid == con.owner) || myself->pid == con.owner)
{ {
request_xterm_mode_output (false, &handle_set); set_output_mode (tty::restore, &get_ttyp ()->ti, &handle_set);
request_xterm_mode_input (false, &handle_set); set_input_mode (tty::restore, &get_ttyp ()->ti, &handle_set);
} }
} }
@ -1561,154 +1553,19 @@ fhandler_console::tcflush (int queue)
return res; return res;
} }
int
fhandler_console::output_tcsetattr (int, struct termios const *t)
{
/* All the output bits we can ignore */
acquire_output_mutex (INFINITE);
DWORD flags = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
DWORD oflags;
acquire_attach_mutex (INFINITE);
GetConsoleMode (get_output_handle (), &oflags);
if (wincap.has_con_24bit_colors () && !con_is_legacy
&& (oflags & ENABLE_VIRTUAL_TERMINAL_PROCESSING))
flags |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
int res = SetConsoleMode (get_output_handle (), flags) ? 0 : -1;
release_attach_mutex ();
if (res)
__seterrno_from_win_error (GetLastError ());
release_output_mutex ();
syscall_printf ("%d = tcsetattr(,%p) (ENABLE FLAGS %y) (lflag %y oflag %y)",
res, t, flags, t->c_lflag, t->c_oflag);
return res;
}
int
fhandler_console::input_tcsetattr (int, struct termios const *t)
{
/* Ignore the optional_actions stuff, since all output is emitted
instantly */
acquire_input_mutex (INFINITE);
DWORD oflags;
acquire_attach_mutex (INFINITE);
if (!GetConsoleMode (get_handle (), &oflags))
oflags = 0;
DWORD flags = 0;
#if 0
/* Enable/disable LF -> CRLF conversions */
rbinary ((t->c_iflag & INLCR) ? false : true);
#endif
/* There's some disparity between what we need and what's
available. We've got ECHO and ICANON, they've
got ENABLE_ECHO_INPUT and ENABLE_LINE_INPUT. */
termios_printf ("this %p, get_ttyp () %p, t %p", this, get_ttyp (), t);
get_ttyp ()->ti = *t;
if (t->c_lflag & ECHO)
{
flags |= ENABLE_ECHO_INPUT;
}
if (t->c_lflag & ICANON)
{
flags |= ENABLE_LINE_INPUT;
}
if (flags & ENABLE_ECHO_INPUT
&& !(flags & ENABLE_LINE_INPUT))
{
/* This is illegal, so turn off the echo here, and fake it
when we read the characters */
flags &= ~ENABLE_ECHO_INPUT;
}
if ((t->c_lflag & ISIG) && !(t->c_iflag & IGNBRK))
{
flags |= ENABLE_PROCESSED_INPUT;
}
flags |= ENABLE_WINDOW_INPUT |
((wincap.has_con_24bit_colors () && !con_is_legacy) ?
0 : ENABLE_MOUSE_INPUT);
if (wincap.has_con_24bit_colors () && !con_is_legacy
&& (oflags & ENABLE_VIRTUAL_TERMINAL_INPUT))
flags |= ENABLE_VIRTUAL_TERMINAL_INPUT;
int res;
if (flags == oflags)
res = 0;
else
{
res = SetConsoleMode (get_handle (), flags) ? 0 : -1;
if (res < 0)
__seterrno ();
syscall_printf ("%d = tcsetattr(,%p) enable flags %y, c_lflag %y iflag %y",
res, t, flags, t->c_lflag, t->c_iflag);
}
release_attach_mutex ();
get_ttyp ()->rstcons (false);
release_input_mutex ();
return res;
}
int int
fhandler_console::tcsetattr (int a, struct termios const *t) fhandler_console::tcsetattr (int a, struct termios const *t)
{ {
int res = output_tcsetattr (a, t); get_ttyp ()->ti = *t;
if (res != 0) return 0;
return res;
return input_tcsetattr (a, t);
} }
int int
fhandler_console::tcgetattr (struct termios *t) fhandler_console::tcgetattr (struct termios *t)
{ {
int res;
*t = get_ttyp ()->ti; *t = get_ttyp ()->ti;
t->c_cflag |= CS8; t->c_cflag |= CS8;
return 0;
DWORD flags;
acquire_attach_mutex (INFINITE);
if (!GetConsoleMode (get_handle (), &flags))
{
__seterrno ();
res = -1;
}
else
{
if (flags & ENABLE_ECHO_INPUT)
t->c_lflag |= ECHO;
if (flags & ENABLE_LINE_INPUT)
t->c_lflag |= ICANON;
if (flags & ENABLE_PROCESSED_INPUT)
t->c_lflag |= ISIG;
else
t->c_iflag |= IGNBRK;
/* What about ENABLE_WINDOW_INPUT
and ENABLE_MOUSE_INPUT ? */
/* All the output bits we can ignore */
res = 0;
}
release_attach_mutex ();
syscall_printf ("%d = tcgetattr(%p) enable flags %y, t->lflag %y, t->iflag %y",
res, t, flags, t->c_lflag, t->c_iflag);
return res;
} }
fhandler_console::fhandler_console (fh_devices unit) : fhandler_console::fhandler_console (fh_devices unit) :
@ -3205,22 +3062,10 @@ fhandler_console::write (const void *vsrc, size_t len)
acquire_attach_mutex (INFINITE); acquire_attach_mutex (INFINITE);
push_process_state process_state (PID_TTYOU); push_process_state process_state (PID_TTYOU);
acquire_output_mutex (INFINITE);
/* If system has 24 bit color capability, use xterm compatible mode. */ set_output_mode (tty::cygwin, &get_ttyp ()->ti, &handle_set);
if (wincap.has_con_24bit_colors ())
request_xterm_mode_output (true, &handle_set); acquire_output_mutex (INFINITE);
if (wincap.has_con_24bit_colors () && !con_is_legacy)
{
DWORD dwMode;
GetConsoleMode (get_output_handle (), &dwMode);
if (!(get_ttyp ()->ti.c_oflag & OPOST) ||
!(get_ttyp ()->ti.c_oflag & ONLCR))
dwMode |= DISABLE_NEWLINE_AUTO_RETURN;
else
dwMode &= ~DISABLE_NEWLINE_AUTO_RETURN;
SetConsoleMode (get_output_handle (), dwMode);
}
/* Run and check for ansi sequences */ /* Run and check for ansi sequences */
unsigned const char *src = (unsigned char *) vsrc; unsigned const char *src = (unsigned char *) vsrc;

View File

@ -1147,8 +1147,8 @@ static int
console_startup (select_record *me, select_stuff *stuff) console_startup (select_record *me, select_stuff *stuff)
{ {
fhandler_console *fh = (fhandler_console *) me->fh; fhandler_console *fh = (fhandler_console *) me->fh;
if (wincap.has_con_24bit_colors ()) fhandler_console::set_input_mode (tty::cygwin, &((tty *)fh->tc ())->ti,
fhandler_console::request_xterm_mode_input (true, fh->get_handle_set ()); fh->get_handle_set ());
select_console_info *ci = stuff->device_specific_console; select_console_info *ci = stuff->device_specific_console;
if (ci->start) if (ci->start)

View File

@ -607,6 +607,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
fhandler_pty_slave *ptys_primary = NULL; fhandler_pty_slave *ptys_primary = NULL;
fhandler_console *cons_native = NULL; fhandler_console *cons_native = NULL;
termios *cons_ti = NULL;
for (int i = 0; i < 3; i ++) for (int i = 0; i < 3; i ++)
{ {
const int chk_order[] = {1, 0, 2}; const int chk_order[] = {1, 0, 2};
@ -621,16 +622,19 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
else if (fh && fh->get_major () == DEV_CONS_MAJOR) else if (fh && fh->get_major () == DEV_CONS_MAJOR)
{ {
fhandler_console *cons = (fhandler_console *) fh; fhandler_console *cons = (fhandler_console *) fh;
if (wincap.has_con_24bit_colors () && !iscygwin ()) if (!iscygwin ())
{ {
if (cons_native == NULL) if (cons_native == NULL)
cons_native = cons; {
cons_native = cons;
cons_ti = &((tty *)cons->tc ())->ti;
}
if (fd == 0) if (fd == 0)
fhandler_console::request_xterm_mode_input (false, fhandler_console::set_input_mode (tty::native,
cons->get_handle_set ()); cons_ti, cons->get_handle_set ());
else if (fd == 1 || fd == 2) else if (fd == 1 || fd == 2)
fhandler_console::request_xterm_mode_output (false, fhandler_console::set_output_mode (tty::native,
cons->get_handle_set ()); cons_ti, cons->get_handle_set ());
} }
} }
} }
@ -996,10 +1000,10 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
} }
if (cons_native) if (cons_native)
{ {
fhandler_console::request_xterm_mode_output (true, fhandler_console::set_output_mode (tty::cygwin, cons_ti,
&cons_handle_set); &cons_handle_set);
fhandler_console::request_xterm_mode_input (true, fhandler_console::set_input_mode (tty::cygwin, cons_ti,
&cons_handle_set); &cons_handle_set);
fhandler_console::close_handle_set (&cons_handle_set); fhandler_console::close_handle_set (&cons_handle_set);
} }
myself.exit (EXITCODE_NOSET); myself.exit (EXITCODE_NOSET);
@ -1031,10 +1035,10 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
} }
if (cons_native) if (cons_native)
{ {
fhandler_console::request_xterm_mode_output (true, fhandler_console::set_output_mode (tty::cygwin, cons_ti,
&cons_handle_set); &cons_handle_set);
fhandler_console::request_xterm_mode_input (true, fhandler_console::set_input_mode (tty::cygwin, cons_ti,
&cons_handle_set); &cons_handle_set);
fhandler_console::close_handle_set (&cons_handle_set); fhandler_console::close_handle_set (&cons_handle_set);
} }
break; break;

View File

@ -39,7 +39,6 @@ class tty_min
struct status_flags struct status_flags
{ {
unsigned initialized : 1; /* Set if tty is initialized */ unsigned initialized : 1; /* Set if tty is initialized */
unsigned rstcons : 1; /* Set if console needs to be set to "non-cooked" */
} status; } status;
public: public:
@ -51,7 +50,6 @@ public:
int last_sig; int last_sig;
IMPLEMENT_STATUS_FLAG (bool, initialized) IMPLEMENT_STATUS_FLAG (bool, initialized)
IMPLEMENT_STATUS_FLAG (bool, rstcons)
struct termios ti; struct termios ti;
struct winsize winsize; struct winsize winsize;
@ -97,6 +95,12 @@ public:
to_cyg, to_cyg,
to_nat to_nat
}; };
enum cons_mode
{
restore, /* For restoring when exit from cygwin. */
cygwin, /* For cygwin apps */
native /* For native apps executed from cygwin. */
};
private: private:
HANDLE _from_master; HANDLE _from_master;