Commit 953106e7 authored by Camilla Löwy's avatar Camilla Löwy
Browse files

Add support for SDL_GameControllerDB

This adds support for importing and applying mappings from the
SDL_GameControllerDB database.

Related to #900.
parent 07bf2b16
......@@ -127,6 +127,14 @@ information on what to include when reporting a bug.
- Added `glfwGetError` function for querying the last error code and its
description (#970)
- Added `glfwUpdateGamepadMappings` function for importing gamepad mappings in
SDL\_GameControllerDB format (#900)
- Added `glfwJoystickIsGamepad` function for querying whether a joystick has
a gamepad mapping (#900)
- Added `glfwGetGamepadName` function for querying the name provided by the
gamepad mapping (#900)
- Added `glfwGetGamepadState` function, `GLFW_GAMEPAD_*` and `GLFWgamepadstate`
for retrieving gamepad input state (#900)
- Added `glfwRequestWindowAttention` function for requesting attention from the
user (#732,#988)
- Added `glfwGetKeyScancode` function that allows retrieving platform dependent
......
......@@ -476,7 +476,7 @@ SORT_MEMBER_DOCS = NO
# by member name. If set to NO (the default) the members will appear in
# declaration order.
SORT_BRIEF_DOCS = YES
SORT_BRIEF_DOCS = NO
# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
# will sort the (brief and detailed) documentation of class members so that
......
......@@ -653,6 +653,143 @@ called by joystick functions. The function will then return whatever it
returns for a disconnected joystick.
@subsection gamepad Gamepad input
The joystick functions provide unlabeled axes, buttons and hats, with no
indication of where they are located on the device. Their order may also vary
between platforms even with the same device.
To solve this problem the SDL community crowdsourced the
[SDL_GameControllerDB](https://github.com/gabomdq/SDL_GameControllerDB) project,
a database of mappings from many different devices to an Xbox-like gamepad.
GLFW supports this mapping format and contains a copy of the mappings
available at the time of release. See @ref gamepad_mapping for how to update
this at runtime. Mappings will be assigned to joysticks automatically any time
a joystick is connected or the mappings are updated.
You can check whether a joystick is both present and has a gamepad mapping with
@ref glfwJoystickIsGamepad.
@code
if (glfwJoystickIsGamepad(GLFW_JOYSTICK_2))
{
// Use as gamepad
}
@endcode
If you are only interested in gamepad input you can use this function instead of
@ref glfwJoystickPresent.
You can query the human-readable name provided by the gamepad mapping with @ref
glfwGetGamepadName. This may or may not be the same as the
[joystick name](@ref joystick_name).
@code
const char* name = glfwGetGamepadName(GLFW_JOYSTICK_7);
@endcode
To retrieve the gamepad state of a joystick, call @ref glfwGetGamepadState.
@code
GLFWgamepadstate state;
if (glfwGetGamepadState(GLFW_JOYSTICK_3, &state))
{
if (state.buttons[GLFW_GAMEPAD_BUTTON_A])
{
input_jump();
}
input_speed(state.axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER]);
}
@endcode
The @ref GLFWgamepadstate struct has two arrays; one for button states and one
for axis states. The values for each button and axis are the same as for the
@ref glfwGetJoystickButtons and @ref glfwGetJoystickAxes functions, i.e.
`GLFW_PRESS` or `GLFW_RELEASE` for buttons and -1.0 to 1.0 inclusive for axes.
The sizes of the arrays and the positions within each array are fixed.
The [button indices](@ref gamepad_buttons) are `GLFW_GAMEPAD_BUTTON_A`,
`GLFW_GAMEPAD_BUTTON_B`, `GLFW_GAMEPAD_BUTTON_X`, `GLFW_GAMEPAD_BUTTON_Y`,
`GLFW_GAMEPAD_BUTTON_LEFT_BUMPER`, `GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER`,
`GLFW_GAMEPAD_BUTTON_BACK`, `GLFW_GAMEPAD_BUTTON_START`,
`GLFW_GAMEPAD_BUTTON_GUIDE`, `GLFW_GAMEPAD_BUTTON_LEFT_THUMB`,
`GLFW_GAMEPAD_BUTTON_RIGHT_THUMB`, `GLFW_GAMEPAD_BUTTON_DPAD_UP`,
`GLFW_GAMEPAD_BUTTON_DPAD_RIGHT`, `GLFW_GAMEPAD_BUTTON_DPAD_DOWN` and
`GLFW_GAMEPAD_BUTTON_DPAD_LEFT`.
For those who prefer, there are also the `GLFW_GAMEPAD_BUTTON_CROSS`,
`GLFW_GAMEPAD_BUTTON_CIRCLE`, `GLFW_GAMEPAD_BUTTON_SQUARE` and
`GLFW_GAMEPAD_BUTTON_TRIANGLE` aliases for the A, B, X and Y button indices.
The [axis indices](@ref gamepad_axes) are `GLFW_GAMEPAD_AXIS_LEFT_X`,
`GLFW_GAMEPAD_AXIS_LEFT_Y`, `GLFW_GAMEPAD_AXIS_RIGHT_X`,
`GLFW_GAMEPAD_AXIS_RIGHT_Y`, `GLFW_GAMEPAD_AXIS_LEFT_TRIGGER` and
`GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER`.
The `GLFW_GAMEPAD_BUTTON_LAST` and `GLFW_GAMEPAD_AXIS_LAST` constants equal
the largest available index for each array.
@subsection gamepad_mapping Gamepad mappings
Newer ones can be added with @ref glfwUpdateGamepadMappings. This function
supports everything from single lines up to the entire unmodified contents of
the `gamecontrollerdb.txt` file.
@code
const char* mappings = load_file_contents("gamecontrollerdb.txt");
glfwUpdateGamepadMappings(mappings);
@endcode
Below is a description of the mapping format. Please keep in mind that __this
description is not authoritative__. The format is defined by the SDL and
SDL_GameControllerDB projects and their documentation and code takes precedence.
Each mapping is a single line of comma-separated values describing the GUID,
name and layout of the gamepad. Lines that do not begin with a hexadecimal
digit are ignored.
The first value is always the gamepad GUID, a 32 character long hexadecimal
string that typically identifies its make, model, revision and the type of
connection to the computer. When this information is not available, the GUID is
generated using the gamepad name. GLFW uses the SDL 2.0.5+ GUID format but can
convert from the older formats.
The second value is always the human-readable name of the gamepad.
All subsequent values are in the form `<field>:<value>` and describe the layout
of the mapping. These fields may not all be present and may occur in any order.
The button fields are `a`, `b`, `c`, `d`, `back`, `start`, `guide`, `dpup`,
`dpright`, `dpdown`, `dpleft`, `leftshoulder`, `rightshoulder`, `leftstick` and
`rightstick`.
The axis fields are `leftx`, `lefty`, `rightx`, `righty`, `lefttrigger` and
`righttrigger`.
The value of an axis or button field can be a joystick button, a joystick axis,
a hat bitmask or empty. Joystick buttons are specified as `bN`, for example
`b2` for the third button. Joystick axes are specified as `aN`, for example
`a7` for the eighth button. Joystick hat bit masks are specified as `hN.N`, for
example `h0.8` for left on the first hat. More than one bit may be set in the
mask.
The hat bit mask match the [hat states](@ref hat_state) in the joystick
functions.
There is also the special `platform` field that specifies which platform the
mapping is valid for. Possible values are `Windows`, `Mac OS X` and `Linux`.
Mappings without this field will always be considered valid.
@note GLFW does not yet support the range and inversion modifiers `+`, `-` and
`~`.
@section time Time input
GLFW provides high-resolution time input, in seconds, with @ref glfwGetTime.
......
......@@ -13,6 +13,16 @@ human-readable description with @ref glfwGetError.
@see @ref error_handling
@subsection news_33_gamepad SDL_GameControllerDB support and gamepad input
GLFW now supports remapping of gamepads and controllers to a 360-like controller
layout with @ref glfwJoystickIsGamepad, @ref glfwGetGamepadName, @ref
glfwGetGamepadState and @ref glfwUpdateGamepadMappings, and the input state
struct @ref GLFWgamepadstate.
@sa @ref gamepad
@subsection news_33_attention User attention request
GLFW now supports requesting user attention to a specific window (on macOS to
......
......@@ -559,6 +559,52 @@ extern "C" {
#define GLFW_JOYSTICK_LAST GLFW_JOYSTICK_16
/*! @} */
/*! @defgroup gamepad_buttons Gamepad buttons
* @brief Gamepad buttons.
*
* See @ref gamepad for how these are used.
*
* @ingroup input
* @{ */
#define GLFW_GAMEPAD_BUTTON_A 0
#define GLFW_GAMEPAD_BUTTON_B 1
#define GLFW_GAMEPAD_BUTTON_X 2
#define GLFW_GAMEPAD_BUTTON_Y 3
#define GLFW_GAMEPAD_BUTTON_LEFT_BUMPER 4
#define GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER 5
#define GLFW_GAMEPAD_BUTTON_BACK 6
#define GLFW_GAMEPAD_BUTTON_START 7
#define GLFW_GAMEPAD_BUTTON_GUIDE 8
#define GLFW_GAMEPAD_BUTTON_LEFT_THUMB 9
#define GLFW_GAMEPAD_BUTTON_RIGHT_THUMB 10
#define GLFW_GAMEPAD_BUTTON_DPAD_UP 11
#define GLFW_GAMEPAD_BUTTON_DPAD_RIGHT 12
#define GLFW_GAMEPAD_BUTTON_DPAD_DOWN 13
#define GLFW_GAMEPAD_BUTTON_DPAD_LEFT 14
#define GLFW_GAMEPAD_BUTTON_LAST GLFW_GAMEPAD_BUTTON_DPAD_LEFT
#define GLFW_GAMEPAD_BUTTON_CROSS GLFW_GAMEPAD_BUTTON_A
#define GLFW_GAMEPAD_BUTTON_CIRCLE GLFW_GAMEPAD_BUTTON_B
#define GLFW_GAMEPAD_BUTTON_SQUARE GLFW_GAMEPAD_BUTTON_X
#define GLFW_GAMEPAD_BUTTON_TRIANGLE GLFW_GAMEPAD_BUTTON_Y
/*! @} */
/*! @defgroup gamepad_axes Gamepad axes
* @brief Gamepad axes.
*
* See @ref gamepad for how these are used.
*
* @ingroup input
* @{ */
#define GLFW_GAMEPAD_AXIS_LEFT_X 0
#define GLFW_GAMEPAD_AXIS_LEFT_Y 1
#define GLFW_GAMEPAD_AXIS_RIGHT_X 2
#define GLFW_GAMEPAD_AXIS_RIGHT_Y 3
#define GLFW_GAMEPAD_AXIS_LEFT_TRIGGER 4
#define GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER 5
#define GLFW_GAMEPAD_AXIS_LAST GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER
/*! @} */
/*! @defgroup errors Error codes
* @brief Error codes.
*
......@@ -1475,6 +1521,27 @@ typedef struct GLFWimage
unsigned char* pixels;
} GLFWimage;
/*! @brief Gamepad input state
*
* This describes the input state of a gamepad.
*
* @sa @ref gamepad
* @sa @ref glfwGetGamepadState
*
* @since Added in version 3.3.
*/
typedef struct GLFWgamepadstate
{
/*! The states of each [gamepad button](@ref gamepad_buttons), `GLFW_PRESS`
* or `GLFW_RELEASE`.
*/
char buttons[15];
/*! The states of each [gamepad axis](@ref gamepad_axes), in the range -1.0
* to 1.0 inclusive.
*/
float axes[6];
} GLFWgamepadstate;
/*************************************************************************
* GLFW API functions
......@@ -4118,9 +4185,9 @@ GLFWAPI int glfwJoystickPresent(int jid);
* This function returns the values of all axes of the specified joystick.
* Each element in the array is a value between -1.0 and 1.0.
*
* Querying a joystick ID with no device present is not an error, but will
* cause this function to return `NULL`. Call @ref glfwJoystickPresent to
* check device presence.
* If the specified joystick is not present this function will return `NULL`
* but will not generate an error. Call @ref glfwJoystickPresent to check
* device presence.
*
* @param[in] jid The [joystick](@ref joysticks) to query.
* @param[out] count Where to store the number of axis values in the returned
......@@ -4158,9 +4225,9 @@ GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count);
* _left_. To disable these extra buttons, set the @ref
* GLFW_JOYSTICK_HAT_BUTTONS init hint before initialization.
*
* Querying a joystick ID with no device present is not an error, but will
* cause this function to return `NULL`. Call @ref glfwJoystickPresent to
* check device presence.
* If the specified joystick is not present this function will return `NULL`
* but will not generate an error. Call @ref glfwJoystickPresent to check
* device presence.
*
* @param[in] jid The [joystick](@ref joysticks) to query.
* @param[out] count Where to store the number of button states in the returned
......@@ -4215,9 +4282,9 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count);
* }
* @endcode
*
* Querying a joystick ID with no device present is not an error, but will
* cause this function to return `NULL`. Call @ref glfwJoystickPresent to
* check device presence.
* If the specified joystick is not present this function will return `NULL`
* but will not generate an error. Call @ref glfwJoystickPresent to check
* device presence.
*
* @param[in] jid The [joystick](@ref joysticks) to query.
* @param[out] count Where to store the number of hat states in the returned
......@@ -4250,9 +4317,9 @@ GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count);
* The returned string is allocated and freed by GLFW. You should not free it
* yourself.
*
* Querying a joystick ID with no device present is not an error, but will
* cause this function to return `NULL`. Call @ref glfwJoystickPresent to
* check device presence.
* If the specified joystick is not present this function will return `NULL`
* but will not generate an error. Call @ref glfwJoystickPresent to check
* device presence.
*
* @param[in] jid The [joystick](@ref joysticks) to query.
* @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick
......@@ -4275,6 +4342,33 @@ GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count);
*/
GLFWAPI const char* glfwGetJoystickName(int jid);
/*! @brief Returns whether the specified joystick has a gamepad mapping.
*
* This function returns whether the specified joystick is both present and has
* a gamepad mapping.
*
* If the specified joystick is present but does not have a gamepad mapping
* this function will return `GLFW_FALSE` but will not generate an error. Call
* @ref glfwJoystickPresent to only check device presence.
*
* @param[in] jid The [joystick](@ref joysticks) to query.
* @return `GLFW_TRUE` if a joystick is both present and has a gamepad mapping,
* or `GLFW_FALSE` otherwise.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_INVALID_ENUM.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref gamepad
* @sa @ref glfwGetGamepadState
*
* @since Added in version 3.3.
*
* @ingroup input
*/
GLFWAPI int glfwJoystickIsGamepad(int jid);
/*! @brief Sets the joystick configuration callback.
*
* This function sets the joystick configuration callback, or removes the
......@@ -4285,7 +4379,7 @@ GLFWAPI const char* glfwGetJoystickName(int jid);
* platforms, you need to call one of the [event processing](@ref events)
* functions. Joystick disconnection may also be detected and the callback
* called by joystick functions. The function will then return whatever it
* returns for a disconnected joystick.
* returns if the joystick is not present.
*
* @param[in] cbfun The new callback, or `NULL` to remove the currently set
* callback.
......@@ -4304,6 +4398,105 @@ GLFWAPI const char* glfwGetJoystickName(int jid);
*/
GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun);
/*! @brief Adds the specified SDL_GameControllerDB gamepad mappings.
*
* This function parses the specified ASCII encoded string and updates the
* internal list with any gamepad mappings it finds. This string may
* contain either a single gamepad mapping or many mappings separated by
* newlines. The parser supports the full format of the `gamecontrollerdb.txt`
* source file including empty lines and comments.
*
* See @ref gamepad_mapping for a description of the format.
*
* If there is already a gamepad mapping for a given GUID in the internal list,
* it will be replaced by the one passed to this function. If the library is
* terminated and re-initialized the internal list will revert to the built-in
* default.
*
* @param[in] string The string containing the gamepad mappings.
* @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an
* [error](@ref error_handling) occurred.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_INVALID_VALUE.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref gamepad
* @sa @ref glfwJoystickIsGamepad
* @sa @ref glfwGetGamepadName
*
* @since Added in version 3.3.
*
* @ingroup input
*/
GLFWAPI int glfwUpdateGamepadMappings(const char* string);
/*! @brief Returns the human-readable gamepad name for the specified joystick.
*
* This function returns the human-readable name of the gamepad from the
* gamepad mapping assigned to the specified joystick.
*
* If the specified joystick is not present or does not have a gamepad mapping
* this function will return `NULL` but will not generate an error. Call @ref
* glfwJoystickIsGamepad to check whether it is present and has a gamepad mapping.
*
* @param[in] jid The [joystick](@ref joysticks) to query.
* @return The UTF-8 encoded name of the gamepad, or `NULL` if the
* joystick is not present, does not have a mapping or an
* [error](@ref error_handling) occurred.
*
* @pointer_lifetime The returned string is allocated and freed by GLFW. You
* should not free it yourself. It is valid until the specified joystick is
* disconnected, the gamepad mappings are updated or the library is terminated.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref gamepad
* @sa @ref glfwJoystickIsGamepad
*
* @since Added in version 3.3.
*
* @ingroup input
*/
GLFWAPI const char* glfwGetGamepadName(int jid);
/*! @brief Retrieves the state of the specified joystick remapped as a gamepad.
*
* This function retrives the state of the specified joystick remapped to
* an Xbox-like gamepad.
*
* If the specified joystick is not present this function will return
* `GLFW_FALSE` but will not generate an error. Call @ref
* glfwJoystickIsGamepad to check whether it is present and has a gamepad
* mapping.
*
* The Guide button may not be available for input as it is often hooked by the
* system or the Steam client.
*
* Not all devices have all the buttons or axes provided by @ref
* GLFWgamepadstate. Unavailable buttons and axes will always report
* `GLFW_RELEASE` and 1.0 respectively.
*
* @param[in] jid The [joystick](@ref joysticks) to query.
* @param[out] state The gamepad input state of the joystick.
* @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if no joystick is
* connected, it has no gamepad mapping or an [error](@ref error_handling)
* occurred.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_INVALID_ENUM.
*
* @sa @ref gamepad
* @sa @ref glfwUpdateGamepadMappings
* @sa @ref glfwJoystickIsGamepad
*
* @since Added in version 3.3.
*
* @ingroup input
*/
GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state);
/*! @brief Sets the clipboard to the specified string.
*
* This function sets the system clipboard to the specified, UTF-8 encoded
......
set(common_HEADERS internal.h
set(common_HEADERS internal.h mappings.h
"${GLFW_BINARY_DIR}/src/glfw_config.h"
"${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h"
"${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h")
......
......@@ -32,6 +32,7 @@
#define _GLFW_PLATFORM_JOYSTICK_STATE _GLFWjoystickNS ns
#define _GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE
#define _GLFW_PLATFORM_MAPPING_NAME "Mac OS X"
// Cocoa-specific per-joystick data
//
......
......@@ -43,6 +43,8 @@
typedef struct _GLFWjoyelementNS
{
IOHIDElementRef native;
uint32_t usage;
int index;
long minimum;
long maximum;
......@@ -69,6 +71,23 @@ static long getElementValue(_GLFWjoystick* js, _GLFWjoyelementNS* element)
return value;
}
// Comparison function for matching the SDL element order
//
static CFComparisonResult compareElements(const void* fp, const void* sp, void* user)
{
const _GLFWjoyelementNS* fe = fp;
const _GLFWjoyelementNS* se = sp;
if (fe->usage < se->usage)
return kCFCompareLessThan;
if (fe->usage > se->usage)
return kCFCompareGreaterThan;
if (fe->index < se->index)
return kCFCompareLessThan;
if (fe->index > se->index)
return kCFCompareGreaterThan;
return kCFCompareEqualTo;
}
// Removes the specified joystick
//
static void closeJoystick(_GLFWjoystick* js)
......@@ -103,8 +122,10 @@ static void matchCallback(void* context,
{
int jid;
char name[256];
char guid[33];
CFIndex i;
CFStringRef productKey;
CFTypeRef property;
uint32_t vendor = 0, product = 0, version = 0;
_GLFWjoystick* js;
CFMutableArrayRef axes, buttons, hats;
......@@ -118,10 +139,10 @@ static void matchCallback(void* context,
buttons = CFArrayCreateMutable(NULL, 0, NULL);
hats = CFArrayCreateMutable(NULL, 0, NULL);
productKey = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
if (productKey)
property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
if (property)
{
CFStringGetCString(productKey,
CFStringGetCString(property,
name,
sizeof(name),
kCFStringEncodingUTF8);
......@@ -129,6 +150,34 @@ static void matchCallback(void* context,
else
strncpy(name, "Unknown", sizeof(name));
property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey));
if (property)
CFNumberGetValue(property, kCFNumberSInt32Type, &vendor);
property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey));
if (property)
CFNumberGetValue(property, kCFNumberSInt32Type, &product);
property = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVersionNumberKey));
if (property)
CFNumberGetValue(property, kCFNumberSInt32Type, &version);
// Generate a joystick GUID that matches the SDL 2.0.5+ one
if (vendor && product)
{
sprintf(guid, "03000000%02x%02x0000%02x%02x0000%02x%02x0000",
(uint8_t) vendor, (uint8_t) (vendor >> 8),
(uint8_t) product, (uint8_t) (product >> 8),
(uint8_t) version, (uint8_t) (version >> 8));
}
else
{
sprintf(guid, "05000000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00",
name[0], name[1], name[2], name[3],
name[4], name[5], name[6], name[7],
name[8], name[9], name[10]);
}
CFArrayRef elements =
IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone);
......@@ -147,12 +196,13 @@ static void matchCallback(void* context,
}
CFMutableArrayRef target = NULL;
const uint32_t usage = IOHIDElementGetUsage(native);
switch (IOHIDElementGetUsagePage(native))
{
case kHIDPage_GenericDesktop:
{
switch (IOHIDElementGetUsage(native))
switch (usage)
{
case kHIDUsage_GD_X:
case kHIDUsage_GD_Y:
......@@ -184,6 +234,8 @@ static void matchCallback(void* context,
{
_GLFWjoyelementNS* element = calloc(1, sizeof(_GLFWjoyelementNS));
element->native = native;
element->usage = usage;
element->index = (int) CFArrayGetCount(target);
element->minimum = IOHIDElementGetLogicalMin(native);
element->maximum = IOHIDElementGetLogicalMax(native);
CFArrayAppendValue(target, element);
......@@ -192,7 +244,14 @@ static void matchCallback(void* context,
CFRelease(elements);
js = _glfwAllocJoystick(name,
CFArraySortValues(axes, CFRangeMake(0, CFArrayGetCount(axes)),
compareElements, NULL);
CFArraySortValues(buttons, CFRangeMake(0, CFArrayGetCount(buttons)),
compareElements, NULL);
CFArraySortValues(hats, CFRangeMake(0, CFArrayGetCount(hats)),
compareElements, NULL);
js = _glfwAllocJoystick(name, guid,
CFArrayGetCount(axes),
CFArrayGetCount(buttons),
CFArrayGetCount(hats));
......@@ -329,7 +388,7 @@ int _glfwPlatformPollJoystick(int jid, int mode)
{
_GLFWjoystick* js = _glfw.joysticks + jid;
if (mode == _GLFW_POLL_AXES)
if (mode & _GLFW_POLL_AXES)
{
CFIndex i;
......@@ -355,7 +414,8 @@ int _glfwPlatformPollJoystick(int jid, int mode)
}
}
}
else if (mode == _GLFW_POLL_BUTTONS)
if (mode & _GLFW_POLL_BUTTONS)
{
CFIndex i;
......@@ -395,3 +455,15 @@ int _glfwPlatformPollJoystick(int jid, int mode)
return js->present;
}
void _glfwPlatformUpdateGamepadGUID(char* guid)
{
if ((strncmp(guid + 4, "000000000000", 12) == 0) &&
(strncmp(guid + 20, "000000000000", 12) == 0))
{
char original[33];
strcpy(original, guid);
sprintf(guid, "03000000%.4s0000%.4s000000000000",
original, original + 16);
}
}
......@@ -26,6 +26,7 @@
//========================================================================