/platform/win/scaffold/console.d

http://github.com/wilkie/djehuty · D · 485 lines · 286 code · 115 blank · 84 comment · 37 complexity · da10494f32f44cdd8931a6eb8d88481b MD5 · raw file

  1. /*
  2. * console.d
  3. *
  4. * This file holds the implementation of the console functionality
  5. * for Windows.
  6. *
  7. * Author: Dave Wilkinson
  8. *
  9. */
  10. module scaffold.console;
  11. import platform.win.common;
  12. import core.main;
  13. import core.unicode;
  14. import core.string;
  15. import core.color;
  16. import synch.thread;
  17. import cui.application;
  18. import cui.window;
  19. private int _toNearestConsoleColor(Color clr) {
  20. // 16 colors on console
  21. // For each channel, it can be 00, 88, or ff
  22. // That is, something mid range
  23. int nearRed, nearGreen, nearBlue;
  24. int ret;
  25. nearRed = cast(int)((clr.red * 3.0) + 0.5);
  26. nearGreen = cast(int)((clr.green * 3.0) + 0.5);
  27. nearBlue = cast(int)((clr.blue * 3.0) + 0.5);
  28. if ((nearRed == nearGreen) && (nearGreen == nearBlue)) {
  29. // gray
  30. if (clr.red < (Color.DarkGray.red / 2.0)) {
  31. // Closer to black
  32. ret = 0;
  33. }
  34. else if (clr.red < ((Color.Gray.red - Color.DarkGray.red) / 2.0) + Color.DarkGray.red) {
  35. // Closer to dark gray
  36. ret = 8;
  37. }
  38. else if (clr.red < ((Color.White.red - Color.Gray.red) / 2.0) + Color.Gray.red) {
  39. // Closer to light gray
  40. ret = 7;
  41. }
  42. else {
  43. // Closer to white
  44. ret = 15;
  45. }
  46. }
  47. else {
  48. // Nearest color match
  49. static int[3][] translations = [
  50. [1,0,0], // 1, Dark Red
  51. [0,1,0], // 2, Dark Green
  52. [1,1,0], // 3, Dark Yellow
  53. [0,0,1], // 4, Dark Blue
  54. [1,0,1], // 5, Dark Magenta
  55. [0,1,1], // 6, Dark Cyan
  56. [2,0,0], // 9, Dark Red
  57. [0,2,0], // 10, Dark Green
  58. [2,2,0], // 11, Dark Yellow
  59. [0,0,2], // 12, Dark Blue
  60. [2,0,2], // 13, Dark Magenta
  61. [0,2,2], // 14, Dark Cyan
  62. ];
  63. float mindistance = 4*3;
  64. foreach(size_t i, coord; translations) {
  65. // Compare euclidian distance
  66. float distance = 0.0;
  67. float intermediate;
  68. intermediate = coord[0] - nearRed;
  69. intermediate *= intermediate;
  70. distance += intermediate;
  71. intermediate = coord[1] - nearGreen;
  72. intermediate *= intermediate;
  73. distance += intermediate;
  74. intermediate = coord[2] - nearBlue;
  75. intermediate *= intermediate;
  76. distance += intermediate;
  77. // Omitting square root, it is unnecessary for comparison
  78. if (mindistance > distance) {
  79. mindistance = distance;
  80. ret = i;
  81. ret++;
  82. if (ret > 6) {
  83. ret += 2;
  84. }
  85. }
  86. }
  87. }
  88. return ret;
  89. }
  90. ushort _fgclrvalues[] =
  91. [
  92. 0,
  93. FOREGROUND_RED,
  94. FOREGROUND_GREEN,
  95. FOREGROUND_GREEN | FOREGROUND_RED,
  96. FOREGROUND_BLUE,
  97. FOREGROUND_RED | FOREGROUND_BLUE,
  98. FOREGROUND_BLUE | FOREGROUND_GREEN,
  99. FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
  100. ];
  101. ushort _bgclrvalues[] =
  102. [
  103. 0,
  104. BACKGROUND_RED,
  105. BACKGROUND_GREEN,
  106. BACKGROUND_GREEN | BACKGROUND_RED,
  107. BACKGROUND_BLUE,
  108. BACKGROUND_RED | BACKGROUND_BLUE,
  109. BACKGROUND_BLUE | BACKGROUND_GREEN,
  110. BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
  111. ];
  112. // I subclass the console window to detect resizes
  113. extern(Windows)
  114. int ConsoleProc(HWND hWnd, uint uMsg, WPARAM wParam, LPARAM lParam)
  115. {
  116. switch(uMsg)
  117. {
  118. case WM_SIZE:
  119. (cast(CuiApplication)Djehuty.app).window.onResize();
  120. return 0;
  121. default:
  122. break;
  123. }
  124. return CallWindowProcW(_console_oldproc, hWnd, uMsg, wParam, lParam);
  125. }
  126. static WNDPROC _console_oldproc = null;
  127. ushort _curAttribs;
  128. void ConsoleUninit() {
  129. HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  130. //SetConsoleOutputCP(_consoleOutputCP);
  131. // SetConsoleCP(_consoleCP);
  132. DWORD consoleMode;
  133. GetConsoleMode(hStdout, &consoleMode);
  134. // Turn on automatic line advancement
  135. consoleMode |= 0x2;
  136. SetConsoleMode(hStdout, consoleMode);
  137. }
  138. void ConsoleSetColors(Color fg, Color bg) {
  139. int fgidx = _toNearestConsoleColor(fg);
  140. int bgidx = _toNearestConsoleColor(bg);
  141. int bright = 0;
  142. if (fgidx > 7) {
  143. fgidx %= 8;
  144. bright = 1;
  145. }
  146. bgidx %= 8;
  147. HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  148. _curAttribs = cast(ushort)(_fgclrvalues[fgidx] | _bgclrvalues[bgidx] | (FOREGROUND_INTENSITY * cast(ushort)bright));
  149. SetConsoleTextAttribute(hStdout, _curAttribs);
  150. }
  151. void ConsoleSetSize(uint width, uint height) {
  152. }
  153. void ConsoleGetSize(out uint width, out uint height) {
  154. CONSOLE_SCREEN_BUFFER_INFO cinfo;
  155. HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  156. GetConsoleScreenBufferInfo(hStdout, &cinfo);
  157. width = cinfo.srWindow.Right - cinfo.srWindow.Left + 1;
  158. height = cinfo.srWindow.Bottom - cinfo.srWindow.Top + 1;
  159. }
  160. void ConsoleClear() {
  161. DWORD cCharsWritten;
  162. CONSOLE_SCREEN_BUFFER_INFO csbi;
  163. DWORD dwConSize;
  164. HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  165. // Get the number of character cells in the current window space.
  166. if( !GetConsoleScreenBufferInfo( hStdout, &csbi )) {
  167. return;
  168. }
  169. COORD coordScreen = {csbi.srWindow.Left,csbi.srWindow.Bottom}; // home for the cursor
  170. dwConSize = (csbi.srWindow.Right - csbi.srWindow.Left+1);
  171. do {
  172. coordScreen.Y--;
  173. // Fill the entire screen with blanks.
  174. if( !FillConsoleOutputCharacterW( hStdout, ' ',
  175. dwConSize, coordScreen, &cCharsWritten )) {
  176. return;
  177. }
  178. // Set the buffer's attributes accordingly.
  179. if( !FillConsoleOutputAttribute( hStdout, csbi.wAttributes,
  180. dwConSize, coordScreen, &cCharsWritten )) {
  181. return;
  182. }
  183. } while (coordScreen.Y >= csbi.srWindow.Top)
  184. // Put the cursor at its home coordinates.
  185. SetConsoleCursorPosition( hStdout, coordScreen );
  186. }
  187. void ConsoleGetPosition(uint* x, uint* y) {
  188. HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  189. CONSOLE_SCREEN_BUFFER_INFO csbi;
  190. if( !GetConsoleScreenBufferInfo( hStdout, &csbi ))
  191. return;
  192. *x = csbi.dwCursorPosition.X - csbi.srWindow.Left;
  193. *y = csbi.dwCursorPosition.Y - csbi.srWindow.Top;
  194. }
  195. uint cur_x, cur_y;
  196. void ConsoleSetPosition(uint x, uint y) {
  197. HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  198. CONSOLE_SCREEN_BUFFER_INFO csbi;
  199. if( !GetConsoleScreenBufferInfo( hStdout, &csbi ))
  200. {
  201. return;
  202. }
  203. COORD coordScreen = {cast(short)(csbi.srWindow.Left + x),cast(short)(csbi.srWindow.Top + y)}; // home for the cursor
  204. if (coordScreen.X >= csbi.srWindow.Right)
  205. {
  206. coordScreen.X = cast(short)(csbi.srWindow.Right-1);
  207. }
  208. SetConsoleCursorPosition( hStdout, coordScreen );
  209. }
  210. void ConsoleSetHome() {
  211. HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  212. CONSOLE_SCREEN_BUFFER_INFO csbi;
  213. if( !GetConsoleScreenBufferInfo( hStdout, &csbi )) {
  214. return;
  215. }
  216. COORD coordScreen = {cast(short)(csbi.srWindow.Left),cast(short)(csbi.dwCursorPosition.Y)}; // home for the cursor
  217. SetConsoleCursorPosition( hStdout, coordScreen );
  218. }
  219. void ConsoleSetRelative(int x, int y) {
  220. HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  221. CONSOLE_SCREEN_BUFFER_INFO csbi;
  222. if( !GetConsoleScreenBufferInfo( hStdout, &csbi )) {
  223. return;
  224. }
  225. COORD coordScreen = {cast(short)(csbi.dwCursorPosition.X + x),cast(short)(csbi.dwCursorPosition.Y + y)}; // home for the cursor
  226. if (coordScreen.X >= csbi.srWindow.Right) {
  227. coordScreen.X = cast(short)(csbi.srWindow.Right-1);
  228. }
  229. if (coordScreen.X < csbi.srWindow.Left) {
  230. coordScreen.X = csbi.srWindow.Left;
  231. }
  232. /* if (coordScreen.Y >= csbi.srWindow.Bottom) {
  233. // scroll down the difference
  234. uint diff = coordScreen.Y - csbi.srWindow.Bottom;
  235. diff++;
  236. SMALL_RECT rt;
  237. rt.Left = csbi.srWindow.Left;
  238. rt.Right = csbi.srWindow.Right;
  239. rt.Top = cast(short)(csbi.srWindow.Top-diff);
  240. rt.Bottom = cast(short)(csbi.srWindow.Bottom-diff);
  241. SetConsoleWindowInfo(hStdout, 1, &rt);
  242. } */
  243. SetConsoleCursorPosition( hStdout, coordScreen );
  244. /*
  245. if (x < 0) {
  246. // move left
  247. }
  248. else if (x > 0) {
  249. // move right
  250. }
  251. if (y < 0) {
  252. // move up
  253. }
  254. else if (y > 0) {
  255. // move down
  256. } */
  257. }
  258. void ConsoleHideCaret() {
  259. CONSOLE_CURSOR_INFO ccinfo;
  260. HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  261. GetConsoleCursorInfo(hStdout, &ccinfo);
  262. ccinfo.bVisible = FALSE;
  263. SetConsoleCursorInfo(hStdout, &ccinfo);
  264. }
  265. void ConsoleShowCaret() {
  266. CONSOLE_CURSOR_INFO ccinfo;
  267. HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  268. GetConsoleCursorInfo(hStdout, &ccinfo);
  269. ccinfo.bVisible = TRUE;
  270. SetConsoleCursorInfo(hStdout, &ccinfo);
  271. }
  272. void ConsolePutString(char[] chrs) {
  273. HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  274. uint numCharsWritten;
  275. uint x, y, w, h;
  276. ConsoleGetPosition(&x,&y);
  277. ConsoleGetSize(w,h);
  278. // print line by line
  279. string str = chrs.dup;
  280. //wstring str = Unicode.toUtf16(chrs);
  281. uint len = str.length;
  282. uint pos = 0;
  283. while (len > 0) {
  284. uint curlen = w - x;
  285. if (len > curlen) {
  286. wstring toprint = Unicode.toUtf16((str[pos..pos+curlen]));
  287. WriteConsoleW(hStdout, toprint.ptr, toprint.length, &numCharsWritten, null);
  288. len -= curlen;
  289. pos += curlen;
  290. x = 0;
  291. if (y <= h) {
  292. y++;
  293. }
  294. }
  295. else {
  296. wstring toprint = Unicode.toUtf16((str[pos..str.length]));
  297. WriteConsoleW(hStdout, toprint.ptr, toprint.length, &numCharsWritten, null);
  298. x += str.length - pos;
  299. len = 0;
  300. }
  301. }
  302. }
  303. void ConsolePutChar(dchar chr) {
  304. ConsolePutString([ chr ]);
  305. /* HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  306. CONSOLE_SCREEN_BUFFER_INFO csbi;
  307. if( !GetConsoleScreenBufferInfo( hStdout, &csbi ))
  308. return;
  309. DWORD ret;
  310. WriteConsoleOutputAttribute(hStdout, &_curAttribs, 1, csbi.dwCursorPosition, &ret);
  311. dstring chrs32 = [ chr ];
  312. wstring chrs = Unicode.toUtf16(chrs32);
  313. WriteConsoleOutputCharacterW(hStdout, chrs.ptr, chrs.length, csbi.dwCursorPosition, &ret);
  314. COORD coordScreen = {cast(short)(csbi.dwCursorPosition.X + 1),cast(short)(csbi.dwCursorPosition.Y)}; // home for the cursor
  315. SetConsoleCursorPosition( hStdout, coordScreen );*/
  316. }
  317. void ConsoleGetChar(out dchar chr, out uint code) {
  318. // get handle to standard in
  319. HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
  320. DWORD cNumRead;
  321. uint i;
  322. INPUT_RECORD irInBuf[128];
  323. for(;;) {
  324. if (! ReadConsoleInputW(
  325. hStdin, // input buffer handle
  326. irInBuf.ptr, // buffer to read into
  327. 128, // size of read buffer
  328. &cNumRead) ){// number of records read
  329. printf("Fatal Error: Cannot Read from Console Event Buffer\n");
  330. }
  331. for (i=0; i<cNumRead; i++) {
  332. switch(irInBuf[i].EventType) {
  333. case KEY_EVENT: // keyboard input
  334. if (irInBuf[i].Event.KeyEvent.bKeyDown == TRUE) {
  335. // KeyDown
  336. // The Current Console View Receives the Event
  337. code = irInBuf[i].Event.KeyEvent.wVirtualKeyCode;
  338. if (irInBuf[i].Event.KeyEvent.uChar.UnicodeChar > 0) {
  339. chr = irInBuf[i].Event.KeyEvent.uChar.UnicodeChar;
  340. }
  341. else {
  342. chr = 0;
  343. }
  344. return;
  345. }
  346. else {
  347. // KeyUp
  348. // The Current Console View Receives the Event
  349. //ConsoleWindowonKeyUp( irInBuf[i].Event.KeyEvent.wVirtualKeyCode );
  350. }
  351. break;
  352. default:
  353. break;
  354. }
  355. }
  356. }
  357. }