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 Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 
23 #ifdef USE_LOCAL_HEADERS
24 #	include "SDL.h"
25 #else
26 #	include <SDL.h>
27 #endif
28 
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 
33 #include "../renderer/tr_local.h"
34 #include "../client/client.h"
35 #include "../sys/sys_local.h"
36 
37 #ifdef MACOS_X
38 // Mouse acceleration needs to be disabled
39 #define MACOS_X_ACCELERATION_HACK
40 // Cursor needs hack to hide
41 #define MACOS_X_CURSOR_HACK
42 #endif
43 
44 #ifdef MACOS_X_ACCELERATION_HACK
45 #include <IOKit/hidsystem/IOHIDLib.h>
46 #include <IOKit/hidsystem/IOHIDParameter.h>
47 #include <IOKit/hidsystem/event_status_driver.h>
48 #endif
49 
50 //#define KBD_DBG
51 
52 static SDL_Joystick *stick = NULL;
53 
54 static qboolean mouseAvailable = qfalse;
55 static qboolean mouseActive = qfalse;
56 static qboolean keyRepeatEnabled = qfalse;
57 
58 static cvar_t *in_mouse;
59 #ifdef MACOS_X_ACCELERATION_HACK
60 static cvar_t *in_disablemacosxmouseaccel;
61 static double originalMouseSpeed = -1.0;
62 #endif
63 static cvar_t *in_nograb;
64 
65 static cvar_t *in_joystick          = NULL;
66 static cvar_t *in_joystickDebug     = NULL;
67 static cvar_t *in_joystickThreshold = NULL;
68 
69 /*
70 ===============
71 IN_TranslateSDLToQ3Key
72 ===============
73 */
IN_TranslateSDLToQ3Key(SDL_keysym * keysym,int * key)74 static const char *IN_TranslateSDLToQ3Key(SDL_keysym *keysym, int *key)
75 {
76 	static char buf[2] = { '\0', '\0' };
77 	*buf = '\0';
78 
79 	*key = 0;
80 
81 	// these happen to match the ASCII chars.
82 	if ((keysym->sym >= ' ') && (keysym->sym <= '~'))
83 	{
84 		*key = (int) keysym->sym;
85 	}
86 	else
87 	{
88 		switch (keysym->sym)
89 		{
90 			case SDLK_PAGEUP:       *key = K_PGUP;          break;
91 			case SDLK_KP9:          *key = K_KP_PGUP;       break;
92 			case SDLK_PAGEDOWN:     *key = K_PGDN;          break;
93 			case SDLK_KP3:          *key = K_KP_PGDN;       break;
94 			case SDLK_KP7:          *key = K_KP_HOME;       break;
95 			case SDLK_HOME:         *key = K_HOME;          break;
96 			case SDLK_KP1:          *key = K_KP_END;        break;
97 			case SDLK_END:          *key = K_END;           break;
98 			case SDLK_KP4:          *key = K_KP_LEFTARROW;  break;
99 			case SDLK_LEFT:         *key = K_LEFTARROW;     break;
100 			case SDLK_KP6:          *key = K_KP_RIGHTARROW; break;
101 			case SDLK_RIGHT:        *key = K_RIGHTARROW;    break;
102 			case SDLK_KP2:          *key = K_KP_DOWNARROW;  break;
103 			case SDLK_DOWN:         *key = K_DOWNARROW;     break;
104 			case SDLK_KP8:          *key = K_KP_UPARROW;    break;
105 			case SDLK_UP:           *key = K_UPARROW;       break;
106 			case SDLK_ESCAPE:       *key = K_ESCAPE;        break;
107 			case SDLK_KP_ENTER:     *key = K_KP_ENTER;      break;
108 			case SDLK_RETURN:       *key = K_ENTER;         break;
109 			case SDLK_TAB:          *key = K_TAB;           break;
110 			case SDLK_F1:           *key = K_F1;            break;
111 			case SDLK_F2:           *key = K_F2;            break;
112 			case SDLK_F3:           *key = K_F3;            break;
113 			case SDLK_F4:           *key = K_F4;            break;
114 			case SDLK_F5:           *key = K_F5;            break;
115 			case SDLK_F6:           *key = K_F6;            break;
116 			case SDLK_F7:           *key = K_F7;            break;
117 			case SDLK_F8:           *key = K_F8;            break;
118 			case SDLK_F9:           *key = K_F9;            break;
119 			case SDLK_F10:          *key = K_F10;           break;
120 			case SDLK_F11:          *key = K_F11;           break;
121 			case SDLK_F12:          *key = K_F12;           break;
122 			case SDLK_F13:          *key = K_F13;           break;
123 			case SDLK_F14:          *key = K_F14;           break;
124 			case SDLK_F15:          *key = K_F15;           break;
125 
126 			case SDLK_BACKSPACE:    *key = K_BACKSPACE;     break; // ctrl-h
127 			case SDLK_KP_PERIOD:    *key = K_KP_DEL;        break;
128 			case SDLK_DELETE:       *key = K_DEL;           break;
129 			case SDLK_PAUSE:        *key = K_PAUSE;         break;
130 
131 			case SDLK_LSHIFT:
132 			case SDLK_RSHIFT:       *key = K_SHIFT;         break;
133 
134 			case SDLK_LCTRL:
135 			case SDLK_RCTRL:        *key = K_CTRL;          break;
136 
137 			case SDLK_RMETA:
138 			case SDLK_LMETA:
139 			case SDLK_RALT:
140 			case SDLK_LALT:         *key = K_ALT;           break;
141 
142 			case SDLK_LSUPER:
143 			case SDLK_RSUPER:       *key = K_SUPER;         break;
144 
145 			case SDLK_KP5:          *key = K_KP_5;          break;
146 			case SDLK_INSERT:       *key = K_INS;           break;
147 			case SDLK_KP0:          *key = K_KP_INS;        break;
148 			case SDLK_KP_MULTIPLY:  *key = K_KP_STAR;       break;
149 			case SDLK_KP_PLUS:      *key = K_KP_PLUS;       break;
150 			case SDLK_KP_MINUS:     *key = K_KP_MINUS;      break;
151 			case SDLK_KP_DIVIDE:    *key = K_KP_SLASH;      break;
152 
153 			case SDLK_MODE:         *key = K_MODE;          break;
154 			case SDLK_COMPOSE:      *key = K_COMPOSE;       break;
155 			case SDLK_HELP:         *key = K_HELP;          break;
156 			case SDLK_PRINT:        *key = K_PRINT;         break;
157 			case SDLK_SYSREQ:       *key = K_SYSREQ;        break;
158 			case SDLK_BREAK:        *key = K_BREAK;         break;
159 			case SDLK_MENU:         *key = K_MENU;          break;
160 			case SDLK_POWER:        *key = K_POWER;         break;
161 			case SDLK_EURO:         *key = K_EURO;          break;
162 			case SDLK_UNDO:         *key = K_UNDO;          break;
163 			case SDLK_SCROLLOCK:    *key = K_SCROLLOCK;     break;
164 			case SDLK_NUMLOCK:      *key = K_KP_NUMLOCK;    break;
165 			case SDLK_CAPSLOCK:     *key = K_CAPSLOCK;      break;
166 
167 			default:
168 				if (keysym->sym >= SDLK_WORLD_0 && keysym->sym <= SDLK_WORLD_95)
169 					*key = (keysym->sym - SDLK_WORLD_0) + K_WORLD_0;
170 				break;
171 		}
172 	}
173 
174 	if( keysym->unicode <= 127 )  // maps to ASCII?
175 	{
176 		char ch = (char) keysym->unicode;
177 		if (ch == '~')
178 			*key = '~'; // console HACK
179 
180 		// translate K_BACKSPACE to ctrl-h for MACOS_X (others?)
181 		if (ch == K_BACKSPACE && keysym->sym != SDLK_DELETE)
182 		{
183 			*key = 'h' - 'a' + 1;
184 			buf[0] = *key;
185 		}
186 		else
187 			buf[0] = ch;
188 	}
189 
190 	return buf;
191 }
192 
193 /*
194 ===============
195 IN_PrintKey
196 ===============
197 */
IN_PrintKey(const SDL_Event * event)198 static void IN_PrintKey(const SDL_Event* event)
199 {
200 #ifdef KBD_DBG
201 	fprintf( stderr, "key name: %s", SDL_GetKeyName (event->key.keysym.sym ) );
202 	if(event->key.keysym.unicode)
203 	{
204 		fprintf( stderr, " unicode: %hx", event->key.keysym.unicode );
205 		if( event->key.keysym.unicode >= '0' &&
206 				event->key.keysym.unicode <= '~')  // printable?
207 		{
208 			fprintf( stderr, " (%c)", (unsigned char)event->key.keysym.unicode );
209 		}
210 	}
211 	fflush( stderr );
212 #endif
213 }
214 
215 #ifdef MACOS_X_ACCELERATION_HACK
216 /*
217 ===============
218 IN_GetIOHandle
219 ===============
220 */
IN_GetIOHandle()221 static io_connect_t IN_GetIOHandle() // mac os x mouse accel hack
222 {
223 	io_connect_t iohandle = MACH_PORT_NULL;
224 	kern_return_t status;
225 	io_service_t iohidsystem = MACH_PORT_NULL;
226 	mach_port_t masterport;
227 
228 	status = IOMasterPort(MACH_PORT_NULL, &masterport);
229 	if(status != KERN_SUCCESS)
230 		return 0;
231 
232 	iohidsystem = IORegistryEntryFromPath(masterport, kIOServicePlane ":/IOResources/IOHIDSystem");
233 	if(!iohidsystem)
234 		return 0;
235 
236 	status = IOServiceOpen(iohidsystem, mach_task_self(), kIOHIDParamConnectType, &iohandle);
237 	IOObjectRelease(iohidsystem);
238 
239 	return iohandle;
240 }
241 #endif
242 
243 /*
244 ===============
245 IN_ActivateMouse
246 ===============
247 */
IN_ActivateMouse(void)248 static void IN_ActivateMouse( void )
249 {
250 	if (!mouseAvailable || !SDL_WasInit( SDL_INIT_VIDEO ) )
251 		return;
252 
253 #ifdef MACOS_X_ACCELERATION_HACK
254 	if (!mouseActive) // mac os x mouse accel hack
255 	{
256 		// Save the status of mouse acceleration
257 		originalMouseSpeed = -1.0; // in case of error
258 		if(in_disablemacosxmouseaccel->integer)
259 		{
260 			io_connect_t mouseDev = IN_GetIOHandle();
261 			if(mouseDev != 0)
262 			{
263 				if(IOHIDGetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), &originalMouseSpeed) == kIOReturnSuccess)
264 				{
265 					Com_Printf("previous mouse acceleration: %f\n", originalMouseSpeed);
266 					if(IOHIDSetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), -1.0) != kIOReturnSuccess)
267 					{
268 						Com_Printf("Could not disable mouse acceleration (failed at IOHIDSetAccelerationWithKey).\n");
269 						Cvar_Set ("in_disablemacosxmouseaccel", 0);
270 					}
271 				}
272 				else
273 				{
274 					Com_Printf("Could not disable mouse acceleration (failed at IOHIDGetAccelerationWithKey).\n");
275 					Cvar_Set ("in_disablemacosxmouseaccel", 0);
276 				}
277 				IOServiceClose(mouseDev);
278 			}
279 			else
280 			{
281 				Com_Printf("Could not disable mouse acceleration (failed at IO_GetIOHandle).\n");
282 				Cvar_Set ("in_disablemacosxmouseaccel", 0);
283 			}
284 		}
285 	}
286 #endif
287 
288 	if( !mouseActive )
289 	{
290 		SDL_WM_GrabInput( SDL_GRAB_ON );
291 		SDL_ShowCursor( 0 );
292 
293 #ifdef MACOS_X_CURSOR_HACK
294 		// This is a bug in the current SDL/macosx...have to toggle it a few
295 		//  times to get the cursor to hide.
296 		SDL_ShowCursor( 1 );
297 		SDL_ShowCursor( 0 );
298 #endif
299 	}
300 
301 	// in_nograb makes no sense unless fullscreen
302 	if( !r_fullscreen->integer )
303 	{
304 		if( in_nograb->modified || !mouseActive )
305 		{
306 			if( in_nograb->integer )
307 				SDL_WM_GrabInput( SDL_GRAB_OFF );
308 			else
309 				SDL_WM_GrabInput( SDL_GRAB_ON );
310 
311 			in_nograb->modified = qfalse;
312 		}
313 	}
314 
315 	mouseActive = qtrue;
316 }
317 
318 /*
319 ===============
320 IN_DeactivateMouse
321 ===============
322 */
IN_DeactivateMouse(void)323 static void IN_DeactivateMouse( void )
324 {
325 	if (!mouseAvailable || !SDL_WasInit( SDL_INIT_VIDEO ) )
326 		return;
327 
328 #ifdef MACOS_X_ACCELERATION_HACK
329 	if (mouseActive) // mac os x mouse accel hack
330 	{
331 		if(originalMouseSpeed != -1.0)
332 		{
333 			io_connect_t mouseDev = IN_GetIOHandle();
334 			if(mouseDev != 0)
335 			{
336 				Com_Printf("restoring mouse acceleration to: %f\n", originalMouseSpeed);
337 				if(IOHIDSetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), originalMouseSpeed) != kIOReturnSuccess)
338 					Com_Printf("Could not re-enable mouse acceleration (failed at IOHIDSetAccelerationWithKey).\n");
339 				IOServiceClose(mouseDev);
340 			}
341 			else
342 				Com_Printf("Could not re-enable mouse acceleration (failed at IO_GetIOHandle).\n");
343 		}
344 	}
345 #endif
346 
347 	if( mouseActive )
348 	{
349 		SDL_ShowCursor( 1 );
350 		SDL_WM_GrabInput( SDL_GRAB_OFF );
351 
352 		mouseActive = qfalse;
353 	}
354 }
355 
356 // We translate axes movement into keypresses
357 static int joy_keys[16] = {
358 	K_LEFTARROW, K_RIGHTARROW,
359 	K_UPARROW, K_DOWNARROW,
360 	K_JOY16, K_JOY17,
361 	K_JOY18, K_JOY19,
362 	K_JOY20, K_JOY21,
363 	K_JOY22, K_JOY23,
364 
365 	K_JOY24, K_JOY25,
366 	K_JOY26, K_JOY27
367 };
368 
369 // translate hat events into keypresses
370 // the 4 highest buttons are used for the first hat ...
371 static int hat_keys[16] = {
372 	K_JOY29, K_JOY30,
373 	K_JOY31, K_JOY32,
374 	K_JOY25, K_JOY26,
375 	K_JOY27, K_JOY28,
376 	K_JOY21, K_JOY22,
377 	K_JOY23, K_JOY24,
378 	K_JOY17, K_JOY18,
379 	K_JOY19, K_JOY20
380 };
381 
382 
383 extern cvar_t *  in_joystick;
384 extern cvar_t *  in_joystickDebug;
385 extern cvar_t *  in_joystickThreshold;
386 cvar_t *in_joystickNo;
387 
388 #define ARRAYLEN(x) (sizeof (x) / sizeof (x[0]))
389 struct
390 {
391 	qboolean buttons[16];  // !!! FIXME: these might be too many.
392 	unsigned int oldaxes;
393 	unsigned int oldhats;
394 } stick_state;
395 
396 
397 /*
398 ===============
399 IN_StartupJoystick
400 ===============
401 */
IN_StartupJoystick(void)402 static void IN_StartupJoystick( void )
403 {
404 	int i = 0;
405 	int total = 0;
406 
407 	if (stick != NULL)
408 		SDL_JoystickClose(stick);
409 
410 	stick = NULL;
411 	memset(&stick_state, '\0', sizeof (stick_state));
412 
413 	if( !in_joystick->integer ) {
414 		Com_DPrintf( "Joystick is not active.\n" );
415 		return;
416 	}
417 
418 	if (!SDL_WasInit(SDL_INIT_JOYSTICK))
419 	{
420 		Com_DPrintf("Calling SDL_Init(SDL_INIT_JOYSTICK)...\n");
421 		if (SDL_Init(SDL_INIT_JOYSTICK) == -1)
422 		{
423 			Com_DPrintf("SDL_Init(SDL_INIT_JOYSTICK) failed: %s\n", SDL_GetError());
424 			return;
425 		}
426 		Com_DPrintf("SDL_Init(SDL_INIT_JOYSTICK) passed.\n");
427 	}
428 
429 	total = SDL_NumJoysticks();
430 	Com_DPrintf("%d possible joysticks\n", total);
431 	for (i = 0; i < total; i++)
432 		Com_DPrintf("[%d] %s\n", i, SDL_JoystickName(i));
433 
434 	in_joystickNo = Cvar_Get( "in_joystickNo", "0", CVAR_ARCHIVE );
435 	if( in_joystickNo->integer < 0 || in_joystickNo->integer >= total )
436 		Cvar_Set( "in_joystickNo", "0" );
437 
438 	stick = SDL_JoystickOpen( in_joystickNo->integer );
439 
440 	if (stick == NULL) {
441 		Com_DPrintf( "No joystick opened.\n" );
442 		return;
443 	}
444 
445 	Com_DPrintf( "Joystick %d opened\n", in_joystickNo->integer );
446 	Com_DPrintf( "Name:    %s\n", SDL_JoystickName(in_joystickNo->integer) );
447 	Com_DPrintf( "Axes:    %d\n", SDL_JoystickNumAxes(stick) );
448 	Com_DPrintf( "Hats:    %d\n", SDL_JoystickNumHats(stick) );
449 	Com_DPrintf( "Buttons: %d\n", SDL_JoystickNumButtons(stick) );
450 	Com_DPrintf( "Balls: %d\n", SDL_JoystickNumBalls(stick) );
451 
452 	SDL_JoystickEventState(SDL_QUERY);
453 
454 	return;
455 }
456 
457 /*
458 ===============
459 IN_JoyMove
460 ===============
461 */
IN_JoyMove(void)462 static void IN_JoyMove( void )
463 {
464 	qboolean joy_pressed[ARRAYLEN(joy_keys)];
465 	unsigned int axes = 0;
466 	unsigned int hats = 0;
467 	int total = 0;
468 	int i = 0;
469 
470 	if (!stick)
471 		return;
472 
473 	SDL_JoystickUpdate();
474 
475 	memset(joy_pressed, '\0', sizeof (joy_pressed));
476 
477 	// update the ball state.
478 	total = SDL_JoystickNumBalls(stick);
479 	if (total > 0)
480 	{
481 		int balldx = 0;
482 		int balldy = 0;
483 		for (i = 0; i < total; i++)
484 		{
485 			int dx = 0;
486 			int dy = 0;
487 			SDL_JoystickGetBall(stick, i, &dx, &dy);
488 			balldx += dx;
489 			balldy += dy;
490 		}
491 		if (balldx || balldy)
492 		{
493 			// !!! FIXME: is this good for stick balls, or just mice?
494 			// Scale like the mouse input...
495 			if (abs(balldx) > 1)
496 				balldx *= 2;
497 			if (abs(balldy) > 1)
498 				balldy *= 2;
499 			Com_QueueEvent( 0, SE_MOUSE, balldx, balldy, 0, NULL );
500 		}
501 	}
502 
503 	// now query the stick buttons...
504 	total = SDL_JoystickNumButtons(stick);
505 	if (total > 0)
506 	{
507 		if (total > ARRAYLEN(stick_state.buttons))
508 			total = ARRAYLEN(stick_state.buttons);
509 		for (i = 0; i < total; i++)
510 		{
511 			qboolean pressed = (SDL_JoystickGetButton(stick, i) != 0);
512 			if (pressed != stick_state.buttons[i])
513 			{
514 				Com_QueueEvent( 0, SE_KEY, K_JOY1 + i, pressed, 0, NULL );
515 				stick_state.buttons[i] = pressed;
516 			}
517 		}
518 	}
519 
520 	// look at the hats...
521 	total = SDL_JoystickNumHats(stick);
522 	if (total > 0)
523 	{
524 		if (total > 4) total = 4;
525 		for (i = 0; i < total; i++)
526 		{
527 			((Uint8 *)&hats)[i] = SDL_JoystickGetHat(stick, i);
528 		}
529 	}
530 
531 	// update hat state
532 	if (hats != stick_state.oldhats)
533 	{
534 		for( i = 0; i < 4; i++ ) {
535 			if( ((Uint8 *)&hats)[i] != ((Uint8 *)&stick_state.oldhats)[i] ) {
536 				// release event
537 				switch( ((Uint8 *)&stick_state.oldhats)[i] ) {
538 					case SDL_HAT_UP:
539 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL );
540 						break;
541 					case SDL_HAT_RIGHT:
542 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL );
543 						break;
544 					case SDL_HAT_DOWN:
545 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL );
546 						break;
547 					case SDL_HAT_LEFT:
548 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL );
549 						break;
550 					case SDL_HAT_RIGHTUP:
551 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL );
552 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL );
553 						break;
554 					case SDL_HAT_RIGHTDOWN:
555 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL );
556 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL );
557 						break;
558 					case SDL_HAT_LEFTUP:
559 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL );
560 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL );
561 						break;
562 					case SDL_HAT_LEFTDOWN:
563 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL );
564 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL );
565 						break;
566 					default:
567 						break;
568 				}
569 				// press event
570 				switch( ((Uint8 *)&hats)[i] ) {
571 					case SDL_HAT_UP:
572 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL );
573 						break;
574 					case SDL_HAT_RIGHT:
575 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL );
576 						break;
577 					case SDL_HAT_DOWN:
578 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL );
579 						break;
580 					case SDL_HAT_LEFT:
581 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL );
582 						break;
583 					case SDL_HAT_RIGHTUP:
584 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL );
585 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL );
586 						break;
587 					case SDL_HAT_RIGHTDOWN:
588 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL );
589 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL );
590 						break;
591 					case SDL_HAT_LEFTUP:
592 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL );
593 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL );
594 						break;
595 					case SDL_HAT_LEFTDOWN:
596 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL );
597 						Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL );
598 						break;
599 					default:
600 						break;
601 				}
602 			}
603 		}
604 	}
605 
606 	// save hat state
607 	stick_state.oldhats = hats;
608 
609 	// finally, look at the axes...
610 	total = SDL_JoystickNumAxes(stick);
611 	if (total > 0)
612 	{
613 		if (total > 16) total = 16;
614 		for (i = 0; i < total; i++)
615 		{
616 			Sint16 axis = SDL_JoystickGetAxis(stick, i);
617 			float f = ( (float) axis ) / 32767.0f;
618 			if( f < -in_joystickThreshold->value ) {
619 				axes |= ( 1 << ( i * 2 ) );
620 			} else if( f > in_joystickThreshold->value ) {
621 				axes |= ( 1 << ( ( i * 2 ) + 1 ) );
622 			}
623 		}
624 	}
625 
626 	/* Time to update axes state based on old vs. new. */
627 	if (axes != stick_state.oldaxes)
628 	{
629 		for( i = 0; i < 16; i++ ) {
630 			if( ( axes & ( 1 << i ) ) && !( stick_state.oldaxes & ( 1 << i ) ) ) {
631 				Com_QueueEvent( 0, SE_KEY, joy_keys[i], qtrue, 0, NULL );
632 			}
633 
634 			if( !( axes & ( 1 << i ) ) && ( stick_state.oldaxes & ( 1 << i ) ) ) {
635 				Com_QueueEvent( 0, SE_KEY, joy_keys[i], qfalse, 0, NULL );
636 			}
637 		}
638 	}
639 
640 	/* Save for future generations. */
641 	stick_state.oldaxes = axes;
642 }
643 
644 /*
645 ===============
646 IN_ProcessEvents
647 ===============
648 */
IN_ProcessEvents(void)649 static void IN_ProcessEvents( void )
650 {
651 	SDL_Event e;
652 	const char *p = NULL;
653 	int key = 0;
654 	int mx = 0, my = 0;
655 
656 	if( !SDL_WasInit( SDL_INIT_VIDEO ) )
657 			return;
658 
659 	if( Key_GetCatcher( ) == 0 && keyRepeatEnabled )
660 	{
661 		SDL_EnableKeyRepeat( 0, 0 );
662 		keyRepeatEnabled = qfalse;
663 	}
664 	else if( !keyRepeatEnabled )
665 	{
666 		SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY,
667 			SDL_DEFAULT_REPEAT_INTERVAL );
668 		keyRepeatEnabled = qtrue;
669 	}
670 
671 	while (SDL_PollEvent(&e))
672 	{
673 		switch (e.type)
674 		{
675 			case SDL_KEYDOWN:
676 				IN_PrintKey(&e);
677 				p = IN_TranslateSDLToQ3Key(&e.key.keysym, &key);
678 				if( key )
679 					Com_QueueEvent( 0, SE_KEY, key, qtrue, 0, NULL );
680 
681 				if( p )
682 				{
683 					while( *p )
684 						Com_QueueEvent( 0, SE_CHAR, *p++, 0, 0, NULL );
685 				}
686 				break;
687 
688 			case SDL_KEYUP:
689 				IN_TranslateSDLToQ3Key(&e.key.keysym, &key);
690 				Com_QueueEvent( 0, SE_KEY, key, qfalse, 0, NULL );
691 				break;
692 
693 			case SDL_MOUSEMOTION:
694 				if (mouseActive)
695 				{
696 					mx += e.motion.xrel;
697 					my += e.motion.yrel;
698 				}
699 				break;
700 
701 			case SDL_MOUSEBUTTONDOWN:
702 			case SDL_MOUSEBUTTONUP:
703 				{
704 					unsigned char b;
705 					switch (e.button.button)
706 					{
707 						case 1:   b = K_MOUSE1;     break;
708 						case 2:   b = K_MOUSE3;     break;
709 						case 3:   b = K_MOUSE2;     break;
710 						case 4:   b = K_MWHEELUP;   break;
711 						case 5:   b = K_MWHEELDOWN; break;
712 						case 6:   b = K_MOUSE4;     break;
713 						case 7:   b = K_MOUSE5;     break;
714 						default:  b = K_AUX1 + (e.button.button - 8)%16; break;
715 					}
716 					Com_QueueEvent( 0, SE_KEY, b,
717 						( e.type == SDL_MOUSEBUTTONDOWN ? qtrue : qfalse ), 0, NULL );
718 				}
719 				break;
720 
721 			case SDL_QUIT:
722 				Sys_Quit();
723 				break;
724 
725 			default:
726 				break;
727 		}
728 	}
729 
730 	if(mx || my)
731 		Com_QueueEvent( 0, SE_MOUSE, mx, my, 0, NULL );
732 }
733 
734 /*
735 ===============
736 IN_Frame
737 ===============
738 */
IN_Frame(void)739 void IN_Frame (void)
740 {
741 	IN_JoyMove( );
742 
743 	// Release the mouse if the console if down and we're windowed
744 	if( ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) && !r_fullscreen->integer )
745 		IN_DeactivateMouse( );
746 	else
747 		IN_ActivateMouse( );
748 
749 	IN_ProcessEvents( );
750 }
751 
752 /*
753 ===============
754 IN_Init
755 ===============
756 */
IN_Init(void)757 void IN_Init(void)
758 {
759 	if( !SDL_WasInit( SDL_INIT_VIDEO ) )
760 	{
761 		Com_Error( ERR_FATAL, "IN_Init called before SDL_Init( SDL_INIT_VIDEO )\n" );
762 		return;
763 	}
764 
765 	Com_DPrintf ("\n------- Input Initialization -------\n");
766 
767 	// mouse variables
768 	in_mouse = Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
769 	in_nograb = Cvar_Get ("in_nograb", "0", CVAR_ARCHIVE);
770 
771 	in_joystick = Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE|CVAR_LATCH);
772 	in_joystickDebug = Cvar_Get ("in_debugjoystick", "0", CVAR_TEMP);
773 	in_joystickThreshold = Cvar_Get ("in_joystickThreshold", "0.15", CVAR_ARCHIVE);
774 
775 #ifdef MACOS_X_ACCELERATION_HACK
776 	in_disablemacosxmouseaccel = Cvar_Get ("in_disablemacosxmouseaccel", "1", CVAR_ARCHIVE);
777 #endif
778 
779 	Cvar_Set( "cl_platformSensitivity", "1.0" );
780 
781 	SDL_EnableUNICODE(1);
782 	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
783 	keyRepeatEnabled = qtrue;
784 
785 	if (in_mouse->value)
786 		mouseAvailable = qtrue;
787 	else
788 		mouseAvailable = qfalse;
789 
790 	IN_StartupJoystick( );
791 	Com_DPrintf ("------------------------------------\n");
792 }
793 
794 /*
795 ===============
796 IN_Shutdown
797 ===============
798 */
IN_Shutdown(void)799 void IN_Shutdown(void)
800 {
801 	IN_DeactivateMouse();
802 
803 	mouseAvailable = qfalse;
804 
805 	if (stick)
806 	{
807 		SDL_JoystickClose(stick);
808 		stick = NULL;
809 	}
810 
811 	SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
812 }
813