1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 // in_win.c -- windows 95 mouse and joystick code
21 // 02/21/97 JCB Added extended DirectInput code to support external controllers.
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "client/client.h"
28 #include "winquake.h"
29
30 extern unsigned sys_msg_time;
31 extern cursor_t cursor;
32 extern qboolean mouse_available;
33
34 // joystick defines and variables
35 // where should defines be moved?
36 #define JOY_ABSOLUTE_AXIS 0x00000000 // control like a joystick
37 #define JOY_RELATIVE_AXIS 0x00000010 // control like a mouse, spinner, trackball
38 #define JOY_MAX_AXES 6 // X, Y, Z, R, U, V
39 #define JOY_AXIS_X 0
40 #define JOY_AXIS_Y 1
41 #define JOY_AXIS_Z 2
42 #define JOY_AXIS_R 3
43 #define JOY_AXIS_U 4
44 #define JOY_AXIS_V 5
45
46 enum _ControlList
47 {
48 AxisNada = 0, AxisForward, AxisLook, AxisSide, AxisTurn, AxisUp
49 };
50
51 DWORD dwAxisFlags[JOY_MAX_AXES] =
52 {
53 JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ, JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
54 };
55
56 DWORD dwAxisMap[JOY_MAX_AXES];
57 DWORD dwControlMap[JOY_MAX_AXES];
58 PDWORD pdwRawValue[JOY_MAX_AXES];
59
60 cvar_t *in_mouse;
61 cvar_t *in_joystick;
62
63
64 // none of these cvars are saved over a session
65 // this means that advanced controller configuration needs to be executed
66 // each time. this avoids any problems with getting back to a default usage
67 // or when changing from one controller to another. this way at least something
68 // works.
69 cvar_t *joy_name;
70 cvar_t *joy_advanced;
71 cvar_t *joy_advaxisx;
72 cvar_t *joy_advaxisy;
73 cvar_t *joy_advaxisz;
74 cvar_t *joy_advaxisr;
75 cvar_t *joy_advaxisu;
76 cvar_t *joy_advaxisv;
77 cvar_t *joy_forwardthreshold;
78 cvar_t *joy_sidethreshold;
79 cvar_t *joy_pitchthreshold;
80 cvar_t *joy_yawthreshold;
81 cvar_t *joy_forwardsensitivity;
82 cvar_t *joy_sidesensitivity;
83 cvar_t *joy_pitchsensitivity;
84 cvar_t *joy_yawsensitivity;
85 cvar_t *joy_upthreshold;
86 cvar_t *joy_upsensitivity;
87
88 qboolean joy_avail, joy_advancedinit, joy_haspov;
89 DWORD joy_oldbuttonstate, joy_oldpovstate;
90
91 int joy_id;
92 DWORD joy_flags;
93 DWORD joy_numbuttons;
94
95 static JOYINFOEX ji;
96
97 qboolean in_appactive;
98
99 // forward-referenced functions
100 void IN_StartupJoystick (void);
101 void Joy_AdvancedUpdate_f (void);
102 void IN_JoyMove (usercmd_t *cmd);
103
104 /*
105 ============================================================
106
107 MOUSE CONTROL
108
109 ============================================================
110 */
111
112 // mouse variables
113 cvar_t *m_filter;
114 cvar_t *m_accel;
115
116 qboolean mlooking;
117
118 int mouse_buttons;
119 int mouse_oldbuttonstate;
120
121 qboolean restore_spi;
122 qboolean mouseinitialized;
123 int originalmouseparms[3], newmouseparms[3] = {0, 0, 1}, noaccelmouseparms[3] = {0, 0, 0};
124 qboolean mouseparmsvalid;
125
126 int window_center_x, window_center_y;
127 RECT window_rect;
128
129
130 /*
131 ===========
132 IN_ActivateMouse
133
134 Called when the window gains focus or changes in some way
135 ===========
136 */
IN_ActivateMouse(void)137 void IN_ActivateMouse (void)
138 {
139 int width, height;
140
141 if (!mouseinitialized)
142 return;
143 if (!in_mouse->value)
144 {
145 mouse_available = false;
146 return;
147 }
148 if (mouse_available)
149 return;
150
151 mouse_available = true;
152
153 if (mouseparmsvalid) {
154 switch(m_accel->integer) {
155 case 0:
156 restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, noaccelmouseparms, 0);
157 break;
158 case 1:
159 default:
160 restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0);
161 break;
162 }
163 }
164
165 width = GetSystemMetrics (SM_CXSCREEN);
166 height = GetSystemMetrics (SM_CYSCREEN);
167
168 GetWindowRect ( cl_hwnd, &window_rect);
169 if (window_rect.left < 0)
170 window_rect.left = 0;
171 if (window_rect.top < 0)
172 window_rect.top = 0;
173 if (window_rect.right >= width)
174 window_rect.right = width-1;
175 if (window_rect.bottom >= height-1)
176 window_rect.bottom = height-1;
177
178 window_center_x = (window_rect.right + window_rect.left)/2;
179 window_center_y = (window_rect.top + window_rect.bottom)/2;
180
181 SetCursorPos (window_center_x, window_center_y);
182
183 SetCapture ( cl_hwnd );
184 ClipCursor (&window_rect);
185 while (ShowCursor (FALSE) >= 0)
186 ;
187 }
188
189
190 /*
191 ===========
192 IN_DeactivateMouse
193
194 Called when the window loses focus
195 ===========
196 */
IN_DeactivateMouse(void)197 void IN_DeactivateMouse (void)
198 {
199 if (!mouseinitialized)
200 return;
201 if (!mouse_available)
202 return;
203
204 if (restore_spi)
205 SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0);
206
207 mouse_available = false;
208
209 ClipCursor (NULL);
210 ReleaseCapture ();
211 while (ShowCursor (TRUE) < 0)
212 ;
213 }
214
215
216
217 /*
218 ===========
219 IN_StartupMouse
220 ===========
221 */
222 void refreshCursorLink (void);
IN_StartupMouse(void)223 void IN_StartupMouse (void)
224 {
225 cvar_t *cv;
226
227 cv = Cvar_Get ("in_initmouse", "1", CVAR_NOSET);
228 if ( !cv->value )
229 return;
230
231 refreshCursorLink();
232
233 cursor.mouseaction = false;
234
235 mouseinitialized = true;
236 mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0);
237 mouse_buttons = 7; /* TODO: Are 9 possible? Do 7 work now? */
238 }
239
240 /*
241 ===========
242 IN_MouseEvent
243 ===========
244 */
245 void M_Think_MouseCursor (void);
IN_MouseEvent(int mstate)246 void IN_MouseEvent (int mstate)
247 {
248 int i;
249
250 if (!mouseinitialized)
251 return;
252
253 // perform button actions
254 for (i=0 ; i<mouse_buttons ; i++)
255 {
256 if ( (mstate & (1<<i)) &&
257 !(mouse_oldbuttonstate & (1<<i)) )
258 {
259 Key_Event (K_MOUSE1 + i, true, sys_msg_time);
260 }
261
262 if ( !(mstate & (1<<i)) &&
263 (mouse_oldbuttonstate & (1<<i)) )
264 {
265 Key_Event (K_MOUSE1 + i, false, sys_msg_time);
266 }
267 }
268
269 //set menu cursor buttons
270 if (cls.key_dest == key_menu)
271 {
272 int multiclicktime = 750;
273 int max = mouse_buttons;
274 if (max > MENU_CURSOR_BUTTON_MAX) max = MENU_CURSOR_BUTTON_MAX;
275
276 for (i=0 ; i<max ; i++)
277 {
278 if ( (mstate & (1<<i)) && !(mouse_oldbuttonstate & (1<<i)))
279 { //mouse press down
280 if (sys_msg_time-cursor.buttontime[i] < multiclicktime)
281 cursor.buttonclicks[i] += 1;
282 else
283 cursor.buttonclicks[i] = 1;
284
285 if (cursor.buttonclicks[i]>max)
286 cursor.buttonclicks[i] = max;
287
288 cursor.buttontime[i] = sys_msg_time;
289
290 cursor.buttondown[i] = true;
291 cursor.buttonused[i] = false;
292 cursor.mouseaction = true;
293 }
294 else if ( !(mstate & (1<<i)) && (mouse_oldbuttonstate & (1<<i)) )
295 { //mouse let go
296 cursor.buttondown[i] = false;
297 cursor.buttonused[i] = false;
298 }
299 }
300 }
301
302 mouse_oldbuttonstate = mstate;
303 }
304
305
306
307 /*
308 =========================================================================
309
310 VIEW CENTERING
311
312 =========================================================================
313 */
314
315 cvar_t *v_centermove;
316 cvar_t *v_centerspeed;
317
318
319 /*
320 ===========
321 IN_Init
322 ===========
323 */
IN_Init(void)324 void IN_Init (void)
325 {
326 // mouse variables
327 m_filter = Cvar_Get ("m_filter", "0", 0);
328 in_mouse = Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
329
330 // joystick variables
331 in_joystick = Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE);
332 joy_name = Cvar_Get ("joy_name", "joystick", 0);
333 joy_advanced = Cvar_Get ("joy_advanced", "0", 0);
334 joy_advaxisx = Cvar_Get ("joy_advaxisx", "0", 0);
335 joy_advaxisy = Cvar_Get ("joy_advaxisy", "0", 0);
336 joy_advaxisz = Cvar_Get ("joy_advaxisz", "0", 0);
337 joy_advaxisr = Cvar_Get ("joy_advaxisr", "0", 0);
338 joy_advaxisu = Cvar_Get ("joy_advaxisu", "0", 0);
339 joy_advaxisv = Cvar_Get ("joy_advaxisv", "0", 0);
340 joy_forwardthreshold = Cvar_Get ("joy_forwardthreshold", "0.15", 0);
341 joy_sidethreshold = Cvar_Get ("joy_sidethreshold", "0.15", 0);
342 joy_upthreshold = Cvar_Get ("joy_upthreshold", "0.15", 0);
343 joy_pitchthreshold = Cvar_Get ("joy_pitchthreshold", "0.15", 0);
344 joy_yawthreshold = Cvar_Get ("joy_yawthreshold", "0.15", 0);
345 joy_forwardsensitivity = Cvar_Get ("joy_forwardsensitivity", "-1", 0);
346 joy_sidesensitivity = Cvar_Get ("joy_sidesensitivity", "-1", 0);
347 joy_upsensitivity = Cvar_Get ("joy_upsensitivity", "-1", 0);
348 joy_pitchsensitivity = Cvar_Get ("joy_pitchsensitivity", "1", 0);
349 joy_yawsensitivity = Cvar_Get ("joy_yawsensitivity", "-1", 0);
350
351 // centering
352 v_centermove = Cvar_Get ("v_centermove", "0.15", 0);
353 v_centerspeed = Cvar_Get ("v_centerspeed", "500", 0);
354
355 Cmd_AddCommand ("+mlook", IN_MLookDown);
356 Cmd_AddCommand ("-mlook", IN_MLookUp);
357
358 Cmd_AddCommand ("joy_advancedupdate", Joy_AdvancedUpdate_f);
359
360 IN_StartupMouse ();
361 IN_StartupJoystick ();
362 }
363
364 /*
365 ===========
366 IN_Shutdown
367 ===========
368 */
IN_Shutdown(void)369 void IN_Shutdown (void)
370 {
371 IN_DeactivateMouse ();
372 }
373
374
375 /*
376 ===========
377 IN_Activate
378
379 Called when the main window gains or loses focus.
380 The window may have been destroyed and recreated
381 between a deactivate and an activate.
382 ===========
383 */
IN_Activate(qboolean active)384 void IN_Activate (qboolean active)
385 {
386 in_appactive = active;
387 mouse_available = !active; // force a new window check or turn off
388 }
389
390
391 /*
392 ==================
393 IN_Frame
394
395 Called every frame, even if not generating commands
396 ==================
397 */
IN_Frame(void)398 void IN_Frame (void)
399 {
400 if (!mouseinitialized)
401 return;
402
403 if (!in_mouse || !in_appactive)
404 {
405 IN_DeactivateMouse ();
406 return;
407 }
408
409 if ( !cl.refresh_prepped && cls.key_dest != key_menu || cls.key_dest == key_console)
410 {
411 // temporarily deactivate if in fullscreen
412 if (Cvar_VariableValue ("vid_fullscreen") == 0)
413 {
414 IN_DeactivateMouse ();
415 return;
416 }
417 }
418
419 IN_ActivateMouse ();
420 }
421
422
423
424 /*
425 ===================
426 IN_ClearStates
427 ===================
428 */
IN_ClearStates(void)429 void IN_ClearStates (void)
430 {
431 mouse_oldbuttonstate = 0;
432 }
433
434
435 /*
436 =========================================================================
437
438 JOYSTICK
439
440 =========================================================================
441 */
442
443 /*
444 ===============
445 IN_StartupJoystick
446 ===============
447 */
IN_StartupJoystick(void)448 void IN_StartupJoystick (void)
449 {
450 int numdevs;
451 JOYCAPS jc;
452 MMRESULT mmr;
453 cvar_t *cv;
454
455 // assume no joystick
456 joy_avail = false;
457
458 // abort startup if user requests no joystick
459 cv = Cvar_Get ("in_initjoy", "1", CVAR_NOSET);
460 if ( !cv->value )
461 return;
462
463 // verify joystick driver is present
464 if ((numdevs = joyGetNumDevs ()) == 0)
465 {
466 // Com_Printf ("\njoystick not found -- driver not present\n\n");
467 return;
468 }
469
470 // cycle through the joystick ids for the first valid one
471 for (joy_id=0 ; joy_id<numdevs ; joy_id++)
472 {
473 memset (&ji, 0, sizeof(ji));
474 ji.dwSize = sizeof(ji);
475 ji.dwFlags = JOY_RETURNCENTERED;
476
477 if ((mmr = joyGetPosEx (joy_id, &ji)) == JOYERR_NOERROR)
478 break;
479 }
480
481 // abort startup if we didn't find a valid joystick
482 if (mmr != JOYERR_NOERROR)
483 {
484 Com_Printf ("\njoystick not found -- no valid joysticks (%x)\n\n", mmr);
485 return;
486 }
487
488 // get the capabilities of the selected joystick
489 // abort startup if command fails
490 memset (&jc, 0, sizeof(jc));
491 if ((mmr = joyGetDevCaps (joy_id, &jc, sizeof(jc))) != JOYERR_NOERROR)
492 {
493 Com_Printf ("\njoystick not found -- invalid joystick capabilities (%x)\n\n", mmr);
494 return;
495 }
496
497 // save the joystick's number of buttons and POV status
498 joy_numbuttons = jc.wNumButtons;
499 joy_haspov = jc.wCaps & JOYCAPS_HASPOV;
500
501 // old button and POV states default to no buttons pressed
502 joy_oldbuttonstate = joy_oldpovstate = 0;
503
504 // mark the joystick as available and advanced initialization not completed
505 // this is needed as cvars are not available during initialization
506
507 joy_avail = true;
508 joy_advancedinit = false;
509
510 Com_Printf ("\njoystick detected\n\n");
511 }
512
513
514 /*
515 ===========
516 RawValuePointer
517 ===========
518 */
RawValuePointer(int axis)519 PDWORD RawValuePointer (int axis)
520 {
521 switch (axis)
522 {
523 case JOY_AXIS_X:
524 return &ji.dwXpos;
525 case JOY_AXIS_Y:
526 return &ji.dwYpos;
527 case JOY_AXIS_Z:
528 return &ji.dwZpos;
529 case JOY_AXIS_R:
530 return &ji.dwRpos;
531 case JOY_AXIS_U:
532 return &ji.dwUpos;
533 case JOY_AXIS_V:
534 return &ji.dwVpos;
535 }
536
537 return NULL;
538 }
539
540
541 /*
542 ===========
543 Joy_AdvancedUpdate_f
544 ===========
545 */
Joy_AdvancedUpdate_f(void)546 void Joy_AdvancedUpdate_f (void)
547 {
548
549 // called once by IN_ReadJoystick and by user whenever an update is needed
550 // cvars are now available
551 int i;
552 DWORD dwTemp;
553
554 // initialize all the maps
555 for (i = 0; i < JOY_MAX_AXES; i++)
556 {
557 dwAxisMap[i] = AxisNada;
558 dwControlMap[i] = JOY_ABSOLUTE_AXIS;
559 pdwRawValue[i] = RawValuePointer(i);
560 }
561
562 if( joy_advanced->value == 0.0)
563 {
564 // default joystick initialization
565 // 2 axes only with joystick control
566 dwAxisMap[JOY_AXIS_X] = AxisTurn;
567 // dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS;
568 dwAxisMap[JOY_AXIS_Y] = AxisForward;
569 // dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS;
570 }
571 else
572 {
573 if (strcmp (joy_name->string, "joystick") != 0)
574 {
575 // notify user of advanced controller
576 Com_Printf ("\n%s configured\n\n", joy_name->string);
577 }
578
579 // advanced initialization here
580 // data supplied by user via joy_axisn cvars
581 dwTemp = (DWORD) joy_advaxisx->value;
582 dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f;
583 dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS;
584 dwTemp = (DWORD) joy_advaxisy->value;
585 dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f;
586 dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS;
587 dwTemp = (DWORD) joy_advaxisz->value;
588 dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f;
589 dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS;
590 dwTemp = (DWORD) joy_advaxisr->value;
591 dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f;
592 dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS;
593 dwTemp = (DWORD) joy_advaxisu->value;
594 dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f;
595 dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS;
596 dwTemp = (DWORD) joy_advaxisv->value;
597 dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f;
598 dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS;
599 }
600
601 // compute the axes to collect from DirectInput
602 joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV;
603 for (i = 0; i < JOY_MAX_AXES; i++)
604 {
605 if (dwAxisMap[i] != AxisNada)
606 {
607 joy_flags |= dwAxisFlags[i];
608 }
609 }
610 }
611
612
613 /*
614 ===========
615 IN_Commands
616 ===========
617 */
IN_Commands(void)618 void IN_Commands (void)
619 {
620 int i, key_index;
621 DWORD buttonstate, povstate;
622
623 if (!joy_avail)
624 {
625 return;
626 }
627
628
629 // loop through the joystick buttons
630 // key a joystick event or auxillary event for higher number buttons for each state change
631 buttonstate = ji.dwButtons;
632 for (i=0 ; i < joy_numbuttons ; i++)
633 {
634 if ( (buttonstate & (1<<i)) && !(joy_oldbuttonstate & (1<<i)) )
635 {
636 key_index = (i < 4) ? K_JOY1 : K_AUX1;
637 Key_Event (key_index + i, true, 0);
638 }
639
640 if ( !(buttonstate & (1<<i)) && (joy_oldbuttonstate & (1<<i)) )
641 {
642 key_index = (i < 4) ? K_JOY1 : K_AUX1;
643 Key_Event (key_index + i, false, 0);
644 }
645 }
646 joy_oldbuttonstate = buttonstate;
647
648 if (joy_haspov)
649 {
650 // convert POV information into 4 bits of state information
651 // this avoids any potential problems related to moving from one
652 // direction to another without going through the center position
653 povstate = 0;
654 if(ji.dwPOV != JOY_POVCENTERED)
655 {
656 if (ji.dwPOV == JOY_POVFORWARD)
657 povstate |= 0x01;
658 if (ji.dwPOV == JOY_POVRIGHT)
659 povstate |= 0x02;
660 if (ji.dwPOV == JOY_POVBACKWARD)
661 povstate |= 0x04;
662 if (ji.dwPOV == JOY_POVLEFT)
663 povstate |= 0x08;
664 }
665 // determine which bits have changed and key an auxillary event for each change
666 for (i=0 ; i < 4 ; i++)
667 {
668 if ( (povstate & (1<<i)) && !(joy_oldpovstate & (1<<i)) )
669 {
670 Key_Event (K_AUX29 + i, true, 0);
671 }
672
673 if ( !(povstate & (1<<i)) && (joy_oldpovstate & (1<<i)) )
674 {
675 Key_Event (K_AUX29 + i, false, 0);
676 }
677 }
678 joy_oldpovstate = povstate;
679 }
680 }
681
682
683 /*
684 ===============
685 IN_ReadJoystick
686 ===============
687 */
IN_ReadJoystick(void)688 qboolean IN_ReadJoystick (void)
689 {
690
691 memset (&ji, 0, sizeof(ji));
692 ji.dwSize = sizeof(ji);
693 ji.dwFlags = joy_flags;
694
695 if (joyGetPosEx (joy_id, &ji) == JOYERR_NOERROR)
696 {
697 return true;
698 }
699 else
700 {
701 // read error occurred
702 // turning off the joystick seems too harsh for 1 read error,\
703 // but what should be done?
704 // Com_Printf ("IN_ReadJoystick: no response\n");
705 // joy_avail = false;
706 return false;
707 }
708 }
709
710
711 /*
712 ===========
713 IN_JoyMove
714 ===========
715 */
IN_JoyMove(usercmd_t * cmd)716 void IN_JoyMove (usercmd_t *cmd)
717 {
718 float speed, aspeed;
719 float fAxisValue;
720 int i;
721
722 if ( !ActiveApp ) {
723 return;
724 }
725
726 // complete initialization if first time in
727 // this is needed as cvars are not available at initialization time
728 if( joy_advancedinit != true )
729 {
730 Joy_AdvancedUpdate_f();
731 joy_advancedinit = true;
732 }
733
734 // verify joystick is available and that the user wants to use it
735 if (!joy_avail || !in_joystick->value)
736 {
737 return;
738 }
739
740 // collect the joystick data, if possible
741 if (IN_ReadJoystick () != true)
742 {
743 return;
744 }
745
746 if (!cl.tactical && ( (in_speed.state & 1) ^ cl_run->integer))
747 speed = 2;
748 else
749 speed = 1;
750 aspeed = speed * cls.frametime;
751
752 // loop through the axes
753 for (i = 0; i < JOY_MAX_AXES; i++)
754 {
755 // get the floating point zero-centered, potentially-inverted data for the current axis
756 fAxisValue = (float) *pdwRawValue[i];
757 // move centerpoint to zero
758 fAxisValue -= 32768.0;
759
760 // convert range from -32768..32767 to -1..1
761 fAxisValue /= 32768.0;
762
763 switch (dwAxisMap[i])
764 {
765 case AxisForward:
766 if ((joy_advanced->value == 0.0) && mlooking)
767 {
768 // user wants forward control to become look control
769 if (fabs(fAxisValue) > joy_pitchthreshold->value)
770 {
771 // if mouse invert is on, invert the joystick pitch value
772 // only absolute control support here (joy_advanced is false)
773 if (m_pitch->value < 0.0)
774 {
775 cl.viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value;
776 }
777 else
778 {
779 cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value;
780 }
781 }
782 }
783 else
784 {
785 // user wants forward control to be forward control
786 if (fabs(fAxisValue) > joy_forwardthreshold->value)
787 {
788 cmd->forwardmove += (fAxisValue * joy_forwardsensitivity->value) * speed * cl_forwardspeed->value;
789 }
790 }
791 break;
792
793 case AxisSide:
794 if (fabs(fAxisValue) > joy_sidethreshold->value)
795 {
796 cmd->sidemove += (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value;
797 }
798 break;
799
800 case AxisUp:
801 if (fabs(fAxisValue) > joy_upthreshold->value)
802 {
803 cmd->upmove += (fAxisValue * joy_upsensitivity->value) * speed * cl_upspeed->value;
804 }
805 break;
806
807 case AxisTurn:
808 if ((in_strafe.state & 1) || (lookstrafe->value && mlooking))
809 {
810 // user wants turn control to become side control
811 if (fabs(fAxisValue) > joy_sidethreshold->value)
812 {
813 cmd->sidemove -= (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value;
814 }
815 }
816 else
817 {
818 // user wants turn control to be turn control
819 if (fabs(fAxisValue) > joy_yawthreshold->value)
820 {
821 if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
822 {
823 cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * aspeed * cl_yawspeed->value;
824 }
825 else
826 {
827 cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * speed * 180.0;
828 }
829
830 }
831 }
832 break;
833
834 case AxisLook:
835 if (mlooking)
836 {
837 if (fabs(fAxisValue) > joy_pitchthreshold->value)
838 {
839 // pitch movement detected and pitch movement desired by user
840 if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
841 {
842 cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value;
843 }
844 else
845 {
846 cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * speed * 180.0;
847 }
848 }
849 }
850 break;
851
852 default:
853 break;
854 }
855 }
856 }
857
858