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