|
|
@@ -1,525 +0,0 @@
|
|
|
-/*
|
|
|
- Copyright (c) 2010 Alex Diener
|
|
|
-
|
|
|
- This software is provided 'as-is', without any express or implied
|
|
|
- warranty. In no event will the authors be held liable for any damages
|
|
|
- arising from the use of this software.
|
|
|
-
|
|
|
- Permission is granted to anyone to use this software for any purpose,
|
|
|
- including commercial applications, and to alter it and redistribute it
|
|
|
- freely, subject to the following restrictions:
|
|
|
-
|
|
|
- 1. The origin of this software must not be misrepresented; you must not
|
|
|
- claim that you wrote the original software. If you use this software
|
|
|
- in a product, an acknowledgment in the product documentation would be
|
|
|
- appreciated but is not required.
|
|
|
- 2. Altered source versions must be plainly marked as such, and must not be
|
|
|
- misrepresented as being the original software.
|
|
|
- 3. This notice may not be removed or altered from any source distribution.
|
|
|
-
|
|
|
- Alex Diener [email protected]
|
|
|
-*/
|
|
|
-
|
|
|
-#include "gamepad/Gamepad.h"
|
|
|
-#include <IOKit/hid/IOHIDLib.h>
|
|
|
-#include <limits.h>
|
|
|
-#include <mach/mach.h>
|
|
|
-#include <mach/mach_time.h>
|
|
|
-
|
|
|
-struct HIDGamepadAxis {
|
|
|
- IOHIDElementCookie cookie;
|
|
|
- CFIndex logicalMin;
|
|
|
- CFIndex logicalMax;
|
|
|
- bool hasNullState;
|
|
|
- bool isHatSwitch;
|
|
|
- bool isHatSwitchSecondAxis;
|
|
|
-};
|
|
|
-
|
|
|
-struct HIDGamepadButton {
|
|
|
- IOHIDElementCookie cookie;
|
|
|
-};
|
|
|
-
|
|
|
-struct Gamepad_devicePrivate {
|
|
|
- IOHIDDeviceRef deviceRef;
|
|
|
- struct HIDGamepadAxis * axisElements;
|
|
|
- struct HIDGamepadButton * buttonElements;
|
|
|
-};
|
|
|
-
|
|
|
-struct Gamepad_queuedEvent {
|
|
|
- EventDispatcher * dispatcher;
|
|
|
- const char * eventType;
|
|
|
- void * eventData;
|
|
|
-};
|
|
|
-
|
|
|
-static IOHIDManagerRef hidManager = NULL;
|
|
|
-static struct Gamepad_device ** devices = NULL;
|
|
|
-static unsigned int numDevices = 0;
|
|
|
-static unsigned int nextDeviceID = 0;
|
|
|
-
|
|
|
-static struct Gamepad_queuedEvent * inputEventQueue = NULL;
|
|
|
-static size_t inputEventQueueSize = 0;
|
|
|
-static size_t inputEventCount = 0;
|
|
|
-
|
|
|
-static struct Gamepad_queuedEvent * deviceEventQueue = NULL;
|
|
|
-static size_t deviceEventQueueSize = 0;
|
|
|
-static size_t deviceEventCount = 0;
|
|
|
-
|
|
|
-static EventDispatcher * eventDispatcher = NULL;
|
|
|
-
|
|
|
-static void hatValueToXY(CFIndex value, CFIndex range, int * outX, int * outY) {
|
|
|
- if (value == range) {
|
|
|
- *outX = *outY = 0;
|
|
|
-
|
|
|
- } else {
|
|
|
- if (value > 0 && value < range / 2) {
|
|
|
- *outX = 1;
|
|
|
-
|
|
|
- } else if (value > range / 2) {
|
|
|
- *outX = -1;
|
|
|
-
|
|
|
- } else {
|
|
|
- *outX = 0;
|
|
|
- }
|
|
|
-
|
|
|
- if (value > range / 4 * 3 || value < range / 4) {
|
|
|
- *outY = -1;
|
|
|
-
|
|
|
- } else if (value > range / 4 && value < range / 4 * 3) {
|
|
|
- *outY = 1;
|
|
|
-
|
|
|
- } else {
|
|
|
- *outY = 0;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static void queueInputEvent(EventDispatcher * dispatcher, const char * eventType, void * eventData) {
|
|
|
- struct Gamepad_queuedEvent queuedEvent;
|
|
|
-
|
|
|
- queuedEvent.dispatcher = dispatcher;
|
|
|
- queuedEvent.eventType = eventType;
|
|
|
- queuedEvent.eventData = eventData;
|
|
|
-
|
|
|
- if (inputEventCount >= inputEventQueueSize) {
|
|
|
- inputEventQueueSize = inputEventQueueSize == 0 ? 1 : inputEventQueueSize * 2;
|
|
|
- inputEventQueue = realloc(inputEventQueue, sizeof(struct Gamepad_queuedEvent) * inputEventQueueSize);
|
|
|
- }
|
|
|
- inputEventQueue[inputEventCount++] = queuedEvent;
|
|
|
-}
|
|
|
-
|
|
|
-static void queueAxisEvent(struct Gamepad_device * device, double timestamp, unsigned int axisID, float value) {
|
|
|
- struct Gamepad_axisEvent * axisEvent;
|
|
|
-
|
|
|
- axisEvent = malloc(sizeof(struct Gamepad_axisEvent));
|
|
|
- axisEvent->device = device;
|
|
|
- axisEvent->timestamp = timestamp;
|
|
|
- axisEvent->axisID = axisID;
|
|
|
- axisEvent->value = value;
|
|
|
-
|
|
|
- queueInputEvent(device->eventDispatcher, GAMEPAD_EVENT_AXIS_MOVED, axisEvent);
|
|
|
-}
|
|
|
-
|
|
|
-static void queueButtonEvent(struct Gamepad_device * device, double timestamp, unsigned int buttonID, bool down) {
|
|
|
- struct Gamepad_buttonEvent * buttonEvent;
|
|
|
-
|
|
|
- buttonEvent = malloc(sizeof(struct Gamepad_buttonEvent));
|
|
|
- buttonEvent->device = device;
|
|
|
- buttonEvent->timestamp = timestamp;
|
|
|
- buttonEvent->buttonID = buttonID;
|
|
|
- buttonEvent->down = down;
|
|
|
-
|
|
|
- queueInputEvent(device->eventDispatcher, down ? GAMEPAD_EVENT_BUTTON_DOWN : GAMEPAD_EVENT_BUTTON_UP, buttonEvent);
|
|
|
-}
|
|
|
-
|
|
|
-static void onDeviceValueChanged(void * context, IOReturn result, void * sender, IOHIDValueRef value) {
|
|
|
- struct Gamepad_device * deviceRecord;
|
|
|
- struct Gamepad_devicePrivate * hidDeviceRecord;
|
|
|
- IOHIDElementRef element;
|
|
|
- IOHIDElementCookie cookie;
|
|
|
- unsigned int axisIndex, buttonIndex;
|
|
|
- static mach_timebase_info_data_t timebaseInfo;
|
|
|
-
|
|
|
- if (timebaseInfo.denom == 0) {
|
|
|
- mach_timebase_info(&timebaseInfo);
|
|
|
- }
|
|
|
-
|
|
|
- deviceRecord = context;
|
|
|
- hidDeviceRecord = deviceRecord->privateData;
|
|
|
- element = IOHIDValueGetElement(value);
|
|
|
- cookie = IOHIDElementGetCookie(element);
|
|
|
-
|
|
|
- for (axisIndex = 0; axisIndex < deviceRecord->numAxes; axisIndex++) {
|
|
|
- if (!hidDeviceRecord->axisElements[axisIndex].isHatSwitchSecondAxis &&
|
|
|
- hidDeviceRecord->axisElements[axisIndex].cookie == cookie) {
|
|
|
- CFIndex integerValue;
|
|
|
-
|
|
|
- if (IOHIDValueGetLength(value) > 4) {
|
|
|
- // Workaround for a strange crash that occurs with PS3 controller; was getting lengths of 39 (!)
|
|
|
- continue;
|
|
|
- }
|
|
|
- integerValue = IOHIDValueGetIntegerValue(value);
|
|
|
-
|
|
|
- if (hidDeviceRecord->axisElements[axisIndex].isHatSwitch) {
|
|
|
- int x, y;
|
|
|
-
|
|
|
- // Fix for Saitek X52
|
|
|
- hidDeviceRecord->axisElements[axisIndex].hasNullState = false;
|
|
|
- if (!hidDeviceRecord->axisElements[axisIndex].hasNullState) {
|
|
|
- if (integerValue < hidDeviceRecord->axisElements[axisIndex].logicalMin) {
|
|
|
- integerValue = hidDeviceRecord->axisElements[axisIndex].logicalMax - hidDeviceRecord->axisElements[axisIndex].logicalMin + 1;
|
|
|
- } else {
|
|
|
- integerValue--;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- hatValueToXY(integerValue, hidDeviceRecord->axisElements[axisIndex].logicalMax - hidDeviceRecord->axisElements[axisIndex].logicalMin + 1, &x, &y);
|
|
|
-
|
|
|
- if (x != deviceRecord->axisStates[axisIndex]) {
|
|
|
- queueAxisEvent(deviceRecord,
|
|
|
- IOHIDValueGetTimeStamp(value) * timebaseInfo.numer / timebaseInfo.denom * 0.000000001,
|
|
|
- axisIndex,
|
|
|
- x);
|
|
|
-
|
|
|
- deviceRecord->axisStates[axisIndex] = x;
|
|
|
- }
|
|
|
-
|
|
|
- if (y != deviceRecord->axisStates[axisIndex + 1]) {
|
|
|
- queueAxisEvent(deviceRecord,
|
|
|
- IOHIDValueGetTimeStamp(value) * timebaseInfo.numer / timebaseInfo.denom * 0.000000001,
|
|
|
- axisIndex + 1,
|
|
|
- y);
|
|
|
-
|
|
|
- deviceRecord->axisStates[axisIndex + 1] = y;
|
|
|
- }
|
|
|
-
|
|
|
- } else {
|
|
|
- float floatValue;
|
|
|
-
|
|
|
- if (integerValue < hidDeviceRecord->axisElements[axisIndex].logicalMin) {
|
|
|
- hidDeviceRecord->axisElements[axisIndex].logicalMin = integerValue;
|
|
|
- }
|
|
|
- if (integerValue > hidDeviceRecord->axisElements[axisIndex].logicalMax) {
|
|
|
- hidDeviceRecord->axisElements[axisIndex].logicalMax = integerValue;
|
|
|
- }
|
|
|
- floatValue = (integerValue - hidDeviceRecord->axisElements[axisIndex].logicalMin) / (float) (hidDeviceRecord->axisElements[axisIndex].logicalMax - hidDeviceRecord->axisElements[axisIndex].logicalMin) * 2.0f - 1.0f;
|
|
|
-
|
|
|
- queueAxisEvent(deviceRecord,
|
|
|
- IOHIDValueGetTimeStamp(value) * timebaseInfo.numer / timebaseInfo.denom * 0.000000001,
|
|
|
- axisIndex,
|
|
|
- floatValue);
|
|
|
-
|
|
|
- deviceRecord->axisStates[axisIndex] = floatValue;
|
|
|
- }
|
|
|
-
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- for (buttonIndex = 0; buttonIndex < deviceRecord->numButtons; buttonIndex++) {
|
|
|
- if (hidDeviceRecord->buttonElements[buttonIndex].cookie == cookie) {
|
|
|
- bool down;
|
|
|
-
|
|
|
- down = IOHIDValueGetIntegerValue(value);
|
|
|
- queueButtonEvent(deviceRecord,
|
|
|
- IOHIDValueGetTimeStamp(value) * timebaseInfo.numer / timebaseInfo.denom * 0.000000001,
|
|
|
- buttonIndex,
|
|
|
- down);
|
|
|
-
|
|
|
- deviceRecord->buttonStates[buttonIndex] = down;
|
|
|
-
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static int IOHIDDeviceGetIntProperty(IOHIDDeviceRef deviceRef, CFStringRef key) {
|
|
|
- CFTypeRef typeRef;
|
|
|
- int value;
|
|
|
-
|
|
|
- typeRef = IOHIDDeviceGetProperty(deviceRef, key);
|
|
|
- if (typeRef == NULL || CFGetTypeID(typeRef) != CFNumberGetTypeID()) {
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- CFNumberGetValue((CFNumberRef) typeRef, kCFNumberSInt32Type, &value);
|
|
|
- return value;
|
|
|
-}
|
|
|
-
|
|
|
-static int IOHIDDeviceGetVendorID(IOHIDDeviceRef deviceRef) {
|
|
|
- return IOHIDDeviceGetIntProperty(deviceRef, CFSTR(kIOHIDVendorIDKey));
|
|
|
-}
|
|
|
-
|
|
|
-static int IOHIDDeviceGetProductID(IOHIDDeviceRef deviceRef) {
|
|
|
- return IOHIDDeviceGetIntProperty(deviceRef, CFSTR(kIOHIDProductIDKey));
|
|
|
-}
|
|
|
-
|
|
|
-static void onDeviceMatched(void * context, IOReturn result, void * sender, IOHIDDeviceRef device) {
|
|
|
- CFArrayRef elements;
|
|
|
- CFIndex elementIndex;
|
|
|
- IOHIDElementRef element;
|
|
|
- CFStringRef cfProductName;
|
|
|
- struct Gamepad_device * deviceRecord;
|
|
|
- struct Gamepad_devicePrivate * hidDeviceRecord;
|
|
|
- IOHIDElementType type;
|
|
|
- char * description;
|
|
|
- struct Gamepad_queuedEvent queuedEvent;
|
|
|
-
|
|
|
- deviceRecord = malloc(sizeof(struct Gamepad_device));
|
|
|
- deviceRecord->deviceID = nextDeviceID++;
|
|
|
- deviceRecord->vendorID = IOHIDDeviceGetVendorID(device);
|
|
|
- deviceRecord->productID = IOHIDDeviceGetProductID(device);
|
|
|
- deviceRecord->numAxes = 0;
|
|
|
- deviceRecord->numButtons = 0;
|
|
|
- deviceRecord->eventDispatcher = EventDispatcher_create(deviceRecord);
|
|
|
- devices = realloc(devices, sizeof(struct Gamepad_device *) * (numDevices + 1));
|
|
|
- devices[numDevices++] = deviceRecord;
|
|
|
-
|
|
|
- hidDeviceRecord = malloc(sizeof(struct Gamepad_devicePrivate));
|
|
|
- hidDeviceRecord->deviceRef = device;
|
|
|
- hidDeviceRecord->axisElements = NULL;
|
|
|
- hidDeviceRecord->buttonElements = NULL;
|
|
|
- deviceRecord->privateData = hidDeviceRecord;
|
|
|
-
|
|
|
- cfProductName = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
|
|
|
- if (cfProductName == NULL || CFGetTypeID(cfProductName) != CFStringGetTypeID()) {
|
|
|
- description = malloc(strlen("[Unknown]" + 1));
|
|
|
- strcpy(description, "[Unknown]");
|
|
|
-
|
|
|
- } else {
|
|
|
- const char * cStringPtr;
|
|
|
-
|
|
|
- cStringPtr = CFStringGetCStringPtr(cfProductName, CFStringGetSmallestEncoding(cfProductName));
|
|
|
- description = malloc(strlen(cStringPtr + 1));
|
|
|
- strcpy(description, cStringPtr);
|
|
|
- }
|
|
|
- deviceRecord->description = description;
|
|
|
-
|
|
|
- elements = IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone);
|
|
|
- for (elementIndex = 0; elementIndex < CFArrayGetCount(elements); elementIndex++) {
|
|
|
- element = (IOHIDElementRef) CFArrayGetValueAtIndex(elements, elementIndex);
|
|
|
- type = IOHIDElementGetType(element);
|
|
|
-
|
|
|
- // All of the axis elements I've ever detected have been kIOHIDElementTypeInput_Misc. kIOHIDElementTypeInput_Axis is only included for good faith...
|
|
|
- if (type == kIOHIDElementTypeInput_Misc ||
|
|
|
- type == kIOHIDElementTypeInput_Axis) {
|
|
|
-
|
|
|
- hidDeviceRecord->axisElements = realloc(hidDeviceRecord->axisElements, sizeof(struct HIDGamepadAxis) * (deviceRecord->numAxes + 1));
|
|
|
- hidDeviceRecord->axisElements[deviceRecord->numAxes].cookie = IOHIDElementGetCookie(element);
|
|
|
- hidDeviceRecord->axisElements[deviceRecord->numAxes].logicalMin = IOHIDElementGetLogicalMin(element);
|
|
|
- hidDeviceRecord->axisElements[deviceRecord->numAxes].logicalMax = IOHIDElementGetLogicalMax(element);
|
|
|
- hidDeviceRecord->axisElements[deviceRecord->numAxes].hasNullState = !!IOHIDElementHasNullState(element);
|
|
|
- hidDeviceRecord->axisElements[deviceRecord->numAxes].isHatSwitch = IOHIDElementGetUsage(element) == kHIDUsage_GD_Hatswitch;
|
|
|
- hidDeviceRecord->axisElements[deviceRecord->numAxes].isHatSwitchSecondAxis = false;
|
|
|
- deviceRecord->numAxes++;
|
|
|
-
|
|
|
- if (hidDeviceRecord->axisElements[deviceRecord->numAxes - 1].isHatSwitch) {
|
|
|
- hidDeviceRecord->axisElements = realloc(hidDeviceRecord->axisElements, sizeof(struct HIDGamepadAxis) * (deviceRecord->numAxes + 1));
|
|
|
- hidDeviceRecord->axisElements[deviceRecord->numAxes].isHatSwitchSecondAxis = true;
|
|
|
- deviceRecord->numAxes++;
|
|
|
- }
|
|
|
-
|
|
|
- } else if (type == kIOHIDElementTypeInput_Button) {
|
|
|
- hidDeviceRecord->buttonElements = realloc(hidDeviceRecord->buttonElements, sizeof(struct HIDGamepadButton) * (deviceRecord->numButtons + 1));
|
|
|
- hidDeviceRecord->buttonElements[deviceRecord->numButtons].cookie = IOHIDElementGetCookie(element);
|
|
|
- deviceRecord->numButtons++;
|
|
|
- }
|
|
|
- }
|
|
|
- CFRelease(elements);
|
|
|
-
|
|
|
- deviceRecord->axisStates = calloc(sizeof(float), deviceRecord->numAxes);
|
|
|
- deviceRecord->buttonStates = calloc(sizeof(bool), deviceRecord->numButtons);
|
|
|
-
|
|
|
- IOHIDDeviceRegisterInputValueCallback(device, onDeviceValueChanged, deviceRecord);
|
|
|
-
|
|
|
- queuedEvent.dispatcher = Gamepad_eventDispatcher();
|
|
|
- queuedEvent.eventType = GAMEPAD_EVENT_DEVICE_ATTACHED;
|
|
|
- queuedEvent.eventData = deviceRecord;
|
|
|
-
|
|
|
- if (deviceEventCount >= deviceEventQueueSize) {
|
|
|
- deviceEventQueueSize = deviceEventQueueSize == 0 ? 1 : deviceEventQueueSize * 2;
|
|
|
- deviceEventQueue = realloc(deviceEventQueue, sizeof(struct Gamepad_queuedEvent) * deviceEventQueueSize);
|
|
|
- }
|
|
|
- deviceEventQueue[deviceEventCount++] = queuedEvent;
|
|
|
-}
|
|
|
-
|
|
|
-static void disposeDevice(struct Gamepad_device * deviceRecord) {
|
|
|
- unsigned int inputEventIndex, deviceEventIndex;
|
|
|
-
|
|
|
- IOHIDDeviceRegisterInputValueCallback(((struct Gamepad_devicePrivate *) deviceRecord->privateData)->deviceRef, NULL, NULL);
|
|
|
-
|
|
|
- for (inputEventIndex = 0; inputEventIndex < inputEventCount; inputEventIndex++) {
|
|
|
- if (inputEventQueue[inputEventIndex].dispatcher == deviceRecord->eventDispatcher) {
|
|
|
- unsigned int inputEventIndex2;
|
|
|
-
|
|
|
- free(inputEventQueue[inputEventIndex].eventData);
|
|
|
- inputEventCount--;
|
|
|
- for (inputEventIndex2 = inputEventIndex; inputEventIndex2 < inputEventCount; inputEventIndex2++) {
|
|
|
- inputEventQueue[inputEventIndex2] = inputEventQueue[inputEventIndex2 + 1];
|
|
|
- }
|
|
|
- inputEventIndex--;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- for (deviceEventIndex = 0; deviceEventIndex < deviceEventCount; deviceEventIndex++) {
|
|
|
- if (deviceEventQueue[deviceEventIndex].dispatcher == deviceRecord->eventDispatcher) {
|
|
|
- unsigned int deviceEventIndex2;
|
|
|
-
|
|
|
- deviceEventCount--;
|
|
|
- for (deviceEventIndex2 = deviceEventIndex; deviceEventIndex2 < deviceEventCount; deviceEventIndex2++) {
|
|
|
- deviceEventQueue[deviceEventIndex2] = deviceEventQueue[deviceEventIndex2 + 1];
|
|
|
- }
|
|
|
- deviceEventIndex--;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- deviceRecord->eventDispatcher->dispose(deviceRecord->eventDispatcher);
|
|
|
-
|
|
|
- free(((struct Gamepad_devicePrivate *) deviceRecord->privateData)->axisElements);
|
|
|
- free(((struct Gamepad_devicePrivate *) deviceRecord->privateData)->buttonElements);
|
|
|
- free(deviceRecord->privateData);
|
|
|
-
|
|
|
- free((void *) deviceRecord->description);
|
|
|
- free(deviceRecord->axisStates);
|
|
|
- free(deviceRecord->buttonStates);
|
|
|
- free(deviceRecord->eventDispatcher);
|
|
|
-
|
|
|
- free(deviceRecord);
|
|
|
-}
|
|
|
-
|
|
|
-static void onDeviceRemoved(void * context, IOReturn result, void * sender, IOHIDDeviceRef device) {
|
|
|
- unsigned int deviceIndex;
|
|
|
-
|
|
|
- for (deviceIndex = 0; deviceIndex < numDevices; deviceIndex++) {
|
|
|
- if (((struct Gamepad_devicePrivate *) devices[deviceIndex]->privateData)->deviceRef == device) {
|
|
|
- Gamepad_eventDispatcher()->dispatchEvent(Gamepad_eventDispatcher(), GAMEPAD_EVENT_DEVICE_REMOVED, devices[deviceIndex]);
|
|
|
-
|
|
|
- disposeDevice(devices[deviceIndex]);
|
|
|
- numDevices--;
|
|
|
- for (; deviceIndex < numDevices; deviceIndex++) {
|
|
|
- devices[deviceIndex] = devices[deviceIndex + 1];
|
|
|
- }
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void Gamepad_init() {
|
|
|
- if (hidManager == NULL) {
|
|
|
- CFStringRef keys[2];
|
|
|
- int value;
|
|
|
- CFNumberRef values[2];
|
|
|
- CFDictionaryRef dictionaries[3];
|
|
|
- CFArrayRef array;
|
|
|
-
|
|
|
- hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
|
|
|
- IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone);
|
|
|
- IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
-
|
|
|
- keys[0] = CFSTR(kIOHIDDeviceUsagePageKey);
|
|
|
- keys[1] = CFSTR(kIOHIDDeviceUsageKey);
|
|
|
-
|
|
|
- value = kHIDPage_GenericDesktop;
|
|
|
- values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
|
|
|
- value = kHIDUsage_GD_Joystick;
|
|
|
- values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
|
|
|
- dictionaries[0] = CFDictionaryCreate(kCFAllocatorDefault, (const void **) keys, (const void **) values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
|
|
- CFRelease(values[0]);
|
|
|
- CFRelease(values[1]);
|
|
|
-
|
|
|
- value = kHIDPage_GenericDesktop;
|
|
|
- values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
|
|
|
- value = kHIDUsage_GD_GamePad;
|
|
|
- values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
|
|
|
- dictionaries[1] = CFDictionaryCreate(kCFAllocatorDefault, (const void **) keys, (const void **) values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
|
|
- CFRelease(values[0]);
|
|
|
- CFRelease(values[1]);
|
|
|
-
|
|
|
- value = kHIDPage_GenericDesktop;
|
|
|
- values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
|
|
|
- value = kHIDUsage_GD_MultiAxisController;
|
|
|
- values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
|
|
|
- dictionaries[2] = CFDictionaryCreate(kCFAllocatorDefault, (const void **) keys, (const void **) values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
|
|
- CFRelease(values[0]);
|
|
|
- CFRelease(values[1]);
|
|
|
-
|
|
|
- array = CFArrayCreate(kCFAllocatorDefault, (const void **) dictionaries, 3, &kCFTypeArrayCallBacks);
|
|
|
- CFRelease(dictionaries[0]);
|
|
|
- CFRelease(dictionaries[1]);
|
|
|
- CFRelease(dictionaries[2]);
|
|
|
- IOHIDManagerSetDeviceMatchingMultiple(hidManager, array);
|
|
|
- CFRelease(array);
|
|
|
-
|
|
|
- IOHIDManagerRegisterDeviceMatchingCallback(hidManager, onDeviceMatched, NULL);
|
|
|
- IOHIDManagerRegisterDeviceRemovalCallback(hidManager, onDeviceRemoved, NULL);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void Gamepad_shutdown() {
|
|
|
- if (hidManager != NULL) {
|
|
|
- unsigned int deviceIndex;
|
|
|
-
|
|
|
- IOHIDManagerUnscheduleFromRunLoop(hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
- IOHIDManagerClose(hidManager, 0);
|
|
|
- CFRelease(hidManager);
|
|
|
- hidManager = NULL;
|
|
|
-
|
|
|
- for (deviceIndex = 0; deviceIndex < numDevices; deviceIndex++) {
|
|
|
- disposeDevice(devices[deviceIndex]);
|
|
|
- }
|
|
|
- free(devices);
|
|
|
- devices = NULL;
|
|
|
- numDevices = 0;
|
|
|
-
|
|
|
- if (eventDispatcher != NULL) {
|
|
|
- eventDispatcher->dispose(eventDispatcher);
|
|
|
- free(eventDispatcher);
|
|
|
- eventDispatcher = NULL;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-EventDispatcher * Gamepad_eventDispatcher() {
|
|
|
- if (eventDispatcher == NULL) {
|
|
|
- eventDispatcher = EventDispatcher_create(NULL);
|
|
|
- }
|
|
|
- return eventDispatcher;
|
|
|
-}
|
|
|
-
|
|
|
-unsigned int Gamepad_numDevices() {
|
|
|
- return numDevices;
|
|
|
-}
|
|
|
-
|
|
|
-struct Gamepad_device * Gamepad_deviceAtIndex(unsigned int deviceIndex) {
|
|
|
- if (deviceIndex >= numDevices) {
|
|
|
- return NULL;
|
|
|
- }
|
|
|
- return devices[deviceIndex];
|
|
|
-}
|
|
|
-
|
|
|
-void Gamepad_detectDevices() {
|
|
|
- unsigned int eventIndex;
|
|
|
-
|
|
|
- if (hidManager == NULL) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- for (eventIndex = 0; eventIndex < deviceEventCount; eventIndex++) {
|
|
|
- deviceEventQueue[eventIndex].dispatcher->dispatchEvent(deviceEventQueue[eventIndex].dispatcher, deviceEventQueue[eventIndex].eventType, deviceEventQueue[eventIndex].eventData);
|
|
|
- }
|
|
|
- deviceEventCount = 0;
|
|
|
-}
|
|
|
-
|
|
|
-void Gamepad_processEvents() {
|
|
|
- unsigned int eventIndex;
|
|
|
-
|
|
|
- if (hidManager == NULL) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- for (eventIndex = 0; eventIndex < inputEventCount; eventIndex++) {
|
|
|
- inputEventQueue[eventIndex].dispatcher->dispatchEvent(inputEventQueue[eventIndex].dispatcher, inputEventQueue[eventIndex].eventType, inputEventQueue[eventIndex].eventData);
|
|
|
- free(inputEventQueue[eventIndex].eventData);
|
|
|
- }
|
|
|
- inputEventCount = 0;
|
|
|
-}
|
|
|
-
|