diff --git a/dlls/kernel32/console.c b/dlls/kernel32/console.c index 9ac7018..5cc5ae1 100644 --- a/dlls/kernel32/console.c +++ b/dlls/kernel32/console.c @@ -54,6 +54,9 @@ #include "excpt.h" #include "console_private.h" #include "kernel_private.h" +#ifdef HAVE_TERMIOS_H +#include +#endif WINE_DEFAULT_DEBUG_CHANNEL(console); @@ -146,6 +149,78 @@ static BOOL get_console_mode(HANDLE conin, DWORD* mode, BOOL* bare) return ret; } +static struct termios S_termios; +static BOOL S_termios_raw /* = FALSE */; + +static int get_console_bare_fd(HANDLE hin) +{ + BOOL is_bare; + int fd; + + if (get_console_mode(hin, NULL, &is_bare) && is_bare && + wine_server_handle_to_fd(hin, 0, &fd, NULL) == 0 /*STATUS_SUCCESS*/) + return fd; + return -1; +} + +static BOOL save_console_mode(HANDLE hin) +{ + int fd; + BOOL ret; + + if ((fd = get_console_bare_fd(hin)) == -1) return FALSE; + ret = tcgetattr(fd, &S_termios) >= 0; + close(fd); + return ret; +} + +static BOOL put_console_into_raw_mode(HANDLE hin) +{ + int fd; + + if ((fd = get_console_bare_fd(hin)) == -1) return FALSE; + + RtlEnterCriticalSection(&CONSOLE_CritSect); + if (!S_termios_raw) + { + struct termios term = S_termios; + + term.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN); + term.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + term.c_cflag &= ~(CSIZE | PARENB); + term.c_cflag |= CS8; + /* FIXME: we should actually disable output processing here + * and let kernel32/console.c do the job (with support of enable/disable of + * processed output) + */ + /* term.c_oflag &= ~(OPOST); */ + term.c_cc[VMIN] = 1; + term.c_cc[VTIME] = 0; + S_termios_raw = tcsetattr(fd, TCSANOW, &term) >= 0; + } + RtlLeaveCriticalSection(&CONSOLE_CritSect); + + close(fd); + return S_termios_raw; +} + +/* put back the console in cooked mode iff we're the process which created the bare console + * we don't test if thie process has set the console in raw mode as it could be one of its + * child who did it + */ +static BOOL put_console_into_cooked_mode(HANDLE hin) +{ + int fd; + BOOL ret; + + if (RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle != KERNEL32_CONSOLE_SHELL) + return TRUE; + if ((fd = get_console_bare_fd(hin)) == -1) return FALSE; + ret = tcsetattr(fd, TCSANOW, &S_termios) >= 0; + close(fd); + return ret; +} + /****************************************************************************** * GetConsoleWindow [KERNEL32.@] Get hwnd of the console window. * @@ -1080,6 +1155,7 @@ static enum read_console_input_return read_console_input(HANDLE handle, PINPUT_R if (bare) { + put_console_into_raw_mode(handle); if (WaitForSingleObject(GetConsoleInputWaitHandle(), 0) != WAIT_OBJECT_0) { ret = bare_console_fetch_input(handle, timeout); @@ -2893,6 +2969,7 @@ DWORD WINAPI GetConsoleProcessList(LPDWORD processlist, DWORD processcount) BOOL CONSOLE_Init(RTL_USER_PROCESS_PARAMETERS *params) { + memset(&S_termios, 0, sizeof(S_termios)); if (params->ConsoleHandle == KERNEL32_CONSOLE_SHELL) { HANDLE conin; @@ -2956,7 +3033,10 @@ BOOL CONSOLE_Init(RTL_USER_PROCESS_PARAMETERS *params) if (!params->hStdInput) params->hStdInput = INVALID_HANDLE_VALUE; else if (VerifyConsoleIoHandle(console_handle_map(params->hStdInput))) + { params->hStdInput = console_handle_map(params->hStdInput); + save_console_mode(params->hStdInput); + } if (!params->hStdOutput) params->hStdOutput = INVALID_HANDLE_VALUE; @@ -2970,3 +3050,10 @@ BOOL CONSOLE_Init(RTL_USER_PROCESS_PARAMETERS *params) return TRUE; } + +BOOL CONSOLE_Exit(void) +{ + /* the console is in raw mode, put it back in cooked mode */ + put_console_into_cooked_mode(GetStdHandle(STD_INPUT_HANDLE)); + return TRUE; +} diff --git a/dlls/kernel32/kernel_main.c b/dlls/kernel32/kernel_main.c index 41647dd..42d038e 100644 --- a/dlls/kernel32/kernel_main.c +++ b/dlls/kernel32/kernel_main.c @@ -138,6 +138,7 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) return process_attach( hinst ); case DLL_PROCESS_DETACH: WritePrivateProfileSectionW( NULL, NULL, NULL ); + CONSOLE_Exit(); break; } return TRUE; diff --git a/dlls/kernel32/kernel_private.h b/dlls/kernel32/kernel_private.h index f741a92..f180e7d 100644 --- a/dlls/kernel32/kernel_private.h +++ b/dlls/kernel32/kernel_private.h @@ -29,6 +29,7 @@ HANDLE WINAPI DuplicateConsoleHandle(HANDLE, DWORD, BOOL, DWORD); BOOL WINAPI CloseConsoleHandle(HANDLE handle); HANDLE WINAPI GetConsoleInputWaitHandle(void); BOOL CONSOLE_Init(RTL_USER_PROCESS_PARAMETERS *params); +BOOL CONSOLE_Exit(void); static inline BOOL is_console_handle(HANDLE h) { diff --git a/server/console.c b/server/console.c index 2ca6bd4..6616bd2 100644 --- a/server/console.c +++ b/server/console.c @@ -28,9 +28,6 @@ #include #include #include -#ifdef HAVE_TERMIOS_H -#include -#endif #include "ntstatus.h" #define WIN32_NO_STATUS @@ -66,7 +63,6 @@ struct console_input user_handle_t win; /* window handle if backend supports it */ struct event *event; /* event to wait on for input queue */ struct fd *fd; /* for bare console, attached input fd */ - struct termios termios; /* for bare console, saved termio info */ }; static void console_input_dump( struct object *obj, int verbose ); @@ -328,38 +324,12 @@ static struct object *create_console_input( struct thread* renderer, int fd ) } if (fd != -1) /* bare console */ { - struct termios term; - if (!(console_input->fd = create_anonymous_fd( &console_fd_ops, fd, &console_input->obj, FILE_SYNCHRONOUS_IO_NONALERT ))) { release_object( console_input ); return NULL; } - if (tcgetattr(fd, &term) < 0) - { - release_object( console_input ); - set_error( STATUS_INVALID_HANDLE ); - return NULL; - } - console_input->termios = term; - term.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN); - term.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); - term.c_cflag &= ~(CSIZE | PARENB); - term.c_cflag |= CS8; - /* FIXME: we should actually disable output processing here - * and let kernel32/console.c do the job (with support of enable/disable of - * processed output) - */ - /* term.c_oflag &= ~(OPOST); */ - term.c_cc[VMIN] = 1; - term.c_cc[VTIME] = 0; - if (tcsetattr(fd, TCSANOW, &term) < 0) - { - release_object( console_input ); - set_error( STATUS_INVALID_HANDLE ); - return NULL; - } allow_fd_caching( console_input->fd ); } @@ -1129,10 +1099,7 @@ static void console_input_destroy( struct object *obj ) } release_object( console_in->event ); if (console_in->fd) - { - tcsetattr(get_unix_fd(console_in->fd), TCSANOW, &console_in->termios); release_object( console_in->fd ); - } for (i = 0; i < console_in->history_size; i++) free( console_in->history[i] );