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