win,tty: fix read stop in line mode
Closing the handle does not make ReadConsoleW exit reliably on Windows 7 and above. Thus, after switching from line to raw mode, keypresses were held until enter was pressed. This makes ReadConsoleW exit by writing a return keypress to its input buffer, similar to what was already done for raw mode. Fixes: https://github.com/libuv/libuv/issues/852 PR-URL: https://github.com/libuv/libuv/pull/866 Reviewed-by: Bert Belder <bertbelder@gmail.com> Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
This commit is contained in:
parent
4e4407b17e
commit
e51442bbc9
@ -59,7 +59,7 @@ AM_CONDITIONAL([OPENBSD], [AS_CASE([$host_os],[openbsd*], [true], [false])
|
||||
AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])])
|
||||
AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])])
|
||||
AS_CASE([$host_os],[mingw*], [
|
||||
LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv"
|
||||
LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32"
|
||||
])
|
||||
AC_CHECK_HEADERS([sys/ahafs_evProds.h])
|
||||
AC_CHECK_PROG(PKG_CONFIG, pkg-config, yes)
|
||||
|
||||
@ -83,6 +83,7 @@ extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
|
||||
#define UV_HANDLE_ZERO_READ 0x00080000
|
||||
#define UV_HANDLE_EMULATE_IOCP 0x00100000
|
||||
#define UV_HANDLE_BLOCKING_WRITES 0x00200000
|
||||
#define UV_HANDLE_CANCELLATION_PENDING 0x00400000
|
||||
|
||||
/* Used by uv_tcp_t and uv_udp_t handles */
|
||||
#define UV_HANDLE_IPV6 0x01000000
|
||||
|
||||
@ -871,10 +871,15 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Read successful */
|
||||
/* TODO: read unicode, convert to utf-8 */
|
||||
DWORD bytes = req->u.io.overlapped.InternalHigh;
|
||||
handle->read_cb((uv_stream_t*) handle, bytes, &buf);
|
||||
if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) {
|
||||
/* Read successful */
|
||||
/* TODO: read unicode, convert to utf-8 */
|
||||
DWORD bytes = req->u.io.overlapped.InternalHigh;
|
||||
handle->read_cb((uv_stream_t*) handle, bytes, &buf);
|
||||
} else {
|
||||
handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING;
|
||||
handle->read_cb((uv_stream_t*) handle, 0, &buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for more input events. */
|
||||
@ -937,6 +942,9 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
|
||||
|
||||
|
||||
int uv_tty_read_stop(uv_tty_t* handle) {
|
||||
INPUT_RECORD record;
|
||||
DWORD written;
|
||||
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
DECREASE_ACTIVE_COUNT(handle->loop, handle);
|
||||
|
||||
@ -944,8 +952,6 @@ int uv_tty_read_stop(uv_tty_t* handle) {
|
||||
if ((handle->flags & UV_HANDLE_READ_PENDING) &&
|
||||
(handle->flags & UV_HANDLE_TTY_RAW)) {
|
||||
/* Write some bullshit event to force the console wait to return. */
|
||||
INPUT_RECORD record;
|
||||
DWORD written;
|
||||
memset(&record, 0, sizeof record);
|
||||
if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) {
|
||||
return GetLastError();
|
||||
@ -954,7 +960,20 @@ int uv_tty_read_stop(uv_tty_t* handle) {
|
||||
|
||||
/* Cancel line-buffered read */
|
||||
if (handle->tty.rd.read_line_handle != NULL) {
|
||||
/* Closing this handle will cancel the ReadConsole operation */
|
||||
if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) {
|
||||
/* Write enter key event to force the console wait to return. */
|
||||
record.EventType = KEY_EVENT;
|
||||
record.Event.KeyEvent.bKeyDown = TRUE;
|
||||
record.Event.KeyEvent.wRepeatCount = 1;
|
||||
record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
|
||||
record.Event.KeyEvent.wVirtualScanCode =
|
||||
MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC);
|
||||
record.Event.KeyEvent.uChar.UnicodeChar = L'\r';
|
||||
record.Event.KeyEvent.dwControlKeyState = 0;
|
||||
WriteConsoleInputW(handle->handle, &record, 1, &written);
|
||||
handle->flags |= UV_HANDLE_CANCELLATION_PENDING;
|
||||
}
|
||||
/* Close line-buffered read handle */
|
||||
CloseHandle(handle->tty.rd.read_line_handle);
|
||||
handle->tty.rd.read_line_handle = NULL;
|
||||
}
|
||||
|
||||
@ -43,6 +43,9 @@ TEST_DECLARE (semaphore_1)
|
||||
TEST_DECLARE (semaphore_2)
|
||||
TEST_DECLARE (semaphore_3)
|
||||
TEST_DECLARE (tty)
|
||||
#ifdef _WIN32
|
||||
TEST_DECLARE (tty_raw)
|
||||
#endif
|
||||
TEST_DECLARE (tty_file)
|
||||
TEST_DECLARE (tty_pty)
|
||||
TEST_DECLARE (stdio_over_pipes)
|
||||
@ -387,6 +390,9 @@ TASK_LIST_START
|
||||
#endif
|
||||
TEST_ENTRY (pipe_set_non_blocking)
|
||||
TEST_ENTRY (tty)
|
||||
#ifdef _WIN32
|
||||
TEST_ENTRY (tty_raw)
|
||||
#endif
|
||||
TEST_ENTRY (tty_file)
|
||||
TEST_ENTRY (tty_pty)
|
||||
TEST_ENTRY (stdio_over_pipes)
|
||||
|
||||
@ -146,6 +146,75 @@ TEST_IMPL(tty) {
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
static void tty_raw_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
|
||||
buf->base = malloc(size);
|
||||
buf->len = size;
|
||||
}
|
||||
|
||||
static void tty_raw_read(uv_stream_t* tty_in, ssize_t nread, const uv_buf_t* buf) {
|
||||
if (nread > 0) {
|
||||
ASSERT(nread == 1);
|
||||
ASSERT(buf->base[0] == ' ');
|
||||
uv_close((uv_handle_t*) tty_in, NULL);
|
||||
} else {
|
||||
ASSERT(nread == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_IMPL(tty_raw) {
|
||||
int r;
|
||||
int ttyin_fd;
|
||||
uv_tty_t tty_in;
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
HANDLE handle;
|
||||
INPUT_RECORD record;
|
||||
DWORD written;
|
||||
|
||||
/* Make sure we have an FD that refers to a tty */
|
||||
handle = CreateFileA("conin$",
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
ASSERT(handle != INVALID_HANDLE_VALUE);
|
||||
ttyin_fd = _open_osfhandle((intptr_t) handle, 0);
|
||||
ASSERT(ttyin_fd >= 0);
|
||||
ASSERT(UV_TTY == uv_guess_handle(ttyin_fd));
|
||||
|
||||
r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */
|
||||
ASSERT(r == 0);
|
||||
|
||||
r = uv_read_start((uv_stream_t*)&tty_in, tty_raw_alloc, tty_raw_read);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Give uv_tty_line_read_thread time to block on ReadConsoleW */
|
||||
Sleep(100);
|
||||
|
||||
/* Turn on raw mode. */
|
||||
r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW);
|
||||
ASSERT(r == 0);
|
||||
|
||||
/* Write ' ' that should be read in raw mode */
|
||||
record.EventType = KEY_EVENT;
|
||||
record.Event.KeyEvent.bKeyDown = TRUE;
|
||||
record.Event.KeyEvent.wRepeatCount = 1;
|
||||
record.Event.KeyEvent.wVirtualKeyCode = VK_SPACE;
|
||||
record.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW(VK_SPACE, MAPVK_VK_TO_VSC);
|
||||
record.Event.KeyEvent.uChar.UnicodeChar = L' ';
|
||||
record.Event.KeyEvent.dwControlKeyState = 0;
|
||||
WriteConsoleInputW(handle, &record, 1, &written);
|
||||
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
MAKE_VALGRIND_HAPPY();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
TEST_IMPL(tty_file) {
|
||||
#ifndef _WIN32
|
||||
uv_loop_t loop;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user