int getkey() { DWORD cnt; INPUT_RECORD ir; HANDLE conin = GetStdHandle(STD_INPUT_HANDLE); if(PeekConsoleInputW(conin,&ir,1,&cnt)) { do ReadConsoleInputW(conin,&ir,1,&cnt); while(ir.EventType!=KEY_EVENT); } FlushConsoleInputBuffer(conin); do ReadConsoleInputW(conin,&ir,1,&cnt); while(ir.EventType!=KEY_EVENT); FlushConsoleInputBuffer(conin); KEY_EVENT_RECORD ke = ir.Event.KeyEvent; int result = ke.uChar.UnicodeChar; if(result==0) return 1000000+ke.wVirtualKeyCode; }
static BOOL WCEL_Get(WCEL_Context* ctx, INPUT_RECORD* ir) { if (ReadConsoleInputW(ctx->hConIn, ir, 1, NULL)) return TRUE; ERR("hmm bad situation\n"); ctx->error = 1; return FALSE; }
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; } /* Discard the event */ ReadConsoleInputW(console->in, &ir, 1, &num_read); } /* We don't find any readable events */ console_unlock(); return LINUX_POLLOUT; }
static inline BOOL w32_read_console_input (HANDLE h, INPUT_RECORD *rec, DWORD recsize, DWORD *waiting) { return (w32_console_unicode_input ? ReadConsoleInputW (h, rec, recsize, waiting) : ReadConsoleInputA (h, rec, recsize, waiting)); }
// async_wait 调用到这里 void operator()(boost::system::error_code ec) { DWORD r =0; INPUT_RECORD ir; ReadConsoleInputW(console_handle.native_handle(), &ir, 1, &r); if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown && ir.Event.KeyEvent.uChar.UnicodeChar) { WCHAR c = ir.Event.KeyEvent.uChar.UnicodeChar; if (c == L'\b') { // 退格键啊,应该删了 // WriteConsoleOutputW(); if (!readbuf.empty()) { WCHAR lc = readbuf.back(); readbuf.pop_back(); if (lc >= 256) { WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), L"\b \b \b", 5, &r, 0); } else { WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), L"\b \b", 3, &r, 0); } } } else { readbuf.push_back(c); } if (iswprint(c)) { WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), &c, 1, &r, 0); } // 判定 是不是读取到了 "\n" // 是的话就可以调用 handler 了 if (c == L'\r') { // 读取到行尾啦!回调吧 std::string thisline = wide_to_utf8(std::wstring(readbuf.data(), readbuf.size())); readbuf.clear(); WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), L"\n", 1, &r, 0); SetConsoleMode(console_handle.native_handle(), m_savedmode); m_handler(thisline); return; } } // 重复读取 console_handle.async_wait(*this); }
void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, uv_req_t* req) { /* Shortcut for handle->last_input_record.Event.KeyEvent. */ #define KEV handle->last_input_record.Event.KeyEvent DWORD records_left, records_read; uv_buf_t buf; off_t buf_used; assert(handle->type == UV_TTY); 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; loop->last_error = GET_REQ_UV_ERROR(req); handle->read_cb((uv_stream_t*)handle, -1, uv_null_buf_); } goto out; } /* Fetch the number of events */ if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) { handle->flags &= ~UV_HANDLE_READING; uv_set_sys_error(loop, GetLastError()); handle->read_cb((uv_stream_t*)handle, -1, 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->last_key_len > 0) && (handle->flags & UV_HANDLE_READING)) { if (handle->last_key_len == 0) { /* Read the next input record */ if (!ReadConsoleInputW(handle->handle, &handle->last_input_record, 1, &records_read)) { uv_set_sys_error(loop, GetLastError()); handle->flags &= ~UV_HANDLE_READING; handle->read_cb((uv_stream_t*) handle, -1, buf); goto out; } records_left--; /* Ignore events that are not keyboard events */ if (handle->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.dwControlKeyState & LEFT_ALT_PRESSED) || 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->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->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] = { handle->last_utf16_high_surrogate, KEV.uChar.UnicodeChar}; char_len = WideCharToMultiByte(CP_UTF8, 0, utf16_buffer, 2, &handle->last_key[prefix_len], sizeof handle->last_key, NULL, NULL); } else { /* Single UTF-16 character */ char_len = WideCharToMultiByte(CP_UTF8, 0, &KEV.uChar.UnicodeChar, 1, &handle->last_key[prefix_len], sizeof handle->last_key, NULL, NULL); } /* Whatever happened, the last character wasn't a high surrogate. */ handle->last_utf16_high_surrogate = 0; /* If the utf16 character(s) couldn't be converted something must */ /* be wrong. */ if (!char_len) { uv_set_sys_error(loop, GetLastError()); handle->flags &= ~UV_HANDLE_READING; handle->read_cb((uv_stream_t*) handle, -1, buf); goto out; } handle->last_key_len = (unsigned char) (prefix_len + char_len); handle->last_key_offset = 0; continue; } else { /* Function key pressed */ const char* vt100; size_t prefix_len, vt100_len; vt100 = get_vt100_fn_key(KEV.wVirtualKeyCode, !!(KEV.dwControlKeyState & SHIFT_PRESSED), !!(KEV.dwControlKeyState & ( LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)), &vt100_len); /* If we were unable to map to a vt100 sequence, just ignore. */ if (!vt100) { continue; } /* Prefix with \x033 when the alt key was held. */ if (KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) { handle->last_key[0] = '\033'; prefix_len = 1; } else { prefix_len = 0; } /* Copy the vt100 sequence to the handle buffer. */ assert(prefix_len + vt100_len < sizeof handle->last_key); memcpy(&handle->last_key[prefix_len], vt100, vt100_len); handle->last_key_len = (unsigned char) (prefix_len + vt100_len); handle->last_key_offset = 0; continue; } } else { /* Copy any bytes left from the last keypress to the user buffer. */ if (handle->last_key_offset < handle->last_key_len) { /* Allocate a buffer if needed */ if (buf_used == 0) { buf = handle->alloc_cb((uv_handle_t*) handle, 1024); } buf.base[buf_used++] = handle->last_key[handle->last_key_offset++]; /* If the buffer is full, emit it */ if (buf_used == buf.len) { handle->read_cb((uv_stream_t*) handle, buf_used, buf); buf = uv_null_buf_; buf_used = 0; } continue; } /* Apply dwRepeat from the last input record. */ if (--KEV.wRepeatCount > 0) { handle->last_key_offset = 0; continue; } handle->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 }
String ReadLine() { String ret; #ifdef _WIN32 HANDLE input = GetStdHandle(STD_INPUT_HANDLE); HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE); if (input == INVALID_HANDLE_VALUE || output == INVALID_HANDLE_VALUE) return ret; // Use char-based input SetConsoleMode(input, ENABLE_PROCESSED_INPUT); INPUT_RECORD record; DWORD events = 0; DWORD readEvents = 0; if (!GetNumberOfConsoleInputEvents(input, &events)) return ret; while (events--) { ReadConsoleInputW(input, &record, 1, &readEvents); if (record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown) { unsigned c = record.Event.KeyEvent.uChar.UnicodeChar; if (c) { if (c == '\b') { PrintUnicode("\b \b"); size_t length = currentLine.LengthUTF8(); if (length) currentLine = currentLine.SubstringUTF8(0, length - 1); } else if (c == '\r') { PrintUnicode("\n"); ret = currentLine; currentLine.Clear(); return ret; } else { // We have disabled echo, so echo manually wchar_t out = (wchar_t)c; DWORD charsWritten; WriteConsoleW(output, &out, 1, &charsWritten, 0); currentLine.AppendUTF8(c); } } } } #else int flags = fcntl(STDIN_FILENO, F_GETFL); fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); for (;;) { int ch = fgetc(stdin); if (ch >= 0 && ch != '\n') ret += (char)ch; else break; } #endif return ret; }
/* acx1_read_event **********************************************************/ ACX1_API unsigned int ACX1_CALL acx1_read_event (acx1_event_t * event_p) { INPUT_RECORD ir; DWORD n; uint16_t ch; uint32_t m; for (;;) { if (!ReadConsoleInputW(hin, &ir, 1, &n)) { LE("read console input failed!\n"); return ACX1_TERM_IO_FAILED; } if (ir.EventType == WINDOW_BUFFER_SIZE_EVENT) { event_p->type = ACX1_RESIZE; event_p->size.w = ir.Event.WindowBufferSizeEvent.dwSize.X; event_p->size.h = ir.Event.WindowBufferSizeEvent.dwSize.Y; LI("screen resized to %ux%u\n", event_p->size.w, event_p->size.h); return 0; } if (ir.EventType == KEY_EVENT) { if (!ir.Event.KeyEvent.bKeyDown) continue; m = 0; if (ir.Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) m |= ACX1_ALT; if (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) m |= ACX1_CTRL; if (ir.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) m |= ACX1_SHIFT; event_p->type = ACX1_KEY; ch = ir.Event.KeyEvent.uChar.UnicodeChar; if (ch >= 0x20) event_p->km = (m & ~ACX1_SHIFT) | ir.Event.KeyEvent.uChar.UnicodeChar; else //if (ch > 0) { if (ch == 0x08 || ch == 0x09 || ch == 0x0D) m = ch; else { // event_p->km = ACX1_CTRL | 0x40 | ch; switch (ch = ir.Event.KeyEvent.wVirtualKeyCode) { case VK_BACK: m |= ACX1_BACKSPACE; break; case VK_TAB: m |= ACX1_TAB; break; case VK_RETURN: m |= ACX1_ENTER; break; case VK_ESCAPE: m |= ACX1_ESC; break; case VK_SPACE: m |= ACX1_SPACE; break; case VK_PRIOR: m |= ACX1_PAGE_UP; break; case VK_NEXT: m |= ACX1_PAGE_DOWN; break; case VK_END: m |= ACX1_END; break; case VK_HOME: m |= ACX1_HOME; break; case VK_LEFT: m |= ACX1_LEFT; break; case VK_UP: m |= ACX1_UP; break; case VK_RIGHT: m |= ACX1_RIGHT; break; case VK_DOWN: m |= ACX1_DOWN; break; case VK_INSERT: m |= ACX1_INS; break; case VK_DELETE: m |= ACX1_DEL; break; case VK_F1: m |= ACX1_F1; break; case VK_F2: m |= ACX1_F2; break; case VK_F3: m |= ACX1_F3; break; case VK_F4: m |= ACX1_F4; break; case VK_F5: m |= ACX1_F5; break; case VK_F6: m |= ACX1_F6; break; case VK_F7: m |= ACX1_F7; break; case VK_F8: m |= ACX1_F8; break; case VK_F9: m |= ACX1_F9; break; case VK_F10: m |= ACX1_F10; break; case VK_F11: m |= ACX1_F11; break; case VK_F12: m |= ACX1_F12; break; default: if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z')) m |= ch; else continue; } } event_p->km = m; } // else { event_p->km = '?'; } LI("got key: 0x%X\n", event_p->km); return 0; } } }
/* Taken from msvcrt.dll's getextendedkeycode() ELSE SHFT CTRL ALTS 00000000`723d36e0 1c 000d 000d 000a a600 00000000`723d36ea 35 002f 003f 9500 a400 00000000`723d36f4 47 47e0 47e0 77e0 9700 00000000`723d36fe 48 48e0 48e0 8de0 9800 00000000`723d3708 49 49e0 49e0 86e0 9900 00000000`723d3712 4b 4be0 4be0 73e0 9b00 00000000`723d371c 4d 4de0 4de0 74e0 9d00 00000000`723d3726 4f 4fe0 4fe0 75e0 9f00 00000000`723d3730 50 50e0 50e0 91e0 a000 00000000`723d373a 51 51e0 51e0 76e0 a100 00000000`723d3744 52 52e0 52e0 92e0 a200 00000000`723d374e 53 53e0 53e0 93e0 a300 home 01 00 00 00 01 00 24 00 47 00 00 00 00 00 00 00 end 01 00 00 00 01 00 23 00 4f 00 00 00 00 00 00 00 pgup 01 00 00 00 01 00 21 00 49 00 00 00 00 00 00 00 pgdn 01 00 00 00 01 00 22 00 51 00 00 00 00 00 00 00 */ static int getc_internal(int* alt) { static int carry = 0; // Multithreading? What's that? static const int CTRL_PRESSED = LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED; int key_char; int key_vk; int key_sc; int key_flags; HANDLE handle; DWORD mode; // Clear all flags so the console doesn't do anything special. This prevents // key presses such as Ctrl-C and Ctrl-S from being swallowed. handle = GetStdHandle(STD_INPUT_HANDLE); GetConsoleMode(handle, &mode); loop: key_char = 0; key_vk = 0; key_sc = 0; key_flags = 0; *alt = 0; // Read a key or use what was carried across from a previous call. if (carry) { key_flags = ENHANCED_KEY; key_char = carry; carry = 0; } else { HANDLE handle_stdout = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO csbi; DWORD i; INPUT_RECORD record; const KEY_EVENT_RECORD* key; int altgr_sub; GetConsoleScreenBufferInfo(handle_stdout, &csbi); // Check for a new buffer size for simulated SIGWINCH signals. i = (csbi.dwSize.X << 16) | csbi.dwSize.Y; if (!g_knownBufferSize || g_knownBufferSize != i) { simulate_sigwinch(csbi.dwCursorPosition); g_knownBufferSize = i; goto loop; } // Fresh read from the console. SetConsoleMode(handle, 0); ReadConsoleInputW(handle, &record, 1, &i); if (record.EventType != KEY_EVENT) { goto loop; } key = &record.Event.KeyEvent; key_char = key->uChar.UnicodeChar; key_vk = key->wVirtualKeyCode; key_sc = key->wVirtualScanCode; key_flags = key->dwControlKeyState; #if defined(DEBUG_GETC) && defined(_DEBUG) { static int id = 0; int i; printf("\n%03d: %s ", id++, key->bKeyDown ? "+" : "-"); for (i = 2; i < sizeof(*key) / sizeof(short); ++i) { printf("%04x ", ((unsigned short*)key)[i]); } } #endif if (key->bKeyDown == FALSE) { // Some times conhost can send through ALT codes, with the resulting // Unicode code point in the Alt key-up event. if (key_vk == VK_MENU && key_char) { goto end; } goto loop; } // Windows supports an AltGr substitute which we check for here. As it // collides with Readline mappings Clink's support can be disabled. altgr_sub = !!(key_flags & LEFT_ALT_PRESSED); altgr_sub &= !!(key_flags & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)); altgr_sub &= !!key_char; altgr_sub &= get_clink_setting_int("use_altgr_substitute"); if (!altgr_sub) { *alt = !!(key_flags & LEFT_ALT_PRESSED); } } // No Unicode character? Then some post-processing is required to make the // output compatible with whatever standard Linux terminals adhere to and // that which Readline expects. if (key_char == 0) { int i; // The numpad keys such as PgUp, End, etc. don't come through with the // ENHANCED_KEY flag set so we'll infer it here. static const int enhanced_vks[] = { VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT, VK_HOME, VK_END, VK_INSERT, VK_DELETE, VK_PRIOR, VK_NEXT, }; for (i = 0; i < sizeof_array(enhanced_vks); ++i) { if (key_vk == enhanced_vks[i]) { key_flags |= ENHANCED_KEY; break; } } // Differentiate enhanced keys depending on modifier key state. MSVC's // runtime does something similar. Slightly non-standard. if (key_flags & ENHANCED_KEY) { static const int mod_map[][4] = { //Nrml Shft Ctrl CtSh { 0x47, 0x61, 0x77, 0x21 }, // Gaw! home { 0x48, 0x62, 0x54, 0x22 }, // HbT" up { 0x49, 0x63, 0x55, 0x23 }, // IcU# pgup { 0x4b, 0x64, 0x73, 0x24 }, // Kds$ left { 0x4d, 0x65, 0x74, 0x25 }, // Met% right { 0x4f, 0x66, 0x75, 0x26 }, // Ofu& end { 0x50, 0x67, 0x56, 0x27 }, // PgV' down { 0x51, 0x68, 0x76, 0x28 }, // Qhv( pgdn { 0x52, 0x69, 0x57, 0x29 }, // RiW) insert { 0x53, 0x6a, 0x58, 0x2a }, // SjX* delete }; for (i = 0; i < sizeof_array(mod_map); ++i) { int j = 0; if (mod_map[i][j] != key_sc) { continue; } j += !!(key_flags & SHIFT_PRESSED); j += !!(key_flags & CTRL_PRESSED) << 1; carry = mod_map[i][j]; break; } // Blacklist. if (!carry) { goto loop; } key_vk = 0xe0; } else if (!(key_flags & CTRL_PRESSED)) { goto loop; } // This builds Ctrl-<key> map to match that as described by Readline's // source for the emacs/vi keymaps. #define CONTAINS(l, r) (unsigned)(key_vk - l) <= (r - l) else if (CONTAINS('A', 'Z')) key_vk -= 'A' - 1; else if (CONTAINS(0xdb, 0xdd)) key_vk -= 0xdb - 0x1b; else if (key_vk == 0x32) key_vk = 0; else if (key_vk == 0x36) key_vk = 0x1e; else if (key_vk == 0xbd) key_vk = 0x1f; else goto loop; #undef CONTAINS key_char = key_vk; } else if (!(key_flags & ENHANCED_KEY) && key_char > 0x7f) { key_char |= 0x8000000; } end: #if defined(DEBUG_GETC) && defined(_DEBUG) printf("\n%08x '%c'", key_char, key_char); #endif SetConsoleMode(handle, mode); return key_char; }
/*--------------------------------------------------------------------------*/ static unsigned char TerminalGetchar(void) { INPUT_RECORD irBuffer; DWORD n = 0; unsigned char ch = 0; do { /* http://bugzilla.scilab.org/show_bug.cgi?id=1052 */ if ( ismenu() == 1 ) { return 0; } WaitForSingleObject(Win32InputStream, INFINITE); PeekConsoleInput (Win32InputStream, &irBuffer, 1, &n); switch (irBuffer.EventType) { case KEY_EVENT: { if (irBuffer.Event.KeyEvent.bKeyDown) { if (irBuffer.Event.KeyEvent.dwControlKeyState) { if (isCTRLPressed(irBuffer.Event.KeyEvent.dwControlKeyState)) { char c = actionControlKey(); if (c) { ReadConsoleInputW (Win32InputStream, &irBuffer, 1, &n); return c; } else { if (irBuffer.Event.KeyEvent.uChar.AsciiChar != '\0') { ReadConsoleInputW (Win32InputStream, &irBuffer, 1, &n); c = irBuffer.Event.KeyEvent.uChar.AsciiChar; if ( (c > 0) && !iscntrl(c) ) { return c; } } else { ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n); } } break; } if (isALTPressed(irBuffer.Event.KeyEvent.dwControlKeyState)) { if (irBuffer.Event.KeyEvent.uChar.AsciiChar != '\0') { ReadConsole (Win32InputStream, &ch, 1, &n, NULL); return ch; } else { DWORD stateKey = 0; WORD vk = 0; ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n); stateKey = irBuffer.Event.KeyEvent.dwControlKeyState; vk = irBuffer.Event.KeyEvent.wVirtualKeyCode; switch (vk) { case VK_F4: ALTF4_Command(); break; default: break; } } break; } } if (irBuffer.Event.KeyEvent.uChar.AsciiChar != '\0') { ReadConsole (Win32InputStream, &ch, 1, &n, NULL); switch (ch) { case VK_TAB: TermCompletion(); break; case VK_BACK: deletePreviousChar(); break; default: { if ( !iscntrl(ch) || (ch == CR_1) || (ch == CR_2) ) { return ch; } } break; } } else { WORD vk = 0; ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n); vk = irBuffer.Event.KeyEvent.wVirtualKeyCode; switch (vk) { case VK_F1: case VK_HELP: F1_Command(); break; case VK_F2: F2_Command(); break; case VK_LEFT: moveBackSingleChar(); break; case VK_RIGHT: moveForwardSingleChar(); break; case VK_UP: moveBackHistory(); break; case VK_DOWN: moveForwardHistory(); break; case VK_DELETE: deleteCurrentChar(); break; case VK_HOME: moveBeginningLine(); break; case VK_END: moveEndLine(); break; default: break; } } } else { ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n); } } break; case MOUSE_EVENT: { /* Read mouse Input but not used */ ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n); } break; case WINDOW_BUFFER_SIZE_EVENT: { /* Read resize event Input */ setColumnsSize(irBuffer.Event.WindowBufferSizeEvent.dwSize.X); setLinesSize(irBuffer.Event.WindowBufferSizeEvent.dwSize.Y); ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n); } break; case MENU_EVENT: { ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n); } break; case FOCUS_EVENT: { ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n); } break; default: { /* Read Input but not used */ ReadConsoleInput (Win32InputStream, &irBuffer, 1, &n); } break; } } while (TRUE); }
int ConsoleReadCh() { const int max_input = 8; static char console_input[8]; static int first_input_char = 0; static int last_input_char = 0; INPUT_RECORD rec; DWORD recRead; HANDLE h; if (first_input_char != last_input_char) { int c = console_input[first_input_char]; first_input_char++; first_input_char %= max_input; return c; } h = GetStdHandle(STD_INPUT_HANDLE); if (h == NULL) return NUL; ReadConsoleInputW(h, &rec, 1, &recRead); /* FIXME: We should handle rec.Event.KeyEvent.wRepeatCount > 1, too. */ if (recRead == 1 && rec.EventType == KEY_EVENT && rec.Event.KeyEvent.bKeyDown && (rec.Event.KeyEvent.wVirtualKeyCode < VK_SHIFT || rec.Event.KeyEvent.wVirtualKeyCode > VK_MENU)) { if (rec.Event.KeyEvent.uChar.UnicodeChar) { if ((rec.Event.KeyEvent.dwControlKeyState == SHIFT_PRESSED) && (rec.Event.KeyEvent.wVirtualKeyCode == VK_TAB)) { return 034; /* remap Shift-Tab */ } else { int i, count; char mbchar[8]; count = WideCharToMultiByte(WinGetCodepage(encoding), 0, &rec.Event.KeyEvent.uChar.UnicodeChar, 1, mbchar, sizeof(mbchar), NULL, NULL); for (i = 1; i < count; i++) { console_input[last_input_char] = mbchar[i]; last_input_char++; last_input_char %= max_input; } return mbchar[0]; } } else { switch (rec.Event.KeyEvent.wVirtualKeyCode) { case VK_UP: return 020; case VK_DOWN: return 016; case VK_LEFT: return 002; case VK_RIGHT: return 006; case VK_HOME: return 001; case VK_END: return 005; case VK_DELETE: return 0117; } } } /* Error reading event or, key up or, one of the following event records: MOUSE_EVENT_RECORD, WINDOW_BUFFER_SIZE_RECORD, MENU_EVENT_RECORD, FOCUS_EVENT_RECORD */ return NUL; }
inline void Console::handle_input (HANDLE in, ConsoleScreenBuffer & buffer) { DWORD num; INPUT_RECORD ir; if (!ReadConsoleInputW( in, &ir, 1, &num )) Raise(); // Nothing was read if (num==0) return; // If a resize event was read, // handle and return if (ir.EventType==WINDOW_BUFFER_SIZE_EVENT) { buffer.Resize(); return; } // We're only concerned with key // press events besides resize // events if (!( (ir.EventType==KEY_EVENT) && (ir.Event.KeyEvent.bKeyDown) )) return; // Loop for the number of times // this key press was repeated for (WORD i=0; i<ir.Event.KeyEvent.wRepeatCount; ++i) { // Switch depending on the key // pressed switch (ir.Event.KeyEvent.wVirtualKeyCode) { case VK_RETURN: { // Enter was pressed // Get line from the screen String line(buffer.Return()); // Dispatch callback (if applicable) if (callback) callback(std::move(line)); } break; case VK_HOME: // Home was pressed // Fire appropriate event // depending on whether CTRL // is pressed or not if (ctrl_pressed(ir)) buffer.CtrlHome(); else buffer.Home(); break; case VK_END: // End was pressed // Fire appropriate event // depending on whether // CTRL is pressed or not if (ctrl_pressed(ir)) buffer.CtrlEnd(); else buffer.End(); break; case VK_RIGHT: // Right was pressed buffer.Right(); break; case VK_LEFT: // Left was pressed buffer.Left(); break; case VK_DELETE: // Delete was pressed buffer.Delete(); break; case VK_BACK: // Backspace was pressed buffer.Backspace(); break; case VK_PRIOR: // Page Up was pressed buffer.PageUp(); break; case VK_NEXT: // Page Down was pressed buffer.PageDown(); break; default: if (ir.Event.KeyEvent.uChar.UnicodeChar!=0) buffer.Add( static_cast<CodePoint>( ir.Event.KeyEvent.uChar.UnicodeChar ) ); break; } } }
JNIEXPORT void JNICALL Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_readInput(JNIEnv *env, jclass target, jobject char_buffer, jobject result) { init_input(env, result); INPUT_RECORD events[1]; DWORD nread; while(TRUE) { if (!ReadConsoleInputW(console_buffer, events, 1, &nread)) { mark_failed_with_errno(env, "could not read from console", result); return; } if (events[0].EventType != KEY_EVENT) { continue; } KEY_EVENT_RECORD keyEvent = events[0].Event.KeyEvent; if (!keyEvent.bKeyDown) { if (keyEvent.wVirtualKeyCode == 0x43 && keyEvent.uChar.UnicodeChar == 3) { // key down event for ctrl-c doesn't seem to be delivered, but key up event does return; } continue; } if ((keyEvent.dwControlKeyState & (LEFT_ALT_PRESSED|LEFT_CTRL_PRESSED|RIGHT_ALT_PRESSED|RIGHT_CTRL_PRESSED|SHIFT_PRESSED)) == 0) { if (keyEvent.wVirtualKeyCode == VK_RETURN) { control_key(env, 0, char_buffer, result); return; } else if (keyEvent.wVirtualKeyCode == VK_UP) { control_key(env, 1, char_buffer, result); return; } else if (keyEvent.wVirtualKeyCode == VK_DOWN) { control_key(env, 2, char_buffer, result); return; } else if (keyEvent.wVirtualKeyCode == VK_LEFT) { control_key(env, 3, char_buffer, result); return; } else if (keyEvent.wVirtualKeyCode == VK_RIGHT) { control_key(env, 4, char_buffer, result); return; } else if (keyEvent.wVirtualKeyCode == VK_HOME) { control_key(env, 5, char_buffer, result); return; } else if (keyEvent.wVirtualKeyCode == VK_END) { control_key(env, 6, char_buffer, result); return; } else if (keyEvent.wVirtualKeyCode == VK_BACK) { control_key(env, 7, char_buffer, result); return; } else if (keyEvent.wVirtualKeyCode == VK_DELETE) { control_key(env, 8, char_buffer, result); return; } else if (keyEvent.wVirtualKeyCode == VK_PRIOR) { // page up control_key(env, 10, char_buffer, result); return; } else if (keyEvent.wVirtualKeyCode == VK_NEXT) { // page down control_key(env, 11, char_buffer, result); return; } } if (keyEvent.wVirtualKeyCode == 0x44 && keyEvent.uChar.UnicodeChar == 4) { // ctrl-d return; } if (keyEvent.uChar.UnicodeChar == 0) { // Some other control key continue; } if (keyEvent.uChar.UnicodeChar == '\t' && (keyEvent.dwControlKeyState & (SHIFT_PRESSED)) == 0) { // shift-tab control_key(env, 9, char_buffer, result); } else { character(env, (jchar)keyEvent.uChar.UnicodeChar, char_buffer, result); } return; } }
static int gl_getc(void) /* get a character without echoing it to screen */ { int c; static char buf[9] = ""; static int bufavail = 0; static int bufpos = 0; if (bufavail > 0) { bufavail--; return buf[bufpos++]; } bufpos = 0; /* guido masarotto (3/12/98) * get Ansi char code from a Win32 console */ DWORD a; INPUT_RECORD r; DWORD st; WORD vk; CONSOLE_SCREEN_BUFFER_INFO csb; int bbb = 0, nAlt=0, n; c = 0; while (!c) { /* Following two lines seem to be needed under Win2k to reshow the cursor */ GetConsoleScreenBufferInfo(Win32OutputStream, &csb); SetConsoleCursorPosition(Win32OutputStream, csb.dwCursorPosition); ReadConsoleInputW(Win32InputStream, &r, 1, &a); if (!(r.EventType == KEY_EVENT)) break; st = r.Event.KeyEvent.dwControlKeyState; vk = r.Event.KeyEvent.wVirtualKeyCode; if (r.Event.KeyEvent.bKeyDown) { AltIsDown = (st & LEFT_ALT_PRESSED); if (vk == VK_MENU && AltIsDown) { /* VK_MENU is Alt or AltGr */ nAlt = 0; bbb = 0; } else if (st & ENHANCED_KEY) { switch(vk) { case VK_LEFT: c=2 ;break; case VK_RIGHT: c=6;break; case VK_HOME: c='\001';break; case VK_END: c='\005';break; case VK_UP: c=16;break; case VK_DOWN: c=14;break; case VK_DELETE: c='\004';break; } } else if (AltIsDown) { /* Interpret Alt+xxx entries */ switch (vk) { case VK_INSERT: n = 0; break; case VK_END: n = 1; break; case VK_DOWN: n = 2; break; case VK_NEXT: n = 3;break; case VK_LEFT: n = 4; break; case VK_CLEAR: n = 5; break; case VK_RIGHT: n = 6; break; case VK_HOME: n = 7; break; case VK_UP: n = 8; break; case VK_PRIOR: n = 9; break; default: n = -1; } if (n >= 0) bbb = 10 * bbb + n; nAlt += 1; if (nAlt==3) { c = (bbb < 256) && (bbb > 0) ? bbb : 0; bbb = 0; nAlt = 0; } } else { /* Originally uChar.AsciiChar was used here and for MBCS characters GetConsoleInput returned as many events as bytes in the character. As of Windows 8 this reportedly no longer works, GetConsoleInput would only generate one event with the first byte in AsciiChar. The bug still exists in Windows 10, and thus we now call GetConsoleInputW to get uchar.UnicodeChar. Ideally (at least for Windows) all of getline code would be refactored to work with wide characters, but for now we just convert the character back to bytes in current native locale to recover the old behavior of gl_getc. */ wchar_t wc = r.Event.KeyEvent.uChar.UnicodeChar; mbstate_t mb_st; mbs_init(&mb_st); if (wc != L'\0') { size_t cres = wcrtomb(buf, wc, &mb_st); if (cres != (size_t)-1) { bufavail = (int) cres - 1; bufpos = 1; c = buf[0]; } } } } else if (vk == VK_MENU && AltIsDown) { /* Alt key up event: could be AltGr, but let's hope users only press one of them at a time. */ AltIsDown = 0; c = (bbb < 256) && (bbb > 0) ? bbb : 0; bbb = 0; nAlt = 0; } if ((c < -127) || (c > 255)) c = 0; if (c < 0) c = 256 + c; } return c; }