Implement glfwGetJoystickHats

This moves the buttons-as-hats logic to shared code and adds the
GLFW_JOYSTICK_HAT_BUTTONS input mode as a way to disable this legacy
behavior.

Fixes #889.
This commit is contained in:
Camilla Löwy
2017-03-01 23:27:20 +01:00
parent 368dec7ac7
commit 798d7c6d68
13 changed files with 282 additions and 82 deletions
+19 -13
View File
@@ -204,7 +204,8 @@ static void matchCallback(void* context,
js = _glfwAllocJoystick(name,
CFArrayGetCount(axes),
CFArrayGetCount(buttons) + CFArrayGetCount(hats) * 4);
CFArrayGetCount(buttons),
CFArrayGetCount(hats));
js->ns.device = device;
js->ns.axes = axes;
@@ -358,33 +359,38 @@ int _glfwPlatformPollJoystick(int jid, int mode)
}
else if (mode == _GLFW_POLL_BUTTONS)
{
CFIndex i, bi = 0;
CFIndex i;
for (i = 0; i < CFArrayGetCount(js->ns.buttons); i++)
{
_GLFWjoyelementNS* button = (_GLFWjoyelementNS*)
CFArrayGetValueAtIndex(js->ns.buttons, i);
const char value = getElementValue(js, button) ? 1 : 0;
_glfwInputJoystickButton(jid, bi++, value);
_glfwInputJoystickButton(jid, i, value);
}
for (i = 0; i < CFArrayGetCount(js->ns.hats); i++)
{
const int states[9] =
{
GLFW_HAT_UP,
GLFW_HAT_RIGHT_UP,
GLFW_HAT_RIGHT,
GLFW_HAT_RIGHT_DOWN,
GLFW_HAT_DOWN,
GLFW_HAT_LEFT_DOWN,
GLFW_HAT_LEFT,
GLFW_HAT_LEFT_UP,
GLFW_HAT_CENTERED
};
_GLFWjoyelementNS* hat = (_GLFWjoyelementNS*)
CFArrayGetValueAtIndex(js->ns.hats, i);
// Bit fields of button presses for each direction, including nil
const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 };
long j, state = getElementValue(js, hat);
long state = getElementValue(js, hat);
if (state < 0 || state > 8)
state = 8;
for (j = 0; j < 4; j++)
{
const char value = directions[state] & (1 << j) ? 1 : 0;
_glfwInputJoystickButton(jid, bi++, value);
}
_glfwInputJoystickHat(jid, i, states[state]);
}
}
+4
View File
@@ -46,6 +46,7 @@ _GLFWlibrary _glfw = { GLFW_FALSE };
static GLFWerrorfun _glfwErrorCallback;
static _GLFWinitconfig _glfwInitHints =
{
GLFW_TRUE, // hat buttons
{
GLFW_TRUE, // menubar
GLFW_TRUE // chdir
@@ -188,6 +189,9 @@ GLFWAPI void glfwInitHint(int hint, int value)
{
switch (hint)
{
case GLFW_JOYSTICK_HAT_BUTTONS:
_glfwInitHints.hatButtons = value;
return;
case GLFW_COCOA_CHDIR_RESOURCES:
_glfwInitHints.ns.chdir = value;
return;
+40 -4
View File
@@ -140,6 +140,19 @@ void _glfwInputJoystickButton(int jid, int button, char value)
_glfw.joysticks[jid].buttons[button] = value;
}
void _glfwInputJoystickHat(int jid, int hat, char value)
{
_GLFWjoystick* js = _glfw.joysticks + jid;
const int base = js->buttonCount + hat * 4;
js->buttons[base + 0] = (value & 0x01) ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[base + 1] = (value & 0x02) ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[base + 2] = (value & 0x04) ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[base + 3] = (value & 0x08) ? GLFW_PRESS : GLFW_RELEASE;
js->hats[hat] = value;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
@@ -152,7 +165,10 @@ GLFWbool _glfwIsPrintable(int key)
key == GLFW_KEY_KP_EQUAL;
}
_GLFWjoystick* _glfwAllocJoystick(const char* name, int axisCount, int buttonCount)
_GLFWjoystick* _glfwAllocJoystick(const char* name,
int axisCount,
int buttonCount,
int hatCount)
{
int jid;
_GLFWjoystick* js;
@@ -170,9 +186,11 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name, int axisCount, int buttonCou
js->present = GLFW_TRUE;
js->name = strdup(name);
js->axes = calloc(axisCount, sizeof(float));
js->buttons = calloc(buttonCount, 1);
js->buttons = calloc(buttonCount + hatCount * 4, 1);
js->hats = calloc(hatCount, 1);
js->axisCount = axisCount;
js->buttonCount = buttonCount;
js->hatCount = hatCount;
return js;
}
@@ -182,6 +200,7 @@ void _glfwFreeJoystick(_GLFWjoystick* js)
free(js->name);
free(js->axes);
free(js->buttons);
free(js->hats);
memset(js, 0, sizeof(_GLFWjoystick));
}
@@ -663,13 +682,23 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count)
if (!_glfwPlatformPollJoystick(jid, _GLFW_POLL_BUTTONS))
return NULL;
*count = _glfw.joysticks[jid].buttonCount;
if (_glfw.hints.init.hatButtons)
{
*count = _glfw.joysticks[jid].buttonCount +
_glfw.joysticks[jid].hatCount * 4;
}
else
*count = _glfw.joysticks[jid].buttonCount;
return _glfw.joysticks[jid].buttons;
}
GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count)
{
assert(jid >= GLFW_JOYSTICK_1);
assert(jid <= GLFW_JOYSTICK_LAST);
assert(count != NULL);
*count = 0;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
@@ -680,7 +709,14 @@ GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count)
return NULL;
}
return NULL;
if (!_glfw.joysticks[jid].present)
return NULL;
if (!_glfwPlatformPollJoystick(jid, _GLFW_POLL_BUTTONS))
return NULL;
*count = _glfw.joysticks[jid].hatCount;
return _glfw.joysticks[jid].hats;
}
GLFWAPI const char* glfwGetJoystickName(int jid)
+11 -1
View File
@@ -266,6 +266,7 @@ typedef void (APIENTRY * PFN_vkVoidFunction)(void);
*/
struct _GLFWinitconfig
{
GLFWbool hatButtons;
struct {
GLFWbool menubar;
GLFWbool chdir;
@@ -476,6 +477,8 @@ struct _GLFWjoystick
int axisCount;
unsigned char* buttons;
int buttonCount;
unsigned char* hats;
int hatCount;
char* name;
// This is defined in the joystick API's joystick.h
@@ -823,6 +826,13 @@ void _glfwInputJoystickAxis(int jid, int axis, float value);
*/
void _glfwInputJoystickButton(int jid, int button, char value);
/*! @brief Notifies shared code of the new value of a joystick hat.
* @param[in] jid The joystick whose hat to update.
* @param[in] button The index of the hat to update.
* @param[in] value The new value of the hat.
*/
void _glfwInputJoystickHat(int jid, int hat, char value);
//========================================================================
// Utility functions
@@ -912,7 +922,7 @@ void _glfwFreeMonitor(_GLFWmonitor* monitor);
/*! @brief Returns an available joystick object with arrays and name allocated.
* @ingroup utility
*/
_GLFWjoystick* _glfwAllocJoystick(const char* name, int axisCount, int buttonCount);
_GLFWjoystick* _glfwAllocJoystick(const char* name, int axisCount, int buttonCount, int hatCount);
/*! @brief Frees arrays and name and flags the joystick object as unused.
* @ingroup utility
+1 -1
View File
@@ -77,7 +77,7 @@ static GLFWbool openJoystickDevice(const char* path)
ioctl(fd, JSIOCGAXES, &axisCount);
ioctl(fd, JSIOCGBUTTONS, &buttonCount);
js = _glfwAllocJoystick(name, axisCount, buttonCount);
js = _glfwAllocJoystick(name, axisCount, buttonCount, 0);
if (!js)
{
close(fd);
+33 -18
View File
@@ -427,7 +427,8 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user)
js = _glfwAllocJoystick(name,
data.axisCount + data.sliderCount,
data.buttonCount + data.povCount * 4);
data.buttonCount,
data.povCount);
if (!js)
{
IDirectInputDevice8_Release(device);
@@ -512,7 +513,7 @@ void _glfwDetectJoystickConnectionWin32(void)
if (XInputGetCapabilities(index, 0, &xic) != ERROR_SUCCESS)
continue;
js = _glfwAllocJoystick(getDeviceDescription(&xic), 6, 14);
js = _glfwAllocJoystick(getDeviceDescription(&xic), 6, 10, 1);
if (!js)
continue;
@@ -561,7 +562,7 @@ int _glfwPlatformPollJoystick(int jid, int mode)
if (js->win32.device)
{
int i, j, ai = 0, bi = 0;
int i, ai = 0, bi = 0, pi = 0;
HRESULT result;
DIJOYSTATE state;
@@ -612,19 +613,26 @@ int _glfwPlatformPollJoystick(int jid, int mode)
case _GLFW_TYPE_POV:
{
const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 };
const int states[9] =
{
GLFW_HAT_UP,
GLFW_HAT_RIGHT_UP,
GLFW_HAT_RIGHT,
GLFW_HAT_RIGHT_DOWN,
GLFW_HAT_DOWN,
GLFW_HAT_LEFT_DOWN,
GLFW_HAT_LEFT,
GLFW_HAT_LEFT_UP,
GLFW_HAT_CENTERED
};
// Screams of horror are appropriate at this point
int state = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES);
if (state < 0 || state > 8)
state = 8;
for (j = 0; j < 4; j++)
{
const char value = (directions[state] & (1 << j)) != 0;
_glfwInputJoystickButton(jid, bi, value);
bi++;
}
_glfwInputJoystickHat(jid, pi, states[state]);
pi++;
break;
}
}
@@ -632,7 +640,7 @@ int _glfwPlatformPollJoystick(int jid, int mode)
}
else
{
int i;
int i, dpad = 0;
DWORD result;
XINPUT_STATE xis;
float axes[6] = { 0.f, 0.f, 0.f, 0.f, -1.f, -1.f };
@@ -647,11 +655,7 @@ int _glfwPlatformPollJoystick(int jid, int mode)
XINPUT_GAMEPAD_BACK,
XINPUT_GAMEPAD_START,
XINPUT_GAMEPAD_LEFT_THUMB,
XINPUT_GAMEPAD_RIGHT_THUMB,
XINPUT_GAMEPAD_DPAD_UP,
XINPUT_GAMEPAD_DPAD_RIGHT,
XINPUT_GAMEPAD_DPAD_DOWN,
XINPUT_GAMEPAD_DPAD_LEFT
XINPUT_GAMEPAD_RIGHT_THUMB
};
result = XInputGetState(js->win32.index, &xis);
@@ -693,11 +697,22 @@ int _glfwPlatformPollJoystick(int jid, int mode)
for (i = 0; i < 6; i++)
_glfwInputJoystickAxis(jid, i, axes[i]);
for (i = 0; i < 14; i++)
for (i = 0; i < 10; i++)
{
const char value = (xis.Gamepad.wButtons & buttons[i]) ? 1 : 0;
_glfwInputJoystickButton(jid, i, value);
}
if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP)
dpad |= GLFW_HAT_UP;
if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)
dpad |= GLFW_HAT_RIGHT;
if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN)
dpad |= GLFW_HAT_DOWN;
if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT)
dpad |= GLFW_HAT_LEFT;
_glfwInputJoystickHat(jid, 0, dpad);
}
return GLFW_TRUE;