1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 Copyright (C) 2000-2006 Tim Angus
5 
6 This file is part of Tremulous.
7 
8 Tremulous is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the License,
11 or (at your option) any later version.
12 
13 Tremulous is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Tremulous; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 ===========================================================================
22 */
23 
24 #include "../client/client.h"
25 #include "win_local.h"
26 
27 WinVars_t	g_wv;
28 
29 #ifndef WM_MOUSEWHEEL
30 #define WM_MOUSEWHEEL (WM_MOUSELAST+1)  // message that will be supported by the OS
31 #endif
32 
33 static UINT MSH_MOUSEWHEEL;
34 
35 // Console variables that we need to access from this module
36 cvar_t		*vid_xpos;			// X coordinate of window position
37 cvar_t		*vid_ypos;			// Y coordinate of window position
38 cvar_t		*r_fullscreen;
39 
40 #define VID_NUM_MODES ( sizeof( vid_modes ) / sizeof( vid_modes[0] ) )
41 
42 LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
43 
44 static qboolean s_alttab_disabled;
45 
WIN_DisableAltTab(void)46 static void WIN_DisableAltTab( void )
47 {
48 	if ( s_alttab_disabled )
49 		return;
50 
51 	if ( !Q_stricmp( Cvar_VariableString( "arch" ), "winnt" ) )
52 	{
53 		RegisterHotKey( 0, 0, MOD_ALT, VK_TAB );
54 	}
55 	else
56 	{
57 		BOOL old;
58 
59 		SystemParametersInfo( SPI_SCREENSAVERRUNNING, 1, &old, 0 );
60 	}
61 	s_alttab_disabled = qtrue;
62 }
63 
WIN_EnableAltTab(void)64 static void WIN_EnableAltTab( void )
65 {
66 	if ( s_alttab_disabled )
67 	{
68 		if ( !Q_stricmp( Cvar_VariableString( "arch" ), "winnt" ) )
69 		{
70 			UnregisterHotKey( 0, 0 );
71 		}
72 		else
73 		{
74 			BOOL old;
75 
76 			SystemParametersInfo( SPI_SCREENSAVERRUNNING, 0, &old, 0 );
77 		}
78 
79 		s_alttab_disabled = qfalse;
80 	}
81 }
82 
83 /*
84 ==================
85 VID_AppActivate
86 ==================
87 */
VID_AppActivate(BOOL fActive,BOOL minimize)88 static void VID_AppActivate(BOOL fActive, BOOL minimize)
89 {
90 	g_wv.isMinimized = minimize;
91 
92 	Com_DPrintf("VID_AppActivate: %i\n", fActive );
93 
94 	Key_ClearStates();	// FIXME!!!
95 
96 	// we don't want to act like we're active if we're minimized
97 	if (fActive && !g_wv.isMinimized )
98 	{
99 		g_wv.activeApp = qtrue;
100 	}
101 	else
102 	{
103 		g_wv.activeApp = qfalse;
104 	}
105 
106 	// minimize/restore mouse-capture on demand
107 	if (!g_wv.activeApp )
108 	{
109 		IN_Activate (qfalse);
110 	}
111 	else
112 	{
113 		IN_Activate (qtrue);
114 	}
115 }
116 
117 //==========================================================================
118 
119 static byte s_scantokey[128] =
120 					{
121 //  0           1       2       3       4       5       6       7
122 //  8           9       A       B       C       D       E       F
123 	0  ,    27,     '1',    '2',    '3',    '4',    '5',    '6',
124 	'7',    '8',    '9',    '0',    '-',    '=',    K_BACKSPACE, 9, // 0
125 	'q',    'w',    'e',    'r',    't',    'y',    'u',    'i',
126 	'o',    'p',    '[',    ']',    13 ,    K_CTRL,'a',  's',      // 1
127 	'd',    'f',    'g',    'h',    'j',    'k',    'l',    ';',
128 	'\'' ,    '`',    K_SHIFT,'\\',  'z',    'x',    'c',    'v',      // 2
129 	'b',    'n',    'm',    ',',    '.',    '/',    K_SHIFT,'*',
130 	K_ALT,' ',   K_CAPSLOCK  ,    K_F1, K_F2, K_F3, K_F4, K_F5,   // 3
131 	K_F6, K_F7, K_F8, K_F9, K_F10,  K_PAUSE,    0  , K_HOME,
132 	K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW, K_KP_PLUS,K_END, //4
133 	K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0,             0,              K_F11,
134 	K_F12,0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 5
135 	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,
136 	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 6
137 	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,
138 	0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0         // 7
139 };
140 
141 /*
142 =======
143 MapKey
144 
145 Map from windows to quake keynums
146 =======
147 */
MapKey(int key)148 static int MapKey (int key)
149 {
150 	int result;
151 	int modified;
152 	qboolean is_extended;
153 
154 //	Com_Printf( "0x%x\n", key);
155 
156 	modified = ( key >> 16 ) & 255;
157 
158 	if ( modified > 127 )
159 		return 0;
160 
161 	if ( key & ( 1 << 24 ) )
162 	{
163 		is_extended = qtrue;
164 	}
165 	else
166 	{
167 		is_extended = qfalse;
168 	}
169 
170 	result = s_scantokey[modified];
171 
172 	if ( !is_extended )
173 	{
174 		switch ( result )
175 		{
176 		case K_HOME:
177 			return K_KP_HOME;
178 		case K_UPARROW:
179 			return K_KP_UPARROW;
180 		case K_PGUP:
181 			return K_KP_PGUP;
182 		case K_LEFTARROW:
183 			return K_KP_LEFTARROW;
184 		case K_RIGHTARROW:
185 			return K_KP_RIGHTARROW;
186 		case K_END:
187 			return K_KP_END;
188 		case K_DOWNARROW:
189 			return K_KP_DOWNARROW;
190 		case K_PGDN:
191 			return K_KP_PGDN;
192 		case K_INS:
193 			return K_KP_INS;
194 		case K_DEL:
195 			return K_KP_DEL;
196 		default:
197 			return result;
198 		}
199 	}
200 	else
201 	{
202 		switch ( result )
203 		{
204 		case K_PAUSE:
205 			return K_KP_NUMLOCK;
206 		case 0x0D:
207 			return K_KP_ENTER;
208 		case 0x2F:
209 			return K_KP_SLASH;
210 		case 0xAF:
211 			return K_KP_PLUS;
212 		}
213 		return result;
214 	}
215 }
216 
217 
218 /*
219 ====================
220 MainWndProc
221 
222 main window procedure
223 ====================
224 */
225 extern cvar_t *in_mouse;
226 extern cvar_t *in_logitechbug;
MainWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)227 LONG WINAPI MainWndProc (
228     HWND    hWnd,
229     UINT    uMsg,
230     WPARAM  wParam,
231     LPARAM  lParam)
232 {
233 	static qboolean flip = qtrue;
234 	int zDelta, i;
235 
236 	// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/mouseinput/aboutmouseinput.asp
237 	// Windows 95, Windows NT 3.51 - uses MSH_MOUSEWHEEL
238 	// only relevant for non-DI input
239 	//
240 	// NOTE: not sure how reliable this is anymore, might trigger double wheel events
241 	if (in_mouse->integer != 1)
242 	{
243 		if ( uMsg == MSH_MOUSEWHEEL )
244 		{
245 			if ( ( ( int ) wParam ) > 0 )
246 			{
247 				Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELUP, qtrue, 0, NULL );
248 				Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELUP, qfalse, 0, NULL );
249 			}
250 			else
251 			{
252 				Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL );
253 				Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL );
254 			}
255 			return DefWindowProc (hWnd, uMsg, wParam, lParam);
256 		}
257 	}
258 
259 	switch (uMsg)
260 	{
261 	case WM_MOUSEWHEEL:
262 		// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/mouseinput/aboutmouseinput.asp
263 		// Windows 98/Me, Windows NT 4.0 and later - uses WM_MOUSEWHEEL
264 		// only relevant for non-DI input and when console is toggled in window mode
265 		//   if console is toggled in window mode (KEYCATCH_CONSOLE) then mouse is released and DI doesn't see any mouse wheel
266 		if (in_mouse->integer != 1 || (!r_fullscreen->integer && (cls.keyCatchers & KEYCATCH_CONSOLE)))
267 		{
268 			// 120 increments, might be 240 and multiples if wheel goes too fast
269 			// NOTE Logitech: logitech drivers are screwed and send the message twice?
270 			//   could add a cvar to interpret the message as successive press/release events
271 			zDelta = ( short ) HIWORD( wParam ) / 120;
272 			if ( zDelta > 0 )
273 			{
274 				for(i=0; i<zDelta; i++)
275 				{
276 					if (!in_logitechbug->integer)
277 					{
278 						Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELUP, qtrue, 0, NULL );
279 						Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELUP, qfalse, 0, NULL );
280 					}
281 					else
282 					{
283 						Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELUP, flip, 0, NULL );
284 						flip = !flip;
285 					}
286 				}
287 			}
288 			else
289 			{
290 				for(i=0; i<-zDelta; i++)
291 				{
292 					if (!in_logitechbug->integer)
293 					{
294 						Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL );
295 						Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL );
296 					}
297 					else
298 					{
299 						Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, K_MWHEELDOWN, flip, 0, NULL );
300 						flip = !flip;
301 					}
302 				}
303 			}
304 			// when an application processes the WM_MOUSEWHEEL message, it must return zero
305 			return 0;
306 		}
307 		break;
308 
309 	case WM_CREATE:
310 
311 		g_wv.hWnd = hWnd;
312 
313 		vid_xpos = Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE);
314 		vid_ypos = Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE);
315 		r_fullscreen = Cvar_Get ("r_fullscreen", "1", CVAR_ARCHIVE | CVAR_LATCH );
316 
317 		MSH_MOUSEWHEEL = RegisterWindowMessage("MSWHEEL_ROLLMSG");
318 		if ( r_fullscreen->integer )
319 		{
320 			WIN_DisableAltTab();
321 		}
322 		else
323 		{
324 			WIN_EnableAltTab();
325 		}
326 
327 		break;
328 #if 0
329 	case WM_DISPLAYCHANGE:
330 		Com_DPrintf( "WM_DISPLAYCHANGE\n" );
331 		// we need to force a vid_restart if the user has changed
332 		// their desktop resolution while the game is running,
333 		// but don't do anything if the message is a result of
334 		// our own calling of ChangeDisplaySettings
335 		if ( com_insideVidInit ) {
336 			break;		// we did this on purpose
337 		}
338 		// something else forced a mode change, so restart all our gl stuff
339 		Cbuf_AddText( "vid_restart\n" );
340 		break;
341 #endif
342 	case WM_DESTROY:
343 		// let sound and input know about this?
344 		g_wv.hWnd = NULL;
345 		if ( r_fullscreen->integer )
346 		{
347 			WIN_EnableAltTab();
348 		}
349 		break;
350 
351 	case WM_CLOSE:
352 		Cbuf_ExecuteText( EXEC_APPEND, "quit" );
353 		break;
354 
355 	case WM_ACTIVATE:
356 		{
357 			int	fActive, fMinimized;
358 
359 			fActive = LOWORD(wParam);
360 			fMinimized = (BOOL) HIWORD(wParam);
361 
362 			VID_AppActivate( fActive != WA_INACTIVE, fMinimized);
363 			SNDDMA_Activate();
364 		}
365 		break;
366 
367 	case WM_MOVE:
368 		{
369 			int		xPos, yPos;
370 			RECT r;
371 			int		style;
372 
373 			if (!r_fullscreen->integer )
374 			{
375 				xPos = (short) LOWORD(lParam);    // horizontal position
376 				yPos = (short) HIWORD(lParam);    // vertical position
377 
378 				r.left   = 0;
379 				r.top    = 0;
380 				r.right  = 1;
381 				r.bottom = 1;
382 
383 				style = GetWindowLong( hWnd, GWL_STYLE );
384 				AdjustWindowRect( &r, style, FALSE );
385 
386 				Cvar_SetValue( "vid_xpos", xPos + r.left);
387 				Cvar_SetValue( "vid_ypos", yPos + r.top);
388 				vid_xpos->modified = qfalse;
389 				vid_ypos->modified = qfalse;
390 				if ( g_wv.activeApp )
391 				{
392 					IN_Activate (qtrue);
393 				}
394 			}
395 		}
396 		break;
397 
398 // this is complicated because Win32 seems to pack multiple mouse events into
399 // one update sometimes, so we always check all states and look for events
400 	case WM_LBUTTONDOWN:
401 	case WM_LBUTTONUP:
402 	case WM_RBUTTONDOWN:
403 	case WM_RBUTTONUP:
404 	case WM_MBUTTONDOWN:
405 	case WM_MBUTTONUP:
406 	case WM_MOUSEMOVE:
407 		{
408 			int	temp;
409 
410 			temp = 0;
411 
412 			if (wParam & MK_LBUTTON)
413 				temp |= 1;
414 
415 			if (wParam & MK_RBUTTON)
416 				temp |= 2;
417 
418 			if (wParam & MK_MBUTTON)
419 				temp |= 4;
420 
421 			IN_MouseEvent (temp);
422 		}
423 		break;
424 
425 	case WM_SYSCOMMAND:
426 		if ( wParam == SC_SCREENSAVE )
427 			return 0;
428 		break;
429 
430 	case WM_SYSKEYDOWN:
431 		if ( wParam == 13 )
432 		{
433 			if ( r_fullscreen )
434 			{
435 				Cvar_SetValue( "r_fullscreen", !r_fullscreen->integer );
436 				Cbuf_AddText( "vid_restart\n" );
437 			}
438 			return 0;
439 		}
440 		// fall through
441 	case WM_KEYDOWN:
442 		Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, MapKey( lParam ), qtrue, 0, NULL );
443 		break;
444 
445 	case WM_SYSKEYUP:
446 	case WM_KEYUP:
447 		Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, MapKey( lParam ), qfalse, 0, NULL );
448 		break;
449 
450 	case WM_CHAR:
451 		Sys_QueEvent( g_wv.sysMsgTime, SE_CHAR, wParam, 0, 0, NULL );
452 		break;
453    }
454 
455     return DefWindowProc( hWnd, uMsg, wParam, lParam );
456 }
457 
458