//Anything above this #include will be ignored by the compiler #include "../qcommon/exe_headers.h" #include "../client/client.h" #include "win_local.h" WinVars_t g_wv; // The only directly referenced keycode - the console key (which gives different ascii codes depending on locale) #define CONSOLE_SCAN_CODE 0x29 #ifndef WM_MOUSEWHEEL #define WM_MOUSEWHEEL (WM_MOUSELAST+1) // message that will be supported by the OS #endif static UINT MSH_MOUSEWHEEL; // Console variables that we need to access from this module cvar_t *vid_xpos; // X coordinate of window position cvar_t *vid_ypos; // Y coordinate of window position static cvar_t *r_fullscreen; #define VID_NUM_MODES ( sizeof( vid_modes ) / sizeof( vid_modes[0] ) ) LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); static qboolean s_alttab_disabled; static void WIN_DisableAltTab( void ) { if ( s_alttab_disabled ) return; if ( !Q_stricmp( Cvar_VariableString( "arch" ), "winnt" ) ) { RegisterHotKey( 0, 0, MOD_ALT, VK_TAB ); } else { BOOL old; SystemParametersInfo( SPI_SCREENSAVERRUNNING, 1, &old, 0 ); } s_alttab_disabled = qtrue; } static void WIN_EnableAltTab( void ) { if ( s_alttab_disabled ) { if ( !Q_stricmp( Cvar_VariableString( "arch" ), "winnt" ) ) { UnregisterHotKey( 0, 0 ); } else { BOOL old; SystemParametersInfo( SPI_SCREENSAVERRUNNING, 0, &old, 0 ); } s_alttab_disabled = qfalse; } } /* ================== VID_AppActivate ================== */ static void VID_AppActivate(BOOL fActive, BOOL minimize) { g_wv.isMinimized = (qboolean)minimize; Com_DPrintf("VID_AppActivate: %i\n", fActive ); Key_ClearStates(); // FIXME!!! // we don't want to act like we're active if we're minimized if (fActive && !g_wv.isMinimized ) { g_wv.activeApp = qtrue; } else { g_wv.activeApp = qfalse; } // minimize/restore mouse-capture on demand if (!g_wv.activeApp ) { IN_Activate (qfalse); } else { IN_Activate (qtrue); } } //========================================================================== static byte virtualKeyConvert[0x92][2] = { { 0, 0 }, { A_MOUSE1, A_MOUSE1 }, // VK_LBUTTON 01 Left mouse button { A_MOUSE2, A_MOUSE2 }, // VK_RBUTTON 02 Right mouse button { 0, 0 }, // VK_CANCEL 03 Control-break processing { A_MOUSE3, A_MOUSE3 }, // VK_MBUTTON 04 Middle mouse button (three-button mouse) { A_MOUSE4, A_MOUSE4 }, // VK_XBUTTON1 05 Windows 2000/XP: X1 mouse button { A_MOUSE5, A_MOUSE5 }, // VK_XBUTTON2 06 Windows 2000/XP: X2 mouse button { 0, 0 }, // 07 Undefined { A_BACKSPACE, A_BACKSPACE }, // VK_BACK 08 BACKSPACE key { A_TAB, A_TAB }, // VK_TAB 09 TAB key { 0, 0 }, // 0A Reserved { 0, 0 }, // 0B Reserved { A_KP_5, 0 }, // VK_CLEAR 0C CLEAR key { A_ENTER, A_KP_ENTER }, // VK_RETURN 0D ENTER key { 0, 0 }, // 0E Undefined { 0, 0 }, // 0F Undefined { A_SHIFT, A_SHIFT }, // VK_SHIFT 10 SHIFT key { A_CTRL, A_CTRL }, // VK_CONTROL 11 CTRL key { A_ALT, A_ALT }, // VK_MENU 12 ALT key { A_PAUSE, A_PAUSE }, // VK_PAUSE 13 PAUSE key { A_CAPSLOCK, A_CAPSLOCK }, // VK_CAPITAL 14 CAPS LOCK key { 0, 0 }, // VK_KANA 15 IME Kana mode { 0, 0 }, // 16 Undefined { 0, 0 }, // VK_JUNJA 17 IME Junja mode { 0, 0 }, // VK_FINAL 18 IME final mode { 0, 0 }, // VK_KANJI 19 IME Kanji mode { 0, 0 }, // 1A Undefined { A_ESCAPE, A_ESCAPE }, // VK_ESCAPE 1B ESC key { 0, 0 }, // VK_CONVERT 1C IME convert { 0, 0 }, // VK_NONCONVERT 1D IME nonconvert { 0, 0 }, // VK_ACCEPT 1E IME accept { 0, 0 }, // VK_MODECHANGE 1F IME mode change request { A_SPACE, A_SPACE }, // VK_SPACE 20 SPACEBAR { A_KP_9, A_PAGE_UP }, // VK_PRIOR 21 PAGE UP key { A_KP_3, A_PAGE_DOWN }, // VK_NEXT 22 PAGE DOWN key { A_KP_1, A_END }, // VK_END 23 END key { A_KP_7, A_HOME }, // VK_HOME 24 HOME key { A_KP_4, A_CURSOR_LEFT }, // VK_LEFT 25 LEFT ARROW key { A_KP_8, A_CURSOR_UP }, // VK_UP 26 UP ARROW key { A_KP_6, A_CURSOR_RIGHT }, // VK_RIGHT 27 RIGHT ARROW key { A_KP_2, A_CURSOR_DOWN }, // VK_DOWN 28 DOWN ARROW key { 0, 0 }, // VK_SELECT 29 SELECT key { 0, 0 }, // VK_PRINT 2A PRINT key { 0, 0 }, // VK_EXECUTE 2B EXECUTE key { A_PRINTSCREEN, A_PRINTSCREEN }, // VK_SNAPSHOT 2C PRINT SCREEN key { A_KP_0, A_INSERT }, // VK_INSERT 2D INS key { A_KP_PERIOD, A_DELETE }, // VK_DELETE 2E DEL key { 0, 0 }, // VK_HELP 2F HELP key { A_0, A_0 }, // 30 0 key { A_1, A_1 }, // 31 1 key { A_2, A_2 }, // 32 2 key { A_3, A_3 }, // 33 3 key { A_4, A_4 }, // 34 4 key { A_5, A_5 }, // 35 5 key { A_6, A_6 }, // 36 6 key { A_7, A_7 }, // 37 7 key { A_8, A_8 }, // 38 8 key { A_9, A_9 }, // 39 9 key { 0, 0 }, // 3A Undefined { 0, 0 }, // 3B Undefined { 0, 0 }, // 3C Undefined { 0, 0 }, // 3D Undefined { 0, 0 }, // 3E Undefined { 0, 0 }, // 3F Undefined { 0, 0 }, // 40 Undefined { A_CAP_A, A_CAP_A }, // 41 A key { A_CAP_B, A_CAP_B }, // 42 B key { A_CAP_C, A_CAP_C }, // 43 C key { A_CAP_D, A_CAP_D }, // 44 D key { A_CAP_E, A_CAP_E }, // 45 E key { A_CAP_F, A_CAP_F }, // 46 F key { A_CAP_G, A_CAP_G }, // 47 G key { A_CAP_H, A_CAP_H }, // 48 H key { A_CAP_I, A_CAP_I }, // 49 I key { A_CAP_J, A_CAP_J }, // 4A J key { A_CAP_K, A_CAP_K }, // 4B K key { A_CAP_L, A_CAP_L }, // 4C L key { A_CAP_M, A_CAP_M }, // 4D M key { A_CAP_N, A_CAP_N }, // 4E N key { A_CAP_O, A_CAP_O }, // 4F O key { A_CAP_P, A_CAP_P }, // 50 P key { A_CAP_Q, A_CAP_Q }, // 51 Q key { A_CAP_R, A_CAP_R }, // 52 R key { A_CAP_S, A_CAP_S }, // 53 S key { A_CAP_T, A_CAP_T }, // 54 T key { A_CAP_U, A_CAP_U }, // 55 U key { A_CAP_V, A_CAP_V }, // 56 V key { A_CAP_W, A_CAP_W }, // 57 W key { A_CAP_X, A_CAP_X }, // 58 X key { A_CAP_Y, A_CAP_Y }, // 59 Y key { A_CAP_Z, A_CAP_Z }, // 5A Z key { 0, 0 }, // VK_LWIN 5B Left Windows key (Microsoft® Natural® keyboard) { 0, 0 }, // VK_RWIN 5C Right Windows key (Natural keyboard) { 0, 0 }, // VK_APPS 5D Applications key (Natural keyboard) { 0, 0 }, // 5E Reserved { 0, 0 }, // VK_SLEEP 5F Computer Sleep key { A_KP_0, A_KP_0 }, // VK_NUMPAD0 60 Numeric keypad 0 key { A_KP_1, A_KP_1 }, // VK_NUMPAD1 61 Numeric keypad 1 key { A_KP_2, A_KP_2 }, // VK_NUMPAD2 62 Numeric keypad 2 key { A_KP_3, A_KP_3 }, // VK_NUMPAD3 63 Numeric keypad 3 key { A_KP_4, A_KP_4 }, // VK_NUMPAD4 64 Numeric keypad 4 key { A_KP_5, A_KP_5 }, // VK_NUMPAD5 65 Numeric keypad 5 key { A_KP_6, A_KP_6 }, // VK_NUMPAD6 66 Numeric keypad 6 key { A_KP_7, A_KP_7 }, // VK_NUMPAD7 67 Numeric keypad 7 key { A_KP_8, A_KP_8 }, // VK_NUMPAD8 68 Numeric keypad 8 key { A_KP_9, A_KP_9 }, // VK_NUMPAD9 69 Numeric keypad 9 key { A_MULTIPLY, A_MULTIPLY }, // VK_MULTIPLY 6A Multiply key { A_KP_PLUS, A_KP_PLUS }, // VK_ADD 6B Add key { 0, 0 }, // VK_SEPARATOR 6C Separator key { A_KP_MINUS, A_KP_MINUS }, // VK_SUBTRACT 6D Subtract key { A_KP_PERIOD, A_KP_PERIOD }, // VK_DECIMAL 6E Decimal key { A_DIVIDE, A_DIVIDE }, // VK_DIVIDE 6F Divide key { A_F1, A_F1 }, // VK_F1 70 F1 key { A_F2, A_F2 }, // VK_F2 71 F2 key { A_F3, A_F3 }, // VK_F3 72 F3 key { A_F4, A_F4 }, // VK_F4 73 F4 key { A_F5, A_F5 }, // VK_F5 74 F5 key { A_F6, A_F6 }, // VK_F6 75 F6 key { A_F7, A_F7 }, // VK_F7 76 F7 key { A_F8, A_F8 }, // VK_F8 77 F8 key { A_F9, A_F9 }, // VK_F9 78 F9 key { A_F10, A_F10 }, // VK_F10 79 F10 key { A_F11, A_F11 }, // VK_F11 7A F11 key { A_F12, A_F12 }, // VK_F12 7B F12 key { 0, 0 }, // VK_F13 7C F13 key { 0, 0 }, // VK_F14 7D F14 key { 0, 0 }, // VK_F15 7E F15 key { 0, 0 }, // VK_F16 7F F16 key { 0, 0 }, // VK_F17 80H F17 key { 0, 0 }, // VK_F18 81H F18 key { 0, 0 }, // VK_F19 82H F19 key { 0, 0 }, // VK_F20 83H F20 key { 0, 0 }, // VK_F21 84H F21 key { 0, 0 }, // VK_F22 85H F22 key { 0, 0 }, // VK_F23 86H F23 key { 0, 0 }, // VK_F24 87H F24 key { 0, 0 }, // 88 Unassigned { 0, 0 }, // 89 Unassigned { 0, 0 }, // 8A Unassigned { 0, 0 }, // 8B Unassigned { 0, 0 }, // 8C Unassigned { 0, 0 }, // 8D Unassigned { 0, 0 }, // 8E Unassigned { 0, 0 }, // 8F Unassigned { A_NUMLOCK, A_NUMLOCK }, // VK_NUMLOCK 90 NUM LOCK key { A_SCROLLLOCK, A_SCROLLLOCK } // VK_SCROLL 91 }; /* ======= MapKey Map from windows to quake keynums ======= */ static int MapKey (ulong key, word wParam) { ulong result, scan, extended; // Check for the console key (hard code to the key you would expect) scan = ( key >> 16 ) & 0xff; if(scan == CONSOLE_SCAN_CODE) { return(A_CONSOLE); } // Try to convert the virtual key directly result = 0; extended = (key >> 24) & 1; if(wParam > 0 && wParam <= VK_SCROLL) { // yeuch, but oh well... // if ( wParam >= VK_NUMPAD0 && wParam <= VK_NUMPAD9 ) { bool bNumlockOn = !!(GetKeyState( VK_NUMLOCK ) & 1); if ( bNumlockOn ) { wParam = 0x30 + (wParam - VK_NUMPAD0); // convert to standard 0..9 } } result = virtualKeyConvert[wParam][extended]; } // Get the unshifted ascii code (if any) if(!result) { result = MapVirtualKey(wParam, 2) & 0xff; } // Output any debug prints // if(in_debug && in_debug->integer & 1) // { // Com_Printf("WM_KEY: %x : %x : %x\n", key, wParam, result); // } return(result); } /* ==================== MainWndProc main window procedure ==================== */ #define WM_BUTTON4DOWN (WM_MOUSELAST+2) #define WM_BUTTON4UP (WM_MOUSELAST+3) #define MK_BUTTON4L 0x0020 #define MK_BUTTON4R 0x0040 LONG WINAPI MainWndProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { byte code; if ( uMsg == MSH_MOUSEWHEEL ) { if ( ( ( int ) wParam ) > 0 ) { Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELUP, qtrue, 0, NULL ); Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELUP, qfalse, 0, NULL ); } else { Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELDOWN, qtrue, 0, NULL ); Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELDOWN, qfalse, 0, NULL ); } return DefWindowProc (hWnd, uMsg, wParam, lParam); } switch (uMsg) { case WM_MOUSEWHEEL: // // // this chunk of code theoretically only works under NT4 and Win98 // since this message doesn't exist under Win95 // if ( ( short ) HIWORD( wParam ) > 0 ) { Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELUP, qtrue, 0, NULL ); Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELUP, qfalse, 0, NULL ); } else { Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELDOWN, qtrue, 0, NULL ); Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, A_MWHEELDOWN, qfalse, 0, NULL ); } break; case WM_CREATE: g_wv.hWnd = hWnd; vid_xpos = Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE); vid_ypos = Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE); r_fullscreen = Cvar_Get ("r_fullscreen", "1", CVAR_ARCHIVE | CVAR_LATCH ); MSH_MOUSEWHEEL = RegisterWindowMessage("MSWHEEL_ROLLMSG"); if ( r_fullscreen->integer ) { WIN_DisableAltTab(); } else { WIN_EnableAltTab(); } break; #if 0 case WM_DISPLAYCHANGE: Com_DPrintf( "WM_DISPLAYCHANGE\n" ); // we need to force a vid_restart if the user has changed // their desktop resolution while the game is running, // but don't do anything if the message is a result of // our own calling of ChangeDisplaySettings if ( com_insideVidInit ) { break; // we did this on purpose } // something else forced a mode change, so restart all our gl stuff Cbuf_AddText( "vid_restart\n" ); break; #endif case WM_DESTROY: // let sound and input know about this? g_wv.hWnd = NULL; if ( r_fullscreen->integer ) { WIN_EnableAltTab(); } break; case WM_CLOSE: Cbuf_ExecuteText( EXEC_APPEND, "quit" ); break; case WM_ACTIVATE: { int fActive, fMinimized; fActive = LOWORD(wParam); fMinimized = (BOOL) HIWORD(wParam); VID_AppActivate( fActive != WA_INACTIVE, fMinimized); SNDDMA_Activate( (qboolean)(fActive != WA_INACTIVE && !fMinimized) ); } break; case WM_MOVE: { int xPos, yPos; RECT r; int style; if (!r_fullscreen->integer ) { xPos = (short) LOWORD(lParam); // horizontal position yPos = (short) HIWORD(lParam); // vertical position r.left = 0; r.top = 0; r.right = 1; r.bottom = 1; style = GetWindowLong( hWnd, GWL_STYLE ); AdjustWindowRect( &r, style, FALSE ); Cvar_SetValue( "vid_xpos", xPos + r.left); Cvar_SetValue( "vid_ypos", yPos + r.top); vid_xpos->modified = qfalse; vid_ypos->modified = qfalse; if ( g_wv.activeApp ) { IN_Activate (qtrue); } } } break; // this is complicated because Win32 seems to pack multiple mouse events into // one update sometimes, so we always check all states and look for events case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONDOWN: case WM_RBUTTONUP: case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_MOUSEMOVE: case WM_BUTTON4DOWN: case WM_BUTTON4UP: { int temp; temp = 0; if (wParam & MK_LBUTTON) temp |= 1; if (wParam & MK_RBUTTON) temp |= 2; if (wParam & MK_MBUTTON) temp |= 4; if (wParam & MK_BUTTON4L) temp |= 8; if (wParam & MK_BUTTON4R) temp |= 16; IN_MouseEvent (temp); } break; case WM_SYSCOMMAND: if ( (wParam&0xFFF0) == SC_SCREENSAVE || (wParam&0xFFF0) == SC_MONITORPOWER) { return 0; } break; case WM_SYSKEYDOWN: if ( wParam == VK_RETURN ) { if ( r_fullscreen && cl_allowAltEnter && (cls.state==CA_DISCONNECTED || cls.state==CA_CONNECTED) ) { if (cl_allowAltEnter->integer) { Cvar_SetValue( "r_fullscreen", !r_fullscreen->integer ); Cbuf_AddText( "vid_restart\n" ); } } return 0; } // fall through case WM_KEYDOWN: code = MapKey( lParam, wParam ); if(code) { Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, code, qtrue, 0, NULL ); } break; case WM_SYSKEYUP: case WM_KEYUP: code = MapKey( lParam, wParam ); if(code) { Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, code, qfalse, 0, NULL ); } break; case WM_CHAR: if(((lParam >> 16) & 0xff) != CONSOLE_SCAN_CODE) { Sys_QueEvent( g_wv.sysMsgTime, SE_CHAR, wParam, 0, 0, NULL ); } // Output any debug prints // if(in_debug && in_debug->integer & 2) // { // Com_Printf("WM_CHAR: %x\n", wParam); // } break; case WM_POWERBROADCAST: if (wParam == PBT_APMQUERYSUSPEND) { #ifndef FINAL_BUILD Com_Printf("Cannot go into hibernate / standby mode while game is running!\n"); #endif return BROADCAST_QUERY_DENY; } break; } return DefWindowProc( hWnd, uMsg, wParam, lParam ); }