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