mirror of
https://github.com/glfw/glfw.git
synced 2026-09-21 00:30:57 +00:00
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:
+19
-13
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user