void Gamepad_processEvents() { unsigned int deviceIndex; static bool inProcessEvents; JOYINFOEX info; MMRESULT result; struct Gamepad_device * device; struct Gamepad_devicePrivate * devicePrivate; if (!inited || inProcessEvents) { return; } inProcessEvents = true; for (deviceIndex = 0; deviceIndex < numDevices; deviceIndex++) { device = devices[deviceIndex]; devicePrivate = device->privateData; info.dwSize = sizeof(info); info.dwFlags = JOY_RETURNALL; result = joyGetPosEx(devicePrivate->joystickID, &info); if (result == JOYERR_UNPLUGGED) { Gamepad_eventDispatcher()->dispatchEvent(Gamepad_eventDispatcher(), Atom_fromString(GAMEPAD_EVENT_DEVICE_REMOVED), device); disposeDevice(device); numDevices--; for (; deviceIndex < numDevices; deviceIndex++) { devices[deviceIndex] = devices[deviceIndex + 1]; } } else if (result == JOYERR_NOERROR) { if (info.dwXpos != devicePrivate->lastState.dwXpos) { handleAxisChange(device, devicePrivate->xAxisIndex, info.dwXpos); } if (info.dwYpos != devicePrivate->lastState.dwYpos) { handleAxisChange(device, devicePrivate->yAxisIndex, info.dwYpos); } if (info.dwZpos != devicePrivate->lastState.dwZpos) { handleAxisChange(device, devicePrivate->zAxisIndex, info.dwZpos); } if (info.dwRpos != devicePrivate->lastState.dwRpos) { handleAxisChange(device, devicePrivate->rAxisIndex, info.dwRpos); } if (info.dwUpos != devicePrivate->lastState.dwUpos) { handleAxisChange(device, devicePrivate->uAxisIndex, info.dwUpos); } if (info.dwVpos != devicePrivate->lastState.dwVpos) { handleAxisChange(device, devicePrivate->vAxisIndex, info.dwVpos); } if (info.dwPOV != devicePrivate->lastState.dwPOV) { handlePOVChange(device, devicePrivate->lastState.dwPOV, info.dwPOV); } if (info.dwButtons != devicePrivate->lastState.dwButtons) { handleButtonChange(device, devicePrivate->lastState.dwButtons, info.dwButtons); } devicePrivate->lastState = info; } } inProcessEvents = false; }
void JoystickHandler::_ThreadFunc() { Gamepad_eventDispatcher()->registerForEvent(Gamepad_eventDispatcher(), GAMEPAD_EVENT_DEVICE_ATTACHED, _OnDeviceAttached, this); Gamepad_eventDispatcher()->registerForEvent(Gamepad_eventDispatcher(), GAMEPAD_EVENT_DEVICE_REMOVED, _OnDeviceRemoved, this); Gamepad_init(); //Gamepad_RunLoop(); }
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_detectDevices() { unsigned int numPaths; char ** gamepadPaths; bool duplicate; unsigned int pathIndex, gamepadIndex; struct stat statBuf; struct Gamepad_device * deviceRecord; struct Gamepad_devicePrivate * deviceRecordPrivate; int fd; char name[128]; char * description; int evKeyBits[(KEY_CNT - 1) / sizeof(int) * 8 + 1]; int evAbsBits[(ABS_CNT - 1) / sizeof(int) * 8 + 1]; int bit; struct input_id id; if (!inited) { return; } gamepadPaths = findGamepadPaths(&numPaths); pthread_mutex_lock(&devicesMutex); for (pathIndex = 0; pathIndex < numPaths; pathIndex++) { duplicate = false; for (gamepadIndex = 0; gamepadIndex < numDevices; gamepadIndex++) { if (!strcmp(((struct Gamepad_devicePrivate *) devices[gamepadIndex]->privateData)->path, gamepadPaths[pathIndex])) { duplicate = true; break; } } if (duplicate) { free(gamepadPaths[pathIndex]); continue; } if (!stat(gamepadPaths[pathIndex], &statBuf)) { deviceRecord = (Gamepad_device*)malloc(sizeof(struct Gamepad_device)); deviceRecord->deviceID = nextDeviceID++; deviceRecord->eventDispatcher = EventDispatcher_create(deviceRecord); devices = (Gamepad_device**)realloc(devices, sizeof(struct Gamepad_device *) * (numDevices + 1)); devices[numDevices++] = deviceRecord; fd = open(gamepadPaths[pathIndex], O_RDONLY, 0); deviceRecordPrivate = (Gamepad_devicePrivate*)malloc(sizeof(struct Gamepad_devicePrivate)); deviceRecordPrivate->fd = fd; deviceRecordPrivate->path = gamepadPaths[pathIndex]; memset(deviceRecordPrivate->buttonMap, 0xFF, sizeof(deviceRecordPrivate->buttonMap)); memset(deviceRecordPrivate->axisMap, 0xFF, sizeof(deviceRecordPrivate->axisMap)); deviceRecord->privateData = deviceRecordPrivate; if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) > 0) { description = (char*)malloc(strlen(name + 1)); strcpy(description, name); } else { description = (char*)malloc(strlen(gamepadPaths[pathIndex] + 1)); strcpy(description, gamepadPaths[pathIndex]); } deviceRecord->description = description; if (!ioctl(fd, EVIOCGID, &id)) { deviceRecord->vendorID = id.vendor; deviceRecord->productID = id.product; } else { deviceRecord->vendorID = deviceRecord->productID = 0; } memset(evKeyBits, 0, sizeof(evKeyBits)); memset(evAbsBits, 0, sizeof(evAbsBits)); ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(evKeyBits)), evKeyBits); ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(evAbsBits)), evAbsBits); deviceRecord->numAxes = 0; for (bit = 0; bit < ABS_CNT; bit++) { if (test_bit(bit, evAbsBits)) { if (ioctl(fd, EVIOCGABS(bit), &deviceRecordPrivate->axisInfo[bit]) < 0 || deviceRecordPrivate->axisInfo[bit].minimum == deviceRecordPrivate->axisInfo[bit].maximum) { continue; } deviceRecordPrivate->axisMap[bit] = deviceRecord->numAxes; deviceRecord->numAxes++; } } deviceRecord->numButtons = 0; for (bit = BTN_MISC; bit < KEY_CNT; bit++) { if (test_bit(bit, evKeyBits)) { deviceRecordPrivate->buttonMap[bit - BTN_MISC] = deviceRecord->numButtons; deviceRecord->numButtons++; } } deviceRecord->axisStates = (float*)calloc(sizeof(float), deviceRecord->numAxes); deviceRecord->buttonStates = (bool*)calloc(sizeof(bool), deviceRecord->numButtons); Gamepad_eventDispatcher()->dispatchEvent(Gamepad_eventDispatcher(), GAMEPAD_EVENT_DEVICE_ATTACHED, deviceRecord); pthread_create(&deviceRecordPrivate->thread, NULL, deviceThread, deviceRecord); } } pthread_mutex_unlock(&devicesMutex); }
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; }
void Gamepad_detectDevices() { unsigned int numPadsSupported; unsigned int deviceIndex, deviceIndex2; JOYINFOEX info; JOYCAPS caps; bool duplicate; struct Gamepad_device * deviceRecord; struct Gamepad_devicePrivate * deviceRecordPrivate; UINT joystickID; int axisIndex; if (!inited) { return; } numPadsSupported = joyGetNumDevs(); for (deviceIndex = 0; deviceIndex < numPadsSupported; deviceIndex++) { info.dwSize = sizeof(info); info.dwFlags = JOY_RETURNALL; joystickID = JOYSTICKID1 + deviceIndex; if (joyGetPosEx(joystickID, &info) == JOYERR_NOERROR && joyGetDevCaps(joystickID, &caps, sizeof(JOYCAPS)) == JOYERR_NOERROR) { duplicate = false; for (deviceIndex2 = 0; deviceIndex2 < numDevices; deviceIndex2++) { if (((struct Gamepad_devicePrivate *) devices[deviceIndex2]->privateData)->joystickID == joystickID) { duplicate = true; break; } } if (duplicate) { continue; } deviceRecord = malloc(sizeof(struct Gamepad_device)); deviceRecord->deviceID = nextDeviceID++; deviceRecord->description = getDeviceDescription(joystickID, caps); deviceRecord->vendorID = caps.wMid; deviceRecord->productID = caps.wPid; deviceRecord->numAxes = caps.wNumAxes + ((caps.wCaps & JOYCAPS_HASPOV) ? 2 : 0); deviceRecord->numButtons = caps.wNumButtons; deviceRecord->axisStates = calloc(sizeof(float), deviceRecord->numAxes); deviceRecord->buttonStates = calloc(sizeof(bool), deviceRecord->numButtons); deviceRecord->eventDispatcher = EventDispatcher_create(deviceRecord); devices = realloc(devices, sizeof(struct Gamepad_device *) * (numDevices + 1)); devices[numDevices++] = deviceRecord; deviceRecordPrivate = malloc(sizeof(struct Gamepad_devicePrivate)); deviceRecordPrivate->joystickID = joystickID; deviceRecordPrivate->lastState = info; deviceRecordPrivate->xAxisIndex = 0; deviceRecordPrivate->yAxisIndex = 1; axisIndex = 2; deviceRecordPrivate->zAxisIndex = (caps.wCaps & JOYCAPS_HASZ) ? axisIndex++ : -1; deviceRecordPrivate->rAxisIndex = (caps.wCaps & JOYCAPS_HASR) ? axisIndex++ : -1; deviceRecordPrivate->uAxisIndex = (caps.wCaps & JOYCAPS_HASU) ? axisIndex++ : -1; deviceRecordPrivate->vAxisIndex = (caps.wCaps & JOYCAPS_HASV) ? axisIndex++ : -1; deviceRecordPrivate->axisRanges = malloc(sizeof(UINT[2]) * axisIndex); deviceRecordPrivate->axisRanges[0][0] = caps.wXmin; deviceRecordPrivate->axisRanges[0][1] = caps.wXmax; deviceRecordPrivate->axisRanges[1][0] = caps.wYmin; deviceRecordPrivate->axisRanges[1][1] = caps.wYmax; if (deviceRecordPrivate->zAxisIndex != -1) { deviceRecordPrivate->axisRanges[deviceRecordPrivate->zAxisIndex][0] = caps.wZmin; deviceRecordPrivate->axisRanges[deviceRecordPrivate->zAxisIndex][1] = caps.wZmax; } if (deviceRecordPrivate->rAxisIndex != -1) { deviceRecordPrivate->axisRanges[deviceRecordPrivate->rAxisIndex][0] = caps.wRmin; deviceRecordPrivate->axisRanges[deviceRecordPrivate->rAxisIndex][1] = caps.wRmax; } if (deviceRecordPrivate->uAxisIndex != -1) { deviceRecordPrivate->axisRanges[deviceRecordPrivate->uAxisIndex][0] = caps.wUmin; deviceRecordPrivate->axisRanges[deviceRecordPrivate->uAxisIndex][1] = caps.wUmax; } if (deviceRecordPrivate->vAxisIndex != -1) { deviceRecordPrivate->axisRanges[deviceRecordPrivate->vAxisIndex][0] = caps.wVmin; deviceRecordPrivate->axisRanges[deviceRecordPrivate->vAxisIndex][1] = caps.wVmax; } deviceRecordPrivate->povXAxisIndex = (caps.wCaps & JOYCAPS_HASPOV) ? axisIndex++ : -1; deviceRecordPrivate->povYAxisIndex = (caps.wCaps & JOYCAPS_HASPOV) ? axisIndex++ : -1; deviceRecord->privateData = deviceRecordPrivate; Gamepad_eventDispatcher()->dispatchEvent(Gamepad_eventDispatcher(), Atom_fromString(GAMEPAD_EVENT_DEVICE_ATTACHED), deviceRecord); } } }
//"initialization code is here, in its own function..." static void initGamepad() { Gamepad_eventDispatcher()->registerForEvent(Gamepad_eventDispatcher(), GAMEPAD_EVENT_DEVICE_ATTACHED, onDeviceAttached, NULL); Gamepad_eventDispatcher()->registerForEvent(Gamepad_eventDispatcher(), GAMEPAD_EVENT_DEVICE_REMOVED, onDeviceRemoved, NULL); Gamepad_init(); }