From a9ffb0002f00c4461daedc1540faf9df7f865a39 Mon Sep 17 00:00:00 2001 From: Dabb Date: Fri, 29 Dec 2000 20:08:43 +0000 Subject: [PATCH] Joystick code for win32. Mostly contains code moved from in_win.c. NOT FINISHED YET. --- source/joy_win.c | 599 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 599 insertions(+) create mode 100644 source/joy_win.c diff --git a/source/joy_win.c b/source/joy_win.c new file mode 100644 index 0000000..226915e --- /dev/null +++ b/source/joy_win.c @@ -0,0 +1,599 @@ +/* + joy_win.c + + Joystick device driver for Win32 + + Copyright (C) 2000 Jeff Teunissen + Copyright (C) 2000 Jukka Sorjonen + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +// fixme: THIS IS NOT FINISHED YET + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "console.h" +#include "cvar.h" +#include "protocol.h" +#include "qtypes.h" + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#ifdef __MINGW32__ +# define INITGUID +#endif +#include "winquake.h" +#include +#include "client.h" +#include "keys.h" +#include "console.h" +#include "qargs.h" +#include "cmd.h" +#include "input.h" +#include "cl_input.h" +#include "view.h" +//#include "dosisms.h" +#include "host.h" + +// Joystick variables and structures +cvar_t *joy_device; // Joystick device name +cvar_t *joy_enable; // Joystick enabling flag +cvar_t *joy_sensitivity; // Joystick sensitivity + +qboolean joy_found = false; +qboolean joy_active = false; + + +// joystick defines and variables +// where should defines be moved? + +#define JOY_ABSOLUTE_AXIS 0x00000000 // control like a joystick +#define JOY_RELATIVE_AXIS 0x00000010 // control like a mouse, spinner, + // trackball +#define JOY_MAX_AXES 6 // X, Y, Z, R, U, V +#define JOY_AXIS_X 0 +#define JOY_AXIS_Y 1 +#define JOY_AXIS_Z 2 +#define JOY_AXIS_R 3 +#define JOY_AXIS_U 4 +#define JOY_AXIS_V 5 + +enum _ControlList { + AxisNada = 0, AxisForward, AxisLook, AxisSide, AxisTurn +}; + +static DWORD dwAxisFlags[JOY_MAX_AXES] = { + JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ, JOY_RETURNR, JOY_RETURNU, JOY_RETURNV +}; + +static DWORD dwAxisMap[JOY_MAX_AXES]; +static DWORD dwControlMap[JOY_MAX_AXES]; +static PDWORD pdwRawValue[JOY_MAX_AXES]; + +static JOYINFOEX ji; +// none of these cvars are saved over a session +// this means that advanced controller configuration needs to be executed +// each time. this avoids any problems with getting back to a default usage +// or when changing from one controller to another. this way at least something +// works. + +static cvar_t *in_joystick; +static cvar_t *joy_name; +static cvar_t *joy_advanced; +static cvar_t *joy_advaxisx; +static cvar_t *joy_advaxisy; +static cvar_t *joy_advaxisz; +static cvar_t *joy_advaxisr; +static cvar_t *joy_advaxisu; +static cvar_t *joy_advaxisv; +static cvar_t *joy_forwardthreshold; +static cvar_t *joy_sidethreshold; +static cvar_t *joy_pitchthreshold; +static cvar_t *joy_yawthreshold; +static cvar_t *joy_forwardsensitivity; +static cvar_t *joy_sidesensitivity; +static cvar_t *joy_pitchsensitivity; +static cvar_t *joy_yawsensitivity; +static cvar_t *joy_wwhack1; +static cvar_t *joy_wwhack2; + +static qboolean joy_avail, joy_advancedinit, joy_haspov; +static DWORD joy_oldbuttonstate, joy_oldpovstate; +static int joy_id; +static DWORD joy_flags; +static DWORD joy_numbuttons; + +// +// +// +void JOY_AdvancedUpdate_f (void); +void JOY_StartupJoystick (void); +void JOY_Move (usercmd_t *cmd); +void JOY_Init_Cvars(void); +PDWORD RawValuePointer (int axis); + +static qboolean +JOY_Read (void) +{ + memset (&ji, 0, sizeof (ji)); + ji.dwSize = sizeof (ji); + ji.dwFlags = joy_flags; + + if (joyGetPosEx (joy_id, &ji) == JOYERR_NOERROR) { + // HACK HACK HACK -- there's a bug in the Logitech Wingman Warrior's + // DInput driver that causes it to make 32668 the center point + // instead + // of 32768 + if (joy_wwhack1->int_val) { + ji.dwUpos += 100; + } + return true; + } else { // read error + return false; + } +} + +void +JOY_Command (void) +{ + int i, key_index; + DWORD buttonstate, povstate; + + if (!joy_avail) { + return; + } + // loop through the joystick buttons + // key a joystick event or auxillary event for higher number buttons for + // each state change + buttonstate = ji.dwButtons; + for (i = 0; i < joy_numbuttons; i++) { + if ((buttonstate & (1 << i)) && !(joy_oldbuttonstate & (1 << i))) { + key_index = (i < 4) ? K_JOY1 : K_AUX1; + Key_Event (key_index + i, -1, true); + } + + if (!(buttonstate & (1 << i)) && (joy_oldbuttonstate & (1 << i))) { + key_index = (i < 4) ? K_JOY1 : K_AUX1; + Key_Event (key_index + i, -1, false); + } + } + joy_oldbuttonstate = buttonstate; + + if (joy_haspov) { + // convert POV information into 4 bits of state information + // this avoids any potential problems related to moving from one + // direction to another without going through the center position + povstate = 0; + if (ji.dwPOV != JOY_POVCENTERED) { + if (ji.dwPOV == JOY_POVFORWARD) + povstate |= 0x01; + if (ji.dwPOV == JOY_POVRIGHT) + povstate |= 0x02; + if (ji.dwPOV == JOY_POVBACKWARD) + povstate |= 0x04; + if (ji.dwPOV == JOY_POVLEFT) + povstate |= 0x08; + } + // determine which bits have changed and key an auxillary event for + // each change + for (i = 0; i < 4; i++) { + if ((povstate & (1 << i)) && !(joy_oldpovstate & (1 << i))) { + Key_Event (K_AUX29 + i, -1, true); + } + + if (!(povstate & (1 << i)) && (joy_oldpovstate & (1 << i))) { + Key_Event (K_AUX29 + i, -1, false); + } + } + joy_oldpovstate = povstate; + } +} + +void +JOY_Move (usercmd_t *cmd) +{ + float speed, aspeed; + float fAxisValue, fTemp; + int i; + + // complete initialization if first time in + // this is needed as cvars are not available at initialization time + if (!joy_advancedinit) { + JOY_AdvancedUpdate_f (); + joy_advancedinit = true; + } + // verify joystick is available and that the user wants to use it + if (!joy_active || !joy_enable->int_val) { + return; + } + // collect the joystick data, if possible + if (!JOY_Read ()) { + return; + } + + if (in_speed.state & 1) + speed = cl_movespeedkey->value; + else + speed = 1; + aspeed = speed * host_frametime; + + // loop through the axes + for (i = 0; i < JOY_MAX_AXES; i++) { + // get the floating point zero-centered, potentially-inverted data + // for the current axis + fAxisValue = (float) *pdwRawValue[i]; + // move centerpoint to zero + fAxisValue -= 32768.0; + + if (joy_wwhack2->int_val) { + if (dwAxisMap[i] == AxisTurn) { + // this is a special formula for the Logitech WingMan Warrior + // y=ax^b; where a = 300 and b = 1.3 + // also x values are in increments of 800 (so this is + // factored out) + // then bounds check result to level out excessively high + // spin rates + fTemp = 300.0 * pow (abs (fAxisValue) / 800.0, 1.3); + if (fTemp > 14000.0) + fTemp = 14000.0; + // restore direction information + fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp; + } + } + // convert range from -32768..32767 to -1..1 + fAxisValue /= 32768.0; + + switch (dwAxisMap[i]) { + case AxisForward: + if (!joy_advanced->int_val && freelook) { + // user wants forward control to become look control + if (fabs (fAxisValue) > joy_pitchthreshold->value) { + // if mouse invert is on, invert the joystick pitch + // value + // only absolute control support here (joy_advanced + // is false) + if (m_pitch->value < 0.0) { + cl.viewangles[PITCH] -= + (fAxisValue * joy_pitchsensitivity->value) * + aspeed * cl_pitchspeed->value; + } else { + cl.viewangles[PITCH] += + (fAxisValue * joy_pitchsensitivity->value) * + aspeed * cl_pitchspeed->value; + } + V_StopPitchDrift (); + } else { + // no pitch movement + // disable pitch return-to-center unless requested by + // user + // *** this code can be removed when the lookspring + // bug is fixed + // *** the bug always has the lookspring feature on + if (!lookspring->int_val) + V_StopPitchDrift (); + } + } else { + // user wants forward control to be forward control + if (fabs (fAxisValue) > joy_forwardthreshold->value) { + cmd->forwardmove += + (fAxisValue * joy_forwardsensitivity->value) * + speed * cl_forwardspeed->value; + } + } + break; + + case AxisSide: + if (fabs (fAxisValue) > joy_sidethreshold->value) { + cmd->sidemove += + (fAxisValue * joy_sidesensitivity->value) * speed * + cl_sidespeed->value; + } + break; + + case AxisTurn: + if ((in_strafe.state & 1) || (lookstrafe->int_val && freelook)) { + // user wants turn control to become side control + if (fabs (fAxisValue) > joy_sidethreshold->value) { + cmd->sidemove -= + (fAxisValue * joy_sidesensitivity->value) * speed * + cl_sidespeed->value; + } + } else { + // user wants turn control to be turn control + if (fabs (fAxisValue) > joy_yawthreshold->value) { + if (dwControlMap[i] == JOY_ABSOLUTE_AXIS) { + cl.viewangles[YAW] += + (fAxisValue * joy_yawsensitivity->value) * + aspeed * cl_yawspeed->value; + } else { + cl.viewangles[YAW] += + (fAxisValue * joy_yawsensitivity->value) * + speed * 180.0; + } + } + } + break; + + case AxisLook: + if (freelook) { + if (fabs (fAxisValue) > joy_pitchthreshold->value) { + // pitch movement detected and pitch movement desired + // by user + if (dwControlMap[i] == JOY_ABSOLUTE_AXIS) { + cl.viewangles[PITCH] += + (fAxisValue * joy_pitchsensitivity->value) * + aspeed * cl_pitchspeed->value; + } else { + cl.viewangles[PITCH] += + (fAxisValue * joy_pitchsensitivity->value) * + speed * 180.0; + } + V_StopPitchDrift (); + } else { + // no pitch movement + // disable pitch return-to-center unless requested by + // user + // *** this code can be removed when the lookspring + // bug is fixed + // *** the bug always has the lookspring feature on + if (!lookspring->int_val) + V_StopPitchDrift (); + } + } + break; + + default: + break; + } + } + + // bounds check pitch + cl.viewangles[PITCH] = bound (-70, cl.viewangles[PITCH], 80); +} + +void +JOY_Init (void) +{ + Cmd_AddCommand ("joyadvancedupdate", JOY_AdvancedUpdate_f); + JOY_Init_Cvars(); + + Con_DPrintf ("This system does not have joystick support.\n"); +} + +void +JOY_Shutdown (void) +{ + joy_active = false; + joy_found = false; +} + +/* +=========== +Joy_AdvancedUpdate_f +=========== +*/ +void +JOY_AdvancedUpdate_f (void) +{ + // called once by JOY_ReadJoystick and by user whenever an update is + // needed + // cvars are now available + int i; + DWORD dwTemp; + + // initialize all the maps + for (i = 0; i < JOY_MAX_AXES; i++) { + dwAxisMap[i] = AxisNada; + dwControlMap[i] = JOY_ABSOLUTE_AXIS; + pdwRawValue[i] = RawValuePointer (i); + } + + if (joy_advanced->int_val) { + // default joystick initialization + // 2 axes only with joystick control + dwAxisMap[JOY_AXIS_X] = AxisTurn; + // dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS; + dwAxisMap[JOY_AXIS_Y] = AxisForward; + // dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS; + } else { + if (strcmp (joy_name->string, "joystick") != 0) { + // notify user of advanced controller + Con_Printf ("\n%s configured\n\n", joy_name->string); + } + // advanced initialization here + // data supplied by user via joy_axisn cvars + dwTemp = joy_advaxisx->int_val; + dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = joy_advaxisy->int_val; + dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = joy_advaxisz->int_val; + dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = joy_advaxisr->int_val; + dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = joy_advaxisu->int_val; + dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = joy_advaxisv->int_val; + dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS; + } + + // compute the axes to collect from DirectInput + joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV; + for (i = 0; i < JOY_MAX_AXES; i++) { + if (dwAxisMap[i] != AxisNada) { + joy_flags |= dwAxisFlags[i]; + } + } +} + + +/* +=============== +IN_StartupJoystick +=============== +*/ +void +JOY_StartupJoystick (void) +{ + int /* i, */ numdevs; + JOYCAPS jc; + MMRESULT mmr = !JOYERR_NOERROR; + + // assume no joystick + joy_avail = false; + + // abort startup if user requests no joystick + if (COM_CheckParm ("-nojoy")) + return; + + // verify joystick driver is present + if ((numdevs = joyGetNumDevs ()) == 0) { + Con_Printf ("\njoystick not found -- driver not present\n\n"); + return; + } + // cycle through the joystick ids for the first valid one + for (joy_id = 0; joy_id < numdevs; joy_id++) { + memset (&ji, 0, sizeof (ji)); + ji.dwSize = sizeof (ji); + ji.dwFlags = JOY_RETURNCENTERED; + + if ((mmr = joyGetPosEx (joy_id, &ji)) == JOYERR_NOERROR) + break; + } + + // abort startup if we didn't find a valid joystick + if (mmr != JOYERR_NOERROR) { + Con_Printf ("\njoystick not found -- no valid joysticks (%x)\n\n", mmr); + return; + } + // get the capabilities of the selected joystick + // abort startup if command fails + memset (&jc, 0, sizeof (jc)); + if ((mmr = joyGetDevCaps (joy_id, &jc, sizeof (jc))) != JOYERR_NOERROR) { + Con_Printf + ("\njoystick not found -- invalid joystick capabilities (%x)\n\n", + mmr); + return; + } + // save the joystick's number of buttons and POV status + joy_numbuttons = jc.wNumButtons; + joy_haspov = jc.wCaps & JOYCAPS_HASPOV; + + // old button and POV states default to no buttons pressed + joy_oldbuttonstate = joy_oldpovstate = 0; + + // mark the joystick as available and advanced initialization not + // completed + // this is needed as cvars are not available during initialization + + joy_avail = true; + joy_advancedinit = false; + + Con_Printf ("\njoystick detected\n\n"); +} + +/* +=========== +RawValuePointer +=========== +*/ +PDWORD +RawValuePointer (int axis) +{ + switch (axis) { + case JOY_AXIS_X: + return &ji.dwXpos; + case JOY_AXIS_Y: + return &ji.dwYpos; + case JOY_AXIS_Z: + return &ji.dwZpos; + case JOY_AXIS_R: + return &ji.dwRpos; + case JOY_AXIS_U: + return &ji.dwUpos; + case JOY_AXIS_V: + return &ji.dwVpos; + } + return NULL; +} + + +void JOY_Init_Cvars(void) +{ + joy_device = + Cvar_Get ("joy_device", "none", CVAR_NONE | CVAR_ROM, + "Joystick device"); + joy_enable = + Cvar_Get ("joy_enable", "1", CVAR_NONE | CVAR_ARCHIVE, + "Joystick enable flag"); + joy_sensitivity = + Cvar_Get ("joy_sensitivity", "1", CVAR_NONE | CVAR_ARCHIVE, + "Joystick sensitivity"); + + // joystick variables + in_joystick = + Cvar_Get ("joystick", "0", CVAR_ARCHIVE, "None"); + joy_name = + Cvar_Get ("joyname", "joystick", CVAR_NONE, "None"); + joy_advanced = + Cvar_Get ("joyadvanced", "0", CVAR_NONE, "None"); + joy_advaxisx = + Cvar_Get ("joyadvaxisx", "0", CVAR_NONE, "None"); + joy_advaxisy = + Cvar_Get ("joyadvaxisy", "0", CVAR_NONE, "None"); + joy_advaxisz = + Cvar_Get ("joyadvaxisz", "0", CVAR_NONE, "None"); + joy_advaxisr = + Cvar_Get ("joyadvaxisr", "0", CVAR_NONE, "None"); + joy_advaxisu = + Cvar_Get ("joyadvaxisu", "0", CVAR_NONE, "None"); + joy_advaxisv = + Cvar_Get ("joyadvaxisv", "0", CVAR_NONE, "None"); + joy_forwardthreshold = + Cvar_Get ("joyforwardthreshold", "0.15", CVAR_NONE, "None"); + joy_sidethreshold = + Cvar_Get ("joysidethreshold", "0.15", CVAR_NONE, "None"); + joy_pitchthreshold = + Cvar_Get ("joypitchthreshold", "0.15", CVAR_NONE, "None"); + joy_yawthreshold = Cvar_Get ("joyyawthreshold", "0.15", CVAR_NONE, "None"); + joy_forwardsensitivity = + Cvar_Get ("joyforwardsensitivity", "-1.0", CVAR_NONE, "None"); + joy_sidesensitivity = + Cvar_Get ("joysidesensitivity", "-1.0", CVAR_NONE, "None"); + joy_pitchsensitivity = + Cvar_Get ("joypitchsensitivity", "1.0", CVAR_NONE, "None"); + joy_yawsensitivity = + Cvar_Get ("joyyawsensitivity", "-1.0", CVAR_NONE, "None"); + joy_wwhack1 = Cvar_Get ("joywwhack1", "0.0", CVAR_NONE, "None"); + joy_wwhack2 = Cvar_Get ("joywwhack2", "0.0", CVAR_NONE, "None"); + + return; +} +