summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Albert2015-03-27 00:28:37 -0500
committerGerrit Code Review2015-03-27 00:28:38 -0500
commit87378814a06f6fa2d22026cbcb2f54be4b65e6c6 (patch)
tree2cafe85a665903d373197548173d0c70d9e0ed3f
parent6e014d774d5ff1fc05d619b348813a5e567f40d2 (diff)
parent50184062b87a121458fff7d8bda6656c59c71c77 (diff)
downloadplatform-system-core-87378814a06f6fa2d22026cbcb2f54be4b65e6c6.tar.gz
platform-system-core-87378814a06f6fa2d22026cbcb2f54be4b65e6c6.tar.xz
platform-system-core-87378814a06f6fa2d22026cbcb2f54be4b65e6c6.zip
Merge "adb shell: Win32: fix Ctrl-C, tab completion, line editing, server echo"
-rw-r--r--adb/commandline.cpp11
-rw-r--r--adb/sysdeps.h6
-rw-r--r--adb/sysdeps_win32.c903
3 files changed, 909 insertions, 11 deletions
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index c9b1eabc7..3330baa64 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -245,13 +245,10 @@ int usage()
245 245
246#if defined(_WIN32) 246#if defined(_WIN32)
247 247
248// Windows does not have <termio.h>. 248// Implemented in sysdeps_win32.c.
249static void stdin_raw_init(int fd) { 249extern "C" {
250 250void stdin_raw_init(int fd);
251} 251void stdin_raw_restore(int fd);
252
253static void stdin_raw_restore(int fd) {
254
255} 252}
256 253
257#else 254#else
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index c317e3ae9..2ad28fa1d 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -150,10 +150,8 @@ static __inline__ int unix_close(int fd)
150#undef close 150#undef close
151#define close ____xxx_close 151#define close ____xxx_close
152 152
153static __inline__ int unix_read(int fd, void* buf, size_t len) 153extern int unix_read(int fd, void* buf, size_t len);
154{ 154
155 return read(fd, buf, len);
156}
157#undef read 155#undef read
158#define read ___xxx_read 156#define read ___xxx_read
159 157
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c
index c28e031c2..c2742f10b 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.c
@@ -22,6 +22,7 @@
22#include <windows.h> 22#include <windows.h>
23 23
24#include <errno.h> 24#include <errno.h>
25#include <stdbool.h>
25#include <stdio.h> 26#include <stdio.h>
26#include <stdlib.h> 27#include <stdlib.h>
27 28
@@ -2250,3 +2251,905 @@ cont:
2250 } 2251 }
2251 /* NOTREACHED */ 2252 /* NOTREACHED */
2252} 2253}
2254
2255/**************************************************************************/
2256/**************************************************************************/
2257/***** *****/
2258/***** Console Window Terminal Emulation *****/
2259/***** *****/
2260/**************************************************************************/
2261/**************************************************************************/
2262
2263// This reads input from a Win32 console window and translates it into Unix
2264// terminal-style sequences. This emulates mostly Gnome Terminal (in Normal
2265// mode, not Application mode), which itself emulates xterm. Gnome Terminal
2266// is emulated instead of xterm because it is probably more popular than xterm:
2267// Ubuntu's default Ctrl-Alt-T shortcut opens Gnome Terminal, Gnome Terminal
2268// supports modern fonts, etc. It seems best to emulate the terminal that most
2269// Android developers use because they'll fix apps (the shell, etc.) to keep
2270// working with that terminal's emulation.
2271//
2272// The point of this emulation is not to be perfect or to solve all issues with
2273// console windows on Windows, but to be better than the original code which
2274// just called read() (which called ReadFile(), which called ReadConsoleA())
2275// which did not support Ctrl-C, tab completion, shell input line editing
2276// keys, server echo, and more.
2277//
2278// This implementation reconfigures the console with SetConsoleMode(), then
2279// calls ReadConsoleInput() to get raw input which it remaps to Unix
2280// terminal-style sequences which is returned via unix_read() which is used
2281// by the 'adb shell' command.
2282//
2283// Code organization:
2284//
2285// * stdin_raw_init() and stdin_raw_restore() reconfigure the console.
2286// * unix_read() detects console windows (as opposed to pipes, files, etc.).
2287// * _console_read() is the main code of the emulation.
2288
2289
2290// Read an input record from the console; one that should be processed.
2291static bool _get_interesting_input_record_uncached(const HANDLE console,
2292 INPUT_RECORD* const input_record) {
2293 for (;;) {
2294 DWORD read_count = 0;
2295 memset(input_record, 0, sizeof(*input_record));
2296 if (!ReadConsoleInputA(console, input_record, 1, &read_count)) {
2297 D("_get_interesting_input_record_uncached: ReadConsoleInputA() "
2298 "failure, error %ld\n", GetLastError());
2299 errno = EIO;
2300 return false;
2301 }
2302
2303 if (read_count == 0) { // should be impossible
2304 fatal("ReadConsoleInputA returned 0");
2305 }
2306
2307 if (read_count != 1) { // should be impossible
2308 fatal("ReadConsoleInputA did not return one input record");
2309 }
2310
2311 if ((input_record->EventType == KEY_EVENT) &&
2312 (input_record->Event.KeyEvent.bKeyDown)) {
2313 if (input_record->Event.KeyEvent.wRepeatCount == 0) {
2314 fatal("ReadConsoleInputA returned a key event with zero repeat"
2315 " count");
2316 }
2317
2318 // Got an interesting INPUT_RECORD, so return
2319 return true;
2320 }
2321 }
2322}
2323
2324// Cached input record (in case _console_read() is passed a buffer that doesn't
2325// have enough space to fit wRepeatCount number of key sequences). A non-zero
2326// wRepeatCount indicates that a record is cached.
2327static INPUT_RECORD _win32_input_record;
2328
2329// Get the next KEY_EVENT_RECORD that should be processed.
2330static KEY_EVENT_RECORD* _get_key_event_record(const HANDLE console) {
2331 // If nothing cached, read directly from the console until we get an
2332 // interesting record.
2333 if (_win32_input_record.Event.KeyEvent.wRepeatCount == 0) {
2334 if (!_get_interesting_input_record_uncached(console,
2335 &_win32_input_record)) {
2336 // There was an error, so make sure wRepeatCount is zero because
2337 // that signifies no cached input record.
2338 _win32_input_record.Event.KeyEvent.wRepeatCount = 0;
2339 return NULL;
2340 }
2341 }
2342
2343 return &_win32_input_record.Event.KeyEvent;
2344}
2345
2346static __inline__ bool _is_shift_pressed(const DWORD control_key_state) {
2347 return (control_key_state & SHIFT_PRESSED) != 0;
2348}
2349
2350static __inline__ bool _is_ctrl_pressed(const DWORD control_key_state) {
2351 return (control_key_state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0;
2352}
2353
2354static __inline__ bool _is_alt_pressed(const DWORD control_key_state) {
2355 return (control_key_state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) != 0;
2356}
2357
2358static __inline__ bool _is_numlock_on(const DWORD control_key_state) {
2359 return (control_key_state & NUMLOCK_ON) != 0;
2360}
2361
2362static __inline__ bool _is_capslock_on(const DWORD control_key_state) {
2363 return (control_key_state & CAPSLOCK_ON) != 0;
2364}
2365
2366static __inline__ bool _is_enhanced_key(const DWORD control_key_state) {
2367 return (control_key_state & ENHANCED_KEY) != 0;
2368}
2369
2370// Constants from MSDN for ToAscii().
2371static const BYTE TOASCII_KEY_OFF = 0x00;
2372static const BYTE TOASCII_KEY_DOWN = 0x80;
2373static const BYTE TOASCII_KEY_TOGGLED_ON = 0x01; // for CapsLock
2374
2375// Given a key event, ignore a modifier key and return the character that was
2376// entered without the modifier. Writes to *ch and returns the number of bytes
2377// written.
2378static size_t _get_char_ignoring_modifier(char* const ch,
2379 const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state,
2380 const WORD modifier) {
2381 // If there is no character from Windows, try ignoring the specified
2382 // modifier and look for a character. Note that if AltGr is being used,
2383 // there will be a character from Windows.
2384 if (key_event->uChar.AsciiChar == '\0') {
2385 // Note that we read the control key state from the passed in argument
2386 // instead of from key_event since the argument has been normalized.
2387 if (((modifier == VK_SHIFT) &&
2388 _is_shift_pressed(control_key_state)) ||
2389 ((modifier == VK_CONTROL) &&
2390 _is_ctrl_pressed(control_key_state)) ||
2391 ((modifier == VK_MENU) && _is_alt_pressed(control_key_state))) {
2392
2393 BYTE key_state[256] = {0};
2394 key_state[VK_SHIFT] = _is_shift_pressed(control_key_state) ?
2395 TOASCII_KEY_DOWN : TOASCII_KEY_OFF;
2396 key_state[VK_CONTROL] = _is_ctrl_pressed(control_key_state) ?
2397 TOASCII_KEY_DOWN : TOASCII_KEY_OFF;
2398 key_state[VK_MENU] = _is_alt_pressed(control_key_state) ?
2399 TOASCII_KEY_DOWN : TOASCII_KEY_OFF;
2400 key_state[VK_CAPITAL] = _is_capslock_on(control_key_state) ?
2401 TOASCII_KEY_TOGGLED_ON : TOASCII_KEY_OFF;
2402
2403 // cause this modifier to be ignored
2404 key_state[modifier] = TOASCII_KEY_OFF;
2405
2406 WORD translated = 0;
2407 if (ToAscii(key_event->wVirtualKeyCode,
2408 key_event->wVirtualScanCode, key_state, &translated, 0) == 1) {
2409 // Ignoring the modifier, we found a character.
2410 *ch = (CHAR)translated;
2411 return 1;
2412 }
2413 }
2414 }
2415
2416 // Just use whatever Windows told us originally.
2417 *ch = key_event->uChar.AsciiChar;
2418
2419 // If the character from Windows is NULL, return a size of zero.
2420 return (*ch == '\0') ? 0 : 1;
2421}
2422
2423// If a Ctrl key is pressed, lookup the character, ignoring the Ctrl key,
2424// but taking into account the shift key. This is because for a sequence like
2425// Ctrl-Alt-0, we want to find the character '0' and for Ctrl-Alt-Shift-0,
2426// we want to find the character ')'.
2427//
2428// Note that Windows doesn't seem to pass bKeyDown for Ctrl-Shift-NoAlt-0
2429// because it is the default key-sequence to switch the input language.
2430// This is configurable in the Region and Language control panel.
2431static __inline__ size_t _get_non_control_char(char* const ch,
2432 const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state) {
2433 return _get_char_ignoring_modifier(ch, key_event, control_key_state,
2434 VK_CONTROL);
2435}
2436
2437// Get without Alt.
2438static __inline__ size_t _get_non_alt_char(char* const ch,
2439 const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state) {
2440 return _get_char_ignoring_modifier(ch, key_event, control_key_state,
2441 VK_MENU);
2442}
2443
2444// Ignore the control key, find the character from Windows, and apply any
2445// Control key mappings (for example, Ctrl-2 is a NULL character). Writes to
2446// *pch and returns number of bytes written.
2447static size_t _get_control_character(char* const pch,
2448 const KEY_EVENT_RECORD* const key_event, const DWORD control_key_state) {
2449 const size_t len = _get_non_control_char(pch, key_event,
2450 control_key_state);
2451
2452 if ((len == 1) && _is_ctrl_pressed(control_key_state)) {
2453 char ch = *pch;
2454 switch (ch) {
2455 case '2':
2456 case '@':
2457 case '`':
2458 ch = '\0';
2459 break;
2460 case '3':
2461 case '[':
2462 case '{':
2463 ch = '\x1b';
2464 break;
2465 case '4':
2466 case '\\':
2467 case '|':
2468 ch = '\x1c';
2469 break;
2470 case '5':
2471 case ']':
2472 case '}':
2473 ch = '\x1d';
2474 break;
2475 case '6':
2476 case '^':
2477 case '~':
2478 ch = '\x1e';
2479 break;
2480 case '7':
2481 case '-':
2482 case '_':
2483 ch = '\x1f';
2484 break;
2485 case '8':
2486 ch = '\x7f';
2487 break;
2488 case '/':
2489 if (!_is_alt_pressed(control_key_state)) {
2490 ch = '\x1f';
2491 }
2492 break;
2493 case '?':
2494 if (!_is_alt_pressed(control_key_state)) {
2495 ch = '\x7f';
2496 }
2497 break;
2498 }
2499 *pch = ch;
2500 }
2501
2502 return len;
2503}
2504
2505static DWORD _normalize_altgr_control_key_state(
2506 const KEY_EVENT_RECORD* const key_event) {
2507 DWORD control_key_state = key_event->dwControlKeyState;
2508
2509 // If we're in an AltGr situation where the AltGr key is down (depending on
2510 // the keyboard layout, that might be the physical right alt key which
2511 // produces a control_key_state where Right-Alt and Left-Ctrl are down) or
2512 // AltGr-equivalent keys are down (any Ctrl key + any Alt key), and we have
2513 // a character (which indicates that there was an AltGr mapping), then act
2514 // as if alt and control are not really down for the purposes of modifiers.
2515 // This makes it so that if the user with, say, a German keyboard layout
2516 // presses AltGr-] (which we see as Right-Alt + Left-Ctrl + key), we just
2517 // output the key and we don't see the Alt and Ctrl keys.
2518 if (_is_ctrl_pressed(control_key_state) &&
2519 _is_alt_pressed(control_key_state)
2520 && (key_event->uChar.AsciiChar != '\0')) {
2521 // Try to remove as few bits as possible to improve our chances of
2522 // detecting combinations like Left-Alt + AltGr, Right-Ctrl + AltGr, or
2523 // Left-Alt + Right-Ctrl + AltGr.
2524 if ((control_key_state & RIGHT_ALT_PRESSED) != 0) {
2525 // Remove Right-Alt.
2526 control_key_state &= ~RIGHT_ALT_PRESSED;
2527 // If uChar is set, a Ctrl key is pressed, and Right-Alt is
2528 // pressed, Left-Ctrl is almost always set, except if the user
2529 // presses Right-Ctrl, then AltGr (in that specific order) for
2530 // whatever reason. At any rate, make sure the bit is not set.
2531 control_key_state &= ~LEFT_CTRL_PRESSED;
2532 } else if ((control_key_state & LEFT_ALT_PRESSED) != 0) {
2533 // Remove Left-Alt.
2534 control_key_state &= ~LEFT_ALT_PRESSED;
2535 // Whichever Ctrl key is down, remove it from the state. We only
2536 // remove one key, to improve our chances of detecting the
2537 // corner-case of Left-Ctrl + Left-Alt + Right-Ctrl.
2538 if ((control_key_state & LEFT_CTRL_PRESSED) != 0) {
2539 // Remove Left-Ctrl.
2540 control_key_state &= ~LEFT_CTRL_PRESSED;
2541 } else if ((control_key_state & RIGHT_CTRL_PRESSED) != 0) {
2542 // Remove Right-Ctrl.
2543 control_key_state &= ~RIGHT_CTRL_PRESSED;
2544 }
2545 }
2546
2547 // Note that this logic isn't 100% perfect because Windows doesn't
2548 // allow us to detect all combinations because a physical AltGr key
2549 // press shows up as two bits, plus some combinations are ambiguous
2550 // about what is actually physically pressed.
2551 }
2552
2553 return control_key_state;
2554}
2555
2556// If NumLock is on and Shift is pressed, SHIFT_PRESSED is not set in
2557// dwControlKeyState for the following keypad keys: period, 0-9. If we detect
2558// this scenario, set the SHIFT_PRESSED bit so we can add modifiers
2559// appropriately.
2560static DWORD _normalize_keypad_control_key_state(const WORD vk,
2561 const DWORD control_key_state) {
2562 if (!_is_numlock_on(control_key_state)) {
2563 return control_key_state;
2564 }
2565 if (!_is_enhanced_key(control_key_state)) {
2566 switch (vk) {
2567 case VK_INSERT: // 0
2568 case VK_DELETE: // .
2569 case VK_END: // 1
2570 case VK_DOWN: // 2
2571 case VK_NEXT: // 3
2572 case VK_LEFT: // 4
2573 case VK_CLEAR: // 5
2574 case VK_RIGHT: // 6
2575 case VK_HOME: // 7
2576 case VK_UP: // 8
2577 case VK_PRIOR: // 9
2578 return control_key_state | SHIFT_PRESSED;
2579 }
2580 }
2581
2582 return control_key_state;
2583}
2584
2585static const char* _get_keypad_sequence(const DWORD control_key_state,
2586 const char* const normal, const char* const shifted) {
2587 if (_is_shift_pressed(control_key_state)) {
2588 // Shift is pressed and NumLock is off
2589 return shifted;
2590 } else {
2591 // Shift is not pressed and NumLock is off, or,
2592 // Shift is pressed and NumLock is on, in which case we want the
2593 // NumLock and Shift to neutralize each other, thus, we want the normal
2594 // sequence.
2595 return normal;
2596 }
2597 // If Shift is not pressed and NumLock is on, a different virtual key code
2598 // is returned by Windows, which can be taken care of by a different case
2599 // statement in _console_read().
2600}
2601
2602// Write sequence to buf and return the number of bytes written.
2603static size_t _get_modifier_sequence(char* const buf, const WORD vk,
2604 DWORD control_key_state, const char* const normal) {
2605 // Copy the base sequence into buf.
2606 const size_t len = strlen(normal);
2607 memcpy(buf, normal, len);
2608
2609 int code = 0;
2610
2611 control_key_state = _normalize_keypad_control_key_state(vk,
2612 control_key_state);
2613
2614 if (_is_shift_pressed(control_key_state)) {
2615 code |= 0x1;
2616 }
2617 if (_is_alt_pressed(control_key_state)) { // any alt key pressed
2618 code |= 0x2;
2619 }
2620 if (_is_ctrl_pressed(control_key_state)) { // any control key pressed
2621 code |= 0x4;
2622 }
2623 // If some modifier was held down, then we need to insert the modifier code
2624 if (code != 0) {
2625 if (len == 0) {
2626 // Should be impossible because caller should pass a string of
2627 // non-zero length.
2628 return 0;
2629 }
2630 size_t index = len - 1;
2631 const char lastChar = buf[index];
2632 if (lastChar != '~') {
2633 buf[index++] = '1';
2634 }
2635 buf[index++] = ';'; // modifier separator
2636 // 2 = shift, 3 = alt, 4 = shift & alt, 5 = control,
2637 // 6 = shift & control, 7 = alt & control, 8 = shift & alt & control
2638 buf[index++] = '1' + code;
2639 buf[index++] = lastChar; // move ~ (or other last char) to the end
2640 return index;
2641 }
2642 return len;
2643}
2644
2645// Write sequence to buf and return the number of bytes written.
2646static size_t _get_modifier_keypad_sequence(char* const buf, const WORD vk,
2647 const DWORD control_key_state, const char* const normal,
2648 const char shifted) {
2649 if (_is_shift_pressed(control_key_state)) {
2650 // Shift is pressed and NumLock is off
2651 if (shifted != '\0') {
2652 buf[0] = shifted;
2653 return sizeof(buf[0]);
2654 } else {
2655 return 0;
2656 }
2657 } else {
2658 // Shift is not pressed and NumLock is off, or,
2659 // Shift is pressed and NumLock is on, in which case we want the
2660 // NumLock and Shift to neutralize each other, thus, we want the normal
2661 // sequence.
2662 return _get_modifier_sequence(buf, vk, control_key_state, normal);
2663 }
2664 // If Shift is not pressed and NumLock is on, a different virtual key code
2665 // is returned by Windows, which can be taken care of by a different case
2666 // statement in _console_read().
2667}
2668
2669// The decimal key on the keypad produces a '.' for U.S. English and a ',' for
2670// Standard German. Figure this out at runtime so we know what to output for
2671// Shift-VK_DELETE.
2672static char _get_decimal_char() {
2673 return (char)MapVirtualKeyA(VK_DECIMAL, MAPVK_VK_TO_CHAR);
2674}
2675
2676// Prefix the len bytes in buf with the escape character, and then return the
2677// new buffer length.
2678size_t _escape_prefix(char* const buf, const size_t len) {
2679 // If nothing to prefix, don't do anything. We might be called with
2680 // len == 0, if alt was held down with a dead key which produced nothing.
2681 if (len == 0) {
2682 return 0;
2683 }
2684
2685 memmove(&buf[1], buf, len);
2686 buf[0] = '\x1b';
2687 return len + 1;
2688}
2689
2690// Writes to buffer buf (of length len), returning number of bytes written or
2691// -1 on error. Never returns zero because Win32 consoles are never 'closed'
2692// (as far as I can tell).
2693static int _console_read(const HANDLE console, void* buf, size_t len) {
2694 for (;;) {
2695 KEY_EVENT_RECORD* const key_event = _get_key_event_record(console);
2696 if (key_event == NULL) {
2697 return -1;
2698 }
2699
2700 const WORD vk = key_event->wVirtualKeyCode;
2701 const CHAR ch = key_event->uChar.AsciiChar;
2702 const DWORD control_key_state = _normalize_altgr_control_key_state(
2703 key_event);
2704
2705 // The following emulation code should write the output sequence to
2706 // either seqstr or to seqbuf and seqbuflen.
2707 const char* seqstr = NULL; // NULL terminated C-string
2708 // Enough space for max sequence string below, plus modifiers and/or
2709 // escape prefix.
2710 char seqbuf[16];
2711 size_t seqbuflen = 0; // Space used in seqbuf.
2712
2713#define MATCH(vk, normal) \
2714 case (vk): \
2715 { \
2716 seqstr = (normal); \
2717 } \
2718 break;
2719
2720 // Modifier keys should affect the output sequence.
2721#define MATCH_MODIFIER(vk, normal) \
2722 case (vk): \
2723 { \
2724 seqbuflen = _get_modifier_sequence(seqbuf, (vk), \
2725 control_key_state, (normal)); \
2726 } \
2727 break;
2728
2729 // The shift key should affect the output sequence.
2730#define MATCH_KEYPAD(vk, normal, shifted) \
2731 case (vk): \
2732 { \
2733 seqstr = _get_keypad_sequence(control_key_state, (normal), \
2734 (shifted)); \
2735 } \
2736 break;
2737
2738 // The shift key and other modifier keys should affect the output
2739 // sequence.
2740#define MATCH_MODIFIER_KEYPAD(vk, normal, shifted) \
2741 case (vk): \
2742 { \
2743 seqbuflen = _get_modifier_keypad_sequence(seqbuf, (vk), \
2744 control_key_state, (normal), (shifted)); \
2745 } \
2746 break;
2747
2748#define ESC "\x1b"
2749#define CSI ESC "["
2750#define SS3 ESC "O"
2751
2752 // Only support normal mode, not application mode.
2753
2754 // Enhanced keys:
2755 // * 6-pack: insert, delete, home, end, page up, page down
2756 // * cursor keys: up, down, right, left
2757 // * keypad: divide, enter
2758 // * Undocumented: VK_PAUSE (Ctrl-NumLock), VK_SNAPSHOT,
2759 // VK_CANCEL (Ctrl-Pause/Break), VK_NUMLOCK
2760 if (_is_enhanced_key(control_key_state)) {
2761 switch (vk) {
2762 case VK_RETURN: // Enter key on keypad
2763 if (_is_ctrl_pressed(control_key_state)) {
2764 seqstr = "\n";
2765 } else {
2766 seqstr = "\r";
2767 }
2768 break;
2769
2770 MATCH_MODIFIER(VK_PRIOR, CSI "5~"); // Page Up
2771 MATCH_MODIFIER(VK_NEXT, CSI "6~"); // Page Down
2772
2773 // gnome-terminal currently sends SS3 "F" and SS3 "H", but that
2774 // will be fixed soon to match xterm which sends CSI "F" and
2775 // CSI "H". https://bugzilla.redhat.com/show_bug.cgi?id=1119764
2776 MATCH(VK_END, CSI "F");
2777 MATCH(VK_HOME, CSI "H");
2778
2779 MATCH_MODIFIER(VK_LEFT, CSI "D");
2780 MATCH_MODIFIER(VK_UP, CSI "A");
2781 MATCH_MODIFIER(VK_RIGHT, CSI "C");
2782 MATCH_MODIFIER(VK_DOWN, CSI "B");
2783
2784 MATCH_MODIFIER(VK_INSERT, CSI "2~");
2785 MATCH_MODIFIER(VK_DELETE, CSI "3~");
2786
2787 MATCH(VK_DIVIDE, "/");
2788 }
2789 } else { // Non-enhanced keys:
2790 switch (vk) {
2791 case VK_BACK: // backspace
2792 if (_is_alt_pressed(control_key_state)) {
2793 seqstr = ESC "\x7f";
2794 } else {
2795 seqstr = "\x7f";
2796 }
2797 break;
2798
2799 case VK_TAB:
2800 if (_is_shift_pressed(control_key_state)) {
2801 seqstr = CSI "Z";
2802 } else {
2803 seqstr = "\t";
2804 }
2805 break;
2806
2807 // Number 5 key in keypad when NumLock is off, or if NumLock is
2808 // on and Shift is down.
2809 MATCH_KEYPAD(VK_CLEAR, CSI "E", "5");
2810
2811 case VK_RETURN: // Enter key on main keyboard
2812 if (_is_alt_pressed(control_key_state)) {
2813 seqstr = ESC "\n";
2814 } else if (_is_ctrl_pressed(control_key_state)) {
2815 seqstr = "\n";
2816 } else {
2817 seqstr = "\r";
2818 }
2819 break;
2820
2821 // VK_ESCAPE: Don't do any special handling. The OS uses many
2822 // of the sequences with Escape and many of the remaining
2823 // sequences don't produce bKeyDown messages, only !bKeyDown
2824 // for whatever reason.
2825
2826 case VK_SPACE:
2827 if (_is_alt_pressed(control_key_state)) {
2828 seqstr = ESC " ";
2829 } else if (_is_ctrl_pressed(control_key_state)) {
2830 seqbuf[0] = '\0'; // NULL char
2831 seqbuflen = 1;
2832 } else {
2833 seqstr = " ";
2834 }
2835 break;
2836
2837 MATCH_MODIFIER_KEYPAD(VK_PRIOR, CSI "5~", '9'); // Page Up
2838 MATCH_MODIFIER_KEYPAD(VK_NEXT, CSI "6~", '3'); // Page Down
2839
2840 MATCH_KEYPAD(VK_END, CSI "4~", "1");
2841 MATCH_KEYPAD(VK_HOME, CSI "1~", "7");
2842
2843 MATCH_MODIFIER_KEYPAD(VK_LEFT, CSI "D", '4');
2844 MATCH_MODIFIER_KEYPAD(VK_UP, CSI "A", '8');
2845 MATCH_MODIFIER_KEYPAD(VK_RIGHT, CSI "C", '6');
2846 MATCH_MODIFIER_KEYPAD(VK_DOWN, CSI "B", '2');
2847
2848 MATCH_MODIFIER_KEYPAD(VK_INSERT, CSI "2~", '0');
2849 MATCH_MODIFIER_KEYPAD(VK_DELETE, CSI "3~",
2850 _get_decimal_char());
2851
2852 case 0x30: // 0
2853 case 0x31: // 1
2854 case 0x39: // 9
2855 case VK_OEM_1: // ;:
2856 case VK_OEM_PLUS: // =+
2857 case VK_OEM_COMMA: // ,<
2858 case VK_OEM_PERIOD: // .>
2859 case VK_OEM_7: // '"
2860 case VK_OEM_102: // depends on keyboard, could be <> or \|
2861 case VK_OEM_2: // /?
2862 case VK_OEM_3: // `~
2863 case VK_OEM_4: // [{
2864 case VK_OEM_5: // \|
2865 case VK_OEM_6: // ]}
2866 {
2867 seqbuflen = _get_control_character(seqbuf, key_event,
2868 control_key_state);
2869
2870 if (_is_alt_pressed(control_key_state)) {
2871 seqbuflen = _escape_prefix(seqbuf, seqbuflen);
2872 }
2873 }
2874 break;
2875
2876 case 0x32: // 2
2877 case 0x36: // 6
2878 case VK_OEM_MINUS: // -_
2879 {
2880 seqbuflen = _get_control_character(seqbuf, key_event,
2881 control_key_state);
2882
2883 // If Alt is pressed and it isn't Ctrl-Alt-ShiftUp, then
2884 // prefix with escape.
2885 if (_is_alt_pressed(control_key_state) &&
2886 !(_is_ctrl_pressed(control_key_state) &&
2887 !_is_shift_pressed(control_key_state))) {
2888 seqbuflen = _escape_prefix(seqbuf, seqbuflen);
2889 }
2890 }
2891 break;
2892
2893 case 0x33: // 3
2894 case 0x34: // 4
2895 case 0x35: // 5
2896 case 0x37: // 7
2897 case 0x38: // 8
2898 {
2899 seqbuflen = _get_control_character(seqbuf, key_event,
2900 control_key_state);
2901
2902 // If Alt is pressed and it isn't Ctrl-Alt-ShiftUp, then
2903 // prefix with escape.
2904 if (_is_alt_pressed(control_key_state) &&
2905 !(_is_ctrl_pressed(control_key_state) &&
2906 !_is_shift_pressed(control_key_state))) {
2907 seqbuflen = _escape_prefix(seqbuf, seqbuflen);
2908 }
2909 }
2910 break;
2911
2912 case 0x41: // a
2913 case 0x42: // b
2914 case 0x43: // c
2915 case 0x44: // d
2916 case 0x45: // e
2917 case 0x46: // f
2918 case 0x47: // g
2919 case 0x48: // h
2920 case 0x49: // i
2921 case 0x4a: // j
2922 case 0x4b: // k
2923 case 0x4c: // l
2924 case 0x4d: // m
2925 case 0x4e: // n
2926 case 0x4f: // o
2927 case 0x50: // p
2928 case 0x51: // q
2929 case 0x52: // r
2930 case 0x53: // s
2931 case 0x54: // t
2932 case 0x55: // u
2933 case 0x56: // v
2934 case 0x57: // w
2935 case 0x58: // x
2936 case 0x59: // y
2937 case 0x5a: // z
2938 {
2939 seqbuflen = _get_non_alt_char(seqbuf, key_event,
2940 control_key_state);
2941
2942 // If Alt is pressed, then prefix with escape.
2943 if (_is_alt_pressed(control_key_state)) {
2944 seqbuflen = _escape_prefix(seqbuf, seqbuflen);
2945 }
2946 }
2947 break;
2948
2949 // These virtual key codes are generated by the keys on the
2950 // keypad *when NumLock is on* and *Shift is up*.
2951 MATCH(VK_NUMPAD0, "0");
2952 MATCH(VK_NUMPAD1, "1");
2953 MATCH(VK_NUMPAD2, "2");
2954 MATCH(VK_NUMPAD3, "3");
2955 MATCH(VK_NUMPAD4, "4");
2956 MATCH(VK_NUMPAD5, "5");
2957 MATCH(VK_NUMPAD6, "6");
2958 MATCH(VK_NUMPAD7, "7");
2959 MATCH(VK_NUMPAD8, "8");
2960 MATCH(VK_NUMPAD9, "9");
2961
2962 MATCH(VK_MULTIPLY, "*");
2963 MATCH(VK_ADD, "+");
2964 MATCH(VK_SUBTRACT, "-");
2965 // VK_DECIMAL is generated by the . key on the keypad *when
2966 // NumLock is on* and *Shift is up* and the sequence is not
2967 // Ctrl-Alt-NoShift-. (which causes Ctrl-Alt-Del and the
2968 // Windows Security screen to come up).
2969 case VK_DECIMAL:
2970 // U.S. English uses '.', Germany German uses ','.
2971 seqbuflen = _get_non_control_char(seqbuf, key_event,
2972 control_key_state);
2973 break;
2974
2975 MATCH_MODIFIER(VK_F1, SS3 "P");
2976 MATCH_MODIFIER(VK_F2, SS3 "Q");
2977 MATCH_MODIFIER(VK_F3, SS3 "R");
2978 MATCH_MODIFIER(VK_F4, SS3 "S");
2979 MATCH_MODIFIER(VK_F5, CSI "15~");
2980 MATCH_MODIFIER(VK_F6, CSI "17~");
2981 MATCH_MODIFIER(VK_F7, CSI "18~");
2982 MATCH_MODIFIER(VK_F8, CSI "19~");
2983 MATCH_MODIFIER(VK_F9, CSI "20~");
2984 MATCH_MODIFIER(VK_F10, CSI "21~");
2985 MATCH_MODIFIER(VK_F11, CSI "23~");
2986 MATCH_MODIFIER(VK_F12, CSI "24~");
2987
2988 MATCH_MODIFIER(VK_F13, CSI "25~");
2989 MATCH_MODIFIER(VK_F14, CSI "26~");
2990 MATCH_MODIFIER(VK_F15, CSI "28~");
2991 MATCH_MODIFIER(VK_F16, CSI "29~");
2992 MATCH_MODIFIER(VK_F17, CSI "31~");
2993 MATCH_MODIFIER(VK_F18, CSI "32~");
2994 MATCH_MODIFIER(VK_F19, CSI "33~");
2995 MATCH_MODIFIER(VK_F20, CSI "34~");
2996
2997 // MATCH_MODIFIER(VK_F21, ???);
2998 // MATCH_MODIFIER(VK_F22, ???);
2999 // MATCH_MODIFIER(VK_F23, ???);
3000 // MATCH_MODIFIER(VK_F24, ???);
3001 }
3002 }
3003
3004#undef MATCH
3005#undef MATCH_MODIFIER
3006#undef MATCH_KEYPAD
3007#undef MATCH_MODIFIER_KEYPAD
3008#undef ESC
3009#undef CSI
3010#undef SS3
3011
3012 const char* out;
3013 size_t outlen;
3014
3015 // Check for output in any of:
3016 // * seqstr is set (and strlen can be used to determine the length).
3017 // * seqbuf and seqbuflen are set
3018 // Fallback to ch from Windows.
3019 if (seqstr != NULL) {
3020 out = seqstr;
3021 outlen = strlen(seqstr);
3022 } else if (seqbuflen > 0) {
3023 out = seqbuf;
3024 outlen = seqbuflen;
3025 } else if (ch != '\0') {
3026 // Use whatever Windows told us it is.
3027 seqbuf[0] = ch;
3028 seqbuflen = 1;
3029 out = seqbuf;
3030 outlen = seqbuflen;
3031 } else {
3032 // No special handling for the virtual key code and Windows isn't
3033 // telling us a character code, then we don't know how to translate
3034 // the key press.
3035 //
3036 // Consume the input and 'continue' to cause us to get a new key
3037 // event.
3038 D("_console_read: unknown virtual key code: %d, enhanced: %s\n",
3039 vk, _is_enhanced_key(control_key_state) ? "true" : "false");
3040 key_event->wRepeatCount = 0;
3041 continue;
3042 }
3043
3044 int bytesRead = 0;
3045
3046 // put output wRepeatCount times into buf/len
3047 while (key_event->wRepeatCount > 0) {
3048 if (len >= outlen) {
3049 // Write to buf/len
3050 memcpy(buf, out, outlen);
3051 buf = (void*)((char*)buf + outlen);
3052 len -= outlen;
3053 bytesRead += outlen;
3054
3055 // consume the input
3056 --key_event->wRepeatCount;
3057 } else {
3058 // Not enough space, so just leave it in _win32_input_record
3059 // for a subsequent retrieval.
3060 if (bytesRead == 0) {
3061 // We didn't write anything because there wasn't enough
3062 // space to even write one sequence. This should never
3063 // happen if the caller uses sensible buffer sizes
3064 // (i.e. >= maximum sequence length which is probably a
3065 // few bytes long).
3066 D("_console_read: no buffer space to write one sequence; "
3067 "buffer: %ld, sequence: %ld\n", (long)len,
3068 (long)outlen);
3069 errno = ENOMEM;
3070 return -1;
3071 } else {
3072 // Stop trying to write to buf/len, just return whatever
3073 // we wrote so far.
3074 break;
3075 }
3076 }
3077 }
3078
3079 return bytesRead;
3080 }
3081}
3082
3083static DWORD _old_console_mode; // previous GetConsoleMode() result
3084static HANDLE _console_handle; // when set, console mode should be restored
3085
3086void stdin_raw_init(const int fd) {
3087 if (STDIN_FILENO == fd) {
3088 const HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
3089 if ((in == INVALID_HANDLE_VALUE) || (in == NULL)) {
3090 return;
3091 }
3092
3093 if (GetFileType(in) != FILE_TYPE_CHAR) {
3094 // stdin might be a file or pipe.
3095 return;
3096 }
3097
3098 if (!GetConsoleMode(in, &_old_console_mode)) {
3099 // If GetConsoleMode() fails, stdin is probably is not a console.
3100 return;
3101 }
3102
3103 // Disable ENABLE_PROCESSED_INPUT so that Ctrl-C is read instead of
3104 // calling the process Ctrl-C routine (configured by
3105 // SetConsoleCtrlHandler()).
3106 // Disable ENABLE_LINE_INPUT so that input is immediately sent.
3107 // Disable ENABLE_ECHO_INPUT to disable local echo. Disabling this
3108 // flag also seems necessary to have proper line-ending processing.
3109 if (!SetConsoleMode(in, _old_console_mode & ~(ENABLE_PROCESSED_INPUT |
3110 ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT))) {
3111 // This really should not fail.
3112 D("stdin_raw_init: SetConsoleMode() failure, error %ld\n",
3113 GetLastError());
3114 }
3115
3116 // Once this is set, it means that stdin has been configured for
3117 // reading from and that the old console mode should be restored later.
3118 _console_handle = in;
3119
3120 // Note that we don't need to configure C Runtime line-ending
3121 // translation because _console_read() does not call the C Runtime to
3122 // read from the console.
3123 }
3124}
3125
3126void stdin_raw_restore(const int fd) {
3127 if (STDIN_FILENO == fd) {
3128 if (_console_handle != NULL) {
3129 const HANDLE in = _console_handle;
3130 _console_handle = NULL; // clear state
3131
3132 if (!SetConsoleMode(in, _old_console_mode)) {
3133 // This really should not fail.
3134 D("stdin_raw_restore: SetConsoleMode() failure, error %ld\n",
3135 GetLastError());
3136 }
3137 }
3138 }
3139}
3140
3141// Called by 'adb shell' command to read from stdin.
3142int unix_read(int fd, void* buf, size_t len) {
3143 if ((fd == STDIN_FILENO) && (_console_handle != NULL)) {
3144 // If it is a request to read from stdin, and stdin_raw_init() has been
3145 // called, and it successfully configured the console, then read from
3146 // the console using Win32 console APIs and partially emulate a unix
3147 // terminal.
3148 return _console_read(_console_handle, buf, len);
3149 } else {
3150 // Just call into C Runtime which can read from pipes/files and which
3151 // can do LF/CR translation.
3152#undef read
3153 return read(fd, buf, len);
3154 }
3155}