1 #include "termdesc.h"
2 #include "internal.h"
3 #include "windows.h"
4 #ifdef __MINGW64__
5 // ti has been memset to all zeroes. windows configuration is static.
prepare_windows_terminal(tinfo * ti,size_t * tablelen,size_t * tableused)6 int prepare_windows_terminal(tinfo* ti, size_t* tablelen, size_t* tableused){
7   const struct wtermdesc {
8     escape_e esc;
9     const char* tinfo;
10   } wterms[] = {
11     { ESCAPE_CUP,   "\x1b[%i%p1%d;%p2%dH", },
12     { ESCAPE_RMKX,  "\x1b[?1h", },
13     { ESCAPE_SMKX,  "\x1b[?1l", },
14     { ESCAPE_VPA,   "\x1b[%i%p1%dd", },
15     { ESCAPE_HPA,   "\x1b[%i%p1%dG", },
16     { ESCAPE_SC,    "\x1b[s", },
17     { ESCAPE_RC,    "\x1b[u", },
18     { ESCAPE_INITC, "\x1b]4;%p1%d;rgb:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\", },
19     { ESCAPE_CLEAR, "\x1b[2J", },
20     { ESCAPE_SMCUP, "\x1b[?1049h", },
21     { ESCAPE_RMCUP, "\x1b[?1049l", },
22     { ESCAPE_SETAF, "\x1b[38;5;%i%p1%dm", },
23     { ESCAPE_SETAB, "\x1b[48;5;%i%p1%dm", },
24     { ESCAPE_OP,    "\x1b[39;49m", },
25     { ESCAPE_CIVIS, "\x1b[?25l", },
26     { ESCAPE_CNORM, "\x1b[?25h", },
27     { ESCAPE_U7,    "\x1b[6n", },
28     { ESCAPE_CUU,   "\x1b[A", },
29     { ESCAPE_CUB,   "\x1b[D", },
30     { ESCAPE_CUD,   "\x1b[B", },
31     { ESCAPE_CUF,   "\x1b[C", },
32     { ESCAPE_BOLD,  "\x1b[1m", },
33     { ESCAPE_SITM,  "\x1b[3m", },
34     { ESCAPE_RITM,  "\x1b[23m", },
35     { ESCAPE_SMUL,  "\x1b[4m", },
36     { ESCAPE_RMUL,  "\x1b[24m", },
37     { ESCAPE_SGR0,  "\x1b[0m", },
38     { ESCAPE_MAX, NULL, }
39   }, *w;
40   for(w = wterms ; w->tinfo; ++w){
41     if(grow_esc_table(ti, w->tinfo, w->esc, tablelen, tableused)){
42       return -1;
43     }
44   }
45   ti->caps.rgb = true;
46   ti->caps.colors = 256;
47   ti->inhandle = GetStdHandle(STD_INPUT_HANDLE);
48   ti->outhandle = GetStdHandle(STD_OUTPUT_HANDLE);
49   if(ti->inhandle == INVALID_HANDLE_VALUE){
50     logerror("couldn't get input handle\n");
51     return -1;
52   }
53   if(ti->outhandle == INVALID_HANDLE_VALUE){
54     logerror("couldn't get output handle\n");
55     return -1;
56   }
57   if(!SetConsoleOutputCP(CP_UTF8)){
58     logerror("couldn't set output page to utf8\n");
59     return -1;
60   }
61   if(!SetConsoleCP(CP_UTF8)){
62     logerror("couldn't set input page to utf8\n");
63     return -1;
64   }
65   DWORD inmode;
66   if(!GetConsoleMode(ti->inhandle, &inmode)){
67     logerror("couldn't get input console mode\n");
68     return -1;
69   }
70   // we don't explicitly disable ENABLE_ECHO_INPUT and ENABLE_LINE_INPUT
71   // yet; those are handled in cbreak_mode(). just get ENABLE_INSERT_MODE.
72   inmode &= ~ENABLE_INSERT_MODE;
73   inmode |= ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT
74             | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS
75             | ENABLE_WINDOW_INPUT | ENABLE_VIRTUAL_TERMINAL_INPUT;
76   if(!SetConsoleMode(ti->inhandle, inmode)){
77     logerror("couldn't set input console mode\n");
78     return -1;
79   }
80   // if we're a true Windows Terminal, SetConsoleMode() ought succeed.
81   // otherwise, we're something else; go ahead and try.
82   // FIXME handle redirection to a file, where this fails
83   if(!SetConsoleMode(ti->outhandle, ENABLE_PROCESSED_OUTPUT
84                      | ENABLE_WRAP_AT_EOL_OUTPUT
85                      | ENABLE_VIRTUAL_TERMINAL_PROCESSING
86                      | DISABLE_NEWLINE_AUTO_RETURN
87                      | ENABLE_LVB_GRID_WORLDWIDE)){
88     logerror("couldn't set output console mode\n");
89     return -1;
90   }
91   loginfo("verified Windows ConPTY\n");
92   // ConPTY intercepts most control sequences. It does pass through XTVERSION
93   // (for now), but since it responds to the DA1 itself, we usually get that
94   // prior to any XTVERSION response. We instead key off of mintty's pretty
95   // reliable use of TERM_PROGRAM and TERM_PROGRAM_VERSION.
96   const char* tp = getenv("TERM_PROGRAM");
97   if(tp){
98     if(strcmp(tp, "mintty") == 0){
99       const char* ver = getenv("TERM_PROGRAM_VERSION");
100       if(ver){
101         ti->termversion = strdup(ver);
102       }
103       loginfo("detected mintty %s\n", ti->termversion ? ti->termversion : "");
104       ti->qterm = TERMINAL_MINTTY;
105       return 0;
106     }
107   }
108   ti->qterm = TERMINAL_MSTERMINAL;
109   return 0;
110 }
111 #endif
112