// NOTE: I pieced this together through trial and error, any corrections are welcome static void hid_device_input_callback(void* context, IOReturn result, void* sender, IOHIDValueRef value) { struct apple_pad_connection* connection = (struct apple_pad_connection*)context; IOHIDElementRef element = IOHIDValueGetElement(value); uint32_t type = IOHIDElementGetType(element); uint32_t page = IOHIDElementGetUsagePage(element); uint32_t use = IOHIDElementGetUsage(element); // Joystick handler: TODO: Can GamePad work the same? if (type == kIOHIDElementTypeInput_Button && page == kHIDPage_Button) { CFIndex state = IOHIDValueGetIntegerValue(value); if (state) g_current_input_data.pad_buttons[connection->slot] |= (1 << (use - 1)); else g_current_input_data.pad_buttons[connection->slot] &= ~(1 << (use - 1)); } else if (type == kIOHIDElementTypeInput_Misc && page == kHIDPage_GenericDesktop) { static const uint32_t axis_use_ids[4] = { 48, 49, 50, 53 }; for (int i = 0; i < 4; i ++) { if (use == axis_use_ids[i]) { CFIndex min = IOHIDElementGetPhysicalMin(element); CFIndex max = IOHIDElementGetPhysicalMax(element) - min; CFIndex state = IOHIDValueGetIntegerValue(value) - min; float val = (float)state / (float)max; g_current_input_data.pad_axis[connection->slot][i] = ((val * 2.0f) - 1.0f) * 32767.0f; } } } }
void osxHIDPointingDevice::hidQueueCallback(void *context, IOReturn /*result*/, void *sender) { // std::cerr << "osxHIDPointingDevice::hidQueueCallback" << std::endl ; osxHIDPointingDevice *self = (osxHIDPointingDevice*)context ; IOHIDQueueRef queue = (IOHIDQueueRef)sender ; while (true) { IOHIDValueRef hidvalue = IOHIDQueueCopyNextValueWithTimeout(queue, 0.) ; if (!hidvalue) break ; #if 1 TimeStamp::inttime uptime = AbsoluteTimeInNanoseconds(IOHIDValueGetTimeStamp(hidvalue)) ; TimeStamp::inttime timestamp = self->epoch + (uptime - self->epoch_mach)*TimeStamp::one_nanosecond ; #else TimeStamp::inttime timestamp = TimeStamp::createAsInt() ; #endif if (self->qreport.isOlderThan(timestamp)) { // Flush the old qreport before creating a new one self->report(self->qreport) ; self->qreport.clear() ; } IOHIDElementRef element = IOHIDValueGetElement(hidvalue) ; uint32_t usagepage = IOHIDElementGetUsagePage(element) ; uint32_t usage = IOHIDElementGetUsage(element) ; //std::cout << usagepage << std::endl; //std::cout << usage << std::endl; if (usagepage==kHIDPage_GenericDesktop) { if (usage==kHIDUsage_GD_X || usage==kHIDUsage_GD_Y) { // Could use IOHIDValueGetScaledValue(hidvalue, kIOHIDValueScaleTypePhysical) CFIndex d = IOHIDValueGetIntegerValue(hidvalue) ; //std::cout << IOHIDValueGetBytePtr(hidvalue) << std::endl; //std::cout << IOHIDValueGetLength(hidvalue) << std::endl; if (d) { if (usage==kHIDUsage_GD_X) self->qreport.dx = (int32_t)d ; else self->qreport.dy = (int32_t)d ; self->qreport.t = timestamp ; } } // FIXME: GD_Z, GD_Wheel, etc. } else if (usagepage==kHIDPage_Button) { // kHIDUsage_Button_1 is 1 self->qreport.setButton(usage-1, (uint32_t)IOHIDValueGetIntegerValue(hidvalue)) ; self->qreport.t = timestamp ; } CFRelease(hidvalue) ; } // Flush the qreport we were constructing, if any if (self->qreport.t!=TimeStamp::undef) self->report(self->qreport) ; self->qreport.clear() ; }
static SDL_bool GetHIDElementState(recDevice *pDevice, recElement *pElement, SInt32 *pValue) { SInt32 value = 0; int returnValue = SDL_FALSE; if (pDevice && pElement) { IOHIDValueRef valueRef; if (IOHIDDeviceGetValue(pDevice->deviceRef, pElement->elementRef, &valueRef) == kIOReturnSuccess) { value = (SInt32) IOHIDValueGetIntegerValue(valueRef); /* record min and max for auto calibration */ if (value < pElement->minReport) { pElement->minReport = value; } if (value > pElement->maxReport) { pElement->maxReport = value; } *pValue = value; returnValue = SDL_TRUE; } } return returnValue; }
void analog_event(IOReturn result, IOHIDElementRef element, IOHIDValueRef value) { int int_value = IOHIDValueGetIntegerValue(value); uint16_t usage = IOHIDElementGetUsage(element); switch (usage) { case kHIDUsage_GD_X: case kHIDUsage_GD_Y: case kHIDUsage_GD_Rx: case kHIDUsage_GD_Ry: { int min = IOHIDElementGetLogicalMin(element); int max = IOHIDElementGetLogicalMax(element); double double_value = int_value; if (int_value < 0) { double_value = -(double_value / min); } else { double_value = (double_value / max); } usage -= kHIDUsage_GD_X; gamepad[usage] = double_value; static const int x_component[] = {0, 0, -1, 3, 3, -1}; double x = gamepad[x_component[usage]]; double y = gamepad[x_component[usage] + 1]; enqueue(new GamepadStickEvent( now_usecs(), kHIDUsage_GD_X + x_component[usage], x, y)); } break; case kHIDUsage_GD_Z: case kHIDUsage_GD_Rz: button_event(result, element, value); break; } }
static void input_callback(void *ctx, IOReturn result, void *sender, IOHIDValueRef value) { struct osx_mouse_data *mdata = static_cast<struct osx_mouse_data *>(ctx); IOHIDElementRef elem = IOHIDValueGetElement(value); uint32_t page = IOHIDElementGetUsagePage(elem); uint32_t usage = IOHIDElementGetUsage(elem); uint32_t val = IOHIDValueGetIntegerValue(value); if (page == kHIDPage_GenericDesktop) { switch (usage) { case kHIDUsage_GD_X: SDL_LockMutex(mdata->mouse_mutex); mdata->mouse_x += val; SDL_UnlockMutex(mdata->mouse_mutex); break; case kHIDUsage_GD_Y: SDL_LockMutex(mdata->mouse_mutex); mdata->mouse_y += val; SDL_UnlockMutex(mdata->mouse_mutex); break; default: break; } } }
bool Joystick::update() { if(!p->deviceId) return false; IOHIDValueRef valueRef; for(int i = 0; i < numOfAxes; ++i) if(p->axisIds[i]) { IOHIDDeviceGetValue((IOHIDDeviceRef) p->deviceId, (IOHIDElementRef) p->axisIds[i], &valueRef); p->axisState[i] = (int) IOHIDValueGetIntegerValue(valueRef); } unsigned newState = 0; for(int i = 0; i < numOfButtons; ++i) if(p->buttonIds[i]) { IOHIDDeviceGetValue((IOHIDDeviceRef) p->deviceId, (IOHIDElementRef) p->buttonIds[i], &valueRef); newState |= IOHIDValueGetIntegerValue(valueRef) ? 1 << i : 0; } p->buttonEvents[0] |= p->buttonState[0] ^ newState; p->buttonState[0] = newState; if(p->hatId) { IOHIDDeviceGetValue((IOHIDDeviceRef) p->deviceId, (IOHIDElementRef) p->hatId, &valueRef); int dir = (int) IOHIDValueGetIntegerValue(valueRef); newState = !(dir & 8) ? 1 << dir : 0; p->buttonEvents[1] |= p->buttonState[1] ^ newState; p->buttonState[1] = newState; p->axisState[6] = p->axisState[7] = 0; if(!(dir & 8)) { if(dir == 7 || dir <= 1) p->axisState[7] = p->axisMin[7]; else if(dir >= 3 && dir <= 5) p->axisState[7] = p->axisMax[7]; if(dir >= 1 && dir <= 3) p->axisState[6] = p->axisMax[6]; else if(dir >= 5 && dir <= 7) p->axisState[6] = p->axisMin[6]; } } return true; }
void setKeyboard(struct __IOHIDDevice *device, CFDictionaryRef keyboardDictionary, LedState changes[]) { CFStringRef deviceNameRef = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)); if (!deviceNameRef) return; const char * deviceName = CFStringGetCStringPtr(deviceNameRef, kCFStringEncodingUTF8); if (nameMatch && fnmatch(nameMatch, deviceName, 0) != 0) return; if (verbose) printf("\n \"%s\" ", deviceName); CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device, keyboardDictionary, kIOHIDOptionsTypeNone); if (elements) { for (CFIndex elementIndex = 0; elementIndex < CFArrayGetCount(elements); elementIndex++) { IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, elementIndex); if (element && kHIDPage_LEDs == IOHIDElementGetUsagePage(element)) { uint32_t led = IOHIDElementGetUsage(element); if (led >= maxLeds) break; // Get current keyboard led status IOHIDValueRef currentValue = 0; if (IOHIDDeviceGetValue(device, element, ¤tValue) == kIOReturnSuccess && IOHIDValueGetLength(currentValue) < 3) { long current = IOHIDValueGetIntegerValue(currentValue); CFRelease(currentValue); // Should we try to set the led? if (changes[led] != NoChange && changes[led] != current) { IOHIDValueRef newValue = IOHIDValueCreateWithIntegerValue(kCFAllocatorDefault, element, 0, changes[led]); if (newValue) { IOReturn changeResult = IOHIDDeviceSetValue(device, element, newValue); // Was the change successful? if (kIOReturnSuccess == changeResult && verbose) { printf("%s%s ", stateSymbol[changes[led]], ledNames[led - 1]); } CFRelease(newValue); } } else if (verbose) { printf("%s%s ", stateSymbol[current], ledNames[led - 1]); } } } } CFRelease(elements); } if (verbose) printf("\n"); }
void button_event(IOReturn result, IOHIDElementRef element, IOHIDValueRef value) { if (!antares_is_active()) { return; } bool down = IOHIDValueGetIntegerValue(value); uint16_t usage = IOHIDElementGetUsage(element); if (down) { enqueue(new GamepadButtonDownEvent(now_usecs(), usage)); } else { enqueue(new GamepadButtonUpEvent(now_usecs(), usage)); } }
void CPH_HidMacOSX::InputValueCallback(IOHIDValueRef valueRef) { IOHIDElementRef elementRef = IOHIDValueGetElement(valueRef); uint32 usage = IOHIDElementGetUsage(elementRef); uint32 usagePage = IOHIDElementGetUsagePage(elementRef); CFIndex state = IOHIDValueGetIntegerValue(valueRef); if(usagePage != kHIDPage_KeyboardOrKeypad) return; for(auto bindingIterator(std::begin(m_bindings)); bindingIterator != std::end(m_bindings); bindingIterator++) { const auto& binding = (*bindingIterator); if(!binding) continue; binding->ProcessEvent(usage, state); } }
HIDInputType HIDGamepad::valueChanged(IOHIDValueRef value) { IOHIDElementCookie cookie = IOHIDElementGetCookie(IOHIDValueGetElement(value)); HIDGamepadElement* element = m_elementMap.get(cookie); // This might be an element we don't currently handle as input so we can skip it. if (!element) return HIDInputType::NotAButtonPress; element->rawValue = IOHIDValueGetScaledValue(value, kIOHIDValueScaleTypePhysical); if (element->isButton()) { for (unsigned i = 0; i < m_buttons.size(); ++i) { if (&m_buttons[i].get() == element) { m_buttonValues[i] = element->normalizedValue(); break; } } } else if (element->isAxis()) { for (unsigned i = 0; i < m_axes.size(); ++i) { if (&m_axes[i].get() == element) { m_axisValues[i] = element->normalizedValue(); break; } } } else if (element->isDPad()) { int intValue = IOHIDValueGetIntegerValue(value) - element->min; for (unsigned i = 0; i < m_dPads.size(); ++i) { if (&m_dPads[i].get() != element) continue; // Each DPad represents 4 button values which are tacked on to the end of the values from non-DPad buttons. unsigned firstButtonValue = m_buttons.size() + i * 4; ASSERT(m_buttonValues.size() > firstButtonValue + 3); fillInButtonValues(intValue, m_buttonValues[firstButtonValue], m_buttonValues[firstButtonValue + 1], m_buttonValues[firstButtonValue + 2], m_buttonValues[firstButtonValue + 3]); } } else ASSERT_NOT_REACHED(); m_lastUpdateTime = monotonicallyIncreasingTime(); return element->isButton() ? HIDInputType::ButtonPress : HIDInputType::NotAButtonPress; }
void key_event(IOReturn result, IOHIDElementRef element, IOHIDValueRef value) { if (!antares_is_active()) { return; } bool down = IOHIDValueGetIntegerValue(value); uint16_t scan_code = IOHIDElementGetUsage(element); if ((scan_code < 4) || (231 < scan_code)) { return; } else if (scan_code == Keys::CAPS_LOCK) { return; } if (down) { enqueue(new KeyDownEvent(now_usecs(), scan_code)); } else { enqueue(new KeyUpEvent(now_usecs(), scan_code)); } }
float GamepadManager::mapAnalogAxis(IOHIDValueRef value, IOHIDElementRef element) { CFIndex val = IOHIDValueGetIntegerValue(value); CFIndex min = IOHIDElementGetLogicalMin(element); CFIndex max = IOHIDElementGetLogicalMax(element); float v = (float) (val - min) / (float) (max - min); v = v * 2.0f - 1.0f; // Dead zone. if (v < 0.1f && v > -0.1f) { v = 0.0f; } return v; }
int joypad::get_hid_element_state(rec_element *p_element) const { int value = 0; if (p_element && p_element->ref) { IOHIDValueRef valueRef; if (IOHIDDeviceGetValue(device_ref, p_element->ref, &valueRef) == kIOReturnSuccess) { value = (SInt32)IOHIDValueGetIntegerValue(valueRef); /* record min and max for auto calibration */ if (value < p_element->min) { p_element->min = value; } if (value > p_element->max) { p_element->max = value; } } } return value; }
int joy_hidlib_get_value(joy_hid_device_t *device, joy_hid_element_t *element, int *value, int phys) { IOHIDValueRef value_ref; IOReturn result = IOHIDDeviceGetValue( device->internal_device, element->internal_element, &value_ref ); if(result == kIOReturnSuccess) { if(phys) { *value = (int)IOHIDValueGetScaledValue( value_ref, kIOHIDValueScaleTypePhysical ); } else { *value = (int)IOHIDValueGetIntegerValue( value_ref ); } return 0; } else { return -1; } }
void CInputProviderMacOsHid::SetInitialBindValues(IOHIDDeviceRef device) { CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device, nullptr, 0); for(int i = 0; i < CFArrayGetCount(elements); i++) { IOHIDElementRef elementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i); uint32 usagePage = IOHIDElementGetUsagePage(elementRef); if( (usagePage != kHIDPage_GenericDesktop) && (usagePage != kHIDPage_Button)) { continue; } IOHIDValueRef valueRef; if(IOHIDDeviceGetValue(device, elementRef, &valueRef) != kIOReturnSuccess) { continue; } CFIndex value = IOHIDValueGetIntegerValue(valueRef); IOHIDElementType type = IOHIDElementGetType(elementRef); uint32 usage = IOHIDElementGetUsage(elementRef); BINDINGTARGET tgt; tgt.providerId = PROVIDER_ID; tgt.deviceId = GetDeviceID(device); tgt.keyId = usage; tgt.keyType = GetKeyType(usage, type); switch(type) { case kIOHIDElementTypeInput_Misc: case kIOHIDElementTypeInput_Button: case kIOHIDElementTypeInput_Axis: OnInput(tgt, value); break; default: break; } } }
void CInputProviderMacOsHid::InputValueCallback(DEVICE_INFO* deviceInfo, IOReturn result, void* sender, IOHIDValueRef valueRef) { if(!OnInput) return; IOHIDElementRef elementRef = IOHIDValueGetElement(valueRef); uint32 usagePage = IOHIDElementGetUsagePage(elementRef); if( (usagePage != kHIDPage_GenericDesktop) && (usagePage != kHIDPage_Button)) { return; } uint32 usage = IOHIDElementGetUsage(elementRef); CFIndex value = IOHIDValueGetIntegerValue(valueRef); IOHIDElementType type = IOHIDElementGetType(elementRef); BINDINGTARGET tgt; tgt.providerId = PROVIDER_ID; tgt.deviceId = deviceInfo->deviceId; tgt.keyId = usage; tgt.keyType = GetKeyType(usage, type); OnInput(tgt, value); }
static void PsychHIDKbQueueCallbackFunction(void *target, IOReturn result, void *sender) { // This routine is executed each time the queue transitions from empty to non-empty // The CFRunLoop of the thread in KbQueueWorkerThreadMain() is the one that executes here: IOHIDQueueRef queue = (IOHIDQueueRef) sender; IOHIDValueRef valueRef = NULL; int deviceIndex = (int) target; double timestamp; int eventValue; long keysUsage = -1; PsychHIDEventRecord evt; result=kIOReturnError; if (!queue) return; // Nothing we can do because we can't access queue, (shouldn't happen) while (1) { // This function only gets called when queue transitions from empty to non-empty // Therefore, we must process all available events in this while loop before // it will be possible for this function to be notified again. if (valueRef) { CFRelease(valueRef); valueRef = NULL; } // Dequeue next event from queue in a polling non-blocking fashion: valueRef = IOHIDQueueCopyNextValueWithTimeout(queue, 0.0); // Done? Exit, if so: if (!valueRef) break; // Get event value, e.g., the key state of a key or button 1 = pressed, 0 = released: eventValue = IOHIDValueGetIntegerValue(valueRef); // Get usage value, ie., the identity of the key: IOHIDElementRef element = IOHIDValueGetElement(valueRef); keysUsage = IOHIDElementGetUsage(element); // Get double GetSecs timestamp, computed from returned uint64 nanoseconds timestamp: timestamp = convertTime(IOHIDValueGetTimeStamp(valueRef)); // Don't bother with keysUsage of 0 (meaningless) or 1 (ErrorRollOver) for keyboards: if ((queueIsAKeyboard[deviceIndex]) && (keysUsage <= 1)) continue; // Clear ringbuffer event: memset(&evt, 0 , sizeof(evt)); // Cooked key code defaults to "unhandled", and stays that way for anything but keyboards: evt.cookedEventCode = -1; // For real keyboards we can compute cooked key codes: Requires OSX 10.5 or later. if (queueIsAKeyboard[deviceIndex]) { // Keyboard(ish) device. We can handle this under some conditions. // Init to a default of handled, but unmappable/ignored keycode: evt.cookedEventCode = 0; // Keypress event code available in mapping table? if (keysUsage < kHID2VKCSize) { // Yes: We try to map this to a character code: // Step 1: Map HID usage value to virtual keycode via LUT: uint16_t vcKey = kHID2VKC[keysUsage]; // Keep track of SHIFT keys as modifier keys: Bits 0 == Command, 1 == Shift, 2 == CapsLock, 3 == Alt/Option, 4 == CTRL if ((vcKey == kVKC_Shift || vcKey == kVKC_rShift) && (eventValue != 0)) modifierKeyState[deviceIndex] |= (1 << 1); if ((vcKey == kVKC_Shift || vcKey == kVKC_rShift) && (eventValue == 0)) modifierKeyState[deviceIndex] &= ~(1 << 1); // Keep track of ALT keys as modifier keys: if ((vcKey == kVKC_Option || vcKey == kVKC_rOption) && (eventValue != 0)) modifierKeyState[deviceIndex] |= (1 << 3); if ((vcKey == kVKC_Option || vcKey == kVKC_rOption) && (eventValue == 0)) modifierKeyState[deviceIndex] &= ~(1 << 3); // Keep track of CTRL keys as modifier keys: if ((vcKey == kVKC_Control || vcKey == kVKC_rControl) && (eventValue != 0)) modifierKeyState[deviceIndex] |= (1 << 4); if ((vcKey == kVKC_Control || vcKey == kVKC_rControl) && (eventValue == 0)) modifierKeyState[deviceIndex] &= ~(1 << 4); // Was this a CTRL + C interrupt request? if ((eventValue != 0) && (vcKey == 0x08) && (modifierKeyState[deviceIndex] & (1 << 4))) { // Yes: Tell the console input helper about it, so it can send interrupt // signals to the runtime and reenable keyboard input if appropriate: // Note: Not sure if the mutex exclusion is needed here, but better safe than sorry. PsychLockMutex(&KbQueueMutex); ConsoleInputHelper(-1); PsychUnlockMutex(&KbQueueMutex); } // Key press? if (eventValue != 0) { // Step 2: Translate virtual key code into unicode char: // Ok, this is the usual horrifying complexity of Apple's system. We use code // snippets found on StackOverflow, modified to suit our needs, e.g., we track // modifier keys manually, at least left and right ALT and SHIFT keys. We don't // care about other modifiers. TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); CFDataRef uchr = (CFDataRef) ((currentKeyboard) ? TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData) : NULL); const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*) ((uchr) ? CFDataGetBytePtr(uchr) : NULL); if (keyboardLayout) { UInt32 deadKeyState = 0; UniCharCount maxStringLength = 255; UniCharCount actualStringLength = 0; UniChar unicodeString[maxStringLength]; OSStatus status = UCKeyTranslate(keyboardLayout, vcKey, kUCKeyActionDown, modifierKeyState[deviceIndex], LMGetKbdType(), 0, &deadKeyState, maxStringLength, &actualStringLength, unicodeString); if ((actualStringLength == 0) && deadKeyState) { status = UCKeyTranslate(keyboardLayout, kVK_Space, kUCKeyActionDown, 0, LMGetKbdType(), 0, &deadKeyState, maxStringLength, &actualStringLength, unicodeString); } if((actualStringLength > 0) && (status == noErr)) { // Assign final cooked / mapped keycode: evt.cookedEventCode = (int) unicodeString[0]; // Send same keystroke character to console input helper. // In kbqueue-based ListenChar(1) mode, the helper will // inject/forward the character into the runtime: // Note: ConsoleInputHelper() should be safe to call without // mutex protection for >= 0 event codes. ConsoleInputHelper(evt.cookedEventCode); } } } } } PsychLockMutex(&KbQueueMutex); // Update records of first and latest key presses and releases if (eventValue != 0) { if (psychHIDKbQueueFirstPress[deviceIndex]) { // First key press timestamp: if (psychHIDKbQueueFirstPress[deviceIndex][keysUsage-1] == 0) { psychHIDKbQueueFirstPress[deviceIndex][keysUsage-1] = timestamp; } } if (psychHIDKbQueueLastPress[deviceIndex]) { // Last key press timestamp: psychHIDKbQueueLastPress[deviceIndex][keysUsage-1] = timestamp; } evt.status |= (1 << 0); } else { if (psychHIDKbQueueFirstRelease[deviceIndex]) { // First key release timestamp: if (psychHIDKbQueueFirstRelease[deviceIndex][keysUsage-1] == 0) psychHIDKbQueueFirstRelease[deviceIndex][keysUsage-1] = timestamp; } if (psychHIDKbQueueLastRelease[deviceIndex]) { // Last key release timestamp: psychHIDKbQueueLastRelease[deviceIndex][keysUsage-1] = timestamp; } evt.status &= ~(1 << 0); } // Update event buffer: evt.timestamp = timestamp; evt.rawEventCode = keysUsage; PsychHIDAddEventToEventBuffer(deviceIndex, &evt); // Tell waiting userspace (under KbQueueMutxex protection for better scheduling) something interesting has changed: PsychSignalCondition(&KbQueueCondition); PsychUnlockMutex(&KbQueueMutex); // Next while loop iteration to dequeue potentially more events: } // Done for this queue transition. Return to runloop. }
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; } } }
static void input_callback(void *context, IOReturn result, void *sender, IOHIDValueRef value) { struct input_data *input = (struct input_data*)context; IOHIDElementRef elem = IOHIDValueGetElement(value); uint32_t page = IOHIDElementGetUsagePage(elem); uint32_t usage = IOHIDElementGetUsage(elem); uint32_t val = IOHIDValueGetIntegerValue(value); if (page == kHIDPage_GenericDesktop) { if (input->ignore_mouse) { return; } switch (usage) { case kHIDUsage_GD_X: pthread_mutex_lock(&input->mouse_mutex); input->mouse_x += val; pthread_mutex_unlock(&input->mouse_mutex); break; case kHIDUsage_GD_Y: pthread_mutex_lock(&input->mouse_mutex); input->mouse_y += val; pthread_mutex_unlock(&input->mouse_mutex); break; case kHIDUsage_GD_Wheel: if ((int32_t)val > 0) { add_to_event_queue(input, K_MWHEELUP, true); add_to_event_queue(input, K_MWHEELUP, false); } else if ((int32_t)val < 0) { add_to_event_queue(input, K_MWHEELDOWN, true); add_to_event_queue(input, K_MWHEELDOWN, false); } break; default: break; } } else if (page == kHIDPage_Button) { if (input->ignore_mouse) { return; } if (usage < 1 || usage > 10) { usage = 10; } add_to_event_queue(input, K_MOUSE1 + usage - 1, val ? true : false); } else if (page == kHIDPage_KeyboardOrKeypad) { if (usage == kHIDUsage_KeyboardLeftGUI) { input->left_cmd_key_active = val ? true : false; } else if (usage == kHIDUsage_KeyboardRightGUI) { input->right_cmd_key_active = val ? true : false; } if (usage < sizeof(keytable) && (input->left_cmd_key_active || input->right_cmd_key_active)) { if (keytable[usage] == 'c' && val) { add_to_event_queue(input, K_COPY, true); add_to_event_queue(input, K_COPY, false); } else if (keytable[usage] == 'v' && val) { add_to_event_queue(input, K_PASTE, true); add_to_event_queue(input, K_PASTE, false); } return; } if (usage < sizeof(keytable)) { add_to_event_queue(input, keytable[usage], val ? true : false); pthread_mutex_lock(&input->key_mutex); if (val) { input->repeatkey = keytable[usage]; input->nextrepeattime = Sys_IntTime() + input->key_repeat_initial_delay; } else { input->repeatkey = 0; input->nextrepeattime = 0; } pthread_mutex_unlock(&input->key_mutex); } } else if (page == 0xFF) { if (usage == kHIDUsage_KeyboardErrorUndefined) { input->fn_key_active = val ? true : false; } } }
JoystickState JoystickImpl::update() { static const JoystickState disconnectedState; // return this if joystick was disconnected JoystickState state; // otherwise return that state.connected = true; // Note: free up is done in close() which is called, if required, // by the joystick manager. So we don't release buttons nor axes here. // First, let's determine if the joystick is still connected Location selfLoc = m_locationIDs[m_index]; // Get all devices CFSetRef devices = HIDJoystickManager::getInstance().copyJoysticks(); if (devices == NULL) return disconnectedState; // Get a usable copy of the joysticks devices. CFIndex joysticksCount = CFSetGetCount(devices); CFTypeRef devicesArray[joysticksCount]; CFSetGetValues(devices, devicesArray); // Search for it bool found = false; for (CFIndex i(0); i < joysticksCount; ++i) { IOHIDDeviceRef d = (IOHIDDeviceRef)devicesArray[i]; if (selfLoc == HIDInputManager::getLocationID(d)) { found = true; break; // Stop looping } } // Release unused stuff CFRelease(devices); // If not found we consider it disconnected if (!found) return disconnectedState; // Update buttons' state unsigned int i = 0; for (ButtonsVector::iterator it(m_buttons.begin()); it != m_buttons.end(); ++it, ++i) { IOHIDValueRef value = 0; IOHIDDeviceGetValue(IOHIDElementGetDevice(*it), *it, &value); // Check for plug out. if (!value) { // No value? Hum... Seems like the joystick is gone return disconnectedState; } // 1 means pressed, others mean released state.buttons[i] = IOHIDValueGetIntegerValue(value) == 1; } // Update axes' state for (AxisMap::iterator it = m_axis.begin(); it != m_axis.end(); ++it) { IOHIDValueRef value = 0; IOHIDDeviceGetValue(IOHIDElementGetDevice(it->second), it->second, &value); // Check for plug out. if (!value) { // No value? Hum... Seems like the joystick is gone return disconnectedState; } // We want to bind [physicalMin,physicalMax] to [-100=min,100=max]. // // General formula to bind [a,b] to [c,d] with a linear progression: // // f: [a, b] -> [c, d] // x |-> (x-a)(d-c)/(b-a)+c // // This method might not be very accurate (the "0 position" can be // slightly shift with some device) but we don't care because most // of devices are so sensitive that this is not relevant. double physicalMax = IOHIDElementGetPhysicalMax(it->second); double physicalMin = IOHIDElementGetPhysicalMin(it->second); double scaledMin = -100; double scaledMax = 100; double physicalValue = IOHIDValueGetScaledValue(value, kIOHIDValueScaleTypePhysical); float scaledValue = (((physicalValue - physicalMin) * (scaledMax - scaledMin)) / (physicalMax - physicalMin)) + scaledMin; state.axes[it->first] = scaledValue; } return state; }
static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface) { JoystickImpl *device = impl_from_IDirectInputDevice8A(iface); IOHIDElementRef tIOHIDTopElementRef; IOHIDDeviceRef tIOHIDDeviceRef; CFArrayRef gElementCFArrayRef = device->elementCFArrayRef; TRACE("polling device %i\n",device->id); if (!gCollections) return; tIOHIDTopElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gCollections, device->id); tIOHIDDeviceRef = IOHIDElementGetDevice(tIOHIDTopElementRef); if (!tIOHIDDeviceRef) return; if (gElementCFArrayRef) { int button_idx = 0; int pov_idx = 0; int slider_idx = 0; int inst_id; CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef ); for ( idx = 0; idx < cnt; idx++ ) { IOHIDValueRef valueRef; int val, oldVal, newVal; IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx ); int eleType = IOHIDElementGetType( tIOHIDElementRef ); switch(eleType) { case kIOHIDElementTypeInput_Button: if(button_idx < 128) { IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef); val = IOHIDValueGetIntegerValue(valueRef); newVal = val ? 0x80 : 0x0; oldVal = device->generic.js.rgbButtons[button_idx]; device->generic.js.rgbButtons[button_idx] = newVal; if (oldVal != newVal) { inst_id = DIDFT_MAKEINSTANCE(button_idx) | DIDFT_PSHBUTTON; queue_event(iface,inst_id,newVal,GetCurrentTime(),device->generic.base.dinput->evsequence++); } button_idx ++; } break; case kIOHIDElementTypeInput_Misc: { uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef ); switch(usage) { case kHIDUsage_GD_Hatswitch: { IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef); val = IOHIDValueGetIntegerValue(valueRef); oldVal = device->generic.js.rgdwPOV[pov_idx]; if (val >= 8) newVal = -1; else newVal = val * 4500; device->generic.js.rgdwPOV[pov_idx] = newVal; if (oldVal != newVal) { inst_id = DIDFT_MAKEINSTANCE(pov_idx) | DIDFT_POV; queue_event(iface,inst_id,newVal,GetCurrentTime(),device->generic.base.dinput->evsequence++); } pov_idx ++; break; } case kHIDUsage_GD_X: case kHIDUsage_GD_Y: case kHIDUsage_GD_Z: case kHIDUsage_GD_Rx: case kHIDUsage_GD_Ry: case kHIDUsage_GD_Rz: case kHIDUsage_GD_Slider: { int wine_obj = -1; IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef); val = IOHIDValueGetIntegerValue(valueRef); newVal = joystick_map_axis(&device->generic.props[idx], val); switch (usage) { case kHIDUsage_GD_X: wine_obj = 0; oldVal = device->generic.js.lX; device->generic.js.lX = newVal; break; case kHIDUsage_GD_Y: wine_obj = 1; oldVal = device->generic.js.lY; device->generic.js.lY = newVal; break; case kHIDUsage_GD_Z: wine_obj = 2; oldVal = device->generic.js.lZ; device->generic.js.lZ = newVal; break; case kHIDUsage_GD_Rx: wine_obj = 3; oldVal = device->generic.js.lRx; device->generic.js.lRx = newVal; break; case kHIDUsage_GD_Ry: wine_obj = 4; oldVal = device->generic.js.lRy; device->generic.js.lRy = newVal; break; case kHIDUsage_GD_Rz: wine_obj = 5; oldVal = device->generic.js.lRz; device->generic.js.lRz = newVal; break; case kHIDUsage_GD_Slider: wine_obj = 6 + slider_idx; oldVal = device->generic.js.rglSlider[slider_idx]; device->generic.js.rglSlider[slider_idx] = newVal; slider_idx ++; break; } if ((wine_obj != -1) && (oldVal != newVal)) { inst_id = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS; queue_event(iface,inst_id,newVal,GetCurrentTime(),device->generic.base.dinput->evsequence++); } break; } default: FIXME("unhandled usage %i\n",usage); } break; } default: FIXME("Unhandled type %i\n",eleType); } } } }
static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface) { JoystickImpl *device = (JoystickImpl*)iface; IOHIDElementRef tIOHIDTopElementRef; IOHIDDeviceRef tIOHIDDeviceRef; CFArrayRef gElementCFArrayRef = device->elementCFArrayRef; TRACE("polling device %i\n",device->id); if (!gCollections) return; tIOHIDTopElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gCollections, device->id); tIOHIDDeviceRef = IOHIDElementGetDevice(tIOHIDTopElementRef); if (!tIOHIDDeviceRef) return; if (gElementCFArrayRef) { int button_idx = 0; int pov_idx = 0; int slider_idx = 0; CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef ); for ( idx = 0; idx < cnt; idx++ ) { IOHIDValueRef valueRef; int val; IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx ); int eleType = IOHIDElementGetType( tIOHIDElementRef ); switch(eleType) { case kIOHIDElementTypeInput_Button: if(button_idx < 128) { IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef); val = IOHIDValueGetIntegerValue(valueRef); device->generic.js.rgbButtons[button_idx] = val ? 0x80 : 0x00; button_idx ++; } break; case kIOHIDElementTypeInput_Misc: { uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef ); switch(usage) { case kHIDUsage_GD_Hatswitch: { IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef); val = IOHIDValueGetIntegerValue(valueRef); if (val >= 8) device->generic.js.rgdwPOV[pov_idx] = -1; else device->generic.js.rgdwPOV[pov_idx] = val * 4500; pov_idx ++; break; } case kHIDUsage_GD_X: case kHIDUsage_GD_Y: case kHIDUsage_GD_Z: case kHIDUsage_GD_Rx: case kHIDUsage_GD_Ry: case kHIDUsage_GD_Rz: case kHIDUsage_GD_Slider: { IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef); val = IOHIDValueGetIntegerValue(valueRef); switch (usage) { case kHIDUsage_GD_X: device->generic.js.lX = joystick_map_axis(&device->generic.props[idx], val); break; case kHIDUsage_GD_Y: device->generic.js.lY = joystick_map_axis(&device->generic.props[idx], val); break; case kHIDUsage_GD_Z: device->generic.js.lZ = joystick_map_axis(&device->generic.props[idx], val); break; case kHIDUsage_GD_Rx: device->generic.js.lRx = joystick_map_axis(&device->generic.props[idx], val); break; case kHIDUsage_GD_Ry: device->generic.js.lRy = joystick_map_axis(&device->generic.props[idx], val); break; case kHIDUsage_GD_Rz: device->generic.js.lRz = joystick_map_axis(&device->generic.props[idx], val); break; case kHIDUsage_GD_Slider: device->generic.js.rglSlider[slider_idx] = joystick_map_axis(&device->generic.props[idx], val); slider_idx ++; break; } break; } default: FIXME("unhandled usage %i\n",usage); } break; } default: FIXME("Unhandled type %i\n",eleType); } } } }
void GamepadManager::onDeviceValueChanged(IOHIDValueRef value) { IOHIDElementRef element = IOHIDValueGetElement(value); IOHIDDeviceRef device = IOHIDElementGetDevice(element); int vendorID = getIntDeviceProperty(device, CFSTR(kIOHIDVendorIDKey)); int productID = getIntDeviceProperty(device, CFSTR(kIOHIDProductIDKey)); uint32_t usagePage = IOHIDElementGetUsagePage(element); uint32_t usage = IOHIDElementGetUsage(element); // The following controller mapping is based on the Logitech F710, however we use it for // all Logitech devices on the assumption that they're likely to share the same mapping. if (vendorID == Logitech_F710_VendorID) { // Logitech F710 mapping. if (usagePage == kHIDPage_Button) { bool buttonState = IOHIDValueGetIntegerValue(value); switch(usage) { case kHIDUsage_Button_1: manipulateBitField(State.Buttons, Gamepad_X, buttonState); break; case kHIDUsage_Button_2: manipulateBitField(State.Buttons, Gamepad_A, buttonState); break; case kHIDUsage_Button_3: manipulateBitField(State.Buttons, Gamepad_B, buttonState); break; case kHIDUsage_Button_4: manipulateBitField(State.Buttons, Gamepad_Y, buttonState); break; case 0x05: manipulateBitField(State.Buttons, Gamepad_L1, buttonState); break; case 0x06: manipulateBitField(State.Buttons, Gamepad_R1, buttonState); break; case 0x07: State.LT = buttonState ? 1.0f:0.0f; break; case 0x08: State.RT = buttonState ? 1.0f:0.0f; break; case 0x09: manipulateBitField(State.Buttons, Gamepad_Back, buttonState); break; case 0x0A: manipulateBitField(State.Buttons, Gamepad_Start, buttonState); break; case 0x0B: manipulateBitField(State.Buttons, Gamepad_LStick, buttonState); break; case 0x0C: manipulateBitField(State.Buttons, Gamepad_RStick, buttonState); break; default: return; } } else if (usagePage == kHIDPage_GenericDesktop) { float v; switch(usage) { case kHIDUsage_GD_X: v = mapAnalogAxis(value, element); if (!setStateIfDifferent(State.LX, v)) return; break; case kHIDUsage_GD_Y: v = mapAnalogAxis(value, element); if (!setStateIfDifferent(State.LY, -v)) return; break; case kHIDUsage_GD_Z: v = mapAnalogAxis(value, element); if (!setStateIfDifferent(State.RX, v)) return; break; case kHIDUsage_GD_Rz: v = mapAnalogAxis(value, element); if (!setStateIfDifferent(State.RY, -v)) return; break; case kHIDUsage_GD_Hatswitch: { CFIndex integerValue = IOHIDValueGetIntegerValue(value); manipulateBitField(State.Buttons, Gamepad_Up, integerValue == 7 || integerValue == 0 || integerValue == 1); manipulateBitField(State.Buttons, Gamepad_Down, integerValue == 3 || integerValue == 4 || integerValue == 5); manipulateBitField(State.Buttons, Gamepad_Left, integerValue == 5 || integerValue == 6 || integerValue == 7); manipulateBitField(State.Buttons, Gamepad_Right, integerValue == 1 || integerValue == 2 || integerValue == 3); } break; default: return; } } } // The following controller mapping is based on the Sony DualShock3, however we use it for // all Sony devices on the assumption that they're likely to share the same mapping. else if (vendorID == Sony_DualShock3_VendorID) { // PS3 Controller. if (usagePage == kHIDPage_Button) { bool buttonState = IOHIDValueGetIntegerValue(value); switch(usage) { case kHIDUsage_Button_1: manipulateBitField(State.Buttons, Gamepad_Back, buttonState); break; case kHIDUsage_Button_2: manipulateBitField(State.Buttons, Gamepad_LStick, buttonState); break; case kHIDUsage_Button_3: manipulateBitField(State.Buttons, Gamepad_RStick, buttonState); break; case kHIDUsage_Button_4: manipulateBitField(State.Buttons, Gamepad_Start, buttonState); break; case 0x05: manipulateBitField(State.Buttons, Gamepad_Up, buttonState); break; case 0x06: manipulateBitField(State.Buttons, Gamepad_Right, buttonState); break; case 0x07: manipulateBitField(State.Buttons, Gamepad_Down, buttonState); break; case 0x08: manipulateBitField(State.Buttons, Gamepad_Left, buttonState); break; case 0x09: State.LT = buttonState ? 1.0f:0.0f; break; case 0x0A: State.RT = buttonState ? 1.0f:0.0f; break; case 0x0B: manipulateBitField(State.Buttons, Gamepad_L1, buttonState); break; case 0x0C: manipulateBitField(State.Buttons, Gamepad_R1, buttonState); break; case 0x0D: // PS3 Triangle. manipulateBitField(State.Buttons, Gamepad_TRIANGLE, buttonState); break; case 0x0E: // PS3 Circle manipulateBitField(State.Buttons, Gamepad_CIRCLE, buttonState); break; case 0x0F: // PS3 Cross manipulateBitField(State.Buttons, Gamepad_CROSS, buttonState); break; case 0x10: // PS3 Square manipulateBitField(State.Buttons, Gamepad_SQUARE, buttonState); break; default: return; } } else if (usagePage == kHIDPage_GenericDesktop) { float v; switch(usage) { case kHIDUsage_GD_X: v = mapAnalogAxis(value, element); if (!setStateIfDifferent(State.LX, v)) return; break; case kHIDUsage_GD_Y: v = mapAnalogAxis(value, element); if (!setStateIfDifferent(State.LY, -v)) return; break; case kHIDUsage_GD_Z: v = mapAnalogAxis(value, element); if (!setStateIfDifferent(State.RX, v)) return; break; case kHIDUsage_GD_Rz: v = mapAnalogAxis(value, element); if (!setStateIfDifferent(State.RY, -v)) return; break; default: return; } } } bStateChanged = true; }
void __deviceValueCallback (void * context, IOReturn result, void * sender, IOHIDValueRef value) { IOHIDElementRef element = IOHIDValueGetElement(value); printf("IOHIDDeviceRef[%p]: value=%p timestamp=%lld cookie=%d usagePage=0x%02X usage=0x%02X intValue=%ld\n", sender, value, IOHIDValueGetTimeStamp(value), (uint32_t)IOHIDElementGetCookie(element), IOHIDElementGetUsagePage(element), IOHIDElementGetUsage(element), IOHIDValueGetIntegerValue(value)); }
static void iohidmanager_hid_device_input_callback(void *data, IOReturn result, void* sender, IOHIDValueRef value) { iohidmanager_hid_t *hid = (iohidmanager_hid_t*)hid_driver_get_data(); struct iohidmanager_hid_adapter *adapter = (struct iohidmanager_hid_adapter*)data; IOHIDElementRef element = IOHIDValueGetElement(value); uint32_t type = (uint32_t)IOHIDElementGetType(element); uint32_t page = (uint32_t)IOHIDElementGetUsagePage(element); uint32_t use = (uint32_t)IOHIDElementGetUsage(element); uint32_t cookie = (uint32_t)IOHIDElementGetCookie(element); apple_input_rec_t *tmp = NULL; if (type != kIOHIDElementTypeInput_Misc) if (type != kIOHIDElementTypeInput_Button) if (type != kIOHIDElementTypeInput_Axis) return; /* Joystick handler. * TODO: Can GamePad work the same? */ int pushed_button = 0; switch (page) { case kHIDPage_GenericDesktop: switch (type) { case kIOHIDElementTypeInput_Misc: switch (use) { case kHIDUsage_GD_Hatswitch: { tmp = adapter->hats; while(tmp && tmp->cookie != (IOHIDElementCookie)cookie) tmp = tmp->next; if(tmp->cookie == (IOHIDElementCookie)cookie) { CFIndex range = IOHIDElementGetLogicalMax(element) - IOHIDElementGetLogicalMin(element); CFIndex val = IOHIDValueGetIntegerValue(value); if(range == 3) val *= 2; switch(val) { case 0: /* pos = up */ hid->hats[adapter->slot][0] = 0; hid->hats[adapter->slot][1] = -1; break; case 1: /* pos = up+right */ hid->hats[adapter->slot][0] = 1; hid->hats[adapter->slot][1] = -1; break; case 2: /* pos = right */ hid->hats[adapter->slot][0] = 1; hid->hats[adapter->slot][1] = 0; break; case 3: /* pos = down+right */ hid->hats[adapter->slot][0] = 1; hid->hats[adapter->slot][1] = 1; break; case 4: /* pos = down */ hid->hats[adapter->slot][0] = 0; hid->hats[adapter->slot][1] = 1; break; case 5: /* pos = down+left */ hid->hats[adapter->slot][0] = -1; hid->hats[adapter->slot][1] = 1; break; case 6: /* pos = left */ hid->hats[adapter->slot][0] = -1; hid->hats[adapter->slot][1] = 0; break; case 7: /* pos = up_left */ hid->hats[adapter->slot][0] = -1; hid->hats[adapter->slot][1] = -1; break; default: /* pos = centered */ hid->hats[adapter->slot][0] = 0; hid->hats[adapter->slot][1] = 0; break; } } } break; default: tmp = adapter->axes; while(tmp && tmp->cookie != (IOHIDElementCookie)cookie) tmp = tmp->next; if (tmp) { if(tmp->cookie == (IOHIDElementCookie)cookie) { CFIndex min = IOHIDElementGetPhysicalMin(element); CFIndex state = IOHIDValueGetIntegerValue(value) - min; CFIndex max = IOHIDElementGetPhysicalMax(element) - min; float val = (float)state / (float)max; hid->axes[adapter->slot][tmp->id] = ((val * 2.0f) - 1.0f) * 32767.0f; } } else pushed_button = 1; break; } break; } break; case kHIDPage_Consumer: case kHIDPage_Button: switch (type) { case kIOHIDElementTypeInput_Misc: case kIOHIDElementTypeInput_Button: pushed_button = 1; break; } break; } if (pushed_button) { tmp = adapter->buttons; uint8_t bit = 0; while(tmp && tmp->cookie != (IOHIDElementCookie)cookie) { bit++; tmp = tmp->next; } if(tmp && tmp->cookie == (IOHIDElementCookie)cookie) { CFIndex state = IOHIDValueGetIntegerValue(value); if (state) BIT64_SET(hid->buttons[adapter->slot], bit); else BIT64_CLEAR(hid->buttons[adapter->slot], bit); } } }
static void apple_hid_device_input_callback(void *data, IOReturn result, void* sender, IOHIDValueRef value) { driver_t *driver = driver_get_ptr(); apple_input_data_t *apple = (apple_input_data_t*)driver->input_data; struct apple_hid_adapter *adapter = (struct apple_hid_adapter*)data; IOHIDElementRef element = IOHIDValueGetElement(value); uint32_t type = IOHIDElementGetType(element); uint32_t page = IOHIDElementGetUsagePage(element); uint32_t use = IOHIDElementGetUsage(element); if (type != kIOHIDElementTypeInput_Misc) if (type != kIOHIDElementTypeInput_Button) if (type != kIOHIDElementTypeInput_Axis) return; /* Joystick handler. * TODO: Can GamePad work the same? */ switch (page) { case kHIDPage_GenericDesktop: switch (type) { case kIOHIDElementTypeInput_Misc: switch (use) { case kHIDUsage_GD_Hatswitch: break; default: { int i; static const uint32_t axis_use_ids[4] = { 48, 49, 50, 53 }; for (i = 0; i < 4; i ++) { CFIndex min = IOHIDElementGetPhysicalMin(element); CFIndex max = IOHIDElementGetPhysicalMax(element) - min; CFIndex state = IOHIDValueGetIntegerValue(value) - min; float val = (float)state / (float)max; if (use != axis_use_ids[i]) continue; apple->axes[adapter->slot][i] = ((val * 2.0f) - 1.0f) * 32767.0f; } } break; } break; } break; case kHIDPage_Button: switch (type) { case kIOHIDElementTypeInput_Button: { CFIndex state = IOHIDValueGetIntegerValue(value); unsigned id = use - 1; if (state) BIT64_SET(apple->buttons[adapter->slot], id); else BIT64_CLEAR(apple->buttons[adapter->slot], id); } break; } break; } }
/************************************************************************** * driver_joyGetPosEx */ LRESULT driver_joyGetPosEx(DWORD_PTR device_id, JOYINFOEX* info) { static const struct { DWORD flag; off_t offset; } axis_map[NUM_AXES] = { { JOY_RETURNX, FIELD_OFFSET(JOYINFOEX, dwXpos) }, { JOY_RETURNY, FIELD_OFFSET(JOYINFOEX, dwYpos) }, { JOY_RETURNZ, FIELD_OFFSET(JOYINFOEX, dwZpos) }, { JOY_RETURNU, FIELD_OFFSET(JOYINFOEX, dwUpos) }, { JOY_RETURNV, FIELD_OFFSET(JOYINFOEX, dwVpos) }, { JOY_RETURNR, FIELD_OFFSET(JOYINFOEX, dwRpos) }, }; joystick_t* joystick; IOHIDDeviceRef device; CFIndex i, count; IOHIDValueRef valueRef; long value; if ((joystick = joystick_from_id(device_id)) == NULL) return MMSYSERR_NODRIVER; if (!open_joystick(joystick)) return JOYERR_PARMS; device = IOHIDElementGetDevice(joystick->element); if (info->dwFlags & JOY_RETURNBUTTONS) { info->dwButtons = 0; info->dwButtonNumber = 0; count = CFArrayGetCount(joystick->buttons); for (i = 0; i < count; i++) { IOHIDElementRef button = (IOHIDElementRef)CFArrayGetValueAtIndex(joystick->buttons, i); IOHIDDeviceGetValue(device, button, &valueRef); value = IOHIDValueGetIntegerValue(valueRef); if (value) { info->dwButtons |= 1 << i; if (!info->dwButtonNumber) info->dwButtonNumber = i + 1; } } } for (i = 0; i < NUM_AXES; i++) { if (info->dwFlags & axis_map[i].flag) { DWORD* field = (DWORD*)((char*)info + axis_map[i].offset); if (joystick->axes[i].element) { IOHIDDeviceGetValue(device, joystick->axes[i].element, &valueRef); value = IOHIDValueGetIntegerValue(valueRef) - joystick->axes[i].min_value; *field = MulDiv(value, 0xFFFF, joystick->axes[i].max_value - joystick->axes[i].min_value); } else { *field = 0; info->dwFlags &= ~axis_map[i].flag; } } } if (info->dwFlags & JOY_RETURNPOV) { if (joystick->hatswitch) { IOHIDDeviceGetValue(device, joystick->hatswitch, &valueRef); value = IOHIDValueGetIntegerValue(valueRef); if (value >= 8) info->dwPOV = JOY_POVCENTERED; else info->dwPOV = value * 4500; } else { info->dwPOV = 0; info->dwFlags &= ~JOY_RETURNPOV; } } TRACE("x: %d, y: %d, z: %d, r: %d, u: %d, v: %d, buttons: 0x%04x, pov %d, flags: 0x%04x\n", info->dwXpos, info->dwYpos, info->dwZpos, info->dwRpos, info->dwUpos, info->dwVpos, info->dwButtons, info->dwPOV, info->dwFlags); return JOYERR_NOERROR; }
void Burger::Mouse::InputCallback(void *pData, int iReturn,void * /* pSender */,IOHIDValueRef pValue) { if (iReturn == kIOReturnSuccess) { Mouse *pMouse = static_cast<Mouse *>(pData); Word uCount = pMouse->m_uMiceCount; if (uCount) { IOHIDElementRef pElement = IOHIDValueGetElement(pValue); IOHIDDeviceRef pDevice = IOHIDElementGetDevice(pElement); #if 0 Word uRatNumber = BURGER_MAXUINT; const DeviceStruct *pRat = pMouse->m_Mice; do { if (pRat->m_pDevice == pDevice) { uRatNumber = pMouse->m_uMiceCount-uCount; break; } ++pRat; } while (--uCount); if (uRatNumber==BURGER_MAXUINT) { } #endif Word32 uTime = static_cast<Word32>(IOHIDValueGetTimeStamp(pValue)); CFIndex iValue = IOHIDValueGetIntegerValue(pValue); uint32_t uPage = IOHIDElementGetUsagePage(pElement); uint32_t uUsage = IOHIDElementGetUsage(pElement); switch (uPage) { case kHIDPage_GenericDesktop: if (iValue) { switch (uUsage) { case kHIDUsage_GD_X: pMouse->PostMouseMotion(static_cast<Int32>(iValue),0,uTime); break; case kHIDUsage_GD_Y: pMouse->PostMouseMotion(0,static_cast<Int32>(iValue),uTime); break; case kHIDUsage_GD_Wheel: pMouse->PostMouseWheel(0,static_cast<Int32>(iValue),uTime); break; default: printf("Unknown usage %u\n",uUsage); break; } } break; case kHIDPage_Button: // iValue == down // Usage = which 1.2.3.4 if (iValue) { pMouse->PostMouseDown(1<<(uUsage-1)); } else { pMouse->PostMouseUp(1<<(uUsage-1)); } break; // Ignore this one case kHIDPage_Consumer: break; default: printf("Unknown page found %u\n",uPage); break; } } } }
static void iohidmanager_hid_device_input_callback(void *data, IOReturn result, void* sender, IOHIDValueRef value) { iohidmanager_hid_t *hid = (iohidmanager_hid_t*)hid_driver_get_data(); struct iohidmanager_hid_adapter *adapter = (struct iohidmanager_hid_adapter*)data; IOHIDElementRef element = IOHIDValueGetElement(value); uint32_t type = IOHIDElementGetType(element); uint32_t page = IOHIDElementGetUsagePage(element); uint32_t use = IOHIDElementGetUsage(element); if (type != kIOHIDElementTypeInput_Misc) if (type != kIOHIDElementTypeInput_Button) if (type != kIOHIDElementTypeInput_Axis) return; /* Joystick handler. * TODO: Can GamePad work the same? */ switch (page) { case kHIDPage_GenericDesktop: switch (type) { case kIOHIDElementTypeInput_Misc: switch (use) { case kHIDUsage_GD_Hatswitch: break; default: { int i; // +0/-0 => Left Stick Horizontal => 48 // +1/-1 => Left Stick Vertical => 49 // +2/-2 => Right Stick Horizontal => 51 // +3/-3 => Right Stick Vertical => 52 // +4/-4 => Left Trigger (if exists) => 50 // +5/-5 => Right Trigger (if exists) => 53 static const uint32_t axis_use_ids[6] = { 48, 49, 51, 52, 50, 53 }; for (i = 0; i < 6; i ++) { CFIndex min = IOHIDElementGetPhysicalMin(element); CFIndex state = IOHIDValueGetIntegerValue(value) - min; CFIndex max = IOHIDElementGetPhysicalMax(element) - min; float val = (float)state / (float)max; if (use != axis_use_ids[i]) continue; hid->axes[adapter->slot][i] = ((val * 2.0f) - 1.0f) * 32767.0f; } } break; } break; } break; case kHIDPage_Button: switch (type) { case kIOHIDElementTypeInput_Button: { CFIndex state = IOHIDValueGetIntegerValue(value); unsigned id = use - 1; if (state) BIT64_SET(hid->buttons[adapter->slot], id); else BIT64_CLEAR(hid->buttons[adapter->slot], id); } break; } break; } }