• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 Copyright (C) 1996-1997 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 <dinput.h>
24 #include "quakedef.h"
25 #include "winquake.h"
26 #include "dosisms.h"
27 
28 #define DINPUT_BUFFERSIZE           16
29 #define iDirectInputCreate(a,b,c,d)	pDirectInputCreate(a,b,c,d)
30 
31 HRESULT (WINAPI *pDirectInputCreate)(HINSTANCE hinst, DWORD dwVersion,
32 	LPDIRECTINPUT * lplpDirectInput, LPUNKNOWN punkOuter);
33 
34 // mouse variables
35 cvar_t	m_filter = {"m_filter","0"};
36 
37 int			mouse_buttons;
38 int			mouse_oldbuttonstate;
39 POINT		current_pos;
40 int			mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum;
41 
42 static qboolean	restore_spi;
43 static int		originalmouseparms[3], newmouseparms[3] = {0, 0, 1};
44 
45 unsigned int uiWheelMessage;
46 qboolean	mouseactive;
47 qboolean		mouseinitialized;
48 static qboolean	mouseparmsvalid, mouseactivatetoggle;
49 static qboolean	mouseshowtoggle = 1;
50 static qboolean	dinput_acquired;
51 
52 static unsigned int		mstate_di;
53 
54 // joystick defines and variables
55 // where should defines be moved?
56 #define JOY_ABSOLUTE_AXIS	0x00000000		// control like a joystick
57 #define JOY_RELATIVE_AXIS	0x00000010		// control like a mouse, spinner, trackball
58 #define	JOY_MAX_AXES		6				// X, Y, Z, R, U, V
59 #define JOY_AXIS_X			0
60 #define JOY_AXIS_Y			1
61 #define JOY_AXIS_Z			2
62 #define JOY_AXIS_R			3
63 #define JOY_AXIS_U			4
64 #define JOY_AXIS_V			5
65 
66 enum _ControlList
67 {
68 	AxisNada = 0, AxisForward, AxisLook, AxisSide, AxisTurn
69 };
70 
71 DWORD	dwAxisFlags[JOY_MAX_AXES] =
72 {
73 	JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ, JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
74 };
75 
76 DWORD	dwAxisMap[JOY_MAX_AXES];
77 DWORD	dwControlMap[JOY_MAX_AXES];
78 PDWORD	pdwRawValue[JOY_MAX_AXES];
79 
80 // none of these cvars are saved over a session
81 // this means that advanced controller configuration needs to be executed
82 // each time.  this avoids any problems with getting back to a default usage
83 // or when changing from one controller to another.  this way at least something
84 // works.
85 cvar_t	in_joystick = {"joystick","0", true};
86 cvar_t	joy_name = {"joyname", "joystick"};
87 cvar_t	joy_advanced = {"joyadvanced", "0"};
88 cvar_t	joy_advaxisx = {"joyadvaxisx", "0"};
89 cvar_t	joy_advaxisy = {"joyadvaxisy", "0"};
90 cvar_t	joy_advaxisz = {"joyadvaxisz", "0"};
91 cvar_t	joy_advaxisr = {"joyadvaxisr", "0"};
92 cvar_t	joy_advaxisu = {"joyadvaxisu", "0"};
93 cvar_t	joy_advaxisv = {"joyadvaxisv", "0"};
94 cvar_t	joy_forwardthreshold = {"joyforwardthreshold", "0.15"};
95 cvar_t	joy_sidethreshold = {"joysidethreshold", "0.15"};
96 cvar_t	joy_pitchthreshold = {"joypitchthreshold", "0.15"};
97 cvar_t	joy_yawthreshold = {"joyyawthreshold", "0.15"};
98 cvar_t	joy_forwardsensitivity = {"joyforwardsensitivity", "-1.0"};
99 cvar_t	joy_sidesensitivity = {"joysidesensitivity", "-1.0"};
100 cvar_t	joy_pitchsensitivity = {"joypitchsensitivity", "1.0"};
101 cvar_t	joy_yawsensitivity = {"joyyawsensitivity", "-1.0"};
102 cvar_t	joy_wwhack1 = {"joywwhack1", "0.0"};
103 cvar_t	joy_wwhack2 = {"joywwhack2", "0.0"};
104 
105 qboolean	joy_avail, joy_advancedinit, joy_haspov;
106 DWORD		joy_oldbuttonstate, joy_oldpovstate;
107 
108 int			joy_id;
109 DWORD		joy_flags;
110 DWORD		joy_numbuttons;
111 
112 static LPDIRECTINPUT		g_pdi;
113 static LPDIRECTINPUTDEVICE	g_pMouse;
114 
115 static JOYINFOEX	ji;
116 
117 static HINSTANCE hInstDI;
118 
119 static qboolean	dinput;
120 
121 typedef struct MYDATA {
122 	LONG  lX;                   // X axis goes here
123 	LONG  lY;                   // Y axis goes here
124 	LONG  lZ;                   // Z axis goes here
125 	BYTE  bButtonA;             // One button goes here
126 	BYTE  bButtonB;             // Another button goes here
127 	BYTE  bButtonC;             // Another button goes here
128 	BYTE  bButtonD;             // Another button goes here
129 } MYDATA;
130 
131 static DIOBJECTDATAFORMAT rgodf[] = {
132   { &GUID_XAxis,    FIELD_OFFSET(MYDATA, lX),       DIDFT_AXIS | DIDFT_ANYINSTANCE,   0,},
133   { &GUID_YAxis,    FIELD_OFFSET(MYDATA, lY),       DIDFT_AXIS | DIDFT_ANYINSTANCE,   0,},
134   { &GUID_ZAxis,    FIELD_OFFSET(MYDATA, lZ),       0x80000000 | DIDFT_AXIS | DIDFT_ANYINSTANCE,   0,},
135   { 0,              FIELD_OFFSET(MYDATA, bButtonA), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
136   { 0,              FIELD_OFFSET(MYDATA, bButtonB), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
137   { 0,              FIELD_OFFSET(MYDATA, bButtonC), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
138   { 0,              FIELD_OFFSET(MYDATA, bButtonD), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
139 };
140 
141 #define NUM_OBJECTS (sizeof(rgodf) / sizeof(rgodf[0]))
142 
143 static DIDATAFORMAT	df = {
144 	sizeof(DIDATAFORMAT),       // this structure
145 	sizeof(DIOBJECTDATAFORMAT), // size of object data format
146 	DIDF_RELAXIS,               // absolute axis coordinates
147 	sizeof(MYDATA),             // device data size
148 	NUM_OBJECTS,                // number of objects
149 	rgodf,                      // and here they are
150 };
151 
152 // forward-referenced functions
153 void IN_StartupJoystick (void);
154 void Joy_AdvancedUpdate_f (void);
155 void IN_JoyMove (usercmd_t *cmd);
156 
157 
158 /*
159 ===========
160 Force_CenterView_f
161 ===========
162 */
Force_CenterView_f(void)163 void Force_CenterView_f (void)
164 {
165 	cl.viewangles[PITCH] = 0;
166 }
167 
168 
169 /*
170 ===========
171 IN_UpdateClipCursor
172 ===========
173 */
IN_UpdateClipCursor(void)174 void IN_UpdateClipCursor (void)
175 {
176 
177 	if (mouseinitialized && mouseactive && !dinput)
178 	{
179 		ClipCursor (&window_rect);
180 	}
181 }
182 
183 
184 /*
185 ===========
186 IN_ShowMouse
187 ===========
188 */
IN_ShowMouse(void)189 void IN_ShowMouse (void)
190 {
191 
192 	if (!mouseshowtoggle)
193 	{
194 		ShowCursor (TRUE);
195 		mouseshowtoggle = 1;
196 	}
197 }
198 
199 
200 /*
201 ===========
202 IN_HideMouse
203 ===========
204 */
IN_HideMouse(void)205 void IN_HideMouse (void)
206 {
207 
208 	if (mouseshowtoggle)
209 	{
210 		ShowCursor (FALSE);
211 		mouseshowtoggle = 0;
212 	}
213 }
214 
215 
216 /*
217 ===========
218 IN_ActivateMouse
219 ===========
220 */
IN_ActivateMouse(void)221 void IN_ActivateMouse (void)
222 {
223 
224 	mouseactivatetoggle = true;
225 
226 	if (mouseinitialized)
227 	{
228 		if (dinput)
229 		{
230 			if (g_pMouse)
231 			{
232 				if (!dinput_acquired)
233 				{
234 					IDirectInputDevice_Acquire(g_pMouse);
235 					dinput_acquired = true;
236 				}
237 			}
238 			else
239 			{
240 				return;
241 			}
242 		}
243 		else
244 		{
245 			if (mouseparmsvalid)
246 				restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0);
247 
248 			SetCursorPos (window_center_x, window_center_y);
249 			SetCapture (mainwindow);
250 			ClipCursor (&window_rect);
251 		}
252 
253 		mouseactive = true;
254 	}
255 }
256 
257 
258 /*
259 ===========
260 IN_SetQuakeMouseState
261 ===========
262 */
IN_SetQuakeMouseState(void)263 void IN_SetQuakeMouseState (void)
264 {
265 	if (mouseactivatetoggle)
266 		IN_ActivateMouse ();
267 }
268 
269 
270 /*
271 ===========
272 IN_DeactivateMouse
273 ===========
274 */
IN_DeactivateMouse(void)275 void IN_DeactivateMouse (void)
276 {
277 
278 	mouseactivatetoggle = false;
279 
280 	if (mouseinitialized)
281 	{
282 		if (dinput)
283 		{
284 			if (g_pMouse)
285 			{
286 				if (dinput_acquired)
287 				{
288 					IDirectInputDevice_Unacquire(g_pMouse);
289 					dinput_acquired = false;
290 				}
291 			}
292 		}
293 		else
294 		{
295 			if (restore_spi)
296 				SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0);
297 
298 			ClipCursor (NULL);
299 			ReleaseCapture ();
300 		}
301 
302 		mouseactive = false;
303 	}
304 }
305 
306 
307 /*
308 ===========
309 IN_RestoreOriginalMouseState
310 ===========
311 */
IN_RestoreOriginalMouseState(void)312 void IN_RestoreOriginalMouseState (void)
313 {
314 	if (mouseactivatetoggle)
315 	{
316 		IN_DeactivateMouse ();
317 		mouseactivatetoggle = true;
318 	}
319 
320 // try to redraw the cursor so it gets reinitialized, because sometimes it
321 // has garbage after the mode switch
322 	ShowCursor (TRUE);
323 	ShowCursor (FALSE);
324 }
325 
326 
327 /*
328 ===========
329 IN_InitDInput
330 ===========
331 */
IN_InitDInput(void)332 qboolean IN_InitDInput (void)
333 {
334     HRESULT		hr;
335 	DIPROPDWORD	dipdw = {
336 		{
337 			sizeof(DIPROPDWORD),        // diph.dwSize
338 			sizeof(DIPROPHEADER),       // diph.dwHeaderSize
339 			0,                          // diph.dwObj
340 			DIPH_DEVICE,                // diph.dwHow
341 		},
342 		DINPUT_BUFFERSIZE,              // dwData
343 	};
344 
345 	if (!hInstDI)
346 	{
347 		hInstDI = LoadLibrary("dinput.dll");
348 
349 		if (hInstDI == NULL)
350 		{
351 			Con_SafePrintf ("Couldn't load dinput.dll\n");
352 			return false;
353 		}
354 	}
355 
356 	if (!pDirectInputCreate)
357 	{
358 		pDirectInputCreate = (void *)GetProcAddress(hInstDI,"DirectInputCreateA");
359 
360 		if (!pDirectInputCreate)
361 		{
362 			Con_SafePrintf ("Couldn't get DI proc addr\n");
363 			return false;
364 		}
365 	}
366 
367 // register with DirectInput and get an IDirectInput to play with.
368 	hr = iDirectInputCreate(global_hInstance, DIRECTINPUT_VERSION, &g_pdi, NULL);
369 
370 	if (FAILED(hr))
371 	{
372 		return false;
373 	}
374 
375 // obtain an interface to the system mouse device.
376 	hr = IDirectInput_CreateDevice(g_pdi, &GUID_SysMouse, &g_pMouse, NULL);
377 
378 	if (FAILED(hr))
379 	{
380 		Con_SafePrintf ("Couldn't open DI mouse device\n");
381 		return false;
382 	}
383 
384 // set the data format to "mouse format".
385 	hr = IDirectInputDevice_SetDataFormat(g_pMouse, &df);
386 
387 	if (FAILED(hr))
388 	{
389 		Con_SafePrintf ("Couldn't set DI mouse format\n");
390 		return false;
391 	}
392 
393 // set the cooperativity level.
394 	hr = IDirectInputDevice_SetCooperativeLevel(g_pMouse, mainwindow,
395 			DISCL_EXCLUSIVE | DISCL_FOREGROUND);
396 
397 	if (FAILED(hr))
398 	{
399 		Con_SafePrintf ("Couldn't set DI coop level\n");
400 		return false;
401 	}
402 
403 
404 // set the buffer size to DINPUT_BUFFERSIZE elements.
405 // the buffer size is a DWORD property associated with the device
406 	hr = IDirectInputDevice_SetProperty(g_pMouse, DIPROP_BUFFERSIZE, &dipdw.diph);
407 
408 	if (FAILED(hr))
409 	{
410 		Con_SafePrintf ("Couldn't set DI buffersize\n");
411 		return false;
412 	}
413 
414 	return true;
415 }
416 
417 
418 /*
419 ===========
420 IN_StartupMouse
421 ===========
422 */
IN_StartupMouse(void)423 void IN_StartupMouse (void)
424 {
425 	HDC			hdc;
426 
427 	if ( COM_CheckParm ("-nomouse") )
428 		return;
429 
430 	mouseinitialized = true;
431 
432 	if (COM_CheckParm ("-dinput"))
433 	{
434 		dinput = IN_InitDInput ();
435 
436 		if (dinput)
437 		{
438 			Con_SafePrintf ("DirectInput initialized\n");
439 		}
440 		else
441 		{
442 			Con_SafePrintf ("DirectInput not initialized\n");
443 		}
444 	}
445 
446 	if (!dinput)
447 	{
448 		mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0);
449 
450 		if (mouseparmsvalid)
451 		{
452 			if ( COM_CheckParm ("-noforcemspd") )
453 				newmouseparms[2] = originalmouseparms[2];
454 
455 			if ( COM_CheckParm ("-noforcemaccel") )
456 			{
457 				newmouseparms[0] = originalmouseparms[0];
458 				newmouseparms[1] = originalmouseparms[1];
459 			}
460 
461 			if ( COM_CheckParm ("-noforcemparms") )
462 			{
463 				newmouseparms[0] = originalmouseparms[0];
464 				newmouseparms[1] = originalmouseparms[1];
465 				newmouseparms[2] = originalmouseparms[2];
466 			}
467 		}
468 	}
469 
470 	mouse_buttons = 3;
471 
472 // if a fullscreen video mode was set before the mouse was initialized,
473 // set the mouse state appropriately
474 	if (mouseactivatetoggle)
475 		IN_ActivateMouse ();
476 }
477 
478 
479 /*
480 ===========
481 IN_Init
482 ===========
483 */
IN_Init(void)484 void IN_Init (void)
485 {
486 	// mouse variables
487 	Cvar_RegisterVariable (&m_filter);
488 
489 	// joystick variables
490 	Cvar_RegisterVariable (&in_joystick);
491 	Cvar_RegisterVariable (&joy_name);
492 	Cvar_RegisterVariable (&joy_advanced);
493 	Cvar_RegisterVariable (&joy_advaxisx);
494 	Cvar_RegisterVariable (&joy_advaxisy);
495 	Cvar_RegisterVariable (&joy_advaxisz);
496 	Cvar_RegisterVariable (&joy_advaxisr);
497 	Cvar_RegisterVariable (&joy_advaxisu);
498 	Cvar_RegisterVariable (&joy_advaxisv);
499 	Cvar_RegisterVariable (&joy_forwardthreshold);
500 	Cvar_RegisterVariable (&joy_sidethreshold);
501 	Cvar_RegisterVariable (&joy_pitchthreshold);
502 	Cvar_RegisterVariable (&joy_yawthreshold);
503 	Cvar_RegisterVariable (&joy_forwardsensitivity);
504 	Cvar_RegisterVariable (&joy_sidesensitivity);
505 	Cvar_RegisterVariable (&joy_pitchsensitivity);
506 	Cvar_RegisterVariable (&joy_yawsensitivity);
507 	Cvar_RegisterVariable (&joy_wwhack1);
508 	Cvar_RegisterVariable (&joy_wwhack2);
509 
510 	Cmd_AddCommand ("force_centerview", Force_CenterView_f);
511 	Cmd_AddCommand ("joyadvancedupdate", Joy_AdvancedUpdate_f);
512 
513 	uiWheelMessage = RegisterWindowMessage ( "MSWHEEL_ROLLMSG" );
514 
515 	IN_StartupMouse ();
516 	IN_StartupJoystick ();
517 }
518 
519 /*
520 ===========
521 IN_Shutdown
522 ===========
523 */
IN_Shutdown(void)524 void IN_Shutdown (void)
525 {
526 
527 	IN_DeactivateMouse ();
528 	IN_ShowMouse ();
529 
530     if (g_pMouse)
531 	{
532 		IDirectInputDevice_Release(g_pMouse);
533 		g_pMouse = NULL;
534 	}
535 
536     if (g_pdi)
537 	{
538 		IDirectInput_Release(g_pdi);
539 		g_pdi = NULL;
540 	}
541 }
542 
543 
544 /*
545 ===========
546 IN_MouseEvent
547 ===========
548 */
IN_MouseEvent(int mstate)549 void IN_MouseEvent (int mstate)
550 {
551 	int	i;
552 
553 	if (mouseactive && !dinput)
554 	{
555 	// perform button actions
556 		for (i=0 ; i<mouse_buttons ; i++)
557 		{
558 			if ( (mstate & (1<<i)) &&
559 				!(mouse_oldbuttonstate & (1<<i)) )
560 			{
561 				Key_Event (K_MOUSE1 + i, true);
562 			}
563 
564 			if ( !(mstate & (1<<i)) &&
565 				(mouse_oldbuttonstate & (1<<i)) )
566 			{
567 				Key_Event (K_MOUSE1 + i, false);
568 			}
569 		}
570 
571 		mouse_oldbuttonstate = mstate;
572 	}
573 }
574 
575 
576 /*
577 ===========
578 IN_MouseMove
579 ===========
580 */
IN_MouseMove(usercmd_t * cmd)581 void IN_MouseMove (usercmd_t *cmd)
582 {
583 	int					mx, my;
584 	HDC					hdc;
585 	int					i;
586 	DIDEVICEOBJECTDATA	od;
587 	DWORD				dwElements;
588 	HRESULT				hr;
589 
590 	if (!mouseactive)
591 		return;
592 
593 	if (dinput)
594 	{
595 		mx = 0;
596 		my = 0;
597 
598 		for (;;)
599 		{
600 			dwElements = 1;
601 
602 			hr = IDirectInputDevice_GetDeviceData(g_pMouse,
603 					sizeof(DIDEVICEOBJECTDATA), &od, &dwElements, 0);
604 
605 			if ((hr == DIERR_INPUTLOST) || (hr == DIERR_NOTACQUIRED))
606 			{
607 				dinput_acquired = true;
608 				IDirectInputDevice_Acquire(g_pMouse);
609 				break;
610 			}
611 
612 			/* Unable to read data or no data available */
613 			if (FAILED(hr) || dwElements == 0)
614 			{
615 				break;
616 			}
617 
618 			/* Look at the element to see what happened */
619 
620 			switch (od.dwOfs)
621 			{
622 				case DIMOFS_X:
623 					mx += od.dwData;
624 					break;
625 
626 				case DIMOFS_Y:
627 					my += od.dwData;
628 					break;
629 
630 				case DIMOFS_BUTTON0:
631 					if (od.dwData & 0x80)
632 						mstate_di |= 1;
633 					else
634 						mstate_di &= ~1;
635 					break;
636 
637 				case DIMOFS_BUTTON1:
638 					if (od.dwData & 0x80)
639 						mstate_di |= (1<<1);
640 					else
641 						mstate_di &= ~(1<<1);
642 					break;
643 
644 				case DIMOFS_BUTTON2:
645 					if (od.dwData & 0x80)
646 						mstate_di |= (1<<2);
647 					else
648 						mstate_di &= ~(1<<2);
649 					break;
650 			}
651 		}
652 
653 	// perform button actions
654 		for (i=0 ; i<mouse_buttons ; i++)
655 		{
656 			if ( (mstate_di & (1<<i)) &&
657 				!(mouse_oldbuttonstate & (1<<i)) )
658 			{
659 				Key_Event (K_MOUSE1 + i, true);
660 			}
661 
662 			if ( !(mstate_di & (1<<i)) &&
663 				(mouse_oldbuttonstate & (1<<i)) )
664 			{
665 				Key_Event (K_MOUSE1 + i, false);
666 			}
667 		}
668 
669 		mouse_oldbuttonstate = mstate_di;
670 	}
671 	else
672 	{
673 		GetCursorPos (&current_pos);
674 		mx = current_pos.x - window_center_x + mx_accum;
675 		my = current_pos.y - window_center_y + my_accum;
676 		mx_accum = 0;
677 		my_accum = 0;
678 	}
679 
680 //if (mx ||  my)
681 //	Con_DPrintf("mx=%d, my=%d\n", mx, my);
682 
683 	if (m_filter.value)
684 	{
685 		mouse_x = (mx + old_mouse_x) * 0.5;
686 		mouse_y = (my + old_mouse_y) * 0.5;
687 	}
688 	else
689 	{
690 		mouse_x = mx;
691 		mouse_y = my;
692 	}
693 
694 	old_mouse_x = mx;
695 	old_mouse_y = my;
696 
697 	mouse_x *= sensitivity.value;
698 	mouse_y *= sensitivity.value;
699 
700 // add mouse X/Y movement to cmd
701 	if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
702 		cmd->sidemove += m_side.value * mouse_x;
703 	else
704 		cl.viewangles[YAW] -= m_yaw.value * mouse_x;
705 
706 	if (in_mlook.state & 1)
707 		V_StopPitchDrift ();
708 
709 	if ( (in_mlook.state & 1) && !(in_strafe.state & 1))
710 	{
711 		cl.viewangles[PITCH] += m_pitch.value * mouse_y;
712 		if (cl.viewangles[PITCH] > 80)
713 			cl.viewangles[PITCH] = 80;
714 		if (cl.viewangles[PITCH] < -70)
715 			cl.viewangles[PITCH] = -70;
716 	}
717 	else
718 	{
719 		if ((in_strafe.state & 1) && noclip_anglehack)
720 			cmd->upmove -= m_forward.value * mouse_y;
721 		else
722 			cmd->forwardmove -= m_forward.value * mouse_y;
723 	}
724 
725 // if the mouse has moved, force it to the center, so there's room to move
726 	if (mx || my)
727 	{
728 		SetCursorPos (window_center_x, window_center_y);
729 	}
730 }
731 
732 
733 /*
734 ===========
735 IN_Move
736 ===========
737 */
IN_Move(usercmd_t * cmd)738 void IN_Move (usercmd_t *cmd)
739 {
740 
741 	if (ActiveApp && !Minimized)
742 	{
743 		IN_MouseMove (cmd);
744 		IN_JoyMove (cmd);
745 	}
746 }
747 
748 
749 /*
750 ===========
751 IN_Accumulate
752 ===========
753 */
IN_Accumulate(void)754 void IN_Accumulate (void)
755 {
756 	int		mx, my;
757 	HDC	hdc;
758 
759 	if (mouseactive)
760 	{
761 		if (!dinput)
762 		{
763 			GetCursorPos (&current_pos);
764 
765 			mx_accum += current_pos.x - window_center_x;
766 			my_accum += current_pos.y - window_center_y;
767 
768 		// force the mouse to the center, so there's room to move
769 			SetCursorPos (window_center_x, window_center_y);
770 		}
771 	}
772 }
773 
774 
775 /*
776 ===================
777 IN_ClearStates
778 ===================
779 */
IN_ClearStates(void)780 void IN_ClearStates (void)
781 {
782 
783 	if (mouseactive)
784 	{
785 		mx_accum = 0;
786 		my_accum = 0;
787 		mouse_oldbuttonstate = 0;
788 	}
789 }
790 
791 
792 /*
793 ===============
794 IN_StartupJoystick
795 ===============
796 */
IN_StartupJoystick(void)797 void IN_StartupJoystick (void)
798 {
799 	int			i, numdevs;
800 	JOYCAPS		jc;
801 	MMRESULT	mmr;
802 
803  	// assume no joystick
804 	joy_avail = false;
805 
806 	// abort startup if user requests no joystick
807 	if ( COM_CheckParm ("-nojoy") )
808 		return;
809 
810 	// verify joystick driver is present
811 	if ((numdevs = joyGetNumDevs ()) == 0)
812 	{
813 		Con_Printf ("\njoystick not found -- driver not present\n\n");
814 		return;
815 	}
816 
817 	// cycle through the joystick ids for the first valid one
818 	for (joy_id=0 ; joy_id<numdevs ; joy_id++)
819 	{
820 		memset (&ji, 0, sizeof(ji));
821 		ji.dwSize = sizeof(ji);
822 		ji.dwFlags = JOY_RETURNCENTERED;
823 
824 		if ((mmr = joyGetPosEx (joy_id, &ji)) == JOYERR_NOERROR)
825 			break;
826 	}
827 
828 	// abort startup if we didn't find a valid joystick
829 	if (mmr != JOYERR_NOERROR)
830 	{
831 		Con_Printf ("\njoystick not found -- no valid joysticks (%x)\n\n", mmr);
832 		return;
833 	}
834 
835 	// get the capabilities of the selected joystick
836 	// abort startup if command fails
837 	memset (&jc, 0, sizeof(jc));
838 	if ((mmr = joyGetDevCaps (joy_id, &jc, sizeof(jc))) != JOYERR_NOERROR)
839 	{
840 		Con_Printf ("\njoystick not found -- invalid joystick capabilities (%x)\n\n", mmr);
841 		return;
842 	}
843 
844 	// save the joystick's number of buttons and POV status
845 	joy_numbuttons = jc.wNumButtons;
846 	joy_haspov = jc.wCaps & JOYCAPS_HASPOV;
847 
848 	// old button and POV states default to no buttons pressed
849 	joy_oldbuttonstate = joy_oldpovstate = 0;
850 
851 	// mark the joystick as available and advanced initialization not completed
852 	// this is needed as cvars are not available during initialization
853 
854 	joy_avail = true;
855 	joy_advancedinit = false;
856 
857 	Con_Printf ("\njoystick detected\n\n");
858 }
859 
860 
861 /*
862 ===========
863 RawValuePointer
864 ===========
865 */
RawValuePointer(int axis)866 PDWORD RawValuePointer (int axis)
867 {
868 	switch (axis)
869 	{
870 	case JOY_AXIS_X:
871 		return &ji.dwXpos;
872 	case JOY_AXIS_Y:
873 		return &ji.dwYpos;
874 	case JOY_AXIS_Z:
875 		return &ji.dwZpos;
876 	case JOY_AXIS_R:
877 		return &ji.dwRpos;
878 	case JOY_AXIS_U:
879 		return &ji.dwUpos;
880 	case JOY_AXIS_V:
881 		return &ji.dwVpos;
882 	}
883 }
884 
885 
886 /*
887 ===========
888 Joy_AdvancedUpdate_f
889 ===========
890 */
Joy_AdvancedUpdate_f(void)891 void Joy_AdvancedUpdate_f (void)
892 {
893 
894 	// called once by IN_ReadJoystick and by user whenever an update is needed
895 	// cvars are now available
896 	int	i;
897 	DWORD dwTemp;
898 
899 	// initialize all the maps
900 	for (i = 0; i < JOY_MAX_AXES; i++)
901 	{
902 		dwAxisMap[i] = AxisNada;
903 		dwControlMap[i] = JOY_ABSOLUTE_AXIS;
904 		pdwRawValue[i] = RawValuePointer(i);
905 	}
906 
907 	if( joy_advanced.value == 0.0)
908 	{
909 		// default joystick initialization
910 		// 2 axes only with joystick control
911 		dwAxisMap[JOY_AXIS_X] = AxisTurn;
912 		// dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS;
913 		dwAxisMap[JOY_AXIS_Y] = AxisForward;
914 		// dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS;
915 	}
916 	else
917 	{
918 		if (Q_strcmp (joy_name.string, "joystick") != 0)
919 		{
920 			// notify user of advanced controller
921 			Con_Printf ("\n%s configured\n\n", joy_name.string);
922 		}
923 
924 		// advanced initialization here
925 		// data supplied by user via joy_axisn cvars
926 		dwTemp = (DWORD) joy_advaxisx.value;
927 		dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f;
928 		dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS;
929 		dwTemp = (DWORD) joy_advaxisy.value;
930 		dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f;
931 		dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS;
932 		dwTemp = (DWORD) joy_advaxisz.value;
933 		dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f;
934 		dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS;
935 		dwTemp = (DWORD) joy_advaxisr.value;
936 		dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f;
937 		dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS;
938 		dwTemp = (DWORD) joy_advaxisu.value;
939 		dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f;
940 		dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS;
941 		dwTemp = (DWORD) joy_advaxisv.value;
942 		dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f;
943 		dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS;
944 	}
945 
946 	// compute the axes to collect from DirectInput
947 	joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV;
948 	for (i = 0; i < JOY_MAX_AXES; i++)
949 	{
950 		if (dwAxisMap[i] != AxisNada)
951 		{
952 			joy_flags |= dwAxisFlags[i];
953 		}
954 	}
955 }
956 
957 
958 /*
959 ===========
960 IN_Commands
961 ===========
962 */
IN_Commands(void)963 void IN_Commands (void)
964 {
965 	int		i, key_index;
966 	DWORD	buttonstate, povstate;
967 
968 	if (!joy_avail)
969 	{
970 		return;
971 	}
972 
973 
974 	// loop through the joystick buttons
975 	// key a joystick event or auxillary event for higher number buttons for each state change
976 	buttonstate = ji.dwButtons;
977 	for (i=0 ; i < joy_numbuttons ; i++)
978 	{
979 		if ( (buttonstate & (1<<i)) && !(joy_oldbuttonstate & (1<<i)) )
980 		{
981 			key_index = (i < 4) ? K_JOY1 : K_AUX1;
982 			Key_Event (key_index + i, true);
983 		}
984 
985 		if ( !(buttonstate & (1<<i)) && (joy_oldbuttonstate & (1<<i)) )
986 		{
987 			key_index = (i < 4) ? K_JOY1 : K_AUX1;
988 			Key_Event (key_index + i, false);
989 		}
990 	}
991 	joy_oldbuttonstate = buttonstate;
992 
993 	if (joy_haspov)
994 	{
995 		// convert POV information into 4 bits of state information
996 		// this avoids any potential problems related to moving from one
997 		// direction to another without going through the center position
998 		povstate = 0;
999 		if(ji.dwPOV != JOY_POVCENTERED)
1000 		{
1001 			if (ji.dwPOV == JOY_POVFORWARD)
1002 				povstate |= 0x01;
1003 			if (ji.dwPOV == JOY_POVRIGHT)
1004 				povstate |= 0x02;
1005 			if (ji.dwPOV == JOY_POVBACKWARD)
1006 				povstate |= 0x04;
1007 			if (ji.dwPOV == JOY_POVLEFT)
1008 				povstate |= 0x08;
1009 		}
1010 		// determine which bits have changed and key an auxillary event for each change
1011 		for (i=0 ; i < 4 ; i++)
1012 		{
1013 			if ( (povstate & (1<<i)) && !(joy_oldpovstate & (1<<i)) )
1014 			{
1015 				Key_Event (K_AUX29 + i, true);
1016 			}
1017 
1018 			if ( !(povstate & (1<<i)) && (joy_oldpovstate & (1<<i)) )
1019 			{
1020 				Key_Event (K_AUX29 + i, false);
1021 			}
1022 		}
1023 		joy_oldpovstate = povstate;
1024 	}
1025 }
1026 
1027 
1028 /*
1029 ===============
1030 IN_ReadJoystick
1031 ===============
1032 */
IN_ReadJoystick(void)1033 qboolean IN_ReadJoystick (void)
1034 {
1035 
1036 	memset (&ji, 0, sizeof(ji));
1037 	ji.dwSize = sizeof(ji);
1038 	ji.dwFlags = joy_flags;
1039 
1040 	if (joyGetPosEx (joy_id, &ji) == JOYERR_NOERROR)
1041 	{
1042 		// this is a hack -- there is a bug in the Logitech WingMan Warrior DirectInput Driver
1043 		// rather than having 32768 be the zero point, they have the zero point at 32668
1044 		// go figure -- anyway, now we get the full resolution out of the device
1045 		if (joy_wwhack1.value != 0.0)
1046 		{
1047 			ji.dwUpos += 100;
1048 		}
1049 		return true;
1050 	}
1051 	else
1052 	{
1053 		// read error occurred
1054 		// turning off the joystick seems too harsh for 1 read error,\
1055 		// but what should be done?
1056 		// Con_Printf ("IN_ReadJoystick: no response\n");
1057 		// joy_avail = false;
1058 		return false;
1059 	}
1060 }
1061 
1062 
1063 /*
1064 ===========
1065 IN_JoyMove
1066 ===========
1067 */
IN_JoyMove(usercmd_t * cmd)1068 void IN_JoyMove (usercmd_t *cmd)
1069 {
1070 	float	speed, aspeed;
1071 	float	fAxisValue, fTemp;
1072 	int		i;
1073 
1074 	// complete initialization if first time in
1075 	// this is needed as cvars are not available at initialization time
1076 	if( joy_advancedinit != true )
1077 	{
1078 		Joy_AdvancedUpdate_f();
1079 		joy_advancedinit = true;
1080 	}
1081 
1082 	// verify joystick is available and that the user wants to use it
1083 	if (!joy_avail || !in_joystick.value)
1084 	{
1085 		return;
1086 	}
1087 
1088 	// collect the joystick data, if possible
1089 	if (IN_ReadJoystick () != true)
1090 	{
1091 		return;
1092 	}
1093 
1094 	if (in_speed.state & 1)
1095 		speed = cl_movespeedkey.value;
1096 	else
1097 		speed = 1;
1098 	aspeed = speed * host_frametime;
1099 
1100 	// loop through the axes
1101 	for (i = 0; i < JOY_MAX_AXES; i++)
1102 	{
1103 		// get the floating point zero-centered, potentially-inverted data for the current axis
1104 		fAxisValue = (float) *pdwRawValue[i];
1105 		// move centerpoint to zero
1106 		fAxisValue -= 32768.0;
1107 
1108 		if (joy_wwhack2.value != 0.0)
1109 		{
1110 			if (dwAxisMap[i] == AxisTurn)
1111 			{
1112 				// this is a special formula for the Logitech WingMan Warrior
1113 				// y=ax^b; where a = 300 and b = 1.3
1114 				// also x values are in increments of 800 (so this is factored out)
1115 				// then bounds check result to level out excessively high spin rates
1116 				fTemp = 300.0 * pow(abs(fAxisValue) / 800.0, 1.3);
1117 				if (fTemp > 14000.0)
1118 					fTemp = 14000.0;
1119 				// restore direction information
1120 				fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp;
1121 			}
1122 		}
1123 
1124 		// convert range from -32768..32767 to -1..1
1125 		fAxisValue /= 32768.0;
1126 
1127 		switch (dwAxisMap[i])
1128 		{
1129 		case AxisForward:
1130 			if ((joy_advanced.value == 0.0) && (in_mlook.state & 1))
1131 			{
1132 				// user wants forward control to become look control
1133 				if (fabs(fAxisValue) > joy_pitchthreshold.value)
1134 				{
1135 					// if mouse invert is on, invert the joystick pitch value
1136 					// only absolute control support here (joy_advanced is false)
1137 					if (m_pitch.value < 0.0)
1138 					{
1139 						cl.viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value;
1140 					}
1141 					else
1142 					{
1143 						cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value;
1144 					}
1145 					V_StopPitchDrift();
1146 				}
1147 				else
1148 				{
1149 					// no pitch movement
1150 					// disable pitch return-to-center unless requested by user
1151 					// *** this code can be removed when the lookspring bug is fixed
1152 					// *** the bug always has the lookspring feature on
1153 					if(lookspring.value == 0.0)
1154 						V_StopPitchDrift();
1155 				}
1156 			}
1157 			else
1158 			{
1159 				// user wants forward control to be forward control
1160 				if (fabs(fAxisValue) > joy_forwardthreshold.value)
1161 				{
1162 					cmd->forwardmove += (fAxisValue * joy_forwardsensitivity.value) * speed * cl_forwardspeed.value;
1163 				}
1164 			}
1165 			break;
1166 
1167 		case AxisSide:
1168 			if (fabs(fAxisValue) > joy_sidethreshold.value)
1169 			{
1170 				cmd->sidemove += (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value;
1171 			}
1172 			break;
1173 
1174 		case AxisTurn:
1175 			if ((in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1)))
1176 			{
1177 				// user wants turn control to become side control
1178 				if (fabs(fAxisValue) > joy_sidethreshold.value)
1179 				{
1180 					cmd->sidemove -= (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value;
1181 				}
1182 			}
1183 			else
1184 			{
1185 				// user wants turn control to be turn control
1186 				if (fabs(fAxisValue) > joy_yawthreshold.value)
1187 				{
1188 					if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
1189 					{
1190 						cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity.value) * aspeed * cl_yawspeed.value;
1191 					}
1192 					else
1193 					{
1194 						cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity.value) * speed * 180.0;
1195 					}
1196 
1197 				}
1198 			}
1199 			break;
1200 
1201 		case AxisLook:
1202 			if (in_mlook.state & 1)
1203 			{
1204 				if (fabs(fAxisValue) > joy_pitchthreshold.value)
1205 				{
1206 					// pitch movement detected and pitch movement desired by user
1207 					if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
1208 					{
1209 						cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value;
1210 					}
1211 					else
1212 					{
1213 						cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * speed * 180.0;
1214 					}
1215 					V_StopPitchDrift();
1216 				}
1217 				else
1218 				{
1219 					// no pitch movement
1220 					// disable pitch return-to-center unless requested by user
1221 					// *** this code can be removed when the lookspring bug is fixed
1222 					// *** the bug always has the lookspring feature on
1223 					if(lookspring.value == 0.0)
1224 						V_StopPitchDrift();
1225 				}
1226 			}
1227 			break;
1228 
1229 		default:
1230 			break;
1231 		}
1232 	}
1233 
1234 	// bounds check pitch
1235 	if (cl.viewangles[PITCH] > 80.0)
1236 		cl.viewangles[PITCH] = 80.0;
1237 	if (cl.viewangles[PITCH] < -70.0)
1238 		cl.viewangles[PITCH] = -70.0;
1239 }
1240