Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

win_wndproc.c (11028B)


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