1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 
21 #include "win_local.h"
22 #ifdef _WIN32_WCE
23 #include <aygshell.h>
24 #endif /* _WIN32_WCE */
25 
26 qboolean		win_initialized;
27 
28 HWND			hWndMain;
29 
30 PRIVATE DWORD	lastMsgTime;
31 static qboolean	s_alttab_disabled;
32 
33 PRIVATE HHOOK kbdHook;
34 
35 static cvar_t	*vid_fullscreen;
36 static cvar_t	*vid_xpos;
37 static cvar_t	*vid_ypos;
38 static cvar_t	*sys_winnt;
39 static cvar_t	*win_hwnd;
40 static cvar_t	*win_noalttab;
41 static cvar_t	*win_disablewinkey;
42 
43 void GLimp_AppActivate( qboolean active );
44 
45 // ============================================================================
46 
47 #ifdef _WIN32_WCE
AdjustWindowRect(LPRECT lpRect,DWORD dwStyle,BOOL bMenu)48 BOOL AdjustWindowRect( LPRECT lpRect, DWORD dwStyle, BOOL bMenu ) {
49 	return AdjustWindowRectEx( lpRect, dwStyle, bMenu, 0 );
50 }
51 #endif
52 
53 
54 /*
55 =================
56 Win_CreateWindow
57 =================
58 */
Win_CreateWindow(int width,int height,qboolean fullscreen)59 HWND Win_CreateWindow( int width, int height, qboolean fullscreen ) {
60 #ifdef _WIN32_WCE
61 	WNDCLASS		wc;
62 #else
63 	WNDCLASSEX		wc;
64 #endif
65 	RECT			r;
66 	HWND			hWnd;
67 	int				stylebits;
68 	int				x, y, w, h;
69 	int				exstyle;
70 	RECT			screen;
71 
72 	/* Register the frame class */
73 	memset( &wc, 0, sizeof( wc ) );
74 #ifndef _WIN32_WCE
75 	wc.cbSize = sizeof( wc );
76 #endif
77 	wc.lpfnWndProc   = ( WNDPROC )Win_MainWndProc;
78 	wc.hInstance     = hGlobalInstance;
79 #ifdef _WIN32_WCE
80 #else
81 	wc.hIcon = LoadImage( hGlobalInstance, MAKEINTRESOURCE( IDI_APP ),
82 		IMAGE_ICON, 32, 32, LR_CREATEDIBSECTION );
83 	wc.hIconSm = LoadImage( hGlobalInstance, MAKEINTRESOURCE( IDI_APP ),
84 		IMAGE_ICON, 16, 16, LR_CREATEDIBSECTION );
85 #endif
86 	wc.hCursor       = LoadCursor ( NULL, IDC_ARROW );
87 	wc.hbrBackground = ( void * )COLOR_GRAYTEXT;
88 	wc.lpszClassName = WINDOW_CLASS_NAME;
89 
90 #ifdef _WIN32_WCE
91 	if( !RegisterClass( &wc ) ) {
92 #else
93 	if( !RegisterClassEx( &wc ) ) {
94 #endif
95 		Com_Error( ERR_FATAL, "Couldn't register window class" );
96 	}
97 
98 	if( fullscreen ) {
99 		exstyle = WS_EX_TOPMOST;
100 		stylebits = WS_POPUP|WS_VISIBLE;
101 	} else {
102 		exstyle = 0;
103 		stylebits = WINDOW_STYLE;
104 	}
105 
106 	r.left = 0;
107 	r.top = 0;
108 	r.right = width;
109 	r.bottom = height;
110 
111 	AdjustWindowRect( &r, stylebits, FALSE );
112 
113 	w = r.right - r.left;
114 	h = r.bottom - r.top;
115 
116 	if( fullscreen ) {
117 		/* postion on primary monitor */
118 		x = 0;
119 		y = 0;
120 	} else {
121 		/* get virtual screen dimensions */
122 		if( GetSystemMetrics( SM_CMONITORS ) > 1 ) {
123 			screen.left = GetSystemMetrics( SM_XVIRTUALSCREEN );
124 			screen.top = GetSystemMetrics( SM_YVIRTUALSCREEN );
125 			screen.right = screen.left + GetSystemMetrics( SM_CXVIRTUALSCREEN );
126 			screen.bottom = screen.top + GetSystemMetrics( SM_CYVIRTUALSCREEN );
127 		} else {
128 			screen.left = 0;
129 			screen.top = 0;
130 			screen.right = GetSystemMetrics( SM_CXSCREEN );
131 			screen.bottom = GetSystemMetrics( SM_CYSCREEN );
132 		}
133 
134 		x = Cvar_VariableInteger( "vid_xpos" );
135 		y = Cvar_VariableInteger( "vid_ypos" );
136 
137 		/* clip to virtual screen */
138 		if( x + w > screen.right ) {
139 			x = screen.right - w;
140 		}
141 		if( y + h > screen.bottom ) {
142 			y = screen.bottom - h;
143 		}
144 		if( x < screen.left ) {
145 			x = screen.left;
146 		}
147 		if( y < screen.top ) {
148 			y = screen.top;
149 		}
150 
151 	}
152 
153 	hWnd = CreateWindowEx(
154 		 exstyle,
155 		 WINDOW_CLASS_NAME,
156 #ifdef _WIN32_WCE
157 		 __TEXT( "q2pro" ),
158 #else
159 		 Cvar_VariableString( "vid_window" ),
160 #endif
161 		 stylebits,
162 		 x, y, w, h,
163 		 NULL,
164 		 NULL,
165 		 hGlobalInstance,
166 		 NULL );
167 
168 	if( !hWnd ) {
169 		Com_Error( ERR_FATAL, "Couldn't create window" );
170 	}
171 
172 	ShowWindow( hWnd, SW_SHOW );
173 	SetForegroundWindow( hWnd );
174 	SetFocus( hWnd );
175 
176 	return hWnd;
177 }
178 
179 /*
180 =================
181 Win_DestroyWindow
182 =================
183 */
184 void Win_DestroyWindow( HWND hWnd ) {
185 	ShowWindow( hWnd, SW_SHOWNORMAL );	// prevents leaving empty slots in the taskbar
186 	if( !DestroyWindow( hWnd ) ) {
187 		Com_Error( ERR_FATAL, "Couldn't destroy window" );
188 	}
189 	if( !UnregisterClass( WINDOW_CLASS_NAME, hGlobalInstance ) ) {
190 		Com_Error( ERR_FATAL, "Couldn't unregister window class" );
191 	}
192 }
193 
194 
195 /*
196 =================
197 Win_DisableAltTab
198 =================
199 */
200 static void Win_DisableAltTab( void ) {
201 #ifndef _WIN32_WCE
202 	if( s_alttab_disabled )
203 		return;
204 
205 	if( !sys_winnt->integer ) {
206 		BOOL old;
207 
208 		SystemParametersInfo( SPI_SETSCREENSAVERRUNNING, 1, &old, 0 );
209 	} else {
210 		RegisterHotKey( 0, 0, MOD_ALT, VK_TAB );
211 		RegisterHotKey( 0, 1, MOD_ALT, VK_RETURN );
212 	}
213 	s_alttab_disabled = qtrue;
214 #endif /* !_WIN32_WCE */
215 }
216 
217 /*
218 =================
219 Win_EnableAltTab
220 =================
221 */
222 static void Win_EnableAltTab( void ) {
223 #ifndef _WIN32_WCE
224 	if( s_alttab_disabled ) {
225 		if( !sys_winnt->integer ) {
226 			BOOL old;
227 
228 			SystemParametersInfo( SPI_SETSCREENSAVERRUNNING, 0, &old, 0 );
229 		} else {
230 			UnregisterHotKey( 0, 0 );
231 			UnregisterHotKey( 0, 1 );
232 		}
233 
234 		s_alttab_disabled = qfalse;
235 	}
236 #endif /* !_WIN32_WCE */
237 }
238 /*
239 ============
240 Win_NotAltTab_OnChange
241 ============
242 */
243 static void Win_NotAltTab_OnChange( cvar_t *self, void *arg ) {
244 	if( self->integer ) {
245 		Win_DisableAltTab();
246 	} else {
247 		Win_EnableAltTab();
248 	}
249 }
250 
251 /*
252 ============
253 Win_VidPos_OnChange
254 ============
255 */
256 static void Win_VidPos_OnChange( cvar_t *self, void *arg ) {
257 	if( vid_fullscreen->integer ) {
258 		return;
259 	}
260 
261 	SetWindowPos( hWndMain, HWND_TOPMOST,
262 		vid_xpos->integer, vid_ypos->integer, 0, 0, SWP_NOSIZE );
263 }
264 
265 /*
266 =================
267 Win_AppActivate
268 
269 =================
270 */
271 static void Win_AppActivate( WPARAM wParam ) {
272 	qboolean active, minimized;
273 
274 	// KJB: Watch this for problems in fullscreen modes with Alt-tabbing.
275 	minimized = active = qfalse;
276 	if( HIWORD( wParam ) ) {
277 		// we don't want to act like we're active if we're minimized
278 		minimized = qtrue;
279 	} else if( LOWORD( wParam ) ) {
280 		active = qtrue;
281 	}
282 
283 	CL_AppActivate( active );
284 
285 	if( win_noalttab->integer ) {
286 		if( !active ) {
287 			Win_EnableAltTab();
288 		} else {
289 			Win_DisableAltTab();
290 		}
291 	}
292 
293 	if( vid_fullscreen->integer ) {
294 		if( active ) {
295 			ShowWindow( hWndMain, SW_RESTORE );
296 		} else {
297 			ShowWindow( hWndMain, SW_MINIMIZE );
298 		}
299 	}
300 
301 #ifndef _WIN32_WCE
302 	GLimp_AppActivate( active );
303 #endif
304 
305 	if( active ) {
306 		SetForegroundWindow( hWndMain );
307 	}
308 }
309 
310 static LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam ) {
311 	PKBDLLHOOKSTRUCT kb = ( PKBDLLHOOKSTRUCT )lParam;
312 	uint32 key;
313 
314 	if( nCode != HC_ACTION ) {
315 		goto ignore;
316 	}
317 
318 	switch( kb->vkCode ) {
319 	case VK_LWIN:
320 		key = K_LWINKEY;
321 		break;
322 	case VK_RWIN:
323 		key = K_RWINKEY;
324 		break;
325 	default:
326 		goto ignore;
327 	}
328 
329 	switch( wParam ) {
330 	case WM_KEYDOWN:
331 		Key_Event( key, qtrue, kb->time );
332 		return TRUE;
333 	case WM_KEYUP:
334 		Key_Event( key, qfalse, kb->time );
335 		return TRUE;
336 	default:
337 		break;
338 	}
339 
340 ignore:
341 	return CallNextHookEx( NULL, nCode, wParam, lParam );
342 }
343 
344 static void DisableWinKey_OnChange( cvar_t *self, void *arg ) {
345 	if( self->integer ) {
346 		if( !sys_winnt->integer ) {
347 			Com_Printf( "Low-level keyboard hook requires Windows NT\n" );
348 			Cvar_Set( "win_disablewinkey", "0" );
349 			return;
350 		}
351 		kbdHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, hGlobalInstance, 0 );
352 		if( !kbdHook ) {
353 			Com_EPrintf( "Couldn't set low-level keyboard hook, error %#lX\n", GetLastError() );
354 			Cvar_Set( "win_disablewinkey", "0" );
355 		}
356 	} else {
357 		if( kbdHook ) {
358 			UnhookWindowsHookEx( kbdHook );
359 			kbdHook = NULL;
360 		}
361 	}
362 }
363 
364 #ifdef _WIN32_WCE
365 
366 static byte        scantokey[256] = {
367 	0,      '\x001', '\x002', '\x003', '\x004', '\x005', '\x006', '\x007', K_BACKSPACE, '\x009',
368 	'\x00a', '\x00b', '\x00c', K_ENTER, '\x00e', '\x00f', K_SHIFT, '\x011', '\x012', '\x013',
369 	'\x014', '\x015', '\x016', '\x017', '\x018', '\x019', '\x01a', '\x01b', '\x01c', '\x01d',
370 	'\x01e', '\x01f', '\x020', '\x021', '\x022', '\x023', '\x024', K_LEFTARROW, K_UPARROW, K_RIGHTARROW,
371 	K_DOWNARROW, '\x029', '\x02a', '\x02b', '\x02c', '\x02d', '\x02e', '\x02f', ')', '!',
372 	'@', '#', '$', '%', '^', '&', '*', '(', '\x03a', '\x03b',
373 	'\x03c', '\x03d', '\x03e', '\x03f', '\x040', '\x041', '\x042', '\x043', '\x044', '\x045',
374 	'\x046', '\x047', '\x048', '\x049', '\x04a', '\x04b', '\x04c', '\x04d', '\x04e', '\x04f',
375 	'\x050', '\x051', '\x052', '\x053', '\x054', '\x055', '\x056', '\x057', '\x058', '\x059',
376 	'\x05a', 0/*'\x05b'*/, '\x05c', '\x05d', '\x05e', '\x05f', '\x060', '\x061', '\x062', '\x063',
377 	'\x064', '\x065', '\x066', '\x067', '\x068', '\x069', '\x06a', '\x06b', '\x06c', '\x06d',
378 	'\x06e', '\x06f', '\x070', '\x071', '\x072', '\x073', '\x074', '\x075', '\x076', '\x077',
379 	'\x078', '\x079', '\x07a', '\x07b', '\x07c', '\x07d', '\x07e', '\x07f', '\x080', '\x081',
380 	'\x082', '\x083', '\x084', '\x085', K_JOY1,  '\x087', '\x088', '\x089', '\x08a', '\x08b',
381 	'\x08c', '\x08d', '\x08e', '\x08f', '\x090', '\x091', '\x092', '\x093', '\x094', '\x095',
382 	'\x096', '\x097', '\x098', '\x099', '\x09a', '\x09b', '\x09c', '\x09d', '\x09e', '\x09f',
383 	'\x0a0', '\x0a1', '\x0a2', '\x0a3', '\x0a4', '\x0a5', '\x0a6', '\x0a7', '\x0a8', '\x0a9',
384 	'\x0aa', '\x0ab', '\x0ac', '\x0ad', '\x0ae', '\x0af', '\x0b0', '\x0b1', '\x0b2', '\x0b3',
385 	'\x0b4', '\x0b5', '\x0b6', '\x0b7', '\x0b8', '\x0b9', ':', '+', '<', '_',
386 	'>', '?', '~', K_AUX1,  K_AUX2,  K_AUX3,  K_AUX4, K_AUX5, '\x0c6', '\x0c7',
387 	'\x0c8', '\x0c9', '\x0ca', '\x0cb', '\x0cc', '\x0cd', '\x0ce', '\x0cf', '\x0d0', '\x0d1',
388 	'\x0d2', '\x0d3', '\x0d4', '\x0d5', '\x0d6', '\x0d7', '\x0d8', '\x0d9', '\x0da', '{',
389 	'|', '}', '"', '\x0df', '\x0e0', '\x0e1', '\x0e2', '\x0e3', '\x0e4', '\x0e5',
390 	'\x0e6', '\x0e7', '\x0e8', '\x0e9', '\x0ea', '\x0eb', '\x0ec', '\x0ed', '\x0ee', '\x0ef',
391 	'\x0f0', '\x0f1', '\x0f2', '\x0f3', '\x0f4', '\x0f5', '\x0f6', '\x0f7', '\x0f8', '\x0f9',
392 	'\x0fa', '\x0fb', '\x0fc', '\x0fd', '\x0fe', '\x0ff'};
393 
394 static int Win_MapKey( WPARAM wParam, LPARAM lParam ) {
395 	if( wParam < 0 || wParam > 255 ) return 0;
396 	return scantokey[wParam];
397 }
398 
399 #else
400 
401 static byte        scantokey[128] = {
402 //  0           1       2			3				4			5				6			7
403 //  8           9       A			B				C			D				E			F
404     0  ,		27,     '1',		'2',			'3',		'4',			'5',		'6',
405     '7',		'8',    '9',		'0',			'-',		'=',			K_BACKSPACE, 9,			// 0
406     'q',		'w',    'e',		'r',			't',		'y',			'u',		'i',
407     'o',		'p',	'[',		']',			13 ,		K_CTRL,			'a',		's',		// 1
408     'd',		'f',	'g',		'h',			'j',		'k',			'l',		';',
409     '\'' ,		'`',	K_SHIFT,	'\\',			'z',		'x',			'c',		'v',		// 2
410     'b',		'n',	'm',		',',			'.',		'/',			K_SHIFT,	'*',
411     K_ALT,		' ',	K_CAPSLOCK,	K_F1,			K_F2,		K_F3,			K_F4,		K_F5,		// 3
412     K_F6,		K_F7,	K_F8,		K_F9,			K_F10,		K_PAUSE,		K_SCROLLOCK, K_HOME,
413     K_UPARROW,	K_PGUP,	K_KP_MINUS,	K_LEFTARROW,	K_KP_5,		K_RIGHTARROW,	K_KP_PLUS,	K_END,		// 4
414     K_DOWNARROW,K_PGDN,	K_INS,		K_DEL,			0,			0,				0,			K_F11,
415     K_F12,		0,		0,			K_LWINKEY,		K_RWINKEY,  K_MENU,			0,			0,			// 5
416     0,			0,		0,			0,				0,			0,				0,			0,
417     0,			0,		0,			0,				0,			0,				0,			0,			// 6
418     0,			0,		0,			0,				0,			0,				0,			0,
419     0,			0,		0,			0,				0,			0,				0,			0			// 7
420 };
421 
422 
423 
424 /*
425 =======
426 Win_KeyEvent
427 
428 Map from windows to quake keynums
429 =======
430 */
431 static void Win_KeyEvent( WPARAM wParam, LPARAM lParam, qboolean down ) {
432 	uint32 result;
433 	uint32 scancode = ( lParam >> 16 ) & 255;
434 	qboolean is_extended = qfalse;
435 
436 	if( scancode > 127 ) {
437 		return;
438     }
439 
440 	if( lParam & ( 1 << 24 ) ) {
441 		is_extended = qtrue;
442     }
443 
444 	result = scantokey[scancode];
445     if( !result ) {
446 		Com_DPrintf( "Win_KeyEvent: unknown scancode %u\n", scancode );
447         return;
448     }
449 
450 	if( !is_extended ) {
451 		switch( result ) {
452 		case K_HOME:
453 			result = K_KP_HOME;
454             break;
455 		case K_UPARROW:
456 			result = K_KP_UPARROW;
457             break;
458 		case K_PGUP:
459 			result = K_KP_PGUP;
460             break;
461 		case K_LEFTARROW:
462 			result = K_KP_LEFTARROW;
463             break;
464 		case K_RIGHTARROW:
465 			result = K_KP_RIGHTARROW;
466             break;
467 		case K_END:
468 			result = K_KP_END;
469             break;
470 		case K_DOWNARROW:
471 			result = K_KP_DOWNARROW;
472             break;
473 		case K_PGDN:
474 			result = K_KP_PGDN;
475             break;
476 		case K_INS:
477 			result = K_KP_INS;
478             break;
479 		case K_DEL:
480 			result = K_KP_DEL;
481             break;
482 		}
483 	} else {
484 		switch( result ) {
485 		case 0x0D:
486 			result = K_KP_ENTER;
487             break;
488 		case 0x2F:
489 			result = K_KP_SLASH;
490             break;
491 		case 0xAF:
492 			result = K_KP_PLUS;
493             break;
494 		}
495 	}
496 
497 	Key_Event( result, down, lastMsgTime );
498 }
499 
500 #endif
501 
502 /*
503 ====================
504 Win_MainWndProc
505 
506 main window procedure
507 ====================
508 */
509 LONG WINAPI Win_MainWndProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
510 	switch( uMsg ) {
511 	case WM_MOUSEWHEEL: {
512 			UINT lines;
513 			int key;
514 
515 // this chunk of code theoretically only works under NT4 and Win98
516 // since this message doesn't exist under Win95
517 			if( ( short )HIWORD( wParam ) > 0 ) {
518 				key = K_MWHEELUP;
519 			} else {
520 				key = K_MWHEELDOWN;
521 			}
522 
523 			if( keys.GetDest() & KEY_CONSOLE ) {
524 				SystemParametersInfo( SPI_GETWHEELSCROLLLINES, 0, &lines, 0 );
525 				if( !lines ) {
526 					lines = 1;
527 				} else if( lines > 6 ) {
528 					lines = 6;
529 				}
530 			} else {
531 				lines = 1;
532 			}
533 
534 			do {
535 				Key_Event( key, qtrue, lastMsgTime );
536 				Key_Event( key, qfalse, lastMsgTime );
537 			} while( --lines );
538 		}
539 		break;
540 
541 // this is complicated because Win32 seems to pack multiple mouse events into
542 // one update sometimes, so we always check all states and look for events
543 	case WM_LBUTTONDOWN:
544 	case WM_LBUTTONUP:
545 	case WM_RBUTTONDOWN:
546 	case WM_RBUTTONUP:
547 	case WM_MBUTTONDOWN:
548 	case WM_MBUTTONUP:
549 	case WM_MOUSEMOVE:
550 	case WM_XBUTTONDOWN:
551 	case WM_XBUTTONUP: {
552 			int	temp = 0;
553 
554 			if( wParam & MK_LBUTTON )
555 				temp |= 1;
556 
557 			if( wParam & MK_RBUTTON )
558 				temp |= 2;
559 
560 			if( wParam & MK_MBUTTON )
561 				temp |= 4;
562 
563 			if( wParam & MK_XBUTTON1 )
564 				temp |= 8;
565 
566 			if( wParam & MK_XBUTTON2 )
567 				temp |= 16;
568 
569 			Win_SendMouseButtonEvents( temp, lastMsgTime );
570 		}
571 		break;
572 	case WM_HOTKEY:
573 		return FALSE;
574 
575 	case WM_CREATE:
576 		hWndMain = hWnd;
577 		Cvar_SetIntegerHex( "win_hwnd", ( uint32 )hWnd );
578 		break;
579 
580 	case WM_CLOSE:
581 		PostQuitMessage( 0 );
582 		return FALSE;
583 
584 	case WM_DESTROY:
585 		hWndMain = NULL;
586 		Cvar_SetInteger( "win_hwnd", 0 );
587 		break;
588 
589 	case WM_ACTIVATE:
590 		Win_AppActivate( wParam );
591 		break;
592 
593 	case WM_SIZE:
594 		if( wParam == SIZE_MAXIMIZED ) {
595 			if( !vid_fullscreen->integer ) {
596 				Cvar_SetInteger( "vid_fullscreen", 1 );
597 				Cbuf_AddText( "vid_restart\n" );
598 			}
599 		}
600 		return FALSE;
601 
602 	case WM_MOVE: {
603 		short		xPos, yPos;
604 		RECT r;
605 		int		style;
606 
607 		if( vid_fullscreen->integer ) {
608 			break;
609 		}
610 
611 		xPos = ( signed short )LOWORD( lParam );    // horizontal position
612 		yPos = ( signed short )HIWORD( lParam );    // vertical position
613 
614 		r.left   = 0;
615 		r.top    = 0;
616 		r.right  = 1;
617 		r.bottom = 1;
618 
619 		style = GetWindowLong( hWnd, GWL_STYLE );
620 		AdjustWindowRect( &r, style, FALSE );
621 
622 		Cvar_SetInteger( "vid_xpos", xPos + r.left );
623 		Cvar_SetInteger( "vid_ypos", yPos + r.top );
624 	}
625 	break;
626 
627 #ifdef _WIN32_WCE
628 	case WM_SETTINGCHANGE:
629 		if( wParam == SPI_SETSIPINFO ) {
630 			SIPINFO si;
631 
632 			/* TODO */
633 			memset( &si, 0, sizeof( si ) );
634 			si.cbSize = sizeof( si );
635 			SHSipInfo( SPI_GETSIPINFO, 0, &si, 0 );
636 
637 			if( si.fdwFlags & SIPF_ON ) {
638 				Con_SetMaxHeight( 1.0f - 80.0f / 296 );
639 			} else {
640 				Con_SetMaxHeight( 1.0f );
641 			}
642 		}
643 		break;
644 
645 #else /* _WIN32_WCE */
646 	case WM_SYSCOMMAND:
647 		if( wParam == SC_SCREENSAVE ) {
648 			return FALSE;
649 		}
650         break;
651 #endif /* !_WIN32_WCE */
652 
653 	case WM_KEYDOWN:
654     case WM_SYSKEYDOWN:
655 		Win_KeyEvent( wParam, lParam, qtrue );
656 		break;
657 
658 	case WM_CHAR:
659 #ifdef UNICODE
660 		{
661 			char tinystr[2];
662 			wchar_t wstr[2];
663 			wstr[0] = wParam;
664 			wstr[1] = 0;
665 			WideCharToMultiByte( CP_ACP, 0, wstr, -1, tinystr, 2, NULL, NULL );
666 			Key_CharEvent( tinystr[0] );
667 		}
668 #elif (defined USE_CHAR_EVENTS)
669 		Key_CharEvent( wParam );
670 #endif
671 		break;
672 
673 	case WM_SYSKEYUP:
674 	case WM_KEYUP:
675 		Win_KeyEvent( wParam, lParam, qfalse );
676 		break;
677 
678 	default:
679         break;
680     }
681 
682 	// pass all unhandled messages to DefWindowProc
683     return DefWindowProc( hWnd, uMsg, wParam, lParam );
684 }
685 
686 /*
687 ============
688 Win_PumpEvents
689 ============
690 */
691 void Video_PumpEvents( void ) {
692 	MSG        msg;
693 
694 	while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) {
695 		if( msg.message == WM_QUIT ) {
696 			Com_Quit();
697 			break;
698 		}
699 		lastMsgTime = msg.time;
700       	TranslateMessage( &msg );
701       	DispatchMessage( &msg );
702 	}
703 }
704 
705 /*
706 ============
707 Win_Init
708 ============
709 */
710 void Win_Init( void ) {
711 	vid_fullscreen = Cvar_Get( "vid_fullscreen", "", CVAR_USER_CREATED );
712 	vid_xpos = Cvar_Get( "vid_xpos", "0", CVAR_ARCHIVE );
713 	vid_xpos->changedFunc = Win_VidPos_OnChange;
714 	vid_ypos = Cvar_Get( "vid_ypos", "0", CVAR_ARCHIVE );
715 	vid_ypos->changedFunc = Win_VidPos_OnChange;
716 	sys_winnt = Cvar_Get( "sys_winnt", "0", CVAR_ROM|CVAR_USER_CREATED );
717 	win_hwnd = Cvar_Get( "win_hwnd", "0", CVAR_ROM );
718 	win_noalttab = Cvar_Get( "win_noalttab", "0", CVAR_ARCHIVE );
719 	win_noalttab->changedFunc = Win_NotAltTab_OnChange;
720 	win_disablewinkey = Cvar_Get( "win_disablewinkey", "0", CVAR_ARCHIVE );
721 	win_disablewinkey->changedFunc = DisableWinKey_OnChange;
722 
723 	DisableWinKey_OnChange( win_disablewinkey, NULL );
724 
725 	win_initialized = qtrue;
726 }
727 
728 /*
729 ============
730 Win_Shutdown
731 ============
732 */
733 void Win_Shutdown( void ) {
734 	if( kbdHook ) {
735 		UnhookWindowsHookEx( kbdHook );
736 		kbdHook = NULL;
737 	}
738 
739 	win_initialized = qfalse;
740 }
741 
742