PageRenderTime 61ms CodeModel.GetById 9ms app.highlight 48ms RepoModel.GetById 2ms app.codeStats 0ms

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