void HIDGamepad::getCurrentValueForElement(const HIDGamepadElement& gamepadElement) { IOHIDElementRef element = gamepadElement.iohidElement.get(); IOHIDValueRef value; if (IOHIDDeviceGetValue(IOHIDElementGetDevice(element), element, &value) == kIOReturnSuccess) valueChanged(value); }
// ************************************************************************* // // IOHIDElement_GetValue(inIOHIDElementRef, inIOHIDValueScaleType) // // Purpose: returns the current value for an element(polling) // // Notes: will return 0 on error conditions which should be accounted for by application // // Inputs: inIOHIDElementRef - the element // inIOHIDValueScaleType - scale type (calibrated or physical) // // Returns: double - current value for element // double IOHIDElement_GetValue(IOHIDElementRef inIOHIDElementRef, IOHIDValueScaleType inIOHIDValueScaleType) { double result = NAN; IOHIDValueRef tIOHIDValueRef; if (kIOReturnSuccess == IOHIDDeviceGetValue(IOHIDElementGetDevice(inIOHIDElementRef), inIOHIDElementRef, &tIOHIDValueRef)) { result = IOHIDValueGetScaledValue(tIOHIDValueRef, inIOHIDValueScaleType); } return (result); } // IOHIDElement_GetValue
void HIDGamepadProvider::valuesChanged(IOHIDValueRef value) { IOHIDDeviceRef device = IOHIDElementGetDevice(IOHIDValueGetElement(value)); HIDGamepad* gamepad = m_gamepadMap.get(device); // When starting monitoring we might get a value changed callback before we even know the device is connected. if (!gamepad) return; gamepad->valueChanged(value); // This isActive check is necessary as we want to delay input notifications from the time of the first input, // and not push the notification out on every subsequent input. if (!m_inputNotificationTimer.isActive()) m_inputNotificationTimer.startOneShot(InputNotificationDelay); }
static int get_osx_device_name(int id, char *name, int length) { CFStringRef str; IOHIDElementRef tIOHIDElementRef; IOHIDDeviceRef tIOHIDDeviceRef; if (!gCollections) return 0; tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(gCollections, id); if (!tIOHIDElementRef) { ERR("Invalid Element requested %i\n",id); return 0; } tIOHIDDeviceRef = IOHIDElementGetDevice(tIOHIDElementRef); if (name) name[0] = 0; if (!tIOHIDDeviceRef) { ERR("Invalid Device requested %i\n",id); return 0; } str = IOHIDDeviceGetProperty(tIOHIDDeviceRef, CFSTR( kIOHIDProductKey )); if (str) { CFIndex len = CFStringGetLength(str); if (length >= len) { CFStringGetCString(str,name,length,kCFStringEncodingASCII); return len; } else return (len+1); } return 0; }
static IOHIDDeviceRef get_device_ref(int id) { IOHIDElementRef tIOHIDElementRef; IOHIDDeviceRef tIOHIDDeviceRef; if (!gCollections) return 0; tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(gCollections, id); if (!tIOHIDElementRef) { ERR("Invalid Element requested %i\n",id); return 0; } tIOHIDDeviceRef = IOHIDElementGetDevice(tIOHIDElementRef); if (!tIOHIDDeviceRef) { ERR("Invalid Device requested %i\n",id); return 0; } return tIOHIDDeviceRef; }
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; } } } }
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; }
// utility routine to dump element info void HIDDumpElementInfo(IOHIDElementRef inIOHIDElementRef) { if (inIOHIDElementRef) { printf(" Element: %p = { ", inIOHIDElementRef); #if false IOHIDDeviceRef tIOHIDDeviceRef = IOHIDElementGetDevice(inIOHIDElementRef); printf("Device: %p, ", tIOHIDDeviceRef); #endif // if 0 IOHIDElementRef parentIOHIDElementRef = IOHIDElementGetParent(inIOHIDElementRef); printf("parent: %p, ", parentIOHIDElementRef); #if false CFArrayRef childrenCFArrayRef = IOHIDElementGetChildren(inIOHIDElementRef); printf("children: %p: { ", childrenCFArrayRef); fflush(stdout); CFShow(childrenCFArrayRef); fflush(stdout); printf(" }, "); #endif // if 0 IOHIDElementCookie tIOHIDElementCookie = IOHIDElementGetCookie(inIOHIDElementRef); printf("cookie: 0x%08lX, ", (long unsigned int) tIOHIDElementCookie); IOHIDElementType tIOHIDElementType = IOHIDElementGetType(inIOHIDElementRef); switch (tIOHIDElementType) { case kIOHIDElementTypeInput_Misc: { printf("type: Misc, "); break; } case kIOHIDElementTypeInput_Button: { printf("type: Button, "); break; } case kIOHIDElementTypeInput_Axis: { printf("type: Axis, "); break; } case kIOHIDElementTypeInput_ScanCodes: { printf("type: ScanCodes, "); break; } case kIOHIDElementTypeOutput: { printf("type: Output, "); break; } case kIOHIDElementTypeFeature: { printf("type: Feature, "); break; } case kIOHIDElementTypeCollection: { IOHIDElementCollectionType tIOHIDElementCollectionType = IOHIDElementGetCollectionType(inIOHIDElementRef); switch (tIOHIDElementCollectionType) { case kIOHIDElementCollectionTypePhysical: { printf("type: Physical Collection, "); break; } case kIOHIDElementCollectionTypeApplication: { printf("type: Application Collection, "); break; } case kIOHIDElementCollectionTypeLogical: { printf("type: Logical Collection, "); break; } case kIOHIDElementCollectionTypeReport: { printf("type: Report Collection, "); break; } case kIOHIDElementCollectionTypeNamedArray: { printf("type: Named Array Collection, "); break; } case kIOHIDElementCollectionTypeUsageSwitch: { printf("type: Usage Switch Collection, "); break; } case kIOHIDElementCollectionTypeUsageModifier: { printf("type: Usage Modifier Collection, "); break; } default: { printf("type: %p Collection, ", (void *) tIOHIDElementCollectionType); break; } } // switch break; } default: { printf("type: %p, ", (void *) tIOHIDElementType); break; } } /* switch */ uint32_t usagePage = IOHIDElementGetUsagePage(inIOHIDElementRef); uint32_t usage = IOHIDElementGetUsage(inIOHIDElementRef); printf("usage: 0x%04lX:0x%04lX, ", (long unsigned int) usagePage, (long unsigned int) usage); CFStringRef tCFStringRef = HIDCopyUsageName(usagePage, usage); if (tCFStringRef) { char usageString[256] = ""; (void) CFStringGetCString(tCFStringRef, usageString, sizeof(usageString), kCFStringEncodingUTF8); printf("\"%s\", ", usageString); CFRelease(tCFStringRef); } CFStringRef nameCFStringRef = IOHIDElementGetName(inIOHIDElementRef); char buffer[256]; if ( nameCFStringRef && CFStringGetCString(nameCFStringRef, buffer, sizeof(buffer), kCFStringEncodingUTF8) ) { printf("name: %s, ", buffer); } uint32_t reportID = IOHIDElementGetReportID(inIOHIDElementRef); uint32_t reportSize = IOHIDElementGetReportSize(inIOHIDElementRef); uint32_t reportCount = IOHIDElementGetReportCount(inIOHIDElementRef); printf("report: { ID: %lu, Size: %lu, Count: %lu }, ", (long unsigned int) reportID, (long unsigned int) reportSize, (long unsigned int) reportCount); uint32_t unit = IOHIDElementGetUnit(inIOHIDElementRef); uint32_t unitExp = IOHIDElementGetUnitExponent(inIOHIDElementRef); if (unit || unitExp) { printf("unit: %lu * 10^%lu, ", (long unsigned int) unit, (long unsigned int) unitExp); } CFIndex logicalMin = IOHIDElementGetLogicalMin(inIOHIDElementRef); CFIndex logicalMax = IOHIDElementGetLogicalMax(inIOHIDElementRef); if (logicalMin != logicalMax) { printf("logical: {min: %ld, max: %ld}, ", logicalMin, logicalMax); } CFIndex physicalMin = IOHIDElementGetPhysicalMin(inIOHIDElementRef); CFIndex physicalMax = IOHIDElementGetPhysicalMax(inIOHIDElementRef); if (physicalMin != physicalMax) { printf("physical: {min: %ld, max: %ld}, ", physicalMin, physicalMax); } Boolean isVirtual = IOHIDElementIsVirtual(inIOHIDElementRef); if (isVirtual) { printf("isVirtual, "); } Boolean isRelative = IOHIDElementIsRelative(inIOHIDElementRef); if (isRelative) { printf("isRelative, "); } Boolean isWrapping = IOHIDElementIsWrapping(inIOHIDElementRef); if (isWrapping) { printf("isWrapping, "); } Boolean isArray = IOHIDElementIsArray(inIOHIDElementRef); if (isArray) { printf("isArray, "); } Boolean isNonLinear = IOHIDElementIsNonLinear(inIOHIDElementRef); if (isNonLinear) { printf("isNonLinear, "); } Boolean hasPreferredState = IOHIDElementHasPreferredState(inIOHIDElementRef); if (hasPreferredState) { printf("hasPreferredState, "); } Boolean hasNullState = IOHIDElementHasNullState(inIOHIDElementRef); if (hasNullState) { printf("hasNullState, "); } printf(" }\n"); } } // HIDDumpElementInfo
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); } } } }
/************************************************************************** * 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; }
/************************************************************************** * driver_joyGetDevCaps */ LRESULT driver_joyGetDevCaps(DWORD_PTR device_id, JOYCAPSW* caps, DWORD size) { joystick_t* joystick; IOHIDDeviceRef device; if ((joystick = joystick_from_id(device_id)) == NULL) return MMSYSERR_NODRIVER; if (!open_joystick(joystick)) return JOYERR_PARMS; caps->szPname[0] = 0; device = IOHIDElementGetDevice(joystick->element); if (device) { CFStringRef product_name = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)); if (product_name) { CFRange range; range.location = 0; range.length = min(MAXPNAMELEN - 1, CFStringGetLength(product_name)); CFStringGetCharacters(product_name, range, (UniChar*)caps->szPname); caps->szPname[range.length] = 0; } } caps->wMid = MM_MICROSOFT; caps->wPid = MM_PC_JOYSTICK; caps->wXmin = 0; caps->wXmax = 0xFFFF; caps->wYmin = 0; caps->wYmax = 0xFFFF; caps->wZmin = 0; caps->wZmax = joystick->axes[AXIS_Z].element ? 0xFFFF : 0; caps->wNumButtons = CFArrayGetCount(joystick->buttons); if (size == sizeof(JOYCAPSW)) { int i; /* complete 95 structure */ caps->wRmin = 0; caps->wRmax = 0xFFFF; caps->wUmin = 0; caps->wUmax = 0xFFFF; caps->wVmin = 0; caps->wVmax = 0xFFFF; caps->wMaxAxes = 6; /* same as MS Joystick Driver */ caps->wNumAxes = 0; caps->wMaxButtons = 32; /* same as MS Joystick Driver */ caps->szRegKey[0] = 0; caps->szOEMVxD[0] = 0; caps->wCaps = 0; for (i = 0; i < NUM_AXES; i++) { if (joystick->axes[i].element) { caps->wNumAxes++; switch (i) { case AXIS_Z: caps->wCaps |= JOYCAPS_HASZ; break; case AXIS_RX: caps->wCaps |= JOYCAPS_HASU; break; case AXIS_RY: caps->wCaps |= JOYCAPS_HASV; break; case AXIS_RZ: caps->wCaps |= JOYCAPS_HASR; break; } } } if (joystick->hatswitch) caps->wCaps |= JOYCAPS_HASPOV | JOYCAPS_POV4DIR; } TRACE("name %s buttons %u axes %d caps 0x%08x\n", debugstr_w(caps->szPname), caps->wNumButtons, caps->wNumAxes, caps->wCaps); return JOYERR_NOERROR; }
static const char* debugstr_element(IOHIDElementRef element) { return wine_dbg_sprintf("<IOHIDElement %p type %d usage %u/%u device %p>", element, IOHIDElementGetType(element), IOHIDElementGetUsagePage(element), IOHIDElementGetUsage(element), IOHIDElementGetDevice(element)); }
// get next element of given device in list given current element as parameter // will walk down each collection then to next element or collection (depthwise traverse) // returns NULL if end of list // uses mask of HIDElementTypeMask to restrict element found // use kHIDElementTypeIO to get previous HIDGetNextDeviceElement functionality IOHIDElementRef HIDGetNextDeviceElement( IOHIDElementRef inIOHIDElementRef, HIDElementTypeMask typeMask ) { IOHIDElementRef result = NULL; if ( inIOHIDElementRef ) { assert( IOHIDElementGetTypeID() == CFGetTypeID( inIOHIDElementRef ) ); IOHIDDeviceRef tIOHIDDeviceRef = IOHIDElementGetDevice( inIOHIDElementRef ); if ( tIOHIDDeviceRef ) { Boolean found = FALSE; gElementCFArrayRef = IOHIDDeviceCopyMatchingElements( tIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone ); if ( gElementCFArrayRef ) { CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef ); for ( idx = 0; idx < cnt; idx++ ) { IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx ); if ( !tIOHIDElementRef ) { continue; } if ( !found ) { if ( inIOHIDElementRef == tIOHIDElementRef ) { found = TRUE; } continue; // next element } else { // we've found the current element; now find the next one of the right type IOHIDElementType type = IOHIDElementGetType( tIOHIDElementRef ); switch ( type ) { case kIOHIDElementTypeInput_Misc: case kIOHIDElementTypeInput_Button: case kIOHIDElementTypeInput_Axis: case kIOHIDElementTypeInput_ScanCodes: { if ( typeMask & kHIDElementTypeInput ) { result = tIOHIDElementRef; } break; } case kIOHIDElementTypeOutput: { if ( typeMask & kHIDElementTypeOutput ) { result = tIOHIDElementRef; } break; } case kIOHIDElementTypeFeature: { if ( typeMask & kHIDElementTypeFeature ) { result = tIOHIDElementRef; } break; } case kIOHIDElementTypeCollection: { if ( typeMask & kHIDElementTypeCollection ) { result = tIOHIDElementRef; } break; } } // switch ( type ) if ( result ) { break; // DONE! } } // if ( !found ) } // next idx CFRelease( gElementCFArrayRef ); gElementCFArrayRef = NULL; } // if ( gElementCFArrayRef ) } // if ( inIOHIDDeviceRef ) } // if ( inIOHIDElementRef ) return result; } /* HIDGetNextDeviceElement */
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; }