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