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