DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

win_wndproc.cpp (12070B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #pragma hdrstop
     30 #include "../../idlib/precompiled.h"
     31 
     32 #include "win_local.h"
     33 #include "../../renderer/tr_local.h"
     34 
     35 #include <Windowsx.h>
     36 
     37 LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
     38 
     39 static bool s_alttab_disabled;
     40 
     41 extern idCVar r_windowX;
     42 extern idCVar r_windowY;
     43 extern idCVar r_windowWidth;
     44 extern idCVar r_windowHeight;
     45 
     46 static void WIN_DisableAltTab() {
     47 	if ( s_alttab_disabled || win32.win_allowAltTab.GetBool() ) {
     48 		return;
     49 	}
     50 	if ( !idStr::Icmp( cvarSystem->GetCVarString( "sys_arch" ), "winnt" ) ) {
     51 		RegisterHotKey( 0, 0, MOD_ALT, VK_TAB );
     52 	} else {
     53 		BOOL old;
     54 
     55 		SystemParametersInfo( SPI_SCREENSAVERRUNNING, 1, &old, 0 );
     56 	}
     57 	s_alttab_disabled = true;
     58 }
     59 
     60 static void WIN_EnableAltTab() {
     61 	if ( !s_alttab_disabled || win32.win_allowAltTab.GetBool() ) {
     62 		return;
     63 	}
     64 	if ( !idStr::Icmp( cvarSystem->GetCVarString( "sys_arch" ), "winnt" ) ) {
     65 		UnregisterHotKey( 0, 0 );
     66 	} else {
     67 		BOOL old;
     68 
     69 		SystemParametersInfo( SPI_SCREENSAVERRUNNING, 0, &old, 0 );
     70 	}
     71 
     72 	s_alttab_disabled = false;
     73 }
     74 
     75 void WIN_Sizing(WORD side, RECT *rect)
     76 {
     77 	if ( !R_IsInitialized() || renderSystem->GetWidth() <= 0 || renderSystem->GetHeight() <= 0 ) {
     78 		return;
     79 	}
     80 
     81 	// restrict to a standard aspect ratio
     82 	int width = rect->right - rect->left;
     83 	int height = rect->bottom - rect->top;
     84 
     85 	// Adjust width/height for window decoration
     86 	RECT decoRect = { 0, 0, 0, 0 };
     87 	AdjustWindowRect( &decoRect, WINDOW_STYLE|WS_SYSMENU, FALSE );
     88 	int decoWidth = decoRect.right - decoRect.left;
     89 	int decoHeight = decoRect.bottom - decoRect.top;
     90 
     91 	width -= decoWidth;
     92 	height -= decoHeight;
     93 
     94 	// Clamp to a minimum size
     95 	if ( width < SCREEN_WIDTH / 4 ) {
     96 		width = SCREEN_WIDTH / 4;
     97 	}
     98 	if ( height < SCREEN_HEIGHT / 4 ) {
     99 		height = SCREEN_HEIGHT / 4;
    100 	}
    101 
    102 	const int minWidth = height * 4 / 3;
    103 	const int maxHeight = width * 3 / 4;
    104 
    105 	const int maxWidth = height * 16 / 9;
    106 	const int minHeight = width * 9 / 16;
    107 
    108 	// Set the new size
    109 	switch ( side ) {
    110 	case WMSZ_LEFT:
    111 		rect->left = rect->right - width - decoWidth;
    112 		rect->bottom = rect->top + idMath::ClampInt( minHeight, maxHeight, height ) + decoHeight;
    113 		break;
    114 	case WMSZ_RIGHT:
    115 		rect->right = rect->left + width + decoWidth;
    116 		rect->bottom = rect->top + idMath::ClampInt( minHeight, maxHeight, height ) + decoHeight;
    117 		break;
    118 	case WMSZ_BOTTOM:
    119 	case WMSZ_BOTTOMRIGHT:
    120 		rect->bottom = rect->top + height + decoHeight;
    121 		rect->right = rect->left + idMath::ClampInt( minWidth, maxWidth, width ) + decoWidth;
    122 		break;
    123 	case WMSZ_TOP:
    124 	case WMSZ_TOPRIGHT:
    125 		rect->top = rect->bottom - height - decoHeight;
    126 		rect->right = rect->left + idMath::ClampInt( minWidth, maxWidth, width ) + decoWidth;
    127 		break;
    128 	case WMSZ_BOTTOMLEFT:
    129 		rect->bottom = rect->top + height + decoHeight;
    130 		rect->left = rect->right - idMath::ClampInt( minWidth, maxWidth, width ) - decoWidth;
    131 		break;
    132 	case WMSZ_TOPLEFT:
    133 		rect->top = rect->bottom - height - decoHeight;
    134 		rect->left = rect->right - idMath::ClampInt( minWidth, maxWidth, width ) - decoWidth;
    135 		break;
    136 	}
    137 }
    138 
    139 /*
    140 ====================
    141 MainWndProc
    142 
    143 main window procedure
    144 ====================
    145 */
    146 LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
    147 	int key;
    148 	switch( uMsg ) {
    149 		case WM_WINDOWPOSCHANGED:
    150 			if (R_IsInitialized()) {
    151 				RECT rect;
    152 				if (::GetClientRect(win32.hWnd, &rect)) {
    153 
    154 					if ( rect.right > rect.left && rect.bottom > rect.top ) {
    155 						glConfig.nativeScreenWidth = rect.right - rect.left;
    156 						glConfig.nativeScreenHeight = rect.bottom - rect.top;
    157 
    158 						// save the window size in cvars if we aren't fullscreen
    159 						int style = GetWindowLong( hWnd, GWL_STYLE );
    160 						if ( ( style & WS_POPUP ) == 0 ) {
    161 							r_windowWidth.SetInteger( glConfig.nativeScreenWidth );
    162 							r_windowHeight.SetInteger( glConfig.nativeScreenHeight );
    163 						}
    164 					}
    165 				}
    166 			}
    167 			break;
    168 		case WM_MOVE: {
    169 			int		xPos, yPos;
    170 			RECT r;
    171 
    172 			// save the window origin in cvars if we aren't fullscreen
    173 			int style = GetWindowLong( hWnd, GWL_STYLE );
    174 			if ( ( style & WS_POPUP ) == 0 ) {
    175 				xPos = (short) LOWORD(lParam);    // horizontal position 
    176 				yPos = (short) HIWORD(lParam);    // vertical position 
    177 
    178 				r.left   = 0;
    179 				r.top    = 0;
    180 				r.right  = 1;
    181 				r.bottom = 1;
    182 
    183 				AdjustWindowRect( &r, style, FALSE );
    184 
    185 				r_windowX.SetInteger( xPos + r.left );
    186 				r_windowY.SetInteger( yPos + r.top );
    187 			}
    188 			break;
    189 		}
    190 		case WM_CREATE:
    191 
    192 			win32.hWnd = hWnd;
    193 
    194 			if ( win32.cdsFullscreen ) {
    195 				WIN_DisableAltTab();
    196 			} else {
    197 				WIN_EnableAltTab();
    198 			}
    199 
    200 			// do the OpenGL setup
    201 			void GLW_WM_CREATE( HWND hWnd );
    202 			GLW_WM_CREATE( hWnd );
    203 
    204 			break;
    205 
    206 		case WM_DESTROY:
    207 			// let sound and input know about this?
    208 			win32.hWnd = NULL;
    209 			if ( win32.cdsFullscreen ) {
    210 				WIN_EnableAltTab();
    211 			}
    212 			break;
    213 
    214 		case WM_CLOSE:
    215 			soundSystem->SetMute( true );
    216 			cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "quit\n" );
    217 			break;
    218 
    219 		case WM_ACTIVATE:
    220 			// if we got here because of an alt-tab or maximize,
    221 			// we should activate immediately.  If we are here because
    222 			// the mouse was clicked on a title bar or drag control,
    223 			// don't activate until the mouse button is released
    224 			{
    225 				int	fActive, fMinimized;
    226 
    227 				fActive = LOWORD(wParam);
    228 				fMinimized = (BOOL) HIWORD(wParam);
    229 
    230 				win32.activeApp = (fActive != WA_INACTIVE);
    231 				if ( win32.activeApp ) {
    232 					idKeyInput::ClearStates();
    233 					Sys_GrabMouseCursor( true );
    234 					if ( common->IsInitialized() ) {
    235 						SetCursor( NULL );
    236 					}
    237 				}
    238 
    239 				if ( fActive == WA_INACTIVE ) {
    240 					win32.movingWindow = false;
    241 					if ( common->IsInitialized() ) {
    242 						SetCursor( LoadCursor( 0, IDC_ARROW ) );
    243 					}
    244 				}
    245 
    246 				// start playing the game sound world
    247 				soundSystem->SetMute( !win32.activeApp );
    248 
    249 				// we do not actually grab or release the mouse here,
    250 				// that will be done next time through the main loop
    251 			}
    252 			break;
    253 		case WM_TIMER: {
    254 			if ( win32.win_timerUpdate.GetBool() ) {
    255 				common->Frame();
    256 			}
    257 			break;
    258 		}
    259 		case WM_SYSCOMMAND:
    260 			if ( wParam == SC_SCREENSAVE || wParam == SC_KEYMENU ) {
    261 				return 0;
    262 			}
    263 			break;
    264 
    265 		case WM_SYSKEYDOWN:
    266 			if ( wParam == 13 ) {	// alt-enter toggles full-screen
    267 				cvarSystem->SetCVarBool( "r_fullscreen", !renderSystem->IsFullScreen() );
    268 				cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "vid_restart\n" );
    269 				return 0;
    270 			}
    271 			// fall through for other keys
    272 		case WM_KEYDOWN:
    273 			key = ( ( lParam >> 16 ) & 0xFF ) | ( ( ( lParam >> 24 ) & 1 ) << 7 );
    274 			if ( key == K_LCTRL || key == K_LALT || key == K_RCTRL || key == K_RALT ) {
    275 				// let direct-input handle this because windows sends Alt-Gr
    276 				// as two events (ctrl then alt)
    277 				break;
    278 			}
    279 			// D
    280 			if ( key == K_NUMLOCK ) {
    281 				key = K_PAUSE;
    282 			} else if ( key == K_PAUSE ) {
    283 				key = K_NUMLOCK;
    284 			}
    285 			Sys_QueEvent( SE_KEY, key, true, 0, NULL, 0 );
    286 			break;
    287 
    288 		case WM_SYSKEYUP:
    289 		case WM_KEYUP:
    290 			key = ( ( lParam >> 16 ) & 0xFF ) | ( ( ( lParam >> 24 ) & 1 ) << 7 );
    291 			if ( key == K_PRINTSCREEN ) {
    292 				// don't queue printscreen keys.  Since windows doesn't send us key
    293 				// down events for this, we handle queueing them with DirectInput
    294 				break;
    295 			} else if ( key == K_LCTRL || key == K_LALT || key == K_RCTRL || key == K_RALT ) {
    296 				// let direct-input handle this because windows sends Alt-Gr
    297 				// as two events (ctrl then alt)
    298 				break;
    299 			}
    300 			Sys_QueEvent( SE_KEY, key, false, 0, NULL, 0 );
    301 			break;
    302 
    303 		case WM_CHAR:
    304 			Sys_QueEvent( SE_CHAR, wParam, 0, 0, NULL, 0 );
    305 			break;
    306 
    307 		case WM_NCLBUTTONDOWN:
    308 //			win32.movingWindow = true;
    309 			break;
    310 
    311 		case WM_ENTERSIZEMOVE:
    312 			win32.movingWindow = true;
    313 			break;
    314 
    315 		case WM_EXITSIZEMOVE:
    316 			win32.movingWindow = false;
    317 			break;
    318 
    319 		case WM_SIZING:
    320 			WIN_Sizing(wParam, (RECT *)lParam);
    321 			break;
    322 		case WM_MOUSEMOVE: {
    323 			if ( !common->IsInitialized() ) {
    324 				break;
    325 			}
    326 
    327 			const bool isShellActive = ( game && ( game->Shell_IsActive() || game->IsPDAOpen() ) );
    328 			const bool isConsoleActive = console->Active();
    329 
    330 			if ( win32.activeApp ) {
    331 				if ( isShellActive ) {
    332 					// If the shell is active, it will display its own cursor.
    333 					SetCursor( NULL );
    334 				} else if ( isConsoleActive ) {
    335 					// The console is active but the shell is not.
    336 					// Show the Windows cursor.
    337 					SetCursor( LoadCursor( 0, IDC_ARROW ) );
    338 				} else {
    339 					// The shell not active and neither is the console.
    340 					// This is normal gameplay, hide the cursor.
    341 					SetCursor( NULL );
    342 				}
    343 			} else {
    344 				if ( !isShellActive ) {
    345 					// Always show the cursor when the window is in the background
    346 					SetCursor( LoadCursor( 0, IDC_ARROW ) );
    347 				} else {
    348 					SetCursor( NULL );
    349 				}
    350 			}
    351 
    352 			const int x = GET_X_LPARAM( lParam );
    353 			const int y = GET_Y_LPARAM( lParam );
    354 
    355 			// Generate an event
    356 			Sys_QueEvent( SE_MOUSE_ABSOLUTE, x, y, 0, NULL, 0 );
    357 			
    358 			// Get a mouse leave message
    359 			TRACKMOUSEEVENT tme = {
    360 				sizeof( TRACKMOUSEEVENT ),
    361 				TME_LEAVE,
    362 				hWnd,
    363 				0
    364 			};
    365 			
    366 			TrackMouseEvent( &tme );
    367 
    368 			return 0;
    369 		}
    370 		case WM_MOUSELEAVE: {
    371 			Sys_QueEvent( SE_MOUSE_LEAVE, 0, 0, 0, NULL, 0 );
    372 			return 0;
    373 		}
    374 		case WM_LBUTTONDOWN: {
    375 			Sys_QueEvent( SE_KEY, K_MOUSE1, 1, 0, NULL, 0 );
    376 			return 0;
    377 		}
    378 		case WM_LBUTTONUP: {
    379 			Sys_QueEvent( SE_KEY, K_MOUSE1, 0, 0, NULL, 0 );
    380 			return 0;
    381 		}
    382 		case WM_RBUTTONDOWN: {
    383 			Sys_QueEvent( SE_KEY, K_MOUSE2, 1, 0, NULL, 0 );
    384 			return 0;
    385 		}
    386 		case WM_RBUTTONUP: {
    387 			Sys_QueEvent( SE_KEY, K_MOUSE2, 0, 0, NULL, 0 );
    388 			return 0;
    389 		}
    390 		case WM_MBUTTONDOWN: {
    391 			Sys_QueEvent( SE_KEY, K_MOUSE3, 1, 0, NULL, 0 );
    392 			return 0;
    393 		}
    394 		case WM_MBUTTONUP: {
    395 			Sys_QueEvent( SE_KEY, K_MOUSE3, 0, 0, NULL, 0 );
    396 			return 0;
    397 		}
    398 		case WM_XBUTTONDOWN: {
    399 			int button = GET_XBUTTON_WPARAM( wParam );
    400 			if ( button == 1 ) {
    401 				Sys_QueEvent( SE_KEY, K_MOUSE4, 1, 0, NULL, 0 );
    402 			} else if ( button == 2 ) {
    403 				Sys_QueEvent( SE_KEY, K_MOUSE5, 1, 0, NULL, 0 );
    404 			}
    405 			return 0;
    406 		}
    407 		case WM_XBUTTONUP: {
    408 			int button = GET_XBUTTON_WPARAM( wParam );
    409 			if ( button == 1 ) {
    410 				Sys_QueEvent( SE_KEY, K_MOUSE4, 0, 0, NULL, 0 );
    411 			} else if ( button == 2 ) {
    412 				Sys_QueEvent( SE_KEY, K_MOUSE5, 0, 0, NULL, 0 );
    413 			}
    414 			return 0;
    415 		}
    416 		case WM_MOUSEWHEEL: {
    417 			int delta = GET_WHEEL_DELTA_WPARAM( wParam ) / WHEEL_DELTA;
    418 			int key = delta < 0 ? K_MWHEELDOWN : K_MWHEELUP;
    419 			delta = abs( delta );
    420 			while( delta-- > 0 ) {
    421 				Sys_QueEvent( SE_KEY, key, true, 0, NULL, 0 );
    422 				Sys_QueEvent( SE_KEY, key, false, 0, NULL, 0 );
    423 			}
    424 			break;
    425 		}
    426 	}
    427 
    428     return DefWindowProc( hWnd, uMsg, wParam, lParam );
    429 }