diff --git a/docs/input.dox b/docs/input.dox index 1d8439d5..940a6827 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -804,6 +804,12 @@ a hat bitmask or empty. Joystick buttons are specified as `bN`, for example example `h0.8` for left on the first hat. More than one bit may be set in the mask. +Before an axis there may be a `+` or `-` range modifier, for example `+a3` for +the positive half of the fourth axis. This restricts input to only the positive +or negative halves of the joystick axis. After an axis or half-axis there may +be the `~` inversion modifier, for example `a2~` or `-a7~`. This negates the +values of the gamepad axis. + The hat bit mask match the [hat states](@ref hat_state) in the joystick functions. @@ -822,8 +828,9 @@ rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4, righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8, @endcode -@note GLFW does not yet support the range and inversion modifiers `+`, `-` and -`~` that were recently added to SDL. +@note GLFW does not yet support the output range and modifiers `+` and `-` that +were recently added to SDL. The input modifiers `+`, `-` and `~` are supported +and described above. @section time Time input diff --git a/src/input.c b/src/input.c index f6fb38fd..d0cbeed8 100644 --- a/src/input.c +++ b/src/input.c @@ -167,6 +167,10 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string) while (*c) { + // TODO: Implement output modifiers + if (*c == '+' || *c == '-') + return GLFW_FALSE; + for (i = 0; i < sizeof(fields) / sizeof(fields[0]); i++) { length = strlen(fields[i].name); @@ -177,23 +181,50 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string) if (fields[i].element) { + _GLFWmapelement* e = fields[i].element; + int8_t minimum = -1; + int8_t maximum = 1; + + if (*c == '+') + { + minimum = 0; + c += 1; + } + else if (*c == '-') + { + maximum = 0; + c += 1; + } + if (*c == 'a') - fields[i].element->type = _GLFW_JOYSTICK_AXIS; + e->type = _GLFW_JOYSTICK_AXIS; else if (*c == 'b') - fields[i].element->type = _GLFW_JOYSTICK_BUTTON; + e->type = _GLFW_JOYSTICK_BUTTON; else if (*c == 'h') - fields[i].element->type = _GLFW_JOYSTICK_HATBIT; + e->type = _GLFW_JOYSTICK_HATBIT; else break; - if (fields[i].element->type == _GLFW_JOYSTICK_HATBIT) + if (e->type == _GLFW_JOYSTICK_HATBIT) { const unsigned long hat = strtoul(c + 1, (char**) &c, 10); const unsigned long bit = strtoul(c + 1, (char**) &c, 10); - fields[i].element->value = (uint8_t) ((hat << 4) | bit); + e->value = (uint8_t) ((hat << 4) | bit); } else - fields[i].element->value = (uint8_t) strtoul(c + 1, (char**) &c, 10); + e->value = (uint8_t) strtoul(c + 1, (char**) &c, 10); + + if (e->type == _GLFW_JOYSTICK_AXIS) + { + e->axisScale = 2 / (maximum - minimum); + e->axisOffset = -(maximum + minimum); + + if (*c == '~') + { + e->axisScale = -e->axisScale; + e->axisOffset = -e->axisOffset; + } + } } else { @@ -1188,35 +1219,41 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) { - if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_AXIS) + const _GLFWmapelement* e = js->mapping->buttons + i; + if (e->type == _GLFW_JOYSTICK_AXIS) { - if (fabsf(js->axes[js->mapping->buttons[i].value]) > 0.5f) + const float value = js->axes[e->value] * e->axisScale + e->axisOffset; + if (value > 0.f) state->buttons[i] = GLFW_PRESS; } - else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_HATBIT) + else if (e->type == _GLFW_JOYSTICK_HATBIT) { - const unsigned int hat = js->mapping->buttons[i].value >> 4; - const unsigned int bit = js->mapping->buttons[i].value & 0xf; + const unsigned int hat = e->value >> 4; + const unsigned int bit = e->value & 0xf; if (js->hats[hat] & bit) state->buttons[i] = GLFW_PRESS; } - else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_BUTTON) - state->buttons[i] = js->buttons[js->mapping->buttons[i].value]; + else if (e->type == _GLFW_JOYSTICK_BUTTON) + state->buttons[i] = js->buttons[e->value]; } for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++) { - if (js->mapping->axes[i].type == _GLFW_JOYSTICK_AXIS) - state->axes[i] = js->axes[js->mapping->axes[i].value]; - else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_HATBIT) + const _GLFWmapelement* e = js->mapping->axes + i; + if (e->type == _GLFW_JOYSTICK_AXIS) { - const unsigned int hat = js->mapping->axes[i].value >> 4; - const unsigned int bit = js->mapping->axes[i].value & 0xf; + const float value = js->axes[e->value] * e->axisScale + e->axisOffset; + state->axes[i] = fminf(fmaxf(value, -1.f), 1.f); + } + else if (e->type == _GLFW_JOYSTICK_HATBIT) + { + const unsigned int hat = e->value >> 4; + const unsigned int bit = e->value & 0xf; if (js->hats[hat] & bit) state->axes[i] = 1.f; } - else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_BUTTON) - state->axes[i] = (float) js->buttons[js->mapping->axes[i].value]; + else if (e->type == _GLFW_JOYSTICK_BUTTON) + state->axes[i] = (float) js->buttons[e->value]; } return GLFW_TRUE; diff --git a/src/internal.h b/src/internal.h index 61f0a9c9..db952ed4 100644 --- a/src/internal.h +++ b/src/internal.h @@ -457,6 +457,8 @@ struct _GLFWmapelement { uint8_t type; uint8_t value; + int8_t axisScale; + int8_t axisOffset; }; // Gamepad mapping structure