PageRenderTime 100ms CodeModel.GetById 33ms app.highlight 62ms RepoModel.GetById 1ms app.codeStats 0ms

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