diff options
-rw-r--r-- | adb/commandline.cpp | 11 | ||||
-rw-r--r-- | adb/sysdeps.h | 6 | ||||
-rw-r--r-- | adb/sysdeps_win32.c | 903 |
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. |
249 | static void stdin_raw_init(int fd) { | 249 | extern "C" { |
250 | 250 | void stdin_raw_init(int fd); | |
251 | } | 251 | void stdin_raw_restore(int fd); |
252 | |||
253 | static 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 | ||
153 | static __inline__ int unix_read(int fd, void* buf, size_t len) | 153 | extern 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. | ||
2291 | static 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. | ||
2327 | static INPUT_RECORD _win32_input_record; | ||
2328 | |||
2329 | // Get the next KEY_EVENT_RECORD that should be processed. | ||
2330 | static 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 | |||
2346 | static __inline__ bool _is_shift_pressed(const DWORD control_key_state) { | ||
2347 | return (control_key_state & SHIFT_PRESSED) != 0; | ||
2348 | } | ||
2349 | |||
2350 | static __inline__ bool _is_ctrl_pressed(const DWORD control_key_state) { | ||
2351 | return (control_key_state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0; | ||
2352 | } | ||
2353 | |||
2354 | static __inline__ bool _is_alt_pressed(const DWORD control_key_state) { | ||
2355 | return (control_key_state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) != 0; | ||
2356 | } | ||
2357 | |||
2358 | static __inline__ bool _is_numlock_on(const DWORD control_key_state) { | ||
2359 | return (control_key_state & NUMLOCK_ON) != 0; | ||
2360 | } | ||
2361 | |||
2362 | static __inline__ bool _is_capslock_on(const DWORD control_key_state) { | ||
2363 | return (control_key_state & CAPSLOCK_ON) != 0; | ||
2364 | } | ||
2365 | |||
2366 | static __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(). | ||
2371 | static const BYTE TOASCII_KEY_OFF = 0x00; | ||
2372 | static const BYTE TOASCII_KEY_DOWN = 0x80; | ||
2373 | static 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. | ||
2378 | static 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. | ||
2431 | static __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. | ||
2438 | static __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. | ||
2447 | static 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 | |||
2505 | static 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. | ||
2560 | static 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 | |||
2585 | static 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. | ||
2603 | static 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. | ||
2646 | static 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. | ||
2672 | static 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. | ||
2678 | size_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). | ||
2693 | static 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 | |||
3083 | static DWORD _old_console_mode; // previous GetConsoleMode() result | ||
3084 | static HANDLE _console_handle; // when set, console mode should be restored | ||
3085 | |||
3086 | void 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 | |||
3126 | void 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. | ||
3142 | int 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 | } | ||