/platform/win/scaffold/cui.d

http://github.com/wilkie/djehuty · D · 363 lines · 258 code · 75 blank · 30 comment · 61 complexity · adb2966971de588bc70d1dd1b40b3d78 MD5 · raw file

  1. /*
  2. * cui.d
  3. *
  4. * This module implements a Cui event loop scaffold for Windows.
  5. *
  6. * Author: Dave Wilkinson
  7. * Originated: August 17th, 2009
  8. *
  9. */
  10. module scaffold.cui;
  11. import synch.thread;
  12. import io.console;
  13. import core.main;
  14. import core.definitions;
  15. import platform.win.common;
  16. import platform.win.main;
  17. import platform.vars.cui;
  18. import scaffold.console;
  19. import data.queue;
  20. void CuiStart(CuiPlatformVars* vars) {
  21. // Window Resize Detect Thread (Silly)
  22. static ResizeThread t;
  23. vars.events = new Queue!(CuiEvent)();
  24. // get handle to standard out
  25. vars.stdout = GetStdHandle(STD_OUTPUT_HANDLE);
  26. // get handle to standard in
  27. vars.stdin = GetStdHandle(STD_INPUT_HANDLE);
  28. // Turn off automatic line advancement
  29. DWORD consoleMode;
  30. GetConsoleMode(vars.stdout, &consoleMode);
  31. consoleMode &= ~(0x2);
  32. SetConsoleMode(vars.stdout, consoleMode);
  33. // Setup mouse handling
  34. if (!SetConsoleMode(vars.stdin, ENABLE_MOUSE_INPUT)) {
  35. Console.putln("Fatal Error: Cannot Set the Console Mode");
  36. }
  37. // Spawn a thread to detect window resizes
  38. t = new ResizeThread();
  39. t.vars = vars;
  40. t.start();
  41. // Set a handler for special signals
  42. SetConsoleCtrlHandler(cast(PHANDLER_ROUTINE)&consoleProc, TRUE);
  43. }
  44. void CuiNextEvent(CuiEvent* evt, CuiPlatformVars* vars) {
  45. while (vars.events.length == 0) {
  46. grabEvent(vars);
  47. }
  48. *evt = vars.events.remove();
  49. }
  50. void CuiEnd(CuiPlatformVars* vars) {
  51. ConsoleClear();
  52. }
  53. private {
  54. // This thread will detect a window resize
  55. class ResizeThread : Thread {
  56. void stop() {
  57. running = false;
  58. super.stop();
  59. }
  60. void run() {
  61. // For the window resize detect
  62. static int _console_x;
  63. static int _console_y;
  64. // keep looking at the console window for size changes
  65. CONSOLE_SCREEN_BUFFER_INFO cinfo;
  66. HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  67. GetConsoleScreenBufferInfo(hStdout, &cinfo);
  68. _console_x = cinfo.srWindow.Right - cinfo.srWindow.Left+1;
  69. _console_y = cinfo.srWindow.Bottom - cinfo.srWindow.Top;
  70. while(running) {
  71. GetConsoleScreenBufferInfo(hStdout, &cinfo);
  72. if (_console_x != cinfo.srWindow.Right - cinfo.srWindow.Left+1 ||
  73. _console_y != cinfo.srWindow.Bottom - cinfo.srWindow.Top) {
  74. _console_x = cinfo.srWindow.Right - cinfo.srWindow.Left+1;
  75. _console_y = cinfo.srWindow.Bottom - cinfo.srWindow.Top;
  76. //(cast(CuiApplication)Djehuty.app).window.onResize();
  77. CuiEvent resizeEvent;
  78. resizeEvent.type = CuiEvent.Type.Size;
  79. resizeEvent.info.size.x = _console_x;
  80. resizeEvent.info.size.y = _console_y;
  81. vars.events.add(resizeEvent);
  82. }
  83. sleep(100);
  84. }
  85. }
  86. static CuiPlatformVars* vars;
  87. bool running = true;
  88. }
  89. BOOL consoleProc(DWORD fdwCtrlType) {
  90. switch(fdwCtrlType) {
  91. // Handle the CTRL-C signal.
  92. // CTRL-CLOSE: confirm that the user wants to exit.
  93. case CTRL_C_EVENT:
  94. case CTRL_CLOSE_EVENT:
  95. Console.putln("Ctrl-Close event");
  96. CuiEvent evt;
  97. evt.type = CuiEvent.Type.Close;
  98. evt.aux = 0;
  99. ResizeThread.vars.events.add(evt);
  100. return( TRUE );
  101. // Pass other signals to the next handler.
  102. case CTRL_BREAK_EVENT:
  103. Console.putln("Ctrl-Break event");
  104. return FALSE;
  105. case CTRL_LOGOFF_EVENT:
  106. Console.putln("Ctrl-Logoff event");
  107. return FALSE;
  108. case CTRL_SHUTDOWN_EVENT:
  109. printf( "Ctrl-Shutdown event\n\n" );
  110. return FALSE;
  111. default:
  112. break;
  113. }
  114. return FALSE;
  115. }
  116. void grabEvent(CuiPlatformVars* vars) {
  117. DWORD cNumRead;
  118. if (!GetNumberOfConsoleInputEvents(vars.stdin, &cNumRead)) {
  119. Console.putln("Fatal Error: Cannot Read from Console Event Buffer");
  120. }
  121. if (cNumRead > 0) {
  122. if (!ReadConsoleInputW(vars.stdin, vars.irInBuf.ptr, 128, &cNumRead)) {
  123. Console.putln("Fatal Error: Cannot Read from Console Event Buffer");
  124. }
  125. }
  126. for (uint i=0; i < cNumRead; i++) {
  127. CuiEvent evt;
  128. switch(vars.irInBuf[i].EventType) {
  129. case KEY_EVENT: // keyboard input
  130. evt.info.key.code = vars.irInBuf[i].Event.KeyEvent.wVirtualKeyCode;
  131. if (evt.info.key.code == VK_MENU) {
  132. // Alt pressed, figure out which one
  133. if ((vars.irInBuf[i].Event.KeyEvent.dwControlKeyState & 0x0002) > 0) {
  134. evt.info.key.code = VK_LMENU;
  135. }
  136. else {
  137. evt.info.key.code = VK_RMENU;
  138. }
  139. }
  140. if (evt.info.key.code == VK_CONTROL) {
  141. // Control pressed, figure out which one
  142. if ((vars.irInBuf[i].Event.KeyEvent.dwControlKeyState & 0x0008) > 0) {
  143. evt.info.key.code = VK_LCONTROL;
  144. }
  145. else {
  146. evt.info.key.code = VK_RCONTROL;
  147. }
  148. }
  149. if (evt.info.key.code == VK_SHIFT) {
  150. // Control pressed, figure out which one (eventually)
  151. evt.info.key.code = VK_LSHIFT;
  152. }
  153. evt.info.key.ctrl = ((vars.irInBuf[i].Event.KeyEvent.dwControlKeyState & 0x000C) > 0);
  154. evt.info.key.alt = ((vars.irInBuf[i].Event.KeyEvent.dwControlKeyState & 0x0003) > 0);
  155. evt.info.key.shift = ((vars.irInBuf[i].Event.KeyEvent.dwControlKeyState & 0x0010) > 0);
  156. if (vars.irInBuf[i].Event.KeyEvent.bKeyDown == TRUE) {
  157. // KeyDown
  158. // The Current Console View Receives the Event
  159. evt.type = CuiEvent.Type.KeyDown;
  160. vars.events.add(evt);
  161. }
  162. else {
  163. // KeyUp
  164. // The Current Console View Receives the Event
  165. evt.type = CuiEvent.Type.KeyUp;
  166. vars.events.add(evt);
  167. }
  168. break;
  169. case MOUSE_EVENT: // mouse input
  170. static int last_x;
  171. static int last_y;
  172. static DWORD last_state;
  173. static bool _last_was_mousepress;
  174. uint curbutton=0;
  175. bool isPressed = true;
  176. bool isMovement = false;
  177. CONSOLE_SCREEN_BUFFER_INFO cinfo;
  178. GetConsoleScreenBufferInfo(vars.stdout, &cinfo);
  179. if (!(vars.irInBuf[i].Event.MouseEvent.dwEventFlags == MOUSE_WHEELED ||
  180. vars.irInBuf[i].Event.MouseEvent.dwEventFlags == MOUSE_HWHEELED )) {
  181. if (last_x != vars.irInBuf[i].Event.MouseEvent.dwMousePosition.X - cinfo.srWindow.Left) {
  182. last_x = vars.irInBuf[i].Event.MouseEvent.dwMousePosition.X - cinfo.srWindow.Left;
  183. isMovement = true;
  184. }
  185. if (last_y != vars.irInBuf[i].Event.MouseEvent.dwMousePosition.Y - cinfo.srWindow.Top) {
  186. last_y = vars.irInBuf[i].Event.MouseEvent.dwMousePosition.Y - cinfo.srWindow.Top;
  187. isMovement = true;
  188. }
  189. }
  190. if (vars.irInBuf[i].Event.MouseEvent.dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) {
  191. if (!(last_state & FROM_LEFT_1ST_BUTTON_PRESSED)) {
  192. curbutton = 1;
  193. evt.info.mouse.leftDown = true;
  194. }
  195. }
  196. else {
  197. if (last_state & FROM_LEFT_1ST_BUTTON_PRESSED) {
  198. curbutton = 1;
  199. evt.info.mouse.leftDown = false;
  200. isPressed = false;
  201. }
  202. }
  203. if (vars.irInBuf[i].Event.MouseEvent.dwButtonState & RIGHTMOST_BUTTON_PRESSED) {
  204. if (!(last_state & RIGHTMOST_BUTTON_PRESSED)) {
  205. curbutton = 5;
  206. evt.info.mouse.rightDown = true;
  207. }
  208. }
  209. else {
  210. if (last_state & RIGHTMOST_BUTTON_PRESSED) {
  211. curbutton = 5;
  212. evt.info.mouse.rightDown = false;
  213. isPressed = false;
  214. }
  215. }
  216. last_state = vars.irInBuf[i].Event.MouseEvent.dwButtonState;
  217. if (isPressed == false) {
  218. evt.type = CuiEvent.Type.MouseUp;
  219. if (curbutton == 1) {
  220. _last_was_mousepress = true;
  221. evt.aux = 0;
  222. vars.events.add(evt);
  223. }
  224. else if (curbutton == 2) {
  225. _last_was_mousepress = true;
  226. evt.aux = 2;
  227. vars.events.add(evt);
  228. }
  229. else if (curbutton == 5) {
  230. _last_was_mousepress = true;
  231. evt.aux = 1;
  232. vars.events.add(evt);
  233. }
  234. }
  235. else if (curbutton > 0) {
  236. evt.type = CuiEvent.Type.MouseDown;
  237. if (curbutton == 1) {
  238. _last_was_mousepress = true;
  239. evt.aux = 0;
  240. vars.events.add(evt);
  241. }
  242. else if (curbutton == 2) {
  243. _last_was_mousepress = true;
  244. evt.aux = 2;
  245. vars.events.add(evt);
  246. }
  247. else if (curbutton == 5) {
  248. _last_was_mousepress = true;
  249. evt.aux = 1;
  250. vars.events.add(evt);
  251. }
  252. }
  253. else {
  254. switch(vars.irInBuf[i].Event.MouseEvent.dwEventFlags) {
  255. case MOUSE_MOVED:
  256. if (isMovement && !_last_was_mousepress) {
  257. evt.type = CuiEvent.Type.MouseMove;
  258. vars.events.add(evt);
  259. }
  260. _last_was_mousepress = false;
  261. break;
  262. case MOUSE_WHEELED:
  263. short delta = cast(short)(vars.irInBuf[i].Event.MouseEvent.dwButtonState >> 16);
  264. delta /= 120;
  265. evt.type = CuiEvent.Type.MouseWheelY;
  266. evt.aux = delta;
  267. vars.events.add(evt);
  268. break;
  269. case MOUSE_HWHEELED:
  270. short delta = cast(short)(vars.irInBuf[i].Event.MouseEvent.dwButtonState >> 16);
  271. delta /= 120;
  272. evt.type = CuiEvent.Type.MouseWheelX;
  273. evt.aux = delta;
  274. vars.events.add(evt);
  275. break;
  276. default:
  277. break;
  278. }
  279. }
  280. break;
  281. case WINDOW_BUFFER_SIZE_EVENT: // scrn buf. resizing
  282. break;
  283. default:
  284. break;
  285. }
  286. }
  287. }
  288. }