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 #define ARRAYLEN(x) (sizeof(x)/sizeof(x[0]))
38
39 #ifdef MACOS_X
40 // Mouse acceleration needs to be disabled
41 #define MACOS_X_ACCELERATION_HACK
42 // Cursor needs hack to hide
43 #define MACOS_X_CURSOR_HACK
44 #endif
45
46 #ifdef MACOS_X_ACCELERATION_HACK
47 #include <IOKit/IOTypes.h>
48 #include <IOKit/hidsystem/IOHIDLib.h>
49 #include <IOKit/hidsystem/IOHIDParameter.h>
50 #include <IOKit/hidsystem/event_status_driver.h>
51 #endif
52
53 static cvar_t *in_keyboardDebug = NULL;
54
55 static SDL_Joystick *stick = NULL;
56
57 static qboolean mouseAvailable = qfalse;
58 static qboolean mouseActive = qfalse;
59 static qboolean keyRepeatEnabled = qfalse;
60
61 static cvar_t *in_mouse = NULL;
62 #ifdef MACOS_X_ACCELERATION_HACK
63 static cvar_t *in_disablemacosxmouseaccel = NULL;
64 static double originalMouseSpeed = -1.0;
65 #endif
66 static cvar_t *in_nograb;
67
68 static cvar_t *in_joystick = NULL;
69 static cvar_t *in_joystickDebug = NULL;
70 static cvar_t *in_joystickThreshold = NULL;
71 static cvar_t *in_joystickNo = NULL;
72
73 #define CTRL(a) ((a)-'a'+1)
74
75 /*
76 ===============
77 IN_PrintKey
78 ===============
79 */
IN_PrintKey(const SDL_keysym * keysym,keyNum_t key,qboolean down)80 static void IN_PrintKey( const SDL_keysym *keysym, keyNum_t key, qboolean down )
81 {
82 if( down )
83 Com_Printf( "+ " );
84 else
85 Com_Printf( " " );
86
87 Com_Printf( "0x%02x \"%s\"", keysym->scancode,
88 SDL_GetKeyName( keysym->sym ) );
89
90 if( keysym->mod & KMOD_LSHIFT ) Com_Printf( " KMOD_LSHIFT" );
91 if( keysym->mod & KMOD_RSHIFT ) Com_Printf( " KMOD_RSHIFT" );
92 if( keysym->mod & KMOD_LCTRL ) Com_Printf( " KMOD_LCTRL" );
93 if( keysym->mod & KMOD_RCTRL ) Com_Printf( " KMOD_RCTRL" );
94 if( keysym->mod & KMOD_LALT ) Com_Printf( " KMOD_LALT" );
95 if( keysym->mod & KMOD_RALT ) Com_Printf( " KMOD_RALT" );
96 if( keysym->mod & KMOD_LMETA ) Com_Printf( " KMOD_LMETA" );
97 if( keysym->mod & KMOD_RMETA ) Com_Printf( " KMOD_RMETA" );
98 if( keysym->mod & KMOD_NUM ) Com_Printf( " KMOD_NUM" );
99 if( keysym->mod & KMOD_CAPS ) Com_Printf( " KMOD_CAPS" );
100 if( keysym->mod & KMOD_MODE ) Com_Printf( " KMOD_MODE" );
101 if( keysym->mod & KMOD_RESERVED ) Com_Printf( " KMOD_RESERVED" );
102
103 Com_Printf( " Q:0x%02x(%s)", key, Key_KeynumToString( key ) );
104
105 if( keysym->unicode )
106 {
107 Com_Printf( " U:0x%02x", keysym->unicode );
108
109 if( keysym->unicode > ' ' && keysym->unicode < '~' )
110 Com_Printf( "(%c)", (char)keysym->unicode );
111 }
112
113 Com_Printf( "\n" );
114 }
115
116 #define MAX_CONSOLE_KEYS 16
117
118 /*
119 ===============
120 IN_IsConsoleKey
121 ===============
122 */
IN_IsConsoleKey(keyNum_t key,const unsigned char character)123 static qboolean IN_IsConsoleKey( keyNum_t key, const unsigned char character )
124 {
125 typedef struct consoleKey_s
126 {
127 enum
128 {
129 KEY,
130 CHARACTER
131 } type;
132
133 union
134 {
135 keyNum_t key;
136 unsigned char character;
137 } u;
138 } consoleKey_t;
139
140 static consoleKey_t consoleKeys[ MAX_CONSOLE_KEYS ];
141 static int numConsoleKeys = 0;
142 int i;
143
144 // Only parse the variable when it changes
145 if( cl_consoleKeys->modified )
146 {
147 char *text_p, *token;
148
149 cl_consoleKeys->modified = qfalse;
150 text_p = cl_consoleKeys->string;
151 numConsoleKeys = 0;
152
153 while( numConsoleKeys < MAX_CONSOLE_KEYS )
154 {
155 consoleKey_t *c = &consoleKeys[ numConsoleKeys ];
156 int charCode = 0;
157
158 token = COM_Parse( &text_p );
159 if( !token[ 0 ] )
160 break;
161
162 if( strlen( token ) == 4 )
163 charCode = Com_HexStrToInt( token );
164
165 if( charCode > 0 )
166 {
167 c->type = CHARACTER;
168 c->u.character = (unsigned char)charCode;
169 }
170 else
171 {
172 c->type = KEY;
173 c->u.key = Key_StringToKeynum( token );
174
175 // 0 isn't a key
176 if( c->u.key <= 0 )
177 continue;
178 }
179
180 numConsoleKeys++;
181 }
182 }
183
184 // If the character is the same as the key, prefer the character
185 if( key == character )
186 key = 0;
187
188 for( i = 0; i < numConsoleKeys; i++ )
189 {
190 consoleKey_t *c = &consoleKeys[ i ];
191
192 switch( c->type )
193 {
194 case KEY:
195 if( key && c->u.key == key )
196 return qtrue;
197 break;
198
199 case CHARACTER:
200 if( c->u.character == character )
201 return qtrue;
202 break;
203 }
204 }
205
206 return qfalse;
207 }
208
209 /*
210 ===============
211 IN_TranslateSDLToQ3Key
212 ===============
213 */
IN_TranslateSDLToQ3Key(SDL_keysym * keysym,keyNum_t * key,qboolean down)214 static const char *IN_TranslateSDLToQ3Key( SDL_keysym *keysym,
215 keyNum_t *key, qboolean down )
216 {
217 static unsigned char buf[ 2 ] = { '\0', '\0' };
218
219 *buf = '\0';
220 *key = 0;
221
222 if( keysym->sym >= SDLK_SPACE && keysym->sym < SDLK_DELETE )
223 {
224 // These happen to match the ASCII chars
225 *key = (int)keysym->sym;
226 }
227 else
228 {
229 switch( keysym->sym )
230 {
231 case SDLK_PAGEUP: *key = K_PGUP; break;
232 case SDLK_KP9: *key = K_KP_PGUP; break;
233 case SDLK_PAGEDOWN: *key = K_PGDN; break;
234 case SDLK_KP3: *key = K_KP_PGDN; break;
235 case SDLK_KP7: *key = K_KP_HOME; break;
236 case SDLK_HOME: *key = K_HOME; break;
237 case SDLK_KP1: *key = K_KP_END; break;
238 case SDLK_END: *key = K_END; break;
239 case SDLK_KP4: *key = K_KP_LEFTARROW; break;
240 case SDLK_LEFT: *key = K_LEFTARROW; break;
241 case SDLK_KP6: *key = K_KP_RIGHTARROW; break;
242 case SDLK_RIGHT: *key = K_RIGHTARROW; break;
243 case SDLK_KP2: *key = K_KP_DOWNARROW; break;
244 case SDLK_DOWN: *key = K_DOWNARROW; break;
245 case SDLK_KP8: *key = K_KP_UPARROW; break;
246 case SDLK_UP: *key = K_UPARROW; break;
247 case SDLK_ESCAPE: *key = K_ESCAPE; break;
248 case SDLK_KP_ENTER: *key = K_KP_ENTER; break;
249 case SDLK_RETURN: *key = K_ENTER; break;
250 case SDLK_TAB: *key = K_TAB; break;
251 case SDLK_F1: *key = K_F1; break;
252 case SDLK_F2: *key = K_F2; break;
253 case SDLK_F3: *key = K_F3; break;
254 case SDLK_F4: *key = K_F4; break;
255 case SDLK_F5: *key = K_F5; break;
256 case SDLK_F6: *key = K_F6; break;
257 case SDLK_F7: *key = K_F7; break;
258 case SDLK_F8: *key = K_F8; break;
259 case SDLK_F9: *key = K_F9; break;
260 case SDLK_F10: *key = K_F10; break;
261 case SDLK_F11: *key = K_F11; break;
262 case SDLK_F12: *key = K_F12; break;
263 case SDLK_F13: *key = K_F13; break;
264 case SDLK_F14: *key = K_F14; break;
265 case SDLK_F15: *key = K_F15; break;
266
267 case SDLK_BACKSPACE: *key = K_BACKSPACE; break;
268 case SDLK_KP_PERIOD: *key = K_KP_DEL; break;
269 case SDLK_DELETE: *key = K_DEL; break;
270 case SDLK_PAUSE: *key = K_PAUSE; break;
271
272 case SDLK_LSHIFT:
273 case SDLK_RSHIFT: *key = K_SHIFT; break;
274
275 case SDLK_LCTRL:
276 case SDLK_RCTRL: *key = K_CTRL; break;
277
278 case SDLK_RMETA:
279 case SDLK_LMETA: *key = K_COMMAND; break;
280
281 case SDLK_RALT:
282 case SDLK_LALT: *key = K_ALT; break;
283
284 case SDLK_LSUPER:
285 case SDLK_RSUPER: *key = K_SUPER; break;
286
287 case SDLK_KP5: *key = K_KP_5; break;
288 case SDLK_INSERT: *key = K_INS; break;
289 case SDLK_KP0: *key = K_KP_INS; break;
290 case SDLK_KP_MULTIPLY: *key = K_KP_STAR; break;
291 case SDLK_KP_PLUS: *key = K_KP_PLUS; break;
292 case SDLK_KP_MINUS: *key = K_KP_MINUS; break;
293 case SDLK_KP_DIVIDE: *key = K_KP_SLASH; break;
294
295 case SDLK_MODE: *key = K_MODE; break;
296 case SDLK_COMPOSE: *key = K_COMPOSE; break;
297 case SDLK_HELP: *key = K_HELP; break;
298 case SDLK_PRINT: *key = K_PRINT; break;
299 case SDLK_SYSREQ: *key = K_SYSREQ; break;
300 case SDLK_BREAK: *key = K_BREAK; break;
301 case SDLK_MENU: *key = K_MENU; break;
302 case SDLK_POWER: *key = K_POWER; break;
303 case SDLK_EURO: *key = K_EURO; break;
304 case SDLK_UNDO: *key = K_UNDO; break;
305 case SDLK_SCROLLOCK: *key = K_SCROLLOCK; break;
306 case SDLK_NUMLOCK: *key = K_KP_NUMLOCK; break;
307 case SDLK_CAPSLOCK: *key = K_CAPSLOCK; break;
308
309 default:
310 if( keysym->sym >= SDLK_WORLD_0 && keysym->sym <= SDLK_WORLD_95 )
311 *key = ( keysym->sym - SDLK_WORLD_0 ) + K_WORLD_0;
312 break;
313 }
314 }
315
316 if( down && keysym->unicode && !( keysym->unicode & 0xFF00 ) )
317 {
318 unsigned char ch = (unsigned char)keysym->unicode & 0xFF;
319
320 switch( ch )
321 {
322 case 127: // ASCII delete
323 if( *key != K_DEL )
324 {
325 // ctrl-h
326 *buf = CTRL('h');
327 break;
328 }
329 // fallthrough
330
331 default: *buf = ch; break;
332 }
333 }
334
335 if( in_keyboardDebug->integer )
336 IN_PrintKey( keysym, *key, down );
337
338 // Keys that have ASCII names but produce no character are probably
339 // dead keys -- ignore them
340 if( down && strlen( Key_KeynumToString( *key ) ) == 1 &&
341 keysym->unicode == 0 )
342 {
343 if( in_keyboardDebug->integer )
344 Com_Printf( " Ignored dead key '%c'\n", *key );
345
346 *key = 0;
347 }
348
349 if( IN_IsConsoleKey( *key, *buf ) )
350 {
351 // Console keys can't be bound or generate characters
352 *key = K_CONSOLE;
353 *buf = '\0';
354 }
355
356 // Don't allow extended ASCII to generate characters
357 if( *buf & 0x80 )
358 *buf = '\0';
359
360 return (char *)buf;
361 }
362
363 #ifdef MACOS_X_ACCELERATION_HACK
364 /*
365 ===============
366 IN_GetIOHandle
367 ===============
368 */
IN_GetIOHandle(void)369 static io_connect_t IN_GetIOHandle(void) // mac os x mouse accel hack
370 {
371 io_connect_t iohandle = MACH_PORT_NULL;
372 kern_return_t status;
373 io_service_t iohidsystem = MACH_PORT_NULL;
374 mach_port_t masterport;
375
376 status = IOMasterPort(MACH_PORT_NULL, &masterport);
377 if(status != KERN_SUCCESS)
378 return 0;
379
380 iohidsystem = IORegistryEntryFromPath(masterport, kIOServicePlane ":/IOResources/IOHIDSystem");
381 if(!iohidsystem)
382 return 0;
383
384 status = IOServiceOpen(iohidsystem, mach_task_self(), kIOHIDParamConnectType, &iohandle);
385 IOObjectRelease(iohidsystem);
386
387 return iohandle;
388 }
389 #endif
390
391 /*
392 ===============
393 IN_GobbleMotionEvents
394 ===============
395 */
IN_GobbleMotionEvents(void)396 static void IN_GobbleMotionEvents( void )
397 {
398 SDL_Event dummy[ 1 ];
399
400 // Gobble any mouse motion events
401 SDL_PumpEvents( );
402 while( SDL_PeepEvents( dummy, 1, SDL_GETEVENT,
403 SDL_EVENTMASK( SDL_MOUSEMOTION ) ) ) { }
404 }
405
406 /*
407 ===============
408 IN_ActivateMouse
409 ===============
410 */
IN_ActivateMouse(void)411 static void IN_ActivateMouse( void )
412 {
413 if (!mouseAvailable || !SDL_WasInit( SDL_INIT_VIDEO ) )
414 return;
415
416 #ifdef MACOS_X_ACCELERATION_HACK
417 if (!mouseActive) // mac os x mouse accel hack
418 {
419 // Save the status of mouse acceleration
420 originalMouseSpeed = -1.0; // in case of error
421 if(in_disablemacosxmouseaccel->integer)
422 {
423 io_connect_t mouseDev = IN_GetIOHandle();
424 if(mouseDev != 0)
425 {
426 if(IOHIDGetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), &originalMouseSpeed) == kIOReturnSuccess)
427 {
428 Com_Printf("previous mouse acceleration: %f\n", originalMouseSpeed);
429 if(IOHIDSetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), -1.0) != kIOReturnSuccess)
430 {
431 Com_Printf("Could not disable mouse acceleration (failed at IOHIDSetAccelerationWithKey).\n");
432 Cvar_Set ("in_disablemacosxmouseaccel", 0);
433 }
434 }
435 else
436 {
437 Com_Printf("Could not disable mouse acceleration (failed at IOHIDGetAccelerationWithKey).\n");
438 Cvar_Set ("in_disablemacosxmouseaccel", 0);
439 }
440 IOServiceClose(mouseDev);
441 }
442 else
443 {
444 Com_Printf("Could not disable mouse acceleration (failed at IO_GetIOHandle).\n");
445 Cvar_Set ("in_disablemacosxmouseaccel", 0);
446 }
447 }
448 }
449 #endif
450
451 if( !mouseActive )
452 {
453 SDL_ShowCursor( 0 );
454 #ifdef MACOS_X_CURSOR_HACK
455 // This is a bug in the current SDL/macosx...have to toggle it a few
456 // times to get the cursor to hide.
457 SDL_ShowCursor( 1 );
458 SDL_ShowCursor( 0 );
459 #endif
460 SDL_WM_GrabInput( SDL_GRAB_ON );
461
462 IN_GobbleMotionEvents( );
463 }
464
465 // in_nograb makes no sense in fullscreen mode
466 if( !r_fullscreen->integer )
467 {
468 if( in_nograb->modified || !mouseActive )
469 {
470 if( in_nograb->integer )
471 SDL_WM_GrabInput( SDL_GRAB_OFF );
472 else
473 SDL_WM_GrabInput( SDL_GRAB_ON );
474
475 in_nograb->modified = qfalse;
476 }
477 }
478
479 mouseActive = qtrue;
480 }
481
482 /*
483 ===============
484 IN_DeactivateMouse
485 ===============
486 */
IN_DeactivateMouse(void)487 static void IN_DeactivateMouse( void )
488 {
489 if( !SDL_WasInit( SDL_INIT_VIDEO ) )
490 return;
491
492 // Always show the cursor when the mouse is disabled,
493 // but not when fullscreen
494 if( !r_fullscreen->integer )
495 SDL_ShowCursor( 1 );
496
497 if( !mouseAvailable )
498 return;
499
500 #ifdef MACOS_X_ACCELERATION_HACK
501 if (mouseActive) // mac os x mouse accel hack
502 {
503 if(originalMouseSpeed != -1.0)
504 {
505 io_connect_t mouseDev = IN_GetIOHandle();
506 if(mouseDev != 0)
507 {
508 Com_Printf("restoring mouse acceleration to: %f\n", originalMouseSpeed);
509 if(IOHIDSetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), originalMouseSpeed) != kIOReturnSuccess)
510 Com_Printf("Could not re-enable mouse acceleration (failed at IOHIDSetAccelerationWithKey).\n");
511 IOServiceClose(mouseDev);
512 }
513 else
514 Com_Printf("Could not re-enable mouse acceleration (failed at IO_GetIOHandle).\n");
515 }
516 }
517 #endif
518
519 if( mouseActive )
520 {
521 IN_GobbleMotionEvents( );
522
523 SDL_WM_GrabInput( SDL_GRAB_OFF );
524
525 // Don't warp the mouse unless the cursor is within the window
526 if( SDL_GetAppState( ) & SDL_APPMOUSEFOCUS )
527 SDL_WarpMouse( glConfig.vidWidth / 2, glConfig.vidHeight / 2 );
528
529 mouseActive = qfalse;
530 }
531 }
532
533 // We translate axes movement into keypresses
534 static int joy_keys[16] = {
535 K_LEFTARROW, K_RIGHTARROW,
536 K_UPARROW, K_DOWNARROW,
537 K_JOY16, K_JOY17,
538 K_JOY18, K_JOY19,
539 K_JOY20, K_JOY21,
540 K_JOY22, K_JOY23,
541
542 K_JOY24, K_JOY25,
543 K_JOY26, K_JOY27
544 };
545
546 // translate hat events into keypresses
547 // the 4 highest buttons are used for the first hat ...
548 static int hat_keys[16] = {
549 K_JOY29, K_JOY30,
550 K_JOY31, K_JOY32,
551 K_JOY25, K_JOY26,
552 K_JOY27, K_JOY28,
553 K_JOY21, K_JOY22,
554 K_JOY23, K_JOY24,
555 K_JOY17, K_JOY18,
556 K_JOY19, K_JOY20
557 };
558
559
560 struct
561 {
562 qboolean buttons[16]; // !!! FIXME: these might be too many.
563 unsigned int oldaxes;
564 unsigned int oldhats;
565 } stick_state;
566
567
568 /*
569 ===============
570 IN_InitJoystick
571 ===============
572 */
IN_InitJoystick(void)573 static void IN_InitJoystick( void )
574 {
575 int i = 0;
576 int total = 0;
577
578 if (stick != NULL)
579 SDL_JoystickClose(stick);
580
581 stick = NULL;
582 memset(&stick_state, '\0', sizeof (stick_state));
583
584 if( !in_joystick->integer ) {
585 Com_DPrintf( "Joystick is not active.\n" );
586 return;
587 }
588
589 if (!SDL_WasInit(SDL_INIT_JOYSTICK))
590 {
591 Com_DPrintf("Calling SDL_Init(SDL_INIT_JOYSTICK)...\n");
592 if (SDL_Init(SDL_INIT_JOYSTICK) == -1)
593 {
594 Com_DPrintf("SDL_Init(SDL_INIT_JOYSTICK) failed: %s\n", SDL_GetError());
595 return;
596 }
597 Com_DPrintf("SDL_Init(SDL_INIT_JOYSTICK) passed.\n");
598 }
599
600 total = SDL_NumJoysticks();
601 Com_DPrintf("%d possible joysticks\n", total);
602 for (i = 0; i < total; i++)
603 Com_DPrintf("[%d] %s\n", i, SDL_JoystickName(i));
604
605 in_joystickNo = Cvar_Get( "in_joystickNo", "0", CVAR_ARCHIVE );
606 if( in_joystickNo->integer < 0 || in_joystickNo->integer >= total )
607 Cvar_Set( "in_joystickNo", "0" );
608
609 stick = SDL_JoystickOpen( in_joystickNo->integer );
610
611 if (stick == NULL) {
612 Com_DPrintf( "No joystick opened.\n" );
613 return;
614 }
615
616 Com_DPrintf( "Joystick %d opened\n", in_joystickNo->integer );
617 Com_DPrintf( "Name: %s\n", SDL_JoystickName(in_joystickNo->integer) );
618 Com_DPrintf( "Axes: %d\n", SDL_JoystickNumAxes(stick) );
619 Com_DPrintf( "Hats: %d\n", SDL_JoystickNumHats(stick) );
620 Com_DPrintf( "Buttons: %d\n", SDL_JoystickNumButtons(stick) );
621 Com_DPrintf( "Balls: %d\n", SDL_JoystickNumBalls(stick) );
622
623 SDL_JoystickEventState(SDL_QUERY);
624 }
625
626 /*
627 ===============
628 IN_ShutdownJoystick
629 ===============
630 */
IN_ShutdownJoystick(void)631 static void IN_ShutdownJoystick( void )
632 {
633 if (stick)
634 {
635 SDL_JoystickClose(stick);
636 stick = NULL;
637 }
638
639 SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
640 }
641
642 /*
643 ===============
644 IN_JoyMove
645 ===============
646 */
IN_JoyMove(void)647 static void IN_JoyMove( void )
648 {
649 qboolean joy_pressed[ARRAYLEN(joy_keys)];
650 unsigned int axes = 0;
651 unsigned int hats = 0;
652 int total = 0;
653 int i = 0;
654
655 if (!stick)
656 return;
657
658 SDL_JoystickUpdate();
659
660 memset(joy_pressed, '\0', sizeof (joy_pressed));
661
662 // update the ball state.
663 total = SDL_JoystickNumBalls(stick);
664 if (total > 0)
665 {
666 int balldx = 0;
667 int balldy = 0;
668 for (i = 0; i < total; i++)
669 {
670 int dx = 0;
671 int dy = 0;
672 SDL_JoystickGetBall(stick, i, &dx, &dy);
673 balldx += dx;
674 balldy += dy;
675 }
676 if (balldx || balldy)
677 {
678 // !!! FIXME: is this good for stick balls, or just mice?
679 // Scale like the mouse input...
680 if (abs(balldx) > 1)
681 balldx *= 2;
682 if (abs(balldy) > 1)
683 balldy *= 2;
684 Com_QueueEvent( 0, SE_MOUSE, balldx, balldy, 0, NULL );
685 }
686 }
687
688 // now query the stick buttons...
689 total = SDL_JoystickNumButtons(stick);
690 if (total > 0)
691 {
692 if (total > ARRAYLEN(stick_state.buttons))
693 total = ARRAYLEN(stick_state.buttons);
694 for (i = 0; i < total; i++)
695 {
696 qboolean pressed = (SDL_JoystickGetButton(stick, i) != 0);
697 if (pressed != stick_state.buttons[i])
698 {
699 Com_QueueEvent( 0, SE_KEY, K_JOY1 + i, pressed, 0, NULL );
700 stick_state.buttons[i] = pressed;
701 }
702 }
703 }
704
705 // look at the hats...
706 total = SDL_JoystickNumHats(stick);
707 if (total > 0)
708 {
709 if (total > 4) total = 4;
710 for (i = 0; i < total; i++)
711 {
712 ((Uint8 *)&hats)[i] = SDL_JoystickGetHat(stick, i);
713 }
714 }
715
716 // update hat state
717 if (hats != stick_state.oldhats)
718 {
719 for( i = 0; i < 4; i++ ) {
720 if( ((Uint8 *)&hats)[i] != ((Uint8 *)&stick_state.oldhats)[i] ) {
721 // release event
722 switch( ((Uint8 *)&stick_state.oldhats)[i] ) {
723 case SDL_HAT_UP:
724 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL );
725 break;
726 case SDL_HAT_RIGHT:
727 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL );
728 break;
729 case SDL_HAT_DOWN:
730 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL );
731 break;
732 case SDL_HAT_LEFT:
733 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL );
734 break;
735 case SDL_HAT_RIGHTUP:
736 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL );
737 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL );
738 break;
739 case SDL_HAT_RIGHTDOWN:
740 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL );
741 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qfalse, 0, NULL );
742 break;
743 case SDL_HAT_LEFTUP:
744 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qfalse, 0, NULL );
745 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL );
746 break;
747 case SDL_HAT_LEFTDOWN:
748 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qfalse, 0, NULL );
749 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qfalse, 0, NULL );
750 break;
751 default:
752 break;
753 }
754 // press event
755 switch( ((Uint8 *)&hats)[i] ) {
756 case SDL_HAT_UP:
757 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL );
758 break;
759 case SDL_HAT_RIGHT:
760 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL );
761 break;
762 case SDL_HAT_DOWN:
763 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL );
764 break;
765 case SDL_HAT_LEFT:
766 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL );
767 break;
768 case SDL_HAT_RIGHTUP:
769 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL );
770 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL );
771 break;
772 case SDL_HAT_RIGHTDOWN:
773 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL );
774 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 1], qtrue, 0, NULL );
775 break;
776 case SDL_HAT_LEFTUP:
777 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 0], qtrue, 0, NULL );
778 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL );
779 break;
780 case SDL_HAT_LEFTDOWN:
781 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 2], qtrue, 0, NULL );
782 Com_QueueEvent( 0, SE_KEY, hat_keys[4*i + 3], qtrue, 0, NULL );
783 break;
784 default:
785 break;
786 }
787 }
788 }
789 }
790
791 // save hat state
792 stick_state.oldhats = hats;
793
794 // finally, look at the axes...
795 total = SDL_JoystickNumAxes(stick);
796 if (total > 0)
797 {
798 if (total > 16) total = 16;
799 for (i = 0; i < total; i++)
800 {
801 Sint16 axis = SDL_JoystickGetAxis(stick, i);
802 float f = ( (float) axis ) / 32767.0f;
803 if( f < -in_joystickThreshold->value ) {
804 axes |= ( 1 << ( i * 2 ) );
805 } else if( f > in_joystickThreshold->value ) {
806 axes |= ( 1 << ( ( i * 2 ) + 1 ) );
807 }
808 }
809 }
810
811 /* Time to update axes state based on old vs. new. */
812 if (axes != stick_state.oldaxes)
813 {
814 for( i = 0; i < 16; i++ ) {
815 if( ( axes & ( 1 << i ) ) && !( stick_state.oldaxes & ( 1 << i ) ) ) {
816 Com_QueueEvent( 0, SE_KEY, joy_keys[i], qtrue, 0, NULL );
817 }
818
819 if( !( axes & ( 1 << i ) ) && ( stick_state.oldaxes & ( 1 << i ) ) ) {
820 Com_QueueEvent( 0, SE_KEY, joy_keys[i], qfalse, 0, NULL );
821 }
822 }
823 }
824
825 /* Save for future generations. */
826 stick_state.oldaxes = axes;
827 }
828
829 /*
830 ===============
831 IN_ProcessEvents
832 ===============
833 */
IN_ProcessEvents(void)834 static void IN_ProcessEvents( void )
835 {
836 SDL_Event e;
837 const char *character = NULL;
838 keyNum_t key = 0;
839
840 if( !SDL_WasInit( SDL_INIT_VIDEO ) )
841 return;
842
843 if( Key_GetCatcher( ) == 0 && keyRepeatEnabled )
844 {
845 SDL_EnableKeyRepeat( 0, 0 );
846 keyRepeatEnabled = qfalse;
847 }
848 else if( !keyRepeatEnabled )
849 {
850 SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY,
851 SDL_DEFAULT_REPEAT_INTERVAL );
852 keyRepeatEnabled = qtrue;
853 }
854
855 while( SDL_PollEvent( &e ) )
856 {
857 switch( e.type )
858 {
859 case SDL_KEYDOWN:
860 character = IN_TranslateSDLToQ3Key( &e.key.keysym, &key, qtrue );
861 if( key )
862 Com_QueueEvent( 0, SE_KEY, key, qtrue, 0, NULL );
863
864 if( character )
865 Com_QueueEvent( 0, SE_CHAR, *character, 0, 0, NULL );
866 break;
867
868 case SDL_KEYUP:
869 IN_TranslateSDLToQ3Key( &e.key.keysym, &key, qfalse );
870
871 if( key )
872 Com_QueueEvent( 0, SE_KEY, key, qfalse, 0, NULL );
873 break;
874
875 case SDL_MOUSEMOTION:
876 if( mouseActive )
877 Com_QueueEvent( 0, SE_MOUSE, e.motion.xrel, e.motion.yrel, 0, NULL );
878 break;
879
880 case SDL_MOUSEBUTTONDOWN:
881 case SDL_MOUSEBUTTONUP:
882 {
883 unsigned char b;
884 switch( e.button.button )
885 {
886 case 1: b = K_MOUSE1; break;
887 case 2: b = K_MOUSE3; break;
888 case 3: b = K_MOUSE2; break;
889 case 4: b = K_MWHEELUP; break;
890 case 5: b = K_MWHEELDOWN; break;
891 case 6: b = K_MOUSE4; break;
892 case 7: b = K_MOUSE5; break;
893 default: b = K_AUX1 + ( e.button.button - 8 ) % 16; break;
894 }
895 Com_QueueEvent( 0, SE_KEY, b,
896 ( e.type == SDL_MOUSEBUTTONDOWN ? qtrue : qfalse ), 0, NULL );
897 }
898 break;
899
900 case SDL_QUIT:
901 Sys_Quit( );
902 break;
903
904 default:
905 break;
906 }
907 }
908 }
909
910 /*
911 ===============
912 IN_Frame
913 ===============
914 */
IN_Frame(void)915 void IN_Frame( void )
916 {
917 qboolean loading;
918
919 IN_JoyMove( );
920 IN_ProcessEvents( );
921
922 // If not DISCONNECTED (main menu) or ACTIVE (in game), we're loading
923 loading = !!( cls.state != CA_DISCONNECTED && cls.state != CA_ACTIVE );
924
925 if( !r_fullscreen->integer && ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) )
926 {
927 // Console is down in windowed mode
928 IN_DeactivateMouse( );
929 }
930 else if( !r_fullscreen->integer && loading )
931 {
932 // Loading in windowed mode
933 IN_DeactivateMouse( );
934 }
935 else if( !( SDL_GetAppState() & SDL_APPINPUTFOCUS ) )
936 {
937 // Window not got focus
938 IN_DeactivateMouse( );
939 }
940 else
941 IN_ActivateMouse( );
942 }
943
944 /*
945 ===============
946 IN_Init
947 ===============
948 */
IN_Init(void)949 void IN_Init( void )
950 {
951 if( !SDL_WasInit( SDL_INIT_VIDEO ) )
952 {
953 Com_Error( ERR_FATAL, "IN_Init called before SDL_Init( SDL_INIT_VIDEO )\n" );
954 return;
955 }
956
957 Com_DPrintf( "\n------- Input Initialization -------\n" );
958
959 in_keyboardDebug = Cvar_Get( "in_keyboardDebug", "0", CVAR_ARCHIVE );
960
961 // mouse variables
962 in_mouse = Cvar_Get( "in_mouse", "1", CVAR_ARCHIVE );
963 in_nograb = Cvar_Get( "in_nograb", "0", CVAR_ARCHIVE );
964
965 in_joystick = Cvar_Get( "in_joystick", "0", CVAR_ARCHIVE|CVAR_LATCH );
966 in_joystickDebug = Cvar_Get( "in_joystickDebug", "0", CVAR_TEMP );
967 in_joystickThreshold = Cvar_Get( "in_joystickThreshold", "0.15", CVAR_ARCHIVE );
968
969 #ifdef MACOS_X_ACCELERATION_HACK
970 in_disablemacosxmouseaccel = Cvar_Get( "in_disablemacosxmouseaccel", "1", CVAR_ARCHIVE );
971 #endif
972
973 SDL_EnableUNICODE( 1 );
974 SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL );
975 keyRepeatEnabled = qtrue;
976
977 if( in_mouse->value )
978 {
979 mouseAvailable = qtrue;
980 IN_ActivateMouse( );
981 }
982 else
983 {
984 IN_DeactivateMouse( );
985 mouseAvailable = qfalse;
986 }
987
988 IN_InitJoystick( );
989 Com_DPrintf( "------------------------------------\n" );
990 }
991
992 /*
993 ===============
994 IN_Shutdown
995 ===============
996 */
IN_Shutdown(void)997 void IN_Shutdown( void )
998 {
999 IN_DeactivateMouse( );
1000 mouseAvailable = qfalse;
1001
1002 IN_ShutdownJoystick( );
1003 }
1004
1005 /*
1006 ===============
1007 IN_Restart
1008 ===============
1009 */
IN_Restart(void)1010 void IN_Restart( void )
1011 {
1012 IN_ShutdownJoystick( );
1013 IN_Init( );
1014 }
1015