/************************************************************************** * button_usage_comparator */ static CFComparisonResult button_usage_comparator(const void *val1, const void *val2, void *context) { IOHIDElementRef element1 = (IOHIDElementRef)val1, element2 = (IOHIDElementRef)val2; int usage1 = IOHIDElementGetUsage(element1), usage2 = IOHIDElementGetUsage(element2); if (usage1 < usage2) return kCFCompareLessThan; if (usage1 > usage2) return kCFCompareGreaterThan; return kCFCompareEqualTo; }
// 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 updateindicators(usbdevice* kb, int force){ // Set NumLock on permanently char ileds = 1; // Set Caps Lock if enabled. Unlike Linux, OSX keyboards have independent caps lock states, so // we use the last-assigned value rather than fetching it from the system if(kb->eflags & kCGEventFlagMaskAlphaShift) ileds |= 2; if(force || ileds != kb->ileds){ kb->ileds = ileds; // Set the LEDs CFArrayRef leds = IOHIDDeviceCopyMatchingElements(kb->handles[0], 0, kIOHIDOptionsTypeNone); CFIndex count = CFArrayGetCount(leds); for(CFIndex i = 0; i < count; i++){ IOHIDElementRef led = (void*)CFArrayGetValueAtIndex(leds, i); uint32_t page = IOHIDElementGetUsagePage(led); if(page != kHIDPage_LEDs) continue; uint32_t usage = IOHIDElementGetUsage(led); IOHIDValueRef value = IOHIDValueCreateWithIntegerValue(kCFAllocatorDefault, led, 0, !!(ileds & (1 << (usage - 1)))); IOHIDDeviceSetValue(kb->handles[0], led, value); CFRelease(value); } CFRelease(leds); IOHIDDeviceSetReport(kb->handles[1], kIOHIDReportTypeOutput, 0, &kb->ileds, 1); } }
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; } } }
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; } }
void os_updateindicators(usbdevice* kb, int force){ if(!IS_CONNECTED(kb) || NEEDS_FW_UPDATE(kb)) return; // Set NumLock on permanently char ileds = 1; // Set Caps Lock if enabled. Unlike Linux, OSX keyboards have independent caps lock states, so // we use the last-assigned value rather than fetching it from the system if(kb->eventflags & kCGEventFlagMaskAlphaShift) ileds |= 2; usbmode* mode = kb->profile.currentmode; if(mode && kb->active) ileds = (ileds & ~mode->ioff) | mode->ion; if(force || ileds != kb->ileds){ kb->ileds = ileds; // Set the LEDs CFArrayRef leds = IOHIDDeviceCopyMatchingElements(kb->handles[0], 0, kIOHIDOptionsTypeNone); CFIndex count = CFArrayGetCount(leds); for(CFIndex i = 0; i < count; i++){ IOHIDElementRef led = (void*)CFArrayGetValueAtIndex(leds, i); uint32_t page = IOHIDElementGetUsagePage(led); if(page != kHIDPage_LEDs) continue; uint32_t usage = IOHIDElementGetUsage(led); IOHIDValueRef value = IOHIDValueCreateWithIntegerValue(kCFAllocatorDefault, led, 0, !!(ileds & (1 << (usage - 1)))); IOHIDDeviceSetValue(kb->handles[0], led, value); CFRelease(value); } CFRelease(leds); } }
// Set up a config record for saving // takes an input records, returns record user can save as they want // Note: the save rec must be pre-allocated by the calling app and will be filled out void HIDSetElementConfig (pRecSaveHID pConfigRec, IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef, int actionCookie) { // must save: // actionCookie // Device: serial,vendorID, productID, location, usagePage, usage // Element: cookie, usagePage, usage, pConfigRec->actionCookie = actionCookie; // device // need to add serial number when I have a test case if (inIOHIDDeviceRef && inIOHIDElementRef) { pConfigRec->device.vendorID = IOHIDDevice_GetVendorID( inIOHIDDeviceRef ); pConfigRec->device.productID = IOHIDDevice_GetProductID( inIOHIDDeviceRef ); pConfigRec->device.locID = IOHIDDevice_GetLocationID( inIOHIDDeviceRef ); pConfigRec->device.usage = IOHIDDevice_GetUsage( inIOHIDDeviceRef ); pConfigRec->device.usagePage = IOHIDDevice_GetUsagePage( inIOHIDDeviceRef ); pConfigRec->element.usagePage = IOHIDElementGetUsagePage( inIOHIDElementRef ); pConfigRec->element.usage = IOHIDElementGetUsage( inIOHIDElementRef ); pConfigRec->element.minReport = IOHIDElement_GetCalibrationSaturationMin( inIOHIDElementRef ); pConfigRec->element.maxReport = IOHIDElement_GetCalibrationSaturationMax( inIOHIDElementRef ); pConfigRec->element.cookie = IOHIDElementGetCookie( inIOHIDElementRef ); } else { pConfigRec->device.vendorID = 0; pConfigRec->device.productID = 0; pConfigRec->device.locID = 0; pConfigRec->device.usage = 0; pConfigRec->device.usagePage = 0; pConfigRec->element.usagePage = 0; pConfigRec->element.usage = 0; pConfigRec->element.minReport = 0; pConfigRec->element.maxReport = 0; pConfigRec->element.cookie = 0; } }
bool HIDGamepad::maybeAddButton(IOHIDElementRef element) { uint32_t usagePage = IOHIDElementGetUsagePage(element); if (usagePage != kHIDPage_Button && usagePage != kHIDPage_GenericDesktop) return false; uint32_t usage = IOHIDElementGetUsage(element); if (usagePage == kHIDPage_GenericDesktop) { if (usage < kHIDUsage_GD_DPadUp || usage > kHIDUsage_GD_DPadLeft) return false; usage = std::numeric_limits<uint32_t>::max(); } else if (!usage) return false; CFIndex min = IOHIDElementGetLogicalMin(element); CFIndex max = IOHIDElementGetLogicalMax(element); m_buttons.append(makeUniqueRef<HIDGamepadButton>(usage, min, max, element)); IOHIDElementCookie cookie = IOHIDElementGetCookie(element); m_elementMap.set(cookie, &m_buttons.last().get()); return true; }
static CFIndex find_top_level(IOHIDDeviceRef tIOHIDDeviceRef, CFArrayRef topLevels) { CFArrayRef gElementCFArrayRef; CFIndex numTops = 0; if (!tIOHIDDeviceRef) return 0; gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(tIOHIDDeviceRef, NULL, 0); if (gElementCFArrayRef) { CFIndex idx, cnt = CFArrayGetCount(gElementCFArrayRef); for (idx=0; idx<cnt; idx++) { IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(gElementCFArrayRef, idx); int eleType = IOHIDElementGetType(tIOHIDElementRef); /* Check for top-level gaming device collections */ if (eleType == kIOHIDElementTypeCollection && IOHIDElementGetParent(tIOHIDElementRef) == 0) { int tUsagePage = IOHIDElementGetUsagePage(tIOHIDElementRef); int tUsage = IOHIDElementGetUsage(tIOHIDElementRef); if (tUsagePage == kHIDPage_GenericDesktop && (tUsage == kHIDUsage_GD_Joystick || tUsage == kHIDUsage_GD_GamePad)) { CFArrayAppendValue((CFMutableArrayRef)topLevels, tIOHIDElementRef); numTops++; } } } } return numTops; }
int joy_hidlib_enumerate_elements(joy_hid_device_t *device) { IOHIDDeviceRef dev = device->internal_device; if(dev == NULL) { return -1; } /* get all elements of device */ CFArrayRef internal_elements = IOHIDDeviceCopyMatchingElements( dev, NULL, 0 ); if(!internal_elements) { return -1; } /* get number of elements */ CFIndex cnt = CFArrayGetCount( internal_elements ); device->num_elements = (int)cnt; /* create elements array */ joy_hid_element_t *elements = (joy_hid_element_t *) lib_malloc(sizeof(joy_hid_element_t) * cnt); if(elements == NULL) { CFRelease(internal_elements); internal_elements = NULL; return -1; } /* enumerate and convert all elements */ CFIndex i; joy_hid_element_t *e = elements; for(i=0;i<cnt;i++) { IOHIDElementRef internal_element = ( IOHIDElementRef ) CFArrayGetValueAtIndex( internal_elements, i ); if ( internal_element ) { uint32_t usage_page = IOHIDElementGetUsagePage( internal_element ); uint32_t usage = IOHIDElementGetUsage( internal_element ); CFIndex min = IOHIDElementGetPhysicalMin( internal_element ); CFIndex max = IOHIDElementGetPhysicalMax( internal_element ); e->usage_page = (int)usage_page; e->usage = (int)usage; e->min_value = (int)min; e->max_value = (int)max; e->internal_element = internal_element; } else { e->usage_page = -1; e->usage = -1; e->min_value = -1; e->max_value = -1; e->internal_element = NULL; } e++; } /* keep the reference until the elements are free'ed again */ device->internal_elements = internal_elements; device->elements = elements; return (int)cnt; }
CFComparisonResult iohidmanager_sort_elements(const void *val1, const void *val2, void *context) { uint32_t page1 = (uint32_t)IOHIDElementGetUsagePage((IOHIDElementRef)val1); uint32_t page2 = (uint32_t)IOHIDElementGetUsagePage((IOHIDElementRef)val2); uint32_t use1 = (uint32_t)IOHIDElementGetUsage((IOHIDElementRef)val1); uint32_t use2 = (uint32_t)IOHIDElementGetUsage((IOHIDElementRef)val2); uint32_t cookie1 = (uint32_t)IOHIDElementGetCookie((IOHIDElementRef)val1); uint32_t cookie2 = (uint32_t)IOHIDElementGetCookie((IOHIDElementRef)val2); if (page1 != page2) return (CFComparisonResult)(page1 > page2); if(use1 != use2) return (CFComparisonResult)(use1 > use2); return (CFComparisonResult)(cookie1 > cookie2); }
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() ; }
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)); } }
Boolean HIDSaveElementPref( const CFStringRef inKeyCFStringRef, CFStringRef inAppCFStringRef, IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef ) { Boolean success = FALSE; if ( inKeyCFStringRef && inAppCFStringRef && inIOHIDDeviceRef && inIOHIDElementRef ) { long vendorID = IOHIDDevice_GetVendorID( inIOHIDDeviceRef ); require( vendorID, Oops ); long productID = IOHIDDevice_GetProductID( inIOHIDDeviceRef ); require( productID, Oops ); long locID = IOHIDDevice_GetLocationID( inIOHIDDeviceRef ); require( locID, Oops ); uint32_t usagePage = IOHIDDevice_GetUsagePage( inIOHIDDeviceRef ); uint32_t usage = IOHIDDevice_GetUsage( inIOHIDDeviceRef ); if ( !usagePage || !usage ) { usagePage = IOHIDDevice_GetPrimaryUsagePage( inIOHIDDeviceRef ); usage = IOHIDDevice_GetPrimaryUsage( inIOHIDDeviceRef ); } require( usagePage && usage, Oops ); uint32_t usagePageE = IOHIDElementGetUsagePage( inIOHIDElementRef ); uint32_t usageE = IOHIDElementGetUsage( inIOHIDElementRef ); IOHIDElementCookie eleCookie = IOHIDElementGetCookie( inIOHIDElementRef ); CFStringRef prefCFStringRef = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR( "d:{v:%ld, p:%ld, l:%ld, p:%ld, u:%ld}, e:{p:%ld, u:%ld, c:%ld}" ), vendorID, productID, locID, usagePage, usage, usagePageE, usageE, eleCookie ); if ( prefCFStringRef ) { CFPreferencesSetAppValue( inKeyCFStringRef, prefCFStringRef, inAppCFStringRef ); CFRelease( prefCFStringRef ); success = TRUE; } } Oops: ; return success; } // HIDSaveElementPref
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); } }
// Set up a config record for saving // takes an input records, returns record user can save as they want // Note: the save rec must be pre-allocated by the calling app and will be filled out void HIDSetElementConfig(HID_info_ptr inHIDInfoPtr, IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef, IOHIDElementCookie actionCookie) { // must save: // actionCookie // Device: serial,vendorID, productID, location, usagePage, usage // Element: cookie, usagePage, usage, inHIDInfoPtr->actionCookie = actionCookie; // device // need to add serial number when I have a test case if (inIOHIDDeviceRef && inIOHIDElementRef) { inHIDInfoPtr->device.vendorID = IOHIDDevice_GetVendorID(inIOHIDDeviceRef); inHIDInfoPtr->device.productID = IOHIDDevice_GetProductID(inIOHIDDeviceRef); inHIDInfoPtr->device.locID = IOHIDDevice_GetLocationID(inIOHIDDeviceRef); inHIDInfoPtr->device.usage = IOHIDDevice_GetUsage(inIOHIDDeviceRef); inHIDInfoPtr->device.usagePage = IOHIDDevice_GetUsagePage(inIOHIDDeviceRef); if (!inHIDInfoPtr->device.usagePage || !inHIDInfoPtr->device.usage) { inHIDInfoPtr->device.usagePage = IOHIDDevice_GetPrimaryUsagePage(inIOHIDDeviceRef); inHIDInfoPtr->device.usage = IOHIDDevice_GetPrimaryUsage(inIOHIDDeviceRef); } inHIDInfoPtr->element.usagePage = IOHIDElementGetUsagePage(inIOHIDElementRef); inHIDInfoPtr->element.usage = IOHIDElementGetUsage(inIOHIDElementRef); inHIDInfoPtr->element.minReport = IOHIDElement_GetCalibrationSaturationMin(inIOHIDElementRef); inHIDInfoPtr->element.maxReport = IOHIDElement_GetCalibrationSaturationMax(inIOHIDElementRef); inHIDInfoPtr->element.cookie = IOHIDElementGetCookie(inIOHIDElementRef); } else { inHIDInfoPtr->device.vendorID = 0; inHIDInfoPtr->device.productID = 0; inHIDInfoPtr->device.locID = 0; inHIDInfoPtr->device.usage = 0; inHIDInfoPtr->device.usagePage = 0; inHIDInfoPtr->element.usagePage = 0; inHIDInfoPtr->element.usage = 0; inHIDInfoPtr->element.minReport = 0; inHIDInfoPtr->element.maxReport = 0; inHIDInfoPtr->element.cookie = 0; } } // HIDSetElementConfig
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)); } }
/************************************************************************** * find_top_level */ static CFIndex find_top_level(IOHIDDeviceRef hid_device, CFMutableArrayRef main_elements) { CFArrayRef elements; CFIndex total = 0; TRACE("hid_device %s\n", debugstr_device(hid_device)); if (!hid_device) return 0; elements = IOHIDDeviceCopyMatchingElements(hid_device, NULL, 0); if (elements) { CFIndex i, count = CFArrayGetCount(elements); for (i = 0; i < count; i++) { IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i); int type = IOHIDElementGetType(element); TRACE("element %s\n", debugstr_element(element)); /* Check for top-level gaming device collections */ if (type == kIOHIDElementTypeCollection && IOHIDElementGetParent(element) == 0) { int usage_page = IOHIDElementGetUsagePage(element); int usage = IOHIDElementGetUsage(element); if (usage_page == kHIDPage_GenericDesktop && (usage == kHIDUsage_GD_Joystick || usage == kHIDUsage_GD_GamePad)) { CFArrayAppendValue(main_elements, element); total++; } } } CFRelease(elements); } TRACE("-> total %d\n", (int)total); return total; }
bool HIDGamepad::maybeAddButton(IOHIDElementRef element) { uint32_t usagePage = IOHIDElementGetUsagePage(element); if (usagePage != kHIDPage_Button) return false; uint32_t usage = IOHIDElementGetUsage(element); if (!usage) return false; CFIndex min = IOHIDElementGetLogicalMin(element); CFIndex max = IOHIDElementGetLogicalMax(element); m_buttons.append(std::make_unique<HIDGamepadButton>(usage, min, max, element)); IOHIDElementCookie cookie = IOHIDElementGetCookie(element); m_elementMap.set(cookie, m_buttons.last().get()); return true; }
bool HIDGamepad::maybeAddDPad(IOHIDElementRef element) { uint32_t usagePage = IOHIDElementGetUsagePage(element); if (usagePage != kHIDPage_GenericDesktop) return false; uint32_t usage = IOHIDElementGetUsage(element); if (!usage || usage != kHIDUsage_GD_Hatswitch) return false; CFIndex min = IOHIDElementGetLogicalMin(element); CFIndex max = IOHIDElementGetLogicalMax(element); m_dPads.append(makeUniqueRef<HIDGamepadDPad>(min, max, element)); IOHIDElementCookie cookie = IOHIDElementGetCookie(element); m_elementMap.set(cookie, &m_dPads.last().get()); return true; }
// Put element into the dictionary and into the queue: PsychError PsychHIDOSKbElementAdd(IOHIDElementRef element, IOHIDQueueRef queue, int deviceIndex) { // If at least one keyboard style device is detected, mark this queue as keyboard queue: if (IOHIDElementGetUsagePage(element) == kHIDPage_KeyboardOrKeypad) queueIsAKeyboard[deviceIndex] = TRUE; // Avoid redundant assignment to same keycode: if (IOHIDQueueContainsElement(queue, element)) { if (getenv("PSYCHHID_TELLME")) printf("--> Key %i Already assigned --> Skipping.\n", IOHIDElementGetUsage(element) - 1); return(PsychError_none); } if (getenv("PSYCHHID_TELLME")) { printf("--> Accepting key %i as new KbQueue element%s.\n", IOHIDElementGetUsage(element) - 1, (queueIsAKeyboard) ? " for a keyboard" : ""); } // Put the element cookie into the queue: IOHIDQueueAddElement(queue, element); return(PsychError_none); }
static void insert_sort_button(int header, IOHIDElementRef tIOHIDElementRef, CFMutableArrayRef elementCFArrayRef, int index, int target) { IOHIDElementRef targetElement; int usage; CFArraySetValueAtIndex(elementCFArrayRef, header+index, NULL); targetElement = ( IOHIDElementRef ) CFArrayGetValueAtIndex( elementCFArrayRef, header+target); if (targetElement == NULL) { CFArraySetValueAtIndex(elementCFArrayRef, header+target,tIOHIDElementRef); return; } usage = IOHIDElementGetUsage( targetElement ); usage --; /* usage 1 based index */ insert_sort_button(header, targetElement, elementCFArrayRef, target, usage); CFArraySetValueAtIndex(elementCFArrayRef, header+target,tIOHIDElementRef); }
bool HIDGamepad::maybeAddAxis(IOHIDElementRef element) { uint32_t usagePage = IOHIDElementGetUsagePage(element); if (usagePage != kHIDPage_GenericDesktop) return false; uint32_t usage = IOHIDElementGetUsage(element); // This range covers the standard axis usages. if (usage < kHIDUsage_GD_X || usage > kHIDUsage_GD_Rz) return false; CFIndex min = IOHIDElementGetPhysicalMin(element); CFIndex max = IOHIDElementGetPhysicalMax(element); m_axes.append(std::make_unique<HIDGamepadAxis>(min, max, element)); IOHIDElementCookie cookie = IOHIDElementGetCookie(element); m_elementMap.set(cookie, m_axes.last().get()); return true; }
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); }
void os_updateindicators(usbdevice* kb, int force){ // Set NumLock on permanently char ileds = 1; // Set Caps Lock if enabled. Unlike Linux, OSX keyboards have independent caps lock states, so // we use the last-assigned value rather than fetching it from the system if(kb->modifiers & kCGEventFlagMaskAlphaShift) ileds |= 2; kb->hw_ileds = ileds; if(kb->active){ usbmode* mode = kb->profile->currentmode; ileds = (ileds & ~mode->ioff) | mode->ion; } if(force || ileds != kb->ileds){ kb->ileds = ileds; // Get a list of LED elements from handle 0 long ledpage = kHIDPage_LEDs; const void* keys[] = { CFSTR(kIOHIDElementUsagePageKey) }; const void* values[] = { CFNumberCreate(kCFAllocatorDefault, kCFNumberLongType, &ledpage) }; CFDictionaryRef matching = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFRelease(values[0]); CFArrayRef leds; kern_return_t res = (*kb->handles[0])->copyMatchingElements(kb->handles[0], matching, &leds, 0); CFRelease(matching); if(res != kIOReturnSuccess) return; // Iterate through them and update the LEDs which have changed DELAY_SHORT(kb); CFIndex count = CFArrayGetCount(leds); for(CFIndex i = 0; i < count; i++){ IOHIDElementRef led = (void*)CFArrayGetValueAtIndex(leds, i); uint32_t usage = IOHIDElementGetUsage(led); IOHIDValueRef value = IOHIDValueCreateWithIntegerValue(kCFAllocatorDefault, led, 0, !!(ileds & (1 << (usage - 1)))); (*kb->handles[0])->setValue(kb->handles[0], led, value, 5000, 0, 0, 0); CFRelease(value); } CFRelease(leds); } }
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; } }
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; } } } }
//int main( int argc, const char * argv[] ) int manipulate_led( int which_led, int led_value ) { #pragma unused ( argc, argv ) IOHIDDeviceRef * tIOHIDDeviceRefs = nil; // create a IO HID Manager reference IOHIDManagerRef tIOHIDManagerRef = IOHIDManagerCreate( kCFAllocatorDefault, kIOHIDOptionsTypeNone ); require( tIOHIDManagerRef, Oops ); // Create a device matching dictionary CFDictionaryRef matchingCFDictRef = hu_CreateMatchingDictionaryUsagePageUsage( TRUE, kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard ); require( matchingCFDictRef, Oops ); // set the HID device matching dictionary IOHIDManagerSetDeviceMatching( tIOHIDManagerRef, matchingCFDictRef ); if ( matchingCFDictRef ) { CFRelease( matchingCFDictRef ); } // Now open the IO HID Manager reference IOReturn tIOReturn = IOHIDManagerOpen( tIOHIDManagerRef, kIOHIDOptionsTypeNone ); require_noerr( tIOReturn, Oops ); // and copy out its devices CFSetRef deviceCFSetRef = IOHIDManagerCopyDevices( tIOHIDManagerRef ); require( deviceCFSetRef, Oops ); // how many devices in the set? CFIndex deviceIndex, deviceCount = CFSetGetCount( deviceCFSetRef ); // allocate a block of memory to extact the device ref's from the set into tIOHIDDeviceRefs = malloc( sizeof( IOHIDDeviceRef ) * deviceCount ); if (!tIOHIDDeviceRefs) { CFRelease(deviceCFSetRef); deviceCFSetRef = NULL; goto Oops; } // now extract the device ref's from the set CFSetGetValues( deviceCFSetRef, (const void **) tIOHIDDeviceRefs ); CFRelease(deviceCFSetRef); deviceCFSetRef = NULL; // before we get into the device loop we'll setup our element matching dictionary matchingCFDictRef = hu_CreateMatchingDictionaryUsagePageUsage( FALSE, kHIDPage_LEDs, 0 ); require( matchingCFDictRef, Oops ); int pass; // do 256 passes //for ( pass = 0; pass < 256; pass++ ) { Boolean delayFlag = FALSE; // if we find an LED element we'll set this to TRUE //printf( "pass = %d.\n", pass ); for ( deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++ ) { // if this isn't a keyboard device... if ( !IOHIDDeviceConformsTo( tIOHIDDeviceRefs[deviceIndex], kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard ) ) { continue; // ...skip it } //printf( " device = %p.\n", tIOHIDDeviceRefs[deviceIndex] ); // copy all the elements CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements( tIOHIDDeviceRefs[deviceIndex], matchingCFDictRef, kIOHIDOptionsTypeNone ); require( elementCFArrayRef, next_device ); // for each device on the system these values are divided by the value ranges of all LED elements found // for example, if the first four LED element have a range of 0-1 then the four least significant bits of // this value will be sent to these first four LED elements, etc. int device_value = pass; // iterate over all the elements CFIndex elementIndex, elementCount = CFArrayGetCount( elementCFArrayRef ); for ( elementIndex = 0; elementIndex < elementCount; elementIndex++ ) { IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( elementCFArrayRef, elementIndex ); require( tIOHIDElementRef, next_element ); uint32_t usagePage = IOHIDElementGetUsagePage( tIOHIDElementRef ); // if this isn't an LED element... if ( kHIDPage_LEDs != usagePage ) { continue; // ...skip it } uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef ); IOHIDElementType tIOHIDElementType = IOHIDElementGetType( tIOHIDElementRef ); //printf( " element = %p (page: %d, usage: %d, type: %d ).\n", // tIOHIDElementRef, usagePage, usage, tIOHIDElementType ); // get the logical mix/max for this LED element CFIndex minCFIndex = IOHIDElementGetLogicalMin( tIOHIDElementRef ); CFIndex maxCFIndex = IOHIDElementGetLogicalMax( tIOHIDElementRef ); // calculate the range CFIndex modCFIndex = maxCFIndex - minCFIndex + 1; // compute the value for this LED element //CFIndex tCFIndex = minCFIndex + ( device_value % modCFIndex ); CFIndex tCFIndex = led_value; device_value /= modCFIndex; //printf( " value = 0x%08lX.\n", tCFIndex ); uint64_t timestamp = 0; // create the IO HID Value to be sent to this LED element IOHIDValueRef tIOHIDValueRef = IOHIDValueCreateWithIntegerValue( kCFAllocatorDefault, tIOHIDElementRef, timestamp, tCFIndex ); if ( tIOHIDValueRef ) { // now set it on the device tIOReturn = IOHIDDeviceSetValue( tIOHIDDeviceRefs[deviceIndex], tIOHIDElementRef, tIOHIDValueRef ); CFRelease( tIOHIDValueRef ); require_noerr( tIOReturn, next_element ); delayFlag = TRUE; // set this TRUE so we'll delay before changing our LED values again } next_element: ; continue; } CFRelease( elementCFArrayRef ); next_device: ; continue; } // if we found an LED we'll delay before continuing //if ( delayFlag ) { // usleep( 500000 ); // sleep one half second //} // if the mouse is down… //if (GetCurrentButtonState()) { // break; // abort pass loop //} //} // next pass if ( matchingCFDictRef ) { CFRelease( matchingCFDictRef ); } Oops: ; if ( tIOHIDDeviceRefs ) { free(tIOHIDDeviceRefs); } if ( tIOHIDManagerRef ) { CFRelease( tIOHIDManagerRef ); } return 0; } /* main */