New joystick API.

This commit is contained in:
Camilla Berglund 2013-04-24 19:25:42 +02:00
parent c4d856bcb2
commit 7f2eb7b15b
10 changed files with 280 additions and 461 deletions

View File

@ -530,10 +530,6 @@ extern "C" {
#define GLFW_CURSOR_HIDDEN 0x00040002
#define GLFW_CURSOR_CAPTURED 0x00040003
#define GLFW_PRESENT 0x00050001
#define GLFW_AXES 0x00050002
#define GLFW_BUTTONS 0x00050003
#define GLFW_GAMMA_RAMP_SIZE 256
#define GLFW_CONNECTED 0x00061000
@ -1930,37 +1926,31 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cb
*
* @ingroup input
*/
GLFWAPI int glfwGetJoystickParam(int joy, int param);
GLFWAPI int glfwJoystickPresent(int joy);
/*! @brief Returns the values of axes of the specified joystick.
*
* This function returns the current positions of axes of the specified
* joystick.
*
/*! @brief Returns the values of all axes of the specified joystick.
* @param[in] joy The joystick to query.
* @param[out] axes The array to hold the values.
* @param[in] numaxes The size of the provided array.
* @return The number of values written to `axes`, or zero if an error
* occurred.
* @param[out] count The size of the returned array.
* @return An array of axis values, or @c NULL if the joystick is not present.
*
* @note The returned array is valid only until the next call to @ref
* glfwGetJoystickAxes for that joystick.
*
* @ingroup input
*/
GLFWAPI int glfwGetJoystickAxes(int joy, float* axes, int numaxes);
GLFWAPI float* glfwGetJoystickAxes(int joy, int* count);
/*! @brief Returns the values of buttons of the specified joystick.
*
* This function returns the current state of buttons of the specified
* joystick.
*
/*! @brief Returns the values of all buttons of the specified joystick.
* @param[in] joy The joystick to query.
* @param[out] buttons The array to hold the values.
* @param[in] numbuttons The size of the provided array.
* @return The number of values written to `buttons`, or zero if an error
* occurred.
* @param[out] count The size of the returned array.
* @return An array of axis values, or @c NULL if the joystick is not present.
*
* @note The returned array is valid only until the next call to @ref
* glfwGetJoystickButtons for that joystick.
*
* @ingroup input
*/
GLFWAPI int glfwGetJoystickButtons(int joy, unsigned char* buttons, int numbuttons);
GLFWAPI unsigned char* glfwGetJoystickButtons(int joy, int* count);
/*! @brief Returns the name of the specified joystick.
*

View File

@ -47,8 +47,6 @@ typedef struct
{
IOHIDElementCookie cookie;
long value;
long min;
long max;
@ -63,20 +61,17 @@ static void getElementsCFArrayHandler(const void* value, void* parameter);
// Adds an element to the specified joystick
//
static void addJoystickElement(_GLFWjoy* joystick, CFTypeRef refElement)
static void addJoystickElement(_GLFWjoy* joystick, CFTypeRef elementRef)
{
long elementType, usagePage, usage;
CFTypeRef refElementType, refUsagePage, refUsage;
refElementType = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementTypeKey));
refUsagePage = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementUsagePageKey));
refUsage = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementUsageKey));
CFMutableArrayRef elementsArray = NULL;
CFNumberGetValue(refElementType, kCFNumberLongType, &elementType);
CFNumberGetValue(refUsagePage, kCFNumberLongType, &usagePage);
CFNumberGetValue(refUsage, kCFNumberLongType, &usage);
CFNumberGetValue(CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementTypeKey)),
kCFNumberLongType, &elementType);
CFNumberGetValue(CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementUsagePageKey)),
kCFNumberLongType, &usagePage);
CFNumberGetValue(CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementUsageKey)),
kCFNumberLongType, &usage);
if ((elementType == kIOHIDElementTypeInput_Axis) ||
(elementType == kIOHIDElementTypeInput_Button) ||
@ -97,12 +92,10 @@ static void addJoystickElement(_GLFWjoy* joystick, CFTypeRef refElement)
case kHIDUsage_GD_Slider:
case kHIDUsage_GD_Dial:
case kHIDUsage_GD_Wheel:
joystick->numAxes++;
elementsArray = joystick->axes;
elementsArray = joystick->axisElements;
break;
case kHIDUsage_GD_Hatswitch:
joystick->numHats++;
elementsArray = joystick->hats;
elementsArray = joystick->hatElements;
break;
}
@ -110,8 +103,7 @@ static void addJoystickElement(_GLFWjoy* joystick, CFTypeRef refElement)
}
case kHIDPage_Button:
joystick->numButtons++;
elementsArray = joystick->buttons;
elementsArray = joystick->buttonElements;
break;
default:
break;
@ -120,35 +112,33 @@ static void addJoystickElement(_GLFWjoy* joystick, CFTypeRef refElement)
if (elementsArray)
{
long number;
CFTypeRef refType;
CFTypeRef numberRef;
_GLFWjoyelement* element = (_GLFWjoyelement*) malloc(sizeof(_GLFWjoyelement));
CFArrayAppendValue(elementsArray, element);
refType = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementCookieKey));
if (refType && CFNumberGetValue(refType, kCFNumberLongType, &number))
numberRef = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementCookieKey));
if (numberRef && CFNumberGetValue(numberRef, kCFNumberLongType, &number))
element->cookie = (IOHIDElementCookie) number;
refType = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementMinKey));
if (refType && CFNumberGetValue(refType, kCFNumberLongType, &number))
numberRef = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementMinKey));
if (numberRef && CFNumberGetValue(numberRef, kCFNumberLongType, &number))
element->minReport = element->min = number;
refType = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementMaxKey));
if (refType && CFNumberGetValue(refType, kCFNumberLongType, &number))
numberRef = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementMaxKey));
if (numberRef && CFNumberGetValue(numberRef, kCFNumberLongType, &number))
element->maxReport = element->max = number;
}
}
else
{
CFTypeRef refElementTop = CFDictionaryGetValue(refElement, CFSTR(kIOHIDElementKey));
if (refElementTop)
CFTypeRef array = CFDictionaryGetValue(elementRef, CFSTR(kIOHIDElementKey));
if (array)
{
CFTypeID type = CFGetTypeID (refElementTop);
if (type == CFArrayGetTypeID())
if (CFGetTypeID(array) == CFArrayGetTypeID())
{
CFRange range = {0, CFArrayGetCount (refElementTop)};
CFArrayApplyFunction(refElementTop, range, getElementsCFArrayHandler, joystick);
CFRange range = { 0, CFArrayGetCount(array) };
CFArrayApplyFunction(array, range, getElementsCFArrayHandler, joystick);
}
}
}
@ -195,42 +185,28 @@ static void removeJoystick(_GLFWjoy* joystick)
{
int i;
if (joystick->present)
{
joystick->present = GL_FALSE;
if (!joystick->present)
return;
for (i = 0; i < joystick->numAxes; i++)
{
_GLFWjoyelement* axes =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->axes, i);
free(axes);
}
CFArrayRemoveAllValues(joystick->axes);
joystick->numAxes = 0;
for (i = 0; i < CFArrayGetCount(joystick->axisElements); i++)
free((void*) CFArrayGetValueAtIndex(joystick->axisElements, i));
CFArrayRemoveAllValues(joystick->axisElements);
for (i = 0; i < joystick->numButtons; i++)
{
_GLFWjoyelement* button =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->buttons, i);
free(button);
}
CFArrayRemoveAllValues(joystick->buttons);
joystick->numButtons = 0;
for (i = 0; i < CFArrayGetCount(joystick->buttonElements); i++)
free((void*) CFArrayGetValueAtIndex(joystick->buttonElements, i));
CFArrayRemoveAllValues(joystick->buttonElements);
for (i = 0; i < joystick->numHats; i++)
{
_GLFWjoyelement* hat =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->hats, i);
free(hat);
}
CFArrayRemoveAllValues(joystick->hats);
joystick->hats = 0;
for (i = 0; i < CFArrayGetCount(joystick->hatElements); i++)
free((void*) CFArrayGetValueAtIndex(joystick->hatElements, i));
CFArrayRemoveAllValues(joystick->hatElements);
(*(joystick->interface))->close(joystick->interface);
(*(joystick->interface))->Release(joystick->interface);
free(joystick->axes);
free(joystick->buttons);
joystick->interface = NULL;
}
(*(joystick->interface))->close(joystick->interface);
(*(joystick->interface))->Release(joystick->interface);
memset(joystick, 0, sizeof(_GLFWjoy));
}
// Callback for user-initiated joystick removal
@ -244,34 +220,63 @@ static void removalCallback(void* target, IOReturn result, void* refcon, void* s
//
static void pollJoystickEvents(void)
{
int i;
CFIndex j;
int joy;
for (i = 0; i < GLFW_JOYSTICK_LAST + 1; i++)
for (joy = 0; joy <= GLFW_JOYSTICK_LAST; joy++)
{
_GLFWjoy* joystick = &_glfw.ns.joysticks[i];
CFIndex i;
int buttonIndex = 0;
_GLFWjoy* joystick = _glfw.ns.joysticks + joy;
if (joystick->present)
if (!joystick->present)
continue;
for (i = 0; i < CFArrayGetCount(joystick->buttonElements); i++)
{
for (j = 0; j < joystick->numButtons; j++)
{
_GLFWjoyelement* button =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->buttons, j);
button->value = getElementValue(joystick, button);
}
_GLFWjoyelement* button =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->buttonElements, i);
for (j = 0; j < joystick->numAxes; j++)
{
_GLFWjoyelement* axes =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->axes, j);
axes->value = getElementValue(joystick, axes);
}
if (getElementValue(joystick, button))
joystick->buttons[buttonIndex++] = GLFW_PRESS;
else
joystick->buttons[buttonIndex++] = GLFW_RELEASE;
}
for (j = 0; j < joystick->numHats; j++)
for (i = 0; i < CFArrayGetCount(joystick->axisElements); i++)
{
_GLFWjoyelement* axis =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->axisElements, i);
long value = getElementValue(joystick, axis);
long readScale = axis->maxReport - axis->minReport;
if (readScale == 0)
joystick->axes[i] = value;
else
joystick->axes[i] = (2.f * (value - axis->minReport) / readScale) - 1.f;
if (i & 1)
joystick->axes[i] = -joystick->axes[i];
}
for (i = 0; i < CFArrayGetCount(joystick->hatElements); i++)
{
_GLFWjoyelement* hat =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->hatElements, 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, value = getElementValue(joystick, hat);
if (value < 0 || value > 8)
value = 8;
for (j = 0; j < 4; j++)
{
_GLFWjoyelement* hat =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick->hats, j);
hat->value = getElementValue(joystick, hat);
if (directions[value] & (1 << j))
joystick->buttons[buttonIndex++] = GLFW_PRESS;
else
joystick->buttons[buttonIndex++] = GLFW_RELEASE;
}
}
}
@ -286,7 +291,7 @@ static void pollJoystickEvents(void)
//
void _glfwInitJoysticks(void)
{
int deviceCounter = 0;
int joy = 0;
IOReturn result = kIOReturnSuccess;
mach_port_t masterPort = 0;
io_iterator_t objectIterator = 0;
@ -318,7 +323,7 @@ void _glfwInitJoysticks(void)
while ((ioHIDDeviceObject = IOIteratorNext(objectIterator)))
{
kern_return_t result;
CFTypeRef refCF = 0;
CFTypeRef valueRef = 0;
IOCFPlugInInterface** ppPlugInInterface = NULL;
HRESULT plugInResult = S_OK;
@ -327,27 +332,29 @@ void _glfwInitJoysticks(void)
long usagePage, usage;
// Check device type
refCF = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
CFSTR(kIOHIDPrimaryUsagePageKey),
kCFAllocatorDefault,
kNilOptions);
if (refCF)
valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
CFSTR(kIOHIDPrimaryUsagePageKey),
kCFAllocatorDefault,
kNilOptions);
if (valueRef)
{
CFNumberGetValue(refCF, kCFNumberLongType, &usagePage);
CFNumberGetValue(valueRef, kCFNumberLongType, &usagePage);
if (usagePage != kHIDPage_GenericDesktop)
{
// This device is not relevant to GLFW
continue;
}
CFRelease(valueRef);
}
refCF = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
CFSTR(kIOHIDPrimaryUsageKey),
kCFAllocatorDefault,
kNilOptions);
if (refCF)
valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
CFSTR(kIOHIDPrimaryUsageKey),
kCFAllocatorDefault,
kNilOptions);
if (valueRef)
{
CFNumberGetValue(refCF, kCFNumberLongType, &usage);
CFNumberGetValue(valueRef, kCFNumberLongType, &usage);
if ((usage != kHIDUsage_GD_Joystick &&
usage != kHIDUsage_GD_GamePad &&
@ -356,10 +363,11 @@ void _glfwInitJoysticks(void)
// This device is not relevant to GLFW
continue;
}
CFRelease(valueRef);
}
_GLFWjoy* joystick = &_glfw.ns.joysticks[deviceCounter];
_GLFWjoy* joystick = _glfw.ns.joysticks + joy;
joystick->present = GL_TRUE;
result = IOCreatePlugInInterfaceForService(ioHIDDeviceObject,
@ -388,42 +396,45 @@ void _glfwInitJoysticks(void)
joystick);
// Get product string
refCF = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
CFSTR(kIOHIDProductKey),
kCFAllocatorDefault,
kNilOptions);
if (refCF)
valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
CFSTR(kIOHIDProductKey),
kCFAllocatorDefault,
kNilOptions);
if (valueRef)
{
CFStringGetCString(refCF,
CFStringGetCString(valueRef,
joystick->name,
sizeof(joystick->name),
kCFStringEncodingUTF8);
CFRelease(valueRef);
}
joystick->numAxes = 0;
joystick->numButtons = 0;
joystick->numHats = 0;
joystick->axes = CFArrayCreateMutable(NULL, 0, NULL);
joystick->buttons = CFArrayCreateMutable(NULL, 0, NULL);
joystick->hats = CFArrayCreateMutable(NULL, 0, NULL);
joystick->axisElements = CFArrayCreateMutable(NULL, 0, NULL);
joystick->buttonElements = CFArrayCreateMutable(NULL, 0, NULL);
joystick->hatElements = CFArrayCreateMutable(NULL, 0, NULL);
CFTypeRef refTopElement;
refTopElement = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
CFSTR(kIOHIDElementKey),
kCFAllocatorDefault,
kNilOptions);
CFTypeID type = CFGetTypeID(refTopElement);
if (type == CFArrayGetTypeID())
valueRef = IORegistryEntryCreateCFProperty(ioHIDDeviceObject,
CFSTR(kIOHIDElementKey),
kCFAllocatorDefault,
kNilOptions);
if (CFGetTypeID(valueRef) == CFArrayGetTypeID())
{
CFRange range = { 0, CFArrayGetCount(refTopElement) };
CFArrayApplyFunction(refTopElement,
CFRange range = { 0, CFArrayGetCount(valueRef) };
CFArrayApplyFunction(valueRef,
range,
getElementsCFArrayHandler,
(void*) joystick);
CFRelease(valueRef);
}
deviceCounter++;
joystick->axes = (float*) calloc(CFArrayGetCount(joystick->axisElements),
sizeof(float));
joystick->buttons = (unsigned char*) calloc(CFArrayGetCount(joystick->buttonElements) +
CFArrayGetCount(joystick->hatElements) * 4, 1);
joy++;
if (joy > GLFW_JOYSTICK_LAST)
break;
}
}
@ -445,118 +456,44 @@ void _glfwTerminateJoysticks(void)
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformGetJoystickParam(int joy, int param)
int _glfwPlatformJoystickPresent(int joy)
{
if (!_glfw.ns.joysticks[joy].present)
return GL_FALSE;
switch (param)
{
case GLFW_PRESENT:
return GL_TRUE;
case GLFW_AXES:
return (int) CFArrayGetCount(_glfw.ns.joysticks[joy].axes);
case GLFW_BUTTONS:
return (int) CFArrayGetCount(_glfw.ns.joysticks[joy].buttons) +
(int) CFArrayGetCount(_glfw.ns.joysticks[joy].hats) * 4;
default:
break;
}
return GL_FALSE;
}
int _glfwPlatformGetJoystickAxes(int joy, float* axes, int numaxes)
{
int i;
if (joy < GLFW_JOYSTICK_1 || joy > GLFW_JOYSTICK_LAST)
return 0;
_GLFWjoy joystick = _glfw.ns.joysticks[joy];
if (!joystick.present)
return 0;
numaxes = numaxes < joystick.numAxes ? numaxes : joystick.numAxes;
// Update joystick state
pollJoystickEvents();
for (i = 0; i < numaxes; i++)
{
_GLFWjoyelement* elements =
(_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick.axes, i);
long readScale = elements->maxReport - elements->minReport;
if (readScale == 0)
axes[i] = elements->value;
else
axes[i] = (2.0f * (elements->value - elements->minReport) / readScale) - 1.0f;
if (i & 1)
axes[i] = -axes[i];
}
return numaxes;
return _glfw.ns.joysticks[joy].present;
}
int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons,
int numbuttons)
float* _glfwPlatformGetJoystickAxes(int joy, int* count)
{
int i, j, button;
_GLFWjoy* joystick = _glfw.ns.joysticks + joy;
if (joy < GLFW_JOYSTICK_1 || joy > GLFW_JOYSTICK_LAST)
return 0;
_GLFWjoy joystick = _glfw.ns.joysticks[joy];
if (!joystick.present)
return 0;
// Update joystick state
pollJoystickEvents();
for (button = 0; button < numbuttons && button < joystick.numButtons; button++)
{
_GLFWjoyelement* element = (_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick.buttons, button);
buttons[button] = element->value ? GLFW_PRESS : GLFW_RELEASE;
}
if (!joystick->present)
return NULL;
// Virtual buttons - Inject data from hats
// Each hat is exposed as 4 buttons which exposes 8 directions with concurrent button presses
*count = (int) CFArrayGetCount(joystick->axisElements);
return joystick->axes;
}
// Bit fields of button presses for each direction, including nil
const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 };
unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
{
_GLFWjoy* joystick = _glfw.ns.joysticks + joy;
for (i = 0; i < joystick.numHats; i++)
{
_GLFWjoyelement* hat = (_GLFWjoyelement*) CFArrayGetValueAtIndex(joystick.hats, i);
pollJoystickEvents();
int value = hat->value;
if (value < 0 || value > 8)
value = 8;
if (!joystick->present)
return NULL;
for (j = 0; j < 4 && button < numbuttons; j++)
{
if (directions[value] & (1 << j))
buttons[button] = GLFW_PRESS;
else
buttons[button] = GLFW_RELEASE;
button++;
}
}
return button;
*count = (int) CFArrayGetCount(joystick->buttonElements) +
(int) CFArrayGetCount(joystick->hatElements) * 4;
return joystick->buttons;
}
const char* _glfwPlatformGetJoystickName(int joy)
{
pollJoystickEvents();
return _glfw.ns.joysticks[joy].name;
}

View File

@ -78,18 +78,17 @@ typedef struct _GLFWwindowNS
//------------------------------------------------------------------------
typedef struct
{
int present;
char name[256];
int present;
char name[256];
IOHIDDeviceInterface** interface;
int numAxes;
int numButtons;
int numHats;
CFMutableArrayRef axisElements;
CFMutableArrayRef buttonElements;
CFMutableArrayRef hatElements;
CFMutableArrayRef axes;
CFMutableArrayRef buttons;
CFMutableArrayRef hats;
float* axes;
unsigned char* buttons;
} _GLFWjoy;

View File

@ -407,20 +407,20 @@ void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string);
*/
const char* _glfwPlatformGetClipboardString(_GLFWwindow* window);
/*! @copydoc glfwGetJoystickParam
/*! @copydoc glfwJoystickPresent
* @ingroup platform
*/
int _glfwPlatformGetJoystickParam(int joy, int param);
int _glfwPlatformJoystickPresent(int joy);
/*! @copydoc glfwGetJoystickAxes
* @ingroup platform
*/
int _glfwPlatformGetJoystickAxes(int joy, float* axes, int numaxes);
float* _glfwPlatformGetJoystickAxes(int joy, int* count);
/*! @copydoc glfwGetJoystickButtons
* @ingroup platform
*/
int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons, int numbuttons);
unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count);
/*! @copydoc glfwGetJoystickName
* @ingroup platform

View File

@ -35,7 +35,7 @@
////// GLFW public API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI int glfwGetJoystickParam(int joy, int param)
GLFWAPI int glfwJoystickPresent(int joy)
{
_GLFW_REQUIRE_INIT_OR_RETURN(0);
@ -45,59 +45,37 @@ GLFWAPI int glfwGetJoystickParam(int joy, int param)
return 0;
}
return _glfwPlatformGetJoystickParam(joy, param);
return _glfwPlatformJoystickPresent(joy);
}
GLFWAPI int glfwGetJoystickAxes(int joy, float* axes, int numaxes)
GLFWAPI float* glfwGetJoystickAxes(int joy, int* count)
{
int i;
*count = 0;
_GLFW_REQUIRE_INIT_OR_RETURN(0);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
{
_glfwInputError(GLFW_INVALID_ENUM, NULL);
return 0;
return NULL;
}
if (axes == NULL || numaxes < 0)
{
_glfwInputError(GLFW_INVALID_VALUE, NULL);
return 0;
}
// Clear positions
for (i = 0; i < numaxes; i++)
axes[i] = 0.0f;
return _glfwPlatformGetJoystickAxes(joy, axes, numaxes);
return _glfwPlatformGetJoystickAxes(joy, count);
}
GLFWAPI int glfwGetJoystickButtons(int joy,
unsigned char* buttons,
int numbuttons)
GLFWAPI unsigned char* glfwGetJoystickButtons(int joy, int* count)
{
int i;
*count = 0;
_GLFW_REQUIRE_INIT_OR_RETURN(0);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
{
_glfwInputError(GLFW_INVALID_ENUM, NULL);
return 0;
return NULL;
}
if (buttons == NULL || numbuttons < 0)
{
_glfwInputError(GLFW_INVALID_VALUE, NULL);
return 0;
}
// Clear button states
for (i = 0; i < numbuttons; i++)
buttons[i] = GLFW_RELEASE;
return _glfwPlatformGetJoystickButtons(joy, buttons, numbuttons);
return _glfwPlatformGetJoystickButtons(joy, count);
}
GLFWAPI const char* glfwGetJoystickName(int joy)

View File

@ -37,23 +37,6 @@
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
// Return GL_TRUE if joystick is present, otherwise GL_FALSE
//
static GLboolean isJoystickPresent(int joy)
{
JOYINFO ji;
// Is it a valid stick ID (Windows don't support more than 16 sticks)?
if (joy < GLFW_JOYSTICK_1 || joy > GLFW_JOYSTICK_16)
return GL_FALSE;
// Is the joystick present?
if (_glfw_joyGetPos(joy - GLFW_JOYSTICK_1, &ji) != JOYERR_NOERROR)
return GL_FALSE;
return GL_TRUE;
}
// Calculate normalized joystick position
//
static float calcJoystickPos(DWORD pos, DWORD min, DWORD max)
@ -91,107 +74,68 @@ void _glfwTerminateJoysticks(void)
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformGetJoystickParam(int joy, int param)
int _glfwPlatformJoystickPresent(int joy)
{
JOYCAPS jc;
int hats;
JOYINFO ji;
if (!isJoystickPresent(joy))
return 0;
if (_glfw_joyGetPos(joy, &ji) != JOYERR_NOERROR)
return GL_FALSE;
// We got this far, the joystick is present
if (param == GLFW_PRESENT)
return GL_TRUE;
// Get joystick capabilities
_glfw_joyGetDevCaps(joy - GLFW_JOYSTICK_1, &jc, sizeof(JOYCAPS));
hats = (jc.wCaps & JOYCAPS_HASPOV) && (jc.wCaps & JOYCAPS_POV4DIR) ? 1 : 0;
switch (param)
{
case GLFW_AXES:
// Return number of joystick axes
return jc.wNumAxes;
case GLFW_BUTTONS:
// Return number of joystick buttons
return jc.wNumButtons + hats * 4;
default:
break;
}
return 0;
return GL_TRUE;
}
int _glfwPlatformGetJoystickAxes(int joy, float* axes, int numaxes)
float* _glfwPlatformGetJoystickAxes(int joy, int* count)
{
JOYCAPS jc;
JOYINFOEX ji;
int axis;
float* axes = _glfw.win32.joystick[joy].axes;
if (!isJoystickPresent(joy))
return 0;
if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR)
return NULL;
// Get joystick capabilities
_glfw_joyGetDevCaps(joy - GLFW_JOYSTICK_1, &jc, sizeof(JOYCAPS));
// Get joystick state
ji.dwSize = sizeof(JOYINFOEX);
ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ |
JOY_RETURNR | JOY_RETURNU | JOY_RETURNV;
_glfw_joyGetPosEx(joy - GLFW_JOYSTICK_1, &ji);
if (_glfw_joyGetPosEx(joy, &ji) != JOYERR_NOERROR)
return NULL;
// Get position values for all axes
axis = 0;
if (axis < numaxes)
axes[axis++] = calcJoystickPos(ji.dwXpos, jc.wXmin, jc.wXmax);
axes[(*count)++] = calcJoystickPos(ji.dwXpos, jc.wXmin, jc.wXmax);
axes[(*count)++] = -calcJoystickPos(ji.dwYpos, jc.wYmin, jc.wYmax);
if (axis < numaxes)
axes[axis++] = -calcJoystickPos(ji.dwYpos, jc.wYmin, jc.wYmax);
if (jc.wCaps & JOYCAPS_HASZ)
axes[(*count)++] = calcJoystickPos(ji.dwZpos, jc.wZmin, jc.wZmax);
if (axis < numaxes && jc.wCaps & JOYCAPS_HASZ)
axes[axis++] = calcJoystickPos(ji.dwZpos, jc.wZmin, jc.wZmax);
if (jc.wCaps & JOYCAPS_HASR)
axes[(*count)++] = calcJoystickPos(ji.dwRpos, jc.wRmin, jc.wRmax);
if (axis < numaxes && jc.wCaps & JOYCAPS_HASR)
axes[axis++] = calcJoystickPos(ji.dwRpos, jc.wRmin, jc.wRmax);
if (jc.wCaps & JOYCAPS_HASU)
axes[(*count)++] = calcJoystickPos(ji.dwUpos, jc.wUmin, jc.wUmax);
if (axis < numaxes && jc.wCaps & JOYCAPS_HASU)
axes[axis++] = calcJoystickPos(ji.dwUpos, jc.wUmin, jc.wUmax);
if (jc.wCaps & JOYCAPS_HASV)
axes[(*count)++] = -calcJoystickPos(ji.dwVpos, jc.wVmin, jc.wVmax);
if (axis < numaxes && jc.wCaps & JOYCAPS_HASV)
axes[axis++] = -calcJoystickPos(ji.dwVpos, jc.wVmin, jc.wVmax);
return axis;
return axes;
}
int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons,
int numbuttons)
unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
{
JOYCAPS jc;
JOYINFOEX ji;
int button, hats;
unsigned char* buttons = _glfw.win32.joystick[joy].buttons;
// Bit fields of button presses for each direction, including nil
const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 };
if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR)
return NULL;
if (!isJoystickPresent(joy))
return 0;
// Get joystick capabilities
_glfw_joyGetDevCaps(joy - GLFW_JOYSTICK_1, &jc, sizeof(JOYCAPS));
// Get joystick state
ji.dwSize = sizeof(JOYINFOEX);
ji.dwFlags = JOY_RETURNBUTTONS | JOY_RETURNPOV;
_glfw_joyGetPosEx(joy - GLFW_JOYSTICK_1, &ji);
if (_glfw_joyGetPosEx(joy, &ji) != JOYERR_NOERROR)
return NULL;
// Get states of all requested buttons
for (button = 0; button < numbuttons && button < (int) jc.wNumButtons; button++)
while (*count < jc.wNumButtons)
{
buttons[button] = (unsigned char)
(ji.dwButtons & (1UL << button) ? GLFW_PRESS : GLFW_RELEASE);
buttons[*count] = (unsigned char)
(ji.dwButtons & (1UL << *count) ? GLFW_PRESS : GLFW_RELEASE);
(*count)++;
}
// Virtual buttons - Inject data from hats
@ -199,42 +143,38 @@ int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons,
// concurrent button presses
// NOTE: this API exposes only one hat
hats = (jc.wCaps & JOYCAPS_HASPOV) && (jc.wCaps & JOYCAPS_POV4DIR) ? 1 : 0;
if (hats > 0)
if ((jc.wCaps & JOYCAPS_HASPOV) && (jc.wCaps & JOYCAPS_POV4DIR))
{
int j, value = ji.dwPOV / 100 / 45;
int i, value = ji.dwPOV / 100 / 45;
// Bit fields of button presses for each direction, including nil
const int directions[9] = { 1, 3, 2, 6, 4, 12, 8, 9, 0 };
if (value < 0 || value > 8)
value = 8;
for (j = 0; j < 4 && button < numbuttons; j++)
for (i = 0; i < 4; i++)
{
if (directions[value] & (1 << j))
buttons[button] = GLFW_PRESS;
if (directions[value] & (1 << i))
buttons[(*count)++] = GLFW_PRESS;
else
buttons[button] = GLFW_RELEASE;
button++;
buttons[(*count)++] = GLFW_RELEASE;
}
}
return button;
return buttons;
}
const char* _glfwPlatformGetJoystickName(int joy)
{
JOYCAPS jc;
const int i = joy - GLFW_JOYSTICK_1;
if (!isJoystickPresent(joy))
if (_glfw_joyGetDevCaps(joy, &jc, sizeof(JOYCAPS)) != JOYERR_NOERROR)
return NULL;
_glfw_joyGetDevCaps(i, &jc, sizeof(JOYCAPS));
free(_glfw.win32.joystick[joy].name);
_glfw.win32.joystick[joy].name = _glfwCreateUTF8FromWideString(jc.szPname);
free(_glfw.win32.joystick[i].name);
_glfw.win32.joystick[i].name = _glfwCreateUTF8FromWideString(jc.szPname);
return _glfw.win32.joystick[i].name;
return _glfw.win32.joystick[joy].name;
}

View File

@ -200,6 +200,8 @@ typedef struct _GLFWlibraryWin32
} dwmapi;
struct {
float axes[6];
unsigned char buttons[36]; // 32 buttons plus one hat
char* name;
} joystick[GLFW_JOYSTICK_LAST + 1];

View File

@ -50,7 +50,7 @@
static int openJoystickDevice(int joy, const char* path)
{
#ifdef __linux__
char numAxes, numButtons;
char axisCount, buttonCount;
char name[256];
int fd, version;
@ -74,14 +74,14 @@ static int openJoystickDevice(int joy, const char* path)
_glfw.x11.joystick[joy].name = strdup(name);
ioctl(fd, JSIOCGAXES, &numAxes);
_glfw.x11.joystick[joy].numAxes = (int) numAxes;
ioctl(fd, JSIOCGAXES, &axisCount);
_glfw.x11.joystick[joy].axisCount = (int) axisCount;
ioctl(fd, JSIOCGBUTTONS, &numButtons);
_glfw.x11.joystick[joy].numButtons = (int) numButtons;
ioctl(fd, JSIOCGBUTTONS, &buttonCount);
_glfw.x11.joystick[joy].buttonCount = (int) buttonCount;
_glfw.x11.joystick[joy].axis = (float*) calloc(numAxes, sizeof(float));
_glfw.x11.joystick[joy].button = (unsigned char*) calloc(numButtons, 1);
_glfw.x11.joystick[joy].axes = (float*) calloc(axisCount, sizeof(float));
_glfw.x11.joystick[joy].buttons = (unsigned char*) calloc(buttonCount, 1);
_glfw.x11.joystick[joy].present = GL_TRUE;
#endif // __linux__
@ -110,7 +110,12 @@ static void pollJoystickEvents(void)
result = read(_glfw.x11.joystick[i].fd, &e, sizeof(e));
if (errno == ENODEV)
{
free(_glfw.x11.joystick[i].axes);
free(_glfw.x11.joystick[i].buttons);
free(_glfw.x11.joystick[i].name);
_glfw.x11.joystick[i].present = GL_FALSE;
}
if (result == -1)
break;
@ -121,21 +126,21 @@ static void pollJoystickEvents(void)
switch (e.type)
{
case JS_EVENT_AXIS:
_glfw.x11.joystick[i].axis[e.number] =
_glfw.x11.joystick[i].axes[e.number] =
(float) e.value / 32767.0f;
// We need to change the sign for the Y axes, so that
// positive = up/forward, according to the GLFW spec.
if (e.number & 1)
{
_glfw.x11.joystick[i].axis[e.number] =
-_glfw.x11.joystick[i].axis[e.number];
_glfw.x11.joystick[i].axes[e.number] =
-_glfw.x11.joystick[i].axes[e.number];
}
break;
case JS_EVENT_BUTTON:
_glfw.x11.joystick[i].button[e.number] =
_glfw.x11.joystick[i].buttons[e.number] =
e.value ? GLFW_PRESS : GLFW_RELEASE;
break;
@ -214,8 +219,8 @@ void _glfwTerminateJoysticks(void)
if (_glfw.x11.joystick[i].present)
{
close(_glfw.x11.joystick[i].fd);
free(_glfw.x11.joystick[i].axis);
free(_glfw.x11.joystick[i].button);
free(_glfw.x11.joystick[i].axes);
free(_glfw.x11.joystick[i].buttons);
free(_glfw.x11.joystick[i].name);
_glfw.x11.joystick[i].present = GL_FALSE;
@ -229,72 +234,38 @@ void _glfwTerminateJoysticks(void)
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwPlatformGetJoystickParam(int joy, int param)
int _glfwPlatformJoystickPresent(int joy)
{
pollJoystickEvents();
if (!_glfw.x11.joystick[joy].present)
return 0;
switch (param)
{
case GLFW_PRESENT:
return GL_TRUE;
case GLFW_AXES:
return _glfw.x11.joystick[joy].numAxes;
case GLFW_BUTTONS:
return _glfw.x11.joystick[joy].numButtons;
default:
_glfwInputError(GLFW_INVALID_ENUM, NULL);
}
return 0;
return _glfw.x11.joystick[joy].present;
}
int _glfwPlatformGetJoystickAxes(int joy, float* axes, int numAxes)
float* _glfwPlatformGetJoystickAxes(int joy, int* count)
{
int i;
pollJoystickEvents();
if (!_glfw.x11.joystick[joy].present)
return 0;
return NULL;
if (_glfw.x11.joystick[joy].numAxes < numAxes)
numAxes = _glfw.x11.joystick[joy].numAxes;
for (i = 0; i < numAxes; i++)
axes[i] = _glfw.x11.joystick[joy].axis[i];
return numAxes;
*count = _glfw.x11.joystick[joy].axisCount;
return _glfw.x11.joystick[joy].axes;
}
int _glfwPlatformGetJoystickButtons(int joy, unsigned char* buttons,
int numButtons)
unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count)
{
int i;
pollJoystickEvents();
if (!_glfw.x11.joystick[joy].present)
return 0;
return NULL;
if (_glfw.x11.joystick[joy].numButtons < numButtons)
numButtons = _glfw.x11.joystick[joy].numButtons;
for (i = 0; i < numButtons; i++)
buttons[i] = _glfw.x11.joystick[joy].button[i];
return numButtons;
*count = _glfw.x11.joystick[joy].buttonCount;
return _glfw.x11.joystick[joy].buttons;
}
const char* _glfwPlatformGetJoystickName(int joy)
{
if (!_glfw.x11.joystick[joy].present)
return NULL;
pollJoystickEvents();
return _glfw.x11.joystick[joy].name;
}

View File

@ -189,10 +189,10 @@ typedef struct _GLFWlibraryX11
struct {
int present;
int fd;
int numAxes;
int numButtons;
float* axis;
unsigned char* button;
float* axes;
int axisCount;
unsigned char* buttons;
int buttonCount;
char* name;
} joystick[GLFW_JOYSTICK_LAST + 1];

View File

@ -136,30 +136,32 @@ static void refresh_joysticks(void)
{
Joystick* j = joysticks + i;
if (glfwGetJoystickParam(GLFW_JOYSTICK_1 + i, GLFW_PRESENT))
if (glfwJoystickPresent(GLFW_JOYSTICK_1 + i))
{
float* axes;
unsigned char* buttons;
int axis_count, button_count;
free(j->name);
j->name = strdup(glfwGetJoystickName(GLFW_JOYSTICK_1 + i));
axis_count = glfwGetJoystickParam(GLFW_JOYSTICK_1 + i, GLFW_AXES);
axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1 + i, &axis_count);
if (axis_count != j->axis_count)
{
j->axis_count = axis_count;
j->axes = realloc(j->axes, j->axis_count * sizeof(float));
}
glfwGetJoystickAxes(GLFW_JOYSTICK_1 + i, j->axes, j->axis_count);
memcpy(j->axes, axes, axis_count * sizeof(float));
button_count = glfwGetJoystickParam(GLFW_JOYSTICK_1 + i, GLFW_BUTTONS);
buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1 + i, &button_count);
if (button_count != j->button_count)
{
j->button_count = button_count;
j->buttons = realloc(j->buttons, j->button_count);
}
glfwGetJoystickButtons(GLFW_JOYSTICK_1 + i, j->buttons, j->button_count);
memcpy(j->buttons, buttons, button_count * sizeof(unsigned char));
if (!j->present)
{