diff --git a/src/d_netcmd.c b/src/d_netcmd.c index dea647a00..056bb721a 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -244,7 +244,7 @@ static CV_PossibleValue_t joyport_cons_t[] = {{1, "/dev/js0"}, {2, "/dev/js1"}, {4, "/dev/js3"}, {0, NULL}}; #else // accept whatever value - it is in fact the joystick device number -static CV_PossibleValue_t usejoystick_cons_t[] = {{-1, "MIN"}, {MAXGAMEPADS, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t usejoystick_cons_t[] = {{0, "MIN"}, {MAXGAMEPADS, "MAX"}, {0, NULL}}; #endif static CV_PossibleValue_t teamscramble_cons_t[] = {{0, "Off"}, {1, "Random"}, {2, "Points"}, {0, NULL}}; @@ -329,10 +329,10 @@ consvar_t cv_usemouse = CVAR_INIT ("use_mouse", "Off", CV_SAVE|CV_CALL,usemouse_ consvar_t cv_laglesscam = CVAR_INIT ("laglesscamera", "Off", CV_SAVE,CV_OnOff, NULL); consvar_t cv_usejoystick[MAXSPLITSCREENPLAYERS] = { - CVAR_INIT ("use_device", "1", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick1), - CVAR_INIT ("use_device2", "2", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick2), - CVAR_INIT ("use_device3", "3", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick3), - CVAR_INIT ("use_device4", "4", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick4) + CVAR_INIT ("use_joystick", "1", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick1), + CVAR_INIT ("use_joystick2", "2", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick2), + CVAR_INIT ("use_joystick3", "3", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick3), + CVAR_INIT ("use_joystick4", "4", CV_SAVE|CV_CALL, usejoystick_cons_t, I_InitJoystick4) }; #if (defined (LJOYSTICK) || defined (HAVE_SDL)) diff --git a/src/g_game.c b/src/g_game.c index 3efdfe0ff..fca617a10 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -763,6 +763,12 @@ INT16 G_SoftwareClipAimingPitch(INT32 *aiming) return (INT16)((*aiming)>>16); } +// returns true if event's axis is within the deadzone for the given player +boolean G_AxisInDeadzone(UINT8 p, event_t *ev) +{ + return abs(ev->data2) <= (JOYAXISRANGE * cv_deadzone[p].value) / FRACUNIT; +} + // check if the given key is bound to the given gamecontrol // if menu is true, also check defaults if the gamecontrol has no binds boolean G_ControlBoundToKey(UINT8 p, INT32 gc, INT32 key, boolean menu) @@ -770,10 +776,13 @@ boolean G_ControlBoundToKey(UINT8 p, INT32 gc, INT32 key, boolean menu) INT32 i; INT32 (*map)[MAXINPUTMAPPING] = &gamecontrol[p][gc]; + if (key <= 0 || key >= NUMINPUTS) + return false; + if (menu) { for (i = 0; i < MAXINPUTMAPPING; i++) - if ((*map)[i]) + if (G_KeyIsAvailable((*map)[i], cv_usejoystick[p].value)) goto bound; map = &gamecontroldefault[gc]; } @@ -831,7 +840,7 @@ retrygetcontrol: } // If you're on controller, try your keyboard-based binds as an immediate backup. - if (p == 0 && deviceID > 0 && !tryingotherID) + if (deviceID > 0 && !tryingotherID) { deviceID = 0; goto retrygetcontrol; diff --git a/src/g_game.h b/src/g_game.h index 8a1d982e6..fa137f136 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -123,6 +123,7 @@ extern INT32 localaiming[MAXSPLITSCREENPLAYERS]; // should be an angle_t but sig INT32 G_PlayerInputAnalog(UINT8 p, INT32 gc, boolean menu); boolean G_PlayerInputDown(UINT8 p, INT32 gc, boolean menu); boolean G_ControlBoundToKey(UINT8 p, INT32 gc, INT32 key, boolean menu); +boolean G_AxisInDeadzone(UINT8 p, event_t *ev); // // GAME diff --git a/src/g_input.c b/src/g_input.c index d64791758..9eea3eff7 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -81,6 +81,12 @@ INT32 G_GetDevicePlayer(INT32 deviceID) return -1; } +// converts ev_joystick axis to its corresponding key +INT32 G_AxisToKey(event_t *ev) +{ + return KEY_AXIS1 + ev->data1*2 + (ev->data2 >= 0); +} + // // Remaps the inputs to game controls. // @@ -191,7 +197,7 @@ void G_MapEventsToControls(event_t *ev) i = ev->data1 * 2; - if (ev->device == 0) + if (G_GetDevicePlayer(ev->device) == 0) { if (CON_Ready() || chat_on) break; @@ -446,6 +452,12 @@ boolean G_KeyIsAvailable(INT32 key, INT32 deviceID) return false; } + // Valid keyboard-specific virtual key, but no keyboard attached for player. + if (key < NUMKEYS && deviceID > 0) + { + return false; + } + // Valid controller-specific virtual key, but no controller attached for player. if (key >= KEY_JOY1 && key < JOYINPUTEND && deviceID <= 0) { diff --git a/src/g_input.h b/src/g_input.h index f24ba4871..d32e5adac 100644 --- a/src/g_input.h +++ b/src/g_input.h @@ -121,6 +121,8 @@ extern const INT32 gcl_full[num_gcl_full]; INT32 G_GetDevicePlayer(INT32 deviceID); +INT32 G_AxisToKey(event_t *ev); + // remaps the input event to a game control. void G_MapEventsToControls(event_t *ev); diff --git a/src/m_menu.c b/src/m_menu.c index e0944a5e7..8791ebfc9 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2479,6 +2479,7 @@ boolean M_Responder(event_t *ev) static INT32 pmousex = 0, pmousey = 0; static INT32 lastx = 0, lasty = 0; void (*routine)(INT32 choice); // for some casting problem + INT32 deviceplayer = G_GetDevicePlayer(ev->device); if (dedicated || (demo.playback && demo.title) || gamestate == GS_INTRO || gamestate == GS_CUTSCENE || gamestate == GS_GAMEEND @@ -2526,15 +2527,14 @@ boolean M_Responder(event_t *ev) } else if (menuactive) { - if (ev->type == ev_joystick && ev->device == 0) + if (ev->type == ev_joystick && deviceplayer == 0) { - const INT32 jdeadzone = (JOYAXISRANGE * cv_deadzone[0].value) / FRACUNIT; static INT32 lastjoy[JOYAXISSET*2] = {0}; - if (abs(ev->data2) <= jdeadzone) + if (G_AxisInDeadzone(deviceplayer, ev)) { lastjoy[ev->data1] = 0; - return true; + return false; } tic_t thistime = I_GetTime(); @@ -2542,7 +2542,7 @@ boolean M_Responder(event_t *ev) // no previous direction OR change direction if (joywait < thistime && (lastjoy[ev->data1] == 0 || (ev->data2 < 0) != (lastjoy[ev->data1] < 0))) { - ch = KEY_AXIS1 + ev->data1*2 + (ev->data2 >= 0); + ch = G_AxisToKey(ev); joywait = thistime + NEWTICRATE/7; } else @@ -2550,6 +2550,14 @@ boolean M_Responder(event_t *ev) lastjoy[ev->data1] = ev->data2; } + // pass through other joysticks + else if (ev->type == ev_joystick) + { + if (!G_AxisInDeadzone(deviceplayer, ev)) + ch = 0; + else + return false; + } else if (ev->type == ev_mouse && mousewait < I_GetTime()) { pmousey += ev->data3; @@ -2583,16 +2591,16 @@ boolean M_Responder(event_t *ev) } // remap to keyboard keys if needed - if (ch >= KEY_JOY1) + if (deviceplayer == 0 && ch >= KEY_JOY1) { static INT32 joyremap[][2] = { + { gc_accelerate, KEY_ENTER }, // these two first + { gc_brake, KEY_ESCAPE }, // in case of conflicts { gc_systemmenu, KEY_ESCAPE }, { gc_aimforward, KEY_UPARROW }, { gc_aimbackward, KEY_DOWNARROW }, { gc_turnleft, KEY_LEFTARROW }, { gc_turnright, KEY_RIGHTARROW }, - { gc_brake, KEY_ESCAPE }, - { gc_accelerate, KEY_ENTER }, }; for (size_t r = 0; r < sizeof(joyremap)/sizeof(*joyremap); r++) @@ -10675,7 +10683,12 @@ static void M_ChangecontrolResponse(event_t *ev) INT32 ch = ev->data1; if (ev->type == ev_joystick) - ch = ev->data1*2 + KEY_AXIS1 + (ev->data2 > 0); + { + if (!G_AxisInDeadzone(setupcontrolplayer-1, ev)) + ch = G_AxisToKey(ev); + else + return; + } // ESCAPE cancels; dummy out PAUSE if (ch != KEY_ESCAPE && ch != KEY_PAUSE)