static void * deviceThread(void * context) { unsigned int gamepadIndex; struct Gamepad_device * device; struct Gamepad_devicePrivate * devicePrivate; struct input_event event; device = context; devicePrivate = device->privateData; while (read(devicePrivate->fd, &event, sizeof(struct input_event)) > 0) { if (event.type == EV_ABS) { float value; if (event.code > ABS_MAX || devicePrivate->axisMap[event.code] == -1) { continue; } value = (event.value - devicePrivate->axisInfo[event.code].minimum) / (float) (devicePrivate->axisInfo[event.code].maximum - devicePrivate->axisInfo[event.code].minimum) * 2.0f - 1.0f; queueAxisEvent(device, event.time.tv_sec + event.time.tv_usec * 0.000001, devicePrivate->axisMap[event.code], value, device->axisStates[devicePrivate->axisMap[event.code]]); device->axisStates[devicePrivate->axisMap[event.code]] = value; } else if (event.type == EV_KEY) { if (event.code < BTN_MISC || event.code > KEY_MAX || devicePrivate->buttonMap[event.code - BTN_MISC] == -1) { continue; } queueButtonEvent(device, event.time.tv_sec + event.time.tv_usec * 0.000001, devicePrivate->buttonMap[event.code - BTN_MISC], !!event.value); device->buttonStates[devicePrivate->buttonMap[event.code - BTN_MISC]] = !!event.value; } } queueEvent(device->deviceID, GAMEPAD_EVENT_DEVICE_REMOVED, device); pthread_mutex_lock(&devicesMutex); for (gamepadIndex = 0; gamepadIndex < numDevices; gamepadIndex++) { if (devices[gamepadIndex] == device) { unsigned int gamepadIndex2; numDevices--; for (gamepadIndex2 = gamepadIndex; gamepadIndex2 < numDevices; gamepadIndex2++) { devices[gamepadIndex2] = devices[gamepadIndex2 + 1]; } gamepadIndex--; } } pthread_mutex_unlock(&devicesMutex); return NULL; }
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 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]); 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]); 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]); 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; } } }