Alien-uv
view release on metacpan or search on metacpan
libuv/src/win/tty.c view on Meta::CPAN
static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
uv_read_t* req;
BOOL r;
assert(handle->flags & UV_HANDLE_READING);
assert(!(handle->flags & UV_HANDLE_READ_PENDING));
assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
handle->tty.rd.read_line_buffer = uv_null_buf_;
req = &handle->read_req;
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
r = RegisterWaitForSingleObject(&handle->tty.rd.read_raw_wait,
handle->handle,
uv_tty_post_raw_read,
(void*) req,
INFINITE,
WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
if (!r) {
handle->tty.rd.read_raw_wait = NULL;
SET_REQ_ERROR(req, GetLastError());
uv_insert_pending_req(loop, (uv_req_t*)req);
}
handle->flags |= UV_HANDLE_READ_PENDING;
handle->reqs_pending++;
}
static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
uv_loop_t* loop;
uv_tty_t* handle;
uv_req_t* req;
DWORD bytes, read_bytes;
WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3];
DWORD chars, read_chars;
LONG status;
COORD pos;
BOOL read_console_success;
assert(data);
req = (uv_req_t*) data;
handle = (uv_tty_t*) req->data;
loop = handle->loop;
assert(handle->tty.rd.read_line_buffer.base != NULL);
assert(handle->tty.rd.read_line_buffer.len > 0);
/* ReadConsole can't handle big buffers. */
if (handle->tty.rd.read_line_buffer.len < MAX_INPUT_BUFFER_LENGTH) {
bytes = handle->tty.rd.read_line_buffer.len;
} else {
bytes = MAX_INPUT_BUFFER_LENGTH;
}
/* At last, unicode! One utf-16 codeunit never takes more than 3 utf-8
* codeunits to encode. */
chars = bytes / 3;
status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS);
if (status == TRAP_REQUESTED) {
SET_REQ_SUCCESS(req);
req->u.io.overlapped.InternalHigh = 0;
POST_COMPLETION_FOR_REQ(loop, req);
return 0;
}
read_console_success = ReadConsoleW(handle->handle,
(void*) utf16,
chars,
&read_chars,
NULL);
if (read_console_success) {
read_bytes = WideCharToMultiByte(CP_UTF8,
0,
utf16,
read_chars,
handle->tty.rd.read_line_buffer.base,
bytes,
NULL,
NULL);
SET_REQ_SUCCESS(req);
req->u.io.overlapped.InternalHigh = read_bytes;
} else {
SET_REQ_ERROR(req, GetLastError());
}
status = InterlockedExchange(&uv__read_console_status, COMPLETED);
if (status == TRAP_REQUESTED) {
/* If we canceled the read by sending a VK_RETURN event, restore the
screen state to undo the visual effect of the VK_RETURN */
if (read_console_success && InterlockedOr(&uv__restore_screen_state, 0)) {
HANDLE active_screen_buffer;
active_screen_buffer = CreateFileA("conout$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (active_screen_buffer != INVALID_HANDLE_VALUE) {
pos = uv__saved_screen_state.dwCursorPosition;
/* If the cursor was at the bottom line of the screen buffer, the
VK_RETURN would have caused the buffer contents to scroll up by one
line. The right position to reset the cursor to is therefore one line
higher */
if (pos.Y == uv__saved_screen_state.dwSize.Y - 1)
pos.Y--;
SetConsoleCursorPosition(active_screen_buffer, pos);
CloseHandle(active_screen_buffer);
}
}
libuv/src/win/tty.c view on Meta::CPAN
off_t buf_used;
assert(handle->type == UV_TTY);
assert(handle->flags & UV_HANDLE_TTY_READABLE);
handle->flags &= ~UV_HANDLE_READ_PENDING;
if (!(handle->flags & UV_HANDLE_READING) ||
!(handle->flags & UV_HANDLE_TTY_RAW)) {
goto out;
}
if (!REQ_SUCCESS(req)) {
/* An error occurred while waiting for the event. */
if ((handle->flags & UV_HANDLE_READING)) {
handle->flags &= ~UV_HANDLE_READING;
handle->read_cb((uv_stream_t*)handle,
uv_translate_sys_error(GET_REQ_ERROR(req)),
&uv_null_buf_);
}
goto out;
}
/* Fetch the number of events */
if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) {
handle->flags &= ~UV_HANDLE_READING;
DECREASE_ACTIVE_COUNT(loop, handle);
handle->read_cb((uv_stream_t*)handle,
uv_translate_sys_error(GetLastError()),
&uv_null_buf_);
goto out;
}
/* Windows sends a lot of events that we're not interested in, so buf will be
* allocated on demand, when there's actually something to emit. */
buf = uv_null_buf_;
buf_used = 0;
while ((records_left > 0 || handle->tty.rd.last_key_len > 0) &&
(handle->flags & UV_HANDLE_READING)) {
if (handle->tty.rd.last_key_len == 0) {
/* Read the next input record */
if (!ReadConsoleInputW(handle->handle,
&handle->tty.rd.last_input_record,
1,
&records_read)) {
handle->flags &= ~UV_HANDLE_READING;
DECREASE_ACTIVE_COUNT(loop, handle);
handle->read_cb((uv_stream_t*) handle,
uv_translate_sys_error(GetLastError()),
&buf);
goto out;
}
records_left--;
/* Ignore other events that are not key events. */
if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) {
continue;
}
/* Ignore keyup events, unless the left alt key was held and a valid
* unicode character was emitted. */
if (!KEV.bKeyDown &&
(KEV.wVirtualKeyCode != VK_MENU ||
KEV.uChar.UnicodeChar == 0)) {
continue;
}
/* Ignore keypresses to numpad number keys if the left alt is held
* because the user is composing a character, or windows simulating this.
*/
if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) &&
!(KEV.dwControlKeyState & ENHANCED_KEY) &&
(KEV.wVirtualKeyCode == VK_INSERT ||
KEV.wVirtualKeyCode == VK_END ||
KEV.wVirtualKeyCode == VK_DOWN ||
KEV.wVirtualKeyCode == VK_NEXT ||
KEV.wVirtualKeyCode == VK_LEFT ||
KEV.wVirtualKeyCode == VK_CLEAR ||
KEV.wVirtualKeyCode == VK_RIGHT ||
KEV.wVirtualKeyCode == VK_HOME ||
KEV.wVirtualKeyCode == VK_UP ||
KEV.wVirtualKeyCode == VK_PRIOR ||
KEV.wVirtualKeyCode == VK_NUMPAD0 ||
KEV.wVirtualKeyCode == VK_NUMPAD1 ||
KEV.wVirtualKeyCode == VK_NUMPAD2 ||
KEV.wVirtualKeyCode == VK_NUMPAD3 ||
KEV.wVirtualKeyCode == VK_NUMPAD4 ||
KEV.wVirtualKeyCode == VK_NUMPAD5 ||
KEV.wVirtualKeyCode == VK_NUMPAD6 ||
KEV.wVirtualKeyCode == VK_NUMPAD7 ||
KEV.wVirtualKeyCode == VK_NUMPAD8 ||
KEV.wVirtualKeyCode == VK_NUMPAD9)) {
continue;
}
if (KEV.uChar.UnicodeChar != 0) {
int prefix_len, char_len;
/* Character key pressed */
if (KEV.uChar.UnicodeChar >= 0xD800 &&
KEV.uChar.UnicodeChar < 0xDC00) {
/* UTF-16 high surrogate */
handle->tty.rd.last_utf16_high_surrogate = KEV.uChar.UnicodeChar;
continue;
}
/* Prefix with \u033 if alt was held, but alt was not used as part a
* compose sequence. */
if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
&& !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED |
RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) {
handle->tty.rd.last_key[0] = '\033';
prefix_len = 1;
} else {
prefix_len = 0;
}
if (KEV.uChar.UnicodeChar >= 0xDC00 &&
KEV.uChar.UnicodeChar < 0xE000) {
/* UTF-16 surrogate pair */
WCHAR utf16_buffer[2];
libuv/src/win/tty.c view on Meta::CPAN
}
continue;
}
/* Apply dwRepeat from the last input record. */
if (--KEV.wRepeatCount > 0) {
handle->tty.rd.last_key_offset = 0;
continue;
}
handle->tty.rd.last_key_len = 0;
continue;
}
}
/* Send the buffer back to the user */
if (buf_used > 0) {
handle->read_cb((uv_stream_t*) handle, buf_used, &buf);
}
out:
/* Wait for more input events. */
if ((handle->flags & UV_HANDLE_READING) &&
!(handle->flags & UV_HANDLE_READ_PENDING)) {
uv_tty_queue_read(loop, handle);
}
DECREASE_PENDING_REQ_COUNT(handle);
#undef KEV
}
void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
uv_req_t* req) {
uv_buf_t buf;
assert(handle->type == UV_TTY);
assert(handle->flags & UV_HANDLE_TTY_READABLE);
buf = handle->tty.rd.read_line_buffer;
handle->flags &= ~UV_HANDLE_READ_PENDING;
handle->tty.rd.read_line_buffer = uv_null_buf_;
if (!REQ_SUCCESS(req)) {
/* Read was not successful */
if (handle->flags & UV_HANDLE_READING) {
/* Real error */
handle->flags &= ~UV_HANDLE_READING;
DECREASE_ACTIVE_COUNT(loop, handle);
handle->read_cb((uv_stream_t*) handle,
uv_translate_sys_error(GET_REQ_ERROR(req)),
&buf);
}
} else {
if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING) &&
req->u.io.overlapped.InternalHigh != 0) {
/* 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);
}
handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING;
}
/* Wait for more input events. */
if ((handle->flags & UV_HANDLE_READING) &&
!(handle->flags & UV_HANDLE_READ_PENDING)) {
uv_tty_queue_read(loop, handle);
}
DECREASE_PENDING_REQ_COUNT(handle);
}
void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
uv_req_t* req) {
assert(handle->type == UV_TTY);
assert(handle->flags & UV_HANDLE_TTY_READABLE);
/* If the read_line_buffer member is zero, it must have been an raw read.
* Otherwise it was a line-buffered read. FIXME: This is quite obscure. Use a
* flag or something. */
if (handle->tty.rd.read_line_buffer.len == 0) {
uv_process_tty_read_raw_req(loop, handle, req);
} else {
uv_process_tty_read_line_req(loop, handle, req);
}
}
int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb) {
uv_loop_t* loop = handle->loop;
if (!(handle->flags & UV_HANDLE_TTY_READABLE)) {
return ERROR_INVALID_PARAMETER;
}
handle->flags |= UV_HANDLE_READING;
INCREASE_ACTIVE_COUNT(loop, handle);
handle->read_cb = read_cb;
handle->alloc_cb = alloc_cb;
/* If reading was stopped and then started again, there could still be a read
* request pending. */
if (handle->flags & UV_HANDLE_READ_PENDING) {
return 0;
}
/* Maybe the user stopped reading half-way while processing key events.
* Short-circuit if this could be the case. */
if (handle->tty.rd.last_key_len > 0) {
SET_REQ_SUCCESS(&handle->read_req);
uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
/* Make sure no attempt is made to insert it again until it's handled. */
handle->flags |= UV_HANDLE_READ_PENDING;
handle->reqs_pending++;
return 0;
( run in 0.622 second using v1.01-cache-2.11-cpan-119454b85a5 )