static int console_get_poll_status(struct file *f) { /* Writing is always ready */ struct console_file *console_file = (struct console_file *) f; if (console->input_buffer_head != console->input_buffer_tail) return LINUX_POLLIN | LINUX_POLLOUT; console_lock(); INPUT_RECORD ir; DWORD num_read; while (PeekConsoleInputW(console->in, &ir, 1, &num_read) && num_read > 0) { /* Test if the event will be discarded */ if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown) { console_unlock(); return LINUX_POLLIN | LINUX_POLLOUT; } else if (ir.EventType == WINDOW_BUFFER_SIZE_EVENT) console_retrieve_state(); /* Discard the event */ ReadConsoleInputW(console->in, &ir, 1, &num_read); } /* We don't find any readable events */ console_unlock(); return LINUX_POLLOUT; }
static size_t console_write(struct file *f, const char *buf, size_t count) { struct console_file *console_file = (struct console_file *)f; console_lock(); console_retrieve_state(); #define OUTPUT() \ if (last != -1) \ { \ write_normal(buf + last, i - last); \ last = -1; \ } size_t last = -1; size_t i; for (i = 0; i < count; i++) { char ch = buf[i]; if (ch == 0x1B) /* Escape */ { OUTPUT(); console->processor = control_escape; } else if (ch == '\t') { OUTPUT(); int x = (console->x + 8) & ~7; if (x < console->width) set_pos(x, console->y); else set_pos(console->width - 1, console->y); } else if (ch == '\b') { OUTPUT(); backspace(FALSE); } else if (ch == '\r') { OUTPUT(); if (console->termios.c_oflag & OCRNL) nl(); else cr(); } else if (ch == '\n' || ch == '\v' || ch == '\f') { OUTPUT(); if (console->termios.c_oflag & ONLCR) crnl(); else nl(); } else if (ch == 0x0E || ch == 0x0F) { /* Shift In and Shift Out */ OUTPUT(); } else if (console->processor) console->processor(ch); else if (ch < 0x20) { OUTPUT(); log_error("Unhandled control character '\\x%x'\n", ch); } else if (last == -1) last = i; } OUTPUT(); /* This will make the caret immediately visible */ set_pos(console->x, console->y); console_unlock(); #if 0 char str[4096]; memcpy(str, buf, count); str[count] = '\n'; str[count + 1] = 0; log_debug(str); #endif return count; }
static size_t console_read(struct file *f, char *buf, size_t count) { struct console_file *console_file = (struct console_file *)f; console_lock(); console_retrieve_state(); size_t bytes_read = 0; while (console->input_buffer_head != console->input_buffer_tail && count > 0) { count--; buf[bytes_read++] = console->input_buffer[console->input_buffer_tail]; console->input_buffer_tail = (console->input_buffer_tail + 1) % MAX_INPUT; } if (console->termios.c_lflag & ICANON) { char line[MAX_CANON + 1]; /* One more for storing CR or LF */ size_t len = 0; while (count > 0) { INPUT_RECORD ir; DWORD read; ReadConsoleInputA(console->in, &ir, 1, &read); if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown) { switch (ir.Event.KeyEvent.wVirtualKeyCode) { case VK_RETURN: { if (!(console->termios.c_iflag & IGNCR)) line[len++] = console->termios.c_iflag & ICRNL ? '\n' : '\r'; size_t r = min(count, len); memcpy(buf + bytes_read, line, r); bytes_read += r; count -= r; if (r < len) { /* Some bytes not fit, add to input buffer */ console_add_input(line + r, len - r); } if (console->termios.c_lflag & ECHO) crnl(); goto read_done; } case VK_BACK: { if (len > 0) { len--; if (console->termios.c_lflag & ECHO) backspace(TRUE); } } default: { char ch = ir.Event.KeyEvent.uChar.AsciiChar; if (ch >= 0x20) { if (len < MAX_CANON) { line[len++] = ch; if (console->termios.c_lflag & ECHO) write_normal(&ch, 1); } } } } } } } else /* Non canonical mode */ { int vtime = console->termios.c_cc[VTIME]; int vmin = console->termios.c_cc[VMIN]; while (count > 0) { if (bytes_read > 0 && bytes_read >= vmin) break; /* If vmin > 0 and vtime == 0, it is a blocking read, otherwise we need to poll first */ if (vtime > 0 || (vmin == 0 && vtime == 0)) { if (WaitForSingleObject(console->in, vtime * 100) == WAIT_TIMEOUT) break; } INPUT_RECORD ir; DWORD read; ReadConsoleInputA(console->in, &ir, 1, &read); if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown) { switch (ir.Event.KeyEvent.wVirtualKeyCode) { case VK_UP: console_buffer_add_string(buf, &bytes_read, &count, console->cursor_key_mode ? "\x1BOA" : "\x1B[A", 3); break; case VK_DOWN: console_buffer_add_string(buf, &bytes_read, &count, console->cursor_key_mode ? "\x1BOB" : "\x1B[B", 3); break; case VK_RIGHT: console_buffer_add_string(buf, &bytes_read, &count, console->cursor_key_mode ? "\x1BOC" : "\x1B[C", 3); break; case VK_LEFT: console_buffer_add_string(buf, &bytes_read, &count, console->cursor_key_mode ? "\x1BOD" : "\x1B[D", 3); break; case VK_HOME: console_buffer_add_string(buf, &bytes_read, &count, console->cursor_key_mode ? "\x1BOH" : "\x1B[H", 3); break; case VK_END: console_buffer_add_string(buf, &bytes_read, &count, console->cursor_key_mode ? "\x1BOF" : "\x1B[F", 3); break; case VK_INSERT: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[2~", 4); break; case VK_DELETE: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[3~", 4); break; case VK_PRIOR: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[5~", 4); break; case VK_NEXT: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[6~", 4); break; case VK_F1: console_buffer_add_string(buf, &bytes_read, &count, "\x1BOP", 3); break; case VK_F2: console_buffer_add_string(buf, &bytes_read, &count, "\x1BOQ", 3); break; case VK_F3: console_buffer_add_string(buf, &bytes_read, &count, "\x1BOR", 3); break; case VK_F4: console_buffer_add_string(buf, &bytes_read, &count, "\x1BOS", 3); break; case VK_F5: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[15~", 5); break; case VK_F6: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[17~", 5); break; case VK_F7: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[18~", 5); break; case VK_F8: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[19~", 5); break; case VK_F9: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[20~", 5); break; case VK_F10: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[21~", 5); break; case VK_F11: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[23~", 5); break; case VK_F12: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[24~", 5); break; case VK_F13: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[25~", 5); break; case VK_F14: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[26~", 5); break; case VK_F15: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[28~", 5); break; case VK_F16: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[29~", 5); break; case VK_F17: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[31~", 5); break; case VK_F18: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[32~", 5); break; case VK_F19: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[33~", 5); break; case VK_F20: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[34~", 5); break; default: { char ch = ir.Event.KeyEvent.uChar.AsciiChar; if (ch == '\r' && console->termios.c_iflag & IGNCR) break; if (ch == '\r' && console->termios.c_iflag & ICRNL) ch = '\n'; else if (ch == '\n' && console->termios.c_iflag & ICRNL) ch = '\r'; if (ch > 0) { count--; buf[bytes_read++] = ch; if (console->termios.c_lflag & ECHO) write_normal(&ch, 1); } } } } else { /* TODO: Other types of input */ } } } read_done: /* This will make the caret immediately visible */ set_pos(console->x, console->y); console_unlock(); return bytes_read; }