Cygwin: CYGWIN_NT-10.0-19045 WEED3 3.5.4-1.x86_64 2024-08-25 16:52 UTC x86_64 Cygwin Windows Terminal version: 1.20.11781.0 Windows build number: 10.0.19045.4780
When running a cygwin64 based terminal application under a MsTerminal session, with win32-raw-mode "\033[?9001h" enabled, after brief input in the application becoming unresponsive and the session rapidly consumes all available memory/cpu.. Test application attached, plus ticket https://github.com/microsoft/terminal/issues/17824 contains additional information. Regards
/* * win32-input-mode key test * * Build: gcc -o rawkey rawkey.c * Usage: rawkey [--noraw] [--mouse] */ #include <termios.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <getopt.h> #include <libgen.h> typedef struct _MSTERMINAL_INPUT_RECORD { unsigned bKeyDown; unsigned wRepeatCount; unsigned wVirtualKeyCode; unsigned wVirtualScanCode; union { unsigned UnicodeChar; char AsciiChar; } uChar; unsigned dwControlKeyState; #define ENHANCED_KEY 0x0100 #define LEFT_ALT_PRESSED 0x0002 #define LEFT_CTRL_PRESSED 0x0008 #define RIGHT_ALT_PRESSED 0x0001 #define RIGHT_CTRL_PRESSED 0x0004 #define SHIFT_PRESSED 0x0010 } MSTERMINAL_INPUT_RECORD; static void usage(void); static void test(int win32_input_mode, int mouse_mode); static void hex(const void *buf, unsigned len); static const char *mskey(MSTERMINAL_INPUT_RECORD *ke, const char *buf, const char *end); static const char *progname = ""; static const char *short_options = "rmh"; static struct option long_options[] = { {"noraw", no_argument, NULL, 'r'}, {"mouse", no_argument, NULL, 'm'}, {"help", no_argument, 0, 'h'}, {0} }; int main(int argc, char **argv) { int win32_input_mode = 1, mouse_mode = 0; int optidx = 0, c; progname = basename(argv[0]); while ((c = getopt_long(argc, argv, short_options, long_options, &optidx)) != EOF) { switch (c) { case 'r': // -r,--noraw win32_input_mode = 0; break; case 'm': // -m,--mouse mouse_mode = 1; break; case 'h': // -h,--help usage(); default: return EXIT_FAILURE; } } argv += optind; if ((argc -= optind) != 0) { printf("%s: unexpected argument(s) %s\n", progname, argv[0]); usage(); } test(win32_input_mode, mouse_mode); return 0; } static void usage(void) { printf("\nUsage %s: rawkey [--noraw] [--mouse]\n", progname); exit(EXIT_FAILURE); } static void prints(const char *str) { fputs(str, stdout); } static void test(int win32_input_mode, int mouse_mode) { struct termios bak, cfg; MSTERMINAL_INPUT_RECORD key; char buf[128]; int cnt, q; tcgetattr(STDIN_FILENO, &cfg); bak = cfg; cfmakeraw(&cfg); cfg.c_lflag &= ~ECHO; tcsetattr(STDIN_FILENO, TCSADRAIN, &cfg); if (win32_input_mode) { // enable win32-input-mode. prints("\033[?9001h"); } if (mouse_mode) { prints("\x1b[?1002h"); // enable cell-motion tracking. prints("\x1b[?1006h"); // enable SGR extended mouse mode. } printf("\n\rraw-mode (press 'q' twice to exit, raw=%d, mouse=%d):\n\r", win32_input_mode, mouse_mode); fflush(stdout); for (q = 0; (cnt = read(STDIN_FILENO, buf, sizeof(buf))) > 0;) { hex(buf, cnt); if (mskey(&key, buf, buf + cnt)) { printf(" Key: %s-%s%s%s%s%s%sVK=0x%02x/%u, UC=0x%04x/%u/%c, SC=0x%x/%u\n\r", (key.bKeyDown ? "DN" : "UP"), ((key.dwControlKeyState & ENHANCED_KEY) ? "Enh-" : ""), (key.dwControlKeyState & LEFT_ALT_PRESSED) ? "LAlt-" : "", (key.dwControlKeyState & RIGHT_ALT_PRESSED) ? "RAlt-" : "", (key.dwControlKeyState & LEFT_CTRL_PRESSED) ? "LCtrl-" : "", (key.dwControlKeyState & RIGHT_CTRL_PRESSED) ? "RCtrl-" : "", (key.dwControlKeyState & SHIFT_PRESSED) ? "Shift-" : "", key.wVirtualKeyCode, key.wVirtualKeyCode, key.uChar.UnicodeChar, key.uChar.UnicodeChar, (key.uChar.UnicodeChar && key.uChar.UnicodeChar < 255 ? key.uChar.UnicodeChar : ' '), key.wVirtualScanCode, key.wVirtualScanCode); if (key.bKeyDown) { if (key.uChar.UnicodeChar == 'q') { if (++q == 2) { break; } } else { q = 0; } } } else { // ascii if (buf[0] == 'q') { if (++q == 2) { break; } } else { q = 0; } } fflush(stdout); } if (mouse_mode) { prints("\x1b[?1006l"); // disable SGR extended mouse mode. prints("\x1b[?1002l"); // disable cell-motion tracking. } if (win32_input_mode) prints("\033[?9001l"); // disable win32-input-mode. fflush(stdout); tcsetattr(STDIN_FILENO, TCSADRAIN, &bak); } static void hex(const void *buf, unsigned len) { #define HEXWIDTH 32 #define HEXCOLUMN 4 const unsigned char *cursor = buf, *end = cursor + len; unsigned offset = 0; for (offset = 0; cursor < end; offset += HEXWIDTH) { const unsigned char *data = cursor; printf("%04x: ", offset); for (unsigned col = 0; col < HEXWIDTH; ++col) { if ((col % HEXCOLUMN) == 0 && col) prints(" |"); if (data == end) { prints(" "); } else { printf(" %02x", *data++); } } prints(" "); for (unsigned col = 0; col < HEXWIDTH && cursor < end; ++col) { const unsigned char c = *cursor++; printf("%c", (c >= ' ' && c < 0x7f ? c : '.')); } prints("\n\r"); } fflush(stdout); } // // Decode a MSTerminal specific key escape sequence. // enum { msVirtualKeyCode, msVirtualScanCode, msUnicodeChar, msKeyDown, msControlKeyState, msRepeatCount, msgArgumentMax }; static const char * DecodeMSTerminalArgs(unsigned arguments[msgArgumentMax], const char *buffer, const char *end) { const char *cursor = buffer + 2; unsigned args = 0, digits = 0; while (cursor < end && *cursor) { const unsigned char c = *cursor++; if (c >= '0' && c <= '9') { if (0 == digits++) { if (args >= msgArgumentMax) { break; // overflow } arguments[args] = (c - '0'); } else { arguments[args] = (arguments[args] * 10) + (c - '0'); } } else if (c == ';' || c == '_') { digits = 0; ++args; if (c == '_') { // terminator return (args >= 1 ? cursor : NULL); } } else { args = 0; // non-digit break; } } return NULL; } static const char * mskey(MSTERMINAL_INPUT_RECORD *ke, const char *buf, const char *end) { if ((buf + 6) < end && buf[0] == '\033' && buf[1] == '[' && buf[2]) { /* * Terminal win32-input-mode * * <ESC>[17;29;0;1;8;1_ * * Format: * * <ESC>[Vk;Sc;Uc;Kd;Cs;Rc_ * * Vk: the value of wVirtualKeyCode - any number. If omitted, defaults to '0'. * Sc: the value of wVirtualScanCode - any number. If omitted, defaults to '0'. * Uc: the decimal value of UnicodeChar - for example, NUL is "0", LF is * "10", the character 'A' is "65". If omitted, defaults to '0'. * Kd: the value of bKeyDown - either a '0' or '1'. If omitted, defaults to '0'. * Cs: the value of dwControlKeyState - any number. If omitted, defaults to '0'. * Rc: the value of wRepeatCount - any number. If omitted, defaults to '1'. * * Reference * https://github.com/microsoft/terminal/blob/main/doc/specs/%234999%20-%20Improved%20keyboard%20handling%20in%20Conpty.md */ unsigned args[msgArgumentMax] = { 0, 0, 0, 0, 0, 1 }; const char *cursor; if (NULL != (cursor = DecodeMSTerminalArgs(args, buf, end))) { memset(ke, 0, sizeof(*ke)); ke->bKeyDown = args[msKeyDown] ? 1U : -0U; ke->wRepeatCount = args[msRepeatCount]; ke->wVirtualKeyCode = args[msVirtualKeyCode]; ke->wVirtualScanCode = args[msVirtualScanCode]; ke->uChar.UnicodeChar = args[msUnicodeChar]; ke->dwControlKeyState = args[msControlKeyState]; return cursor; } } return NULL; } //end
-- Problem reports: https://cygwin.com/problems.html FAQ: https://cygwin.com/faq/ Documentation: https://cygwin.com/docs.html Unsubscribe info: https://cygwin.com/ml/#unsubscribe-simple