1 /++
2 Windows specific terminal utils. Made only to handle unicode page and get terminal size.
3 It is not in any means stable or finished or should be used in production.
4 Please just use linux, it's so much better in that regard
5 +/
6 module sily.terminal.windows;
7 
8 version(Windows):
9 
10 static this() {
11     // To prevent from killing terminal by calling reset before set
12     GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &originalMode);
13 
14     import core.sys.windows.windows : SetConsoleOutputCP;
15     SetConsoleOutputCP(65_001);
16 }
17 
18 /* ------------------------------ TERMINAL SIZE ----------------------------- */
19 
20 import core.sys.windows.windows;
21 
22 /// Returns bash terminal width
23 int terminalWidth() {
24     CONSOLE_SCREEN_BUFFER_INFO csbi;
25     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
26     return csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
27 }
28 
29 /// Returns bash terminal height
30 int terminalHeight() {
31     CONSOLE_SCREEN_BUFFER_INFO csbi;
32     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
33     return csbi.srWindow.Right - csbi.srWindow.Left + 1;
34 }
35 
36 /* -------------------------------- RAW MODE -------------------------------- */
37 import core.stdc.stdio: setvbuf, _IONBF, _IOLBF;
38 import core.stdc.stdlib: atexit;
39 import core.stdc.string: memcpy;
40 
41 import std.stdio: stdin, stdout, File;
42 
43 private uint originalMode;
44 
45 private bool __isTermiosRaw = false;
46 
47 /// Is terminal in raw mode (have `setTerminalModeRaw` been called yet?)
48 bool isTerminalRaw() nothrow {
49     // HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
50     // uint mr = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
51     // uint mc;
52     // GetConsoleMode(h, &mc);
53     // return !(mc & mr);
54     return false;
55 }
56 
57 /// Resets termios back to default and buffers stdout
58 extern(C) alias terminalModeReset = function() {
59     HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
60     SetConsoleMode(h, originalMode);
61     __isTermiosRaw = false;
62 };
63 
64 /** 
65 Creates new termios and unbuffers stdout. Required for `kbhit` and `getch`
66 DO NOT USE IF YOU DON'T KNOW WHAT YOU'RE DOING
67 
68 Note that in raw mode CRLF (`\r\n`) newline will be 
69 required instead of normal LF (`\n`)
70 Params:
71     removeStdoutBuffer = Does nothing on windows
72 */
73 void terminalModeSetRaw(bool removeStdoutBuffer = true) {
74     // HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
75     // uint mr = originalMode;
76     // mr &= ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_INSERT_MODE ;
77     // SetConsoleMode(h, mr);
78 
79     // atexit(terminalModeReset);
80     // __isTermiosRaw = true;
81 }
82 
83 /// Returns true if any key was pressed
84 bool kbhit() {
85 	// HANDLE stdIn = GetStdHandle(STD_INPUT_HANDLE);
86 	// DWORD saveMode;
87 
88 	// GetConsoleMode(stdIn, &saveMode);
89 	// SetConsoleMode(stdIn, ENABLE_PROCESSED_INPUT);
90 
91 	// bool ret = false;
92 
93 	// if (WaitForSingleObject(stdIn, INFINITE) == WAIT_OBJECT_0) {
94 	// 	uint num;
95 	// 	char ch;
96 
97 	// 	ReadConsoleA(stdIn, &ch, 1, &num, cast(void *) 0L);
98 	// 	ret = true;
99 	// }
100 
101 	// SetConsoleMode(stdIn, saveMode);
102 	// return ret;
103     return false;
104 }
105 
106 /// Returns last pressed key
107 int getch() {
108     // int r;
109     // uint c;
110     // stdin.readf!"%d"(r);
111     // if (r < 0) {
112     //     return r;
113     // } else {
114     //     return c;
115     // }
116     return 0;
117 }
118 
119 /* ---------------------------------- MISC ---------------------------------- */
120 // import core.sys.posix.unistd: posixIsATTY = isatty;
121 // import std.stdio: File;
122 import core.stdc.stdio: FILE, cfileno = fileno;
123 import core.stdc.errno;
124 
125 /// Returns true if file is a tty (can't promice it'll work on windows properly)
126 bool isatty(File file) {
127     return false;
128     // return cast(bool) posixIsATTY(file.fileno);
129 }
130 /// Ditto
131 bool isatty(FILE* handle) {
132     return false;
133     // return cast(bool) posixIsATTY(handle.cfileno);
134 }
135 /// Ditto
136 bool isatty(int fd_set) {
137     return false;
138     // return cast(bool) posixIsATTY(fd_set);
139 }