diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index c60b874f9..5485cb2c4 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -113,6 +113,34 @@ SDL_JoystickNameForIndex(int device_index) return (SDL_SYS_JoystickNameForDeviceIndex(device_index)); } +/* + * Return true if this joystick is known to have all axes centered at zero + * This isn't generally needed unless the joystick never generates an initial axis value near zero, + * e.g. it's emulating axes with digital buttons + */ +static SDL_bool +SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick) +{ + struct { + Uint16 vendor; + Uint16 product; + } zero_centered_joysticks[] = { + { 0x0e8f, 0x3013 }, /* Unknown Super NES USB adapter */ + }; + + int i; + Uint16 vendor = SDL_JoystickGetVendor(joystick); + Uint16 product = SDL_JoystickGetProduct(joystick); + + for (i = 0; i < SDL_arraysize(zero_centered_joysticks); ++i) { + if (vendor == zero_centered_joysticks[i].vendor && + product == zero_centered_joysticks[i].product) { + return SDL_TRUE; + } + } + return SDL_FALSE; +} + /* * Open a joystick for use - the index passed as an argument refers to * the N'th joystick on the system. This index is the value which will @@ -192,6 +220,15 @@ SDL_JoystickOpen(int device_index) } joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN; + /* If this joystick is known to have all zero centered axes, skip the auto-centering code */ + if (SDL_JoystickAxesCenteredAtZero(joystick)) { + int i; + + for (i = 0; i < joystick->naxes; ++i) { + joystick->axes[i].has_initial_value = SDL_TRUE; + } + } + /* Add joystick to list */ ++joystick->ref_count; /* Link the joystick in the list */ @@ -597,25 +634,25 @@ int SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value) { int posted; + const int MAX_ALLOWED_JITTER = SDL_JOYSTICK_AXIS_MAX / 256; /* Make sure we're not getting garbage or duplicate events */ if (axis >= joystick->naxes) { return 0; } - if (value == joystick->axes[axis].value) { + if (!joystick->axes[axis].has_initial_value) { + joystick->axes[axis].value = value; + joystick->axes[axis].zero = value; + joystick->axes[axis].has_initial_value = SDL_TRUE; + } + if (SDL_abs(value - joystick->axes[axis].value) <= MAX_ALLOWED_JITTER) { return 0; } - if (!joystick->axes[axis].moved) { - if (joystick->axes[axis].intial_value == 0) { - joystick->axes[axis].intial_value = value; - return 0; - } - if (value == joystick->axes[axis].intial_value) { - return 0; - } - - /* We got more than 0 and the initial value from the joystick, consider it as having actually moved */ - joystick->axes[axis].moved = SDL_TRUE; + if (!joystick->axes[axis].sent_initial_value) { + int initial_value = joystick->axes[axis].value; + joystick->axes[axis].sent_initial_value = SDL_TRUE; + joystick->axes[axis].value = value; /* Just so we pass the check above */ + SDL_PrivateJoystickAxis(joystick, axis, initial_value); } /* We ignore events if we don't have keyboard focus, except for centering @@ -798,9 +835,11 @@ SDL_JoystickUpdate(void) if (joystick->force_recentering) { int i; - /* Tell the app that everything is centered/unpressed... */ + /* Tell the app that everything is centered/unpressed... */ for (i = 0; i < joystick->naxes; i++) { - SDL_PrivateJoystickAxis(joystick, i, joystick->axes[i].zero); + if (joystick->axes[i].has_initial_value) { + SDL_PrivateJoystickAxis(joystick, i, joystick->axes[i].zero); + } } for (i = 0; i < joystick->nbuttons; i++) { diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h index 250b70389..09b7e5892 100644 --- a/src/joystick/SDL_sysjoystick.h +++ b/src/joystick/SDL_sysjoystick.h @@ -31,10 +31,10 @@ /* The SDL joystick structure */ typedef struct _SDL_JoystickAxisInfo { - Sint16 value; /* Current axis states */ - Sint16 zero; /* Zero point on the axis (-32768 for triggers) */ - Sint16 intial_value; /* The very first value we saw on this axis */ - SDL_bool moved; /* Whether the axis has moved */ + Sint16 value; /* Current axis states */ + Sint16 zero; /* Zero point on the axis (-32768 for triggers) */ + SDL_bool has_initial_value; /* Whether we've seen a value on the axis yet */ + SDL_bool sent_initial_value; /* Whether we've sent the initial axis value */ } SDL_JoystickAxisInfo; struct _SDL_Joystick diff --git a/src/joystick/bsd/SDL_sysjoystick.c b/src/joystick/bsd/SDL_sysjoystick.c index 0ee540924..89e1d8fe8 100644 --- a/src/joystick/bsd/SDL_sysjoystick.c +++ b/src/joystick/bsd/SDL_sysjoystick.c @@ -522,12 +522,8 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joy) v *= 32768 / ((ymax - ymin + 1) / 2); SDL_PrivateJoystickAxis(joy, 1, v); } - if (gameport.b1 != joy->buttons[0]) { - SDL_PrivateJoystickButton(joy, 0, gameport.b1); - } - if (gameport.b2 != joy->buttons[1]) { - SDL_PrivateJoystickButton(joy, 1, gameport.b2); - } + SDL_PrivateJoystickButton(joy, 0, gameport.b1); + SDL_PrivateJoystickButton(joy, 1, gameport.b2); } return; } @@ -563,9 +559,7 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joy) v *= 32768 / ((hitem.logical_maximum - hitem.logical_minimum + 1) / 2); - if (v != joy->axes[naxe].value) { - SDL_PrivateJoystickAxis(joy, naxe, v); - } + SDL_PrivateJoystickAxis(joy, naxe, v); } else if (usage == HUG_HAT_SWITCH) { v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem); SDL_PrivateJoystickHat(joy, 0, @@ -576,9 +570,7 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joy) } case HUP_BUTTON: v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem); - if (joy->buttons[nbutton] != v) { - SDL_PrivateJoystickButton(joy, nbutton, v); - } + SDL_PrivateJoystickButton(joy, nbutton, v); nbutton++; break; default: diff --git a/src/joystick/darwin/SDL_sysjoystick.c b/src/joystick/darwin/SDL_sysjoystick.c index 8f10b913d..e8d04a636 100644 --- a/src/joystick/darwin/SDL_sysjoystick.c +++ b/src/joystick/darwin/SDL_sysjoystick.c @@ -692,9 +692,7 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) i = 0; while (element) { value = GetHIDScaledCalibratedState(device, element, -32768, 32767); - if (value != joystick->axes[i].value) { - SDL_PrivateJoystickAxis(joystick, i, value); - } + SDL_PrivateJoystickAxis(joystick, i, value); element = element->pNext; ++i; } @@ -706,9 +704,7 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) if (value > 1) { /* handle pressure-sensitive buttons */ value = 1; } - if (value != joystick->buttons[i]) { - SDL_PrivateJoystickButton(joystick, i, value); - } + SDL_PrivateJoystickButton(joystick, i, value); element = element->pNext; ++i; } @@ -759,9 +755,7 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) break; } - if (pos != joystick->hats[i]) { - SDL_PrivateJoystickHat(joystick, i, pos); - } + SDL_PrivateJoystickHat(joystick, i, pos); element = element->pNext; ++i; diff --git a/src/joystick/emscripten/SDL_sysjoystick.c b/src/joystick/emscripten/SDL_sysjoystick.c index 485aa6c80..9aae4d45a 100644 --- a/src/joystick/emscripten/SDL_sysjoystick.c +++ b/src/joystick/emscripten/SDL_sysjoystick.c @@ -146,7 +146,7 @@ Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gam /* Need to decrement the joystick count before we post the event */ --numjoysticks; - SDL_PrivateJoystickRemoved(item->device_instance); + SDL_PrivateJoystickRemoved(item->device_instance); #ifdef DEBUG_JOYSTICK SDL_Log("Removed joystick with id %d", item->device_instance); diff --git a/src/joystick/haiku/SDL_haikujoystick.cc b/src/joystick/haiku/SDL_haikujoystick.cc index 90ed9b361..07ee5a746 100644 --- a/src/joystick/haiku/SDL_haikujoystick.cc +++ b/src/joystick/haiku/SDL_haikujoystick.cc @@ -176,7 +176,6 @@ extern "C" SDL_HAT_LEFT, SDL_HAT_LEFTUP }; - const int JITTER = (32768 / 10); /* 10% jitter threshold (ok?) */ BJoystick *stick; int i, change; @@ -197,24 +196,17 @@ extern "C" /* Generate axis motion events */ for (i = 0; i < joystick->naxes; ++i) { - change = ((int32) axes[i] - joystick->axes[i].value); - if ((change > JITTER) || (change < -JITTER)) { - SDL_PrivateJoystickAxis(joystick, i, axes[i]); - } + SDL_PrivateJoystickAxis(joystick, i, axes[i]); } /* Generate hat change events */ for (i = 0; i < joystick->nhats; ++i) { - if (hats[i] != joystick->hats[i]) { - SDL_PrivateJoystickHat(joystick, i, hat_map[hats[i]]); - } + SDL_PrivateJoystickHat(joystick, i, hat_map[hats[i]]); } /* Generate button events */ for (i = 0; i < joystick->nbuttons; ++i) { - if ((buttons & 0x01) != joystick->buttons[i]) { - SDL_PrivateJoystickButton(joystick, i, (buttons & 0x01)); - } + SDL_PrivateJoystickButton(joystick, i, (buttons & 0x01)); buttons >>= 1; } } diff --git a/src/joystick/windows/SDL_mmjoystick.c b/src/joystick/windows/SDL_mmjoystick.c index 6dcf6f97f..c3148e852 100644 --- a/src/joystick/windows/SDL_mmjoystick.c +++ b/src/joystick/windows/SDL_mmjoystick.c @@ -41,8 +41,6 @@ #define MAX_JOYSTICKS 16 #define MAX_AXES 6 /* each joystick can have up to 6 axes */ #define MAX_BUTTONS 32 /* and 32 buttons */ -/* limit axis to 256 possible positions to filter out noise */ -#define JOY_AXIS_THRESHOLD (((SDL_JOYSTICK_AXIS_MAX)-(SDL_JOYSTICK_AXIS_MIN))/256) #define JOY_BUTTON_FLAG(n) (1<hwdata->transaxis; for (i = 0; i < joystick->naxes; i++) { if (joyinfo.dwFlags & flags[i]) { - value = - (int) (((float) pos[i] + - transaxis[i].offset) * transaxis[i].scale); - change = (value - joystick->axes[i].value); - if ((change < -JOY_AXIS_THRESHOLD) - || (change > JOY_AXIS_THRESHOLD)) { - SDL_PrivateJoystickAxis(joystick, (Uint8) i, (Sint16) value); - } + value = (int) (((float) pos[i] + transaxis[i].offset) * transaxis[i].scale); + SDL_PrivateJoystickAxis(joystick, (Uint8) i, (Sint16) value); } } @@ -355,15 +347,9 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) if (joyinfo.dwFlags & JOY_RETURNBUTTONS) { for (i = 0; i < joystick->nbuttons; ++i) { if (joyinfo.dwButtons & JOY_BUTTON_FLAG(i)) { - if (!joystick->buttons[i]) { - SDL_PrivateJoystickButton(joystick, (Uint8) i, - SDL_PRESSED); - } + SDL_PrivateJoystickButton(joystick, (Uint8) i, SDL_PRESSED); } else { - if (joystick->buttons[i]) { - SDL_PrivateJoystickButton(joystick, (Uint8) i, - SDL_RELEASED); - } + SDL_PrivateJoystickButton(joystick, (Uint8) i, SDL_RELEASED); } } } @@ -373,9 +359,7 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) Uint8 pos; pos = TranslatePOV(joyinfo.dwPOV); - if (pos != joystick->hats[0]) { - SDL_PrivateJoystickHat(joystick, 0, pos); - } + SDL_PrivateJoystickHat(joystick, 0, pos); } } diff --git a/test/controllermap.c b/test/controllermap.c index df25af994..1cd0c0eca 100644 --- a/test/controllermap.c +++ b/test/controllermap.c @@ -197,6 +197,7 @@ StandardizeAxisValue(int nValue) static void SetCurrentBinding(int iBinding) { + int iIndex; SDL_GameControllerExtendedBind *pBinding; if (iBinding < 0) { @@ -213,11 +214,39 @@ SetCurrentBinding(int iBinding) pBinding = &s_arrBindings[s_arrBindingOrder[s_iCurrentBinding]]; SDL_zerop(pBinding); - SDL_memset(s_arrAxisState, 0, s_nNumAxes*sizeof(*s_arrAxisState)); + for (iIndex = 0; iIndex < s_nNumAxes; ++iIndex) { + s_arrAxisState[iIndex].m_nFarthestValue = s_arrAxisState[iIndex].m_nStartingValue; + } s_unPendingAdvanceTime = 0; } +static SDL_bool +BBindingContainsBinding(const SDL_GameControllerExtendedBind *pBindingA, const SDL_GameControllerExtendedBind *pBindingB) +{ + if (pBindingA->bindType != pBindingB->bindType) + { + return SDL_FALSE; + } + switch (pBindingA->bindType) + { + case SDL_CONTROLLER_BINDTYPE_AXIS: + if (pBindingA->value.axis.axis != pBindingB->value.axis.axis) { + return SDL_FALSE; + } + { + int minA = SDL_min(pBindingA->value.axis.axis_min, pBindingA->value.axis.axis_max); + int maxA = SDL_max(pBindingA->value.axis.axis_min, pBindingA->value.axis.axis_max); + int minB = SDL_min(pBindingB->value.axis.axis_min, pBindingB->value.axis.axis_max); + int maxB = SDL_max(pBindingB->value.axis.axis_min, pBindingB->value.axis.axis_max); + return (minA <= minB && maxA >= maxB); + } + /* Not reached */ + default: + return SDL_memcmp(pBindingA, pBindingB, sizeof(*pBindingA)) == 0; + } +} + static void ConfigureBinding(const SDL_GameControllerExtendedBind *pBinding) { @@ -227,7 +256,8 @@ ConfigureBinding(const SDL_GameControllerExtendedBind *pBinding) /* Do we already have this binding? */ for (iIndex = 0; iIndex < SDL_arraysize(s_arrBindings); ++iIndex) { - if (SDL_memcmp(pBinding, &s_arrBindings[iIndex], sizeof(*pBinding)) == 0) { + pCurrent = &s_arrBindings[iIndex]; + if (BBindingContainsBinding(pCurrent, pBinding)) { if (iIndex == SDL_CONTROLLER_BUTTON_A && iCurrentElement != SDL_CONTROLLER_BUTTON_B) { /* Skip to the next binding */ SetCurrentBinding(s_iCurrentBinding + 1); @@ -263,7 +293,9 @@ ConfigureBinding(const SDL_GameControllerExtendedBind *pBinding) bNativeAxis = (iCurrentElement >= SDL_CONTROLLER_BUTTON_MAX); bCurrentAxis = (pCurrent->bindType == SDL_CONTROLLER_BINDTYPE_AXIS); - if (bNativeAxis == bCurrentAxis) { + if (bNativeAxis == bCurrentAxis && + (pBinding->bindType != SDL_CONTROLLER_BINDTYPE_AXIS || + pBinding->value.axis.axis != pCurrent->value.axis.axis)) { /* We already have a binding of the type we want, ignore the new one */ return; } @@ -412,8 +444,8 @@ WatchJoystick(SDL_Joystick * joystick) if (nCurrentDistance > nFarthestDistance) { pAxisState->m_nFarthestValue = nValue; } - if (nCurrentDistance <= 8000 && nFarthestDistance >= 20000) { - /* We've gone out and back, let's bind this axis */ + if (nFarthestDistance >= 20000 && nCurrentDistance <= 10000) { + /* We've gone out far enough and started to come back, let's bind this axis */ SDL_GameControllerExtendedBind binding; SDL_zero(binding); binding.bindType = SDL_CONTROLLER_BINDTYPE_AXIS;