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 }