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