int prHIDDequeueElement(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; //class PyrSlot *b = g->sp - 1; //locID device PyrSlot *c = g->sp; //element cookie int locID, cookieNum; int err = slotIntVal(b, &locID); if (err) return err; err = slotIntVal(c, &cookieNum); if (err) return err; IOHIDElementCookie cookie = (IOHIDElementCookie) cookieNum; //look for the right device: pRecDevice pCurrentHIDDevice = HIDGetFirstDevice (); while (pCurrentHIDDevice && (pCurrentHIDDevice->locID !=locID)) pCurrentHIDDevice = HIDGetNextDevice (pCurrentHIDDevice); if(!pCurrentHIDDevice) return errFailed; //look for the right element: pRecElement pCurrentHIDElement = HIDGetFirstDeviceElement (pCurrentHIDDevice, kHIDElementTypeAll); while (pCurrentHIDElement && (pCurrentHIDElement->cookie != cookie)) pCurrentHIDElement = HIDGetNextDeviceElement (pCurrentHIDElement, kHIDElementTypeAll); if(!pCurrentHIDElement) return errFailed; HIDDequeueElement(pCurrentHIDDevice, pCurrentHIDElement); return errNone; }
int prHIDGetValue(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; //class PyrSlot *b = g->sp - 1; //locID device PyrSlot *c = g->sp; //element cookie int locID, cookieNum; int err = slotIntVal(b, &locID); if (err) return err; err = slotIntVal(c, &cookieNum); if (err) return err; IOHIDElementCookie cookie = (IOHIDElementCookie) cookieNum; //look for the right device: pRecDevice pCurrentHIDDevice = HIDGetFirstDevice (); while (pCurrentHIDDevice && (pCurrentHIDDevice->locID !=locID)) pCurrentHIDDevice = HIDGetNextDevice (pCurrentHIDDevice); if(!pCurrentHIDDevice) return errFailed; //look for the right element: pRecElement pCurrentHIDElement = HIDGetFirstDeviceElement (pCurrentHIDDevice, kHIDElementTypeAll); // use gElementCookie to find current element while (pCurrentHIDElement && (pCurrentHIDElement->cookie != cookie)) pCurrentHIDElement = HIDGetNextDeviceElement (pCurrentHIDElement, kHIDElementTypeAll); if (pCurrentHIDElement) { SInt32 value = HIDGetElementValue (pCurrentHIDDevice, pCurrentHIDElement); // if it's not a button and it's not a hatswitch then calibrate if(( pCurrentHIDElement->type != kIOHIDElementTypeInput_Button ) && ( pCurrentHIDElement->usagePage == 0x01 && pCurrentHIDElement->usage != kHIDUsage_GD_Hatswitch)) value = HIDCalibrateValue ( value, pCurrentHIDElement ); SetInt(a, value); } else SetNil(a); return errNone; }
int prHIDBuildElementList(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; //class PyrSlot *b = g->sp - 1; //locID device PyrSlot *c = g->sp; //array int locID; int err = slotIntVal(b, &locID); if (err) return err; //look for the right device: pRecDevice pCurrentHIDDevice = HIDGetFirstDevice (); while (pCurrentHIDDevice && (pCurrentHIDDevice->locID !=locID)) pCurrentHIDDevice = HIDGetNextDevice (pCurrentHIDDevice); if(!pCurrentHIDDevice) return errFailed; pRecElement devElement = HIDGetFirstDeviceElement (pCurrentHIDDevice, kHIDElementTypeAll ); UInt32 numElements = HIDCountDeviceElements (pCurrentHIDDevice, kHIDElementTypeAll ); // PyrObject* devAllElementsArray = newPyrArray(g->gc, numElements * sizeof(PyrObject), 0 , true); PyrObject *devAllElementsArray = c->uo; // post("numElements: %d\n", numElements); numElements = sc_clip(numElements, 0, devAllElementsArray->size); for(uint i=0; i<numElements; i++){ if(devElement){ char cstrElementName [256]; PyrObject* devElementArray = newPyrArray(g->gc, 8 * sizeof(PyrObject), 0 , true); // type name (1) HIDGetTypeName((IOHIDElementType) devElement->type, cstrElementName); PyrString *devstring = newPyrString(g->gc, cstrElementName, 0, true); SetObject(devElementArray->slots+devElementArray->size++, devstring); //g->gc->GCWrite(devElementArray, (PyrObject*) devstring); //usage (2) HIDGetUsageName (devElement->usagePage, devElement->usage, cstrElementName); PyrString *usestring = newPyrString(g->gc, cstrElementName, 0, true); SetObject(devElementArray->slots+devElementArray->size++, usestring); //g->gc->GCWrite(devElementArray, (PyrObject*) usestring); //cookie (3) SetInt(devElementArray->slots+devElementArray->size++, (long) devElement->cookie); // min (4) SetInt(devElementArray->slots+devElementArray->size++, (long) devElement->min); // max (5) SetInt(devElementArray->slots+devElementArray->size++, (long) devElement->max); // IO type as int: (6) SetInt(devElementArray->slots+devElementArray->size++, (int) devElement->type); // Usage page as int: (7) SetInt(devElementArray->slots+devElementArray->size++, (long) devElement->usagePage); // Usage type as int: (8) SetInt(devElementArray->slots+devElementArray->size++, (long) devElement->usage); SetObject(devAllElementsArray->slots+i, devElementArray); //g->gc->GCWrite(devAllElementsArray, (PyrObject*) devElementArray); } devElement = HIDGetNextDeviceElement (devElement, kHIDElementTypeAll); } SetObject(a, devAllElementsArray); return errNone; }
void PushQueueEvents_CalibratedValue (){ IOHIDEventStruct event; pRecDevice pCurrentHIDDevice = HIDGetFirstDevice (); int numdevs = gNumberOfHIDDevices; unsigned char result; for(int i=0; i< numdevs; i++){ result = HIDGetEvent(pCurrentHIDDevice, (void*) &event); if(result && compiledOK) { SInt32 value = event.value; int vendorID = pCurrentHIDDevice->vendorID; int productID = pCurrentHIDDevice->productID; int locID = pCurrentHIDDevice->locID; IOHIDElementCookie cookie = (IOHIDElementCookie) event.elementCookie; pRecElement pCurrentHIDElement = HIDGetFirstDeviceElement (pCurrentHIDDevice, kHIDElementTypeAll); // use gElementCookie to find current element while (pCurrentHIDElement && ( (pCurrentHIDElement->cookie) != cookie)) pCurrentHIDElement = HIDGetNextDeviceElement (pCurrentHIDElement, kHIDElementTypeAll); if (pCurrentHIDElement) { value = HIDCalibrateValue(value, pCurrentHIDElement); //find element to calibrate VMGlobals *g = gMainVMGlobals; pthread_mutex_lock (&gLangMutex); g->canCallOS = false; // cannot call the OS ++g->sp; SetObject(g->sp, s_hid->u.classobj); // Set the class HIDService //set arguments: ++g->sp;SetInt(g->sp, vendorID); ++g->sp;SetInt(g->sp, productID); ++g->sp;SetInt(g->sp, locID); ++g->sp;SetInt(g->sp, (int) cookie); ++g->sp;SetInt(g->sp, value); runInterpreter(g, s_hidAction, 6); g->canCallOS = false; // cannot call the OS pthread_mutex_unlock (&gLangMutex); } } /* FIXME: this does not seem to be working! if ( !HIDIsValidDevice(pCurrentHIDDevice) ) { // readError post("HID: read Error\n"); int locID = pCurrentHIDDevice->locID; VMGlobals *g = gMainVMGlobals; pthread_mutex_lock (&gLangMutex); g->canCallOS = false; // cannot call the OS ++g->sp; SetObject(g->sp, s_hid->u.classobj); // Set the class HIDService ++g->sp;SetInt(g->sp, locID); runInterpreter(g, s_readError, 2); g->canCallOS = false; // cannot call the OS pthread_mutex_unlock (&gLangMutex); }*/ pCurrentHIDDevice = HIDGetNextDevice(pCurrentHIDDevice); } }
int prHIDSetValue(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 3; //class PyrSlot *b = g->sp - 2; //locID PyrSlot *c = g->sp - 1; //element device PyrSlot *d = g->sp; //value cookie int locID, cookieNum, value; int err = slotIntVal(b, &locID); if (err) return err; err = slotIntVal(c, &cookieNum); if (err) return err; IOHIDElementCookie cookie = (IOHIDElementCookie) cookieNum; err = slotIntVal(d, &value); if (err) return err; //look for the right device: pRecDevice pCurrentHIDDevice = HIDGetFirstDevice (); while (pCurrentHIDDevice && (pCurrentHIDDevice->locID !=locID)) pCurrentHIDDevice = HIDGetNextDevice (pCurrentHIDDevice); if(!pCurrentHIDDevice) return errFailed; //look for the right element: pRecElement pCurrentHIDElement = HIDGetFirstDeviceElement (pCurrentHIDDevice, kHIDElementTypeAll); // use gElementCookie to find current element while (pCurrentHIDElement && (pCurrentHIDElement->cookie != cookie)) pCurrentHIDElement = HIDGetNextDeviceElement (pCurrentHIDElement, kHIDElementTypeAll); //struct IOHIDEventStruct //{ // IOHIDElementType type; // IOHIDElementCookie elementCookie; // SInt32 value; // AbsoluteTime timestamp; // UInt32 longValueSize; // void * longValue; //}; if (pCurrentHIDElement) { IOHIDEventStruct event = { kIOHIDElementTypeOutput, pCurrentHIDElement->cookie, value, {0}, sizeof(int), NULL }; SInt32 value = HIDSetElementValue (pCurrentHIDDevice, pCurrentHIDElement, &event); // if it's not a button and it's not a hatswitch then calibrate // if(( pCurrentHIDElement->type != kIOHIDElementTypeInput_Button ) && // ( pCurrentHIDElement->usagePage == 0x01 && pCurrentHIDElement->usage != kHIDUsage_GD_Hatswitch)) // value = HIDCalibrateValue ( value, pCurrentHIDElement ); SetInt(a, value); } else SetNil(a); return errNone; }
// adds all elements to queue, performing any device queue set up required // queue is started and ready to return events on exit from this function int HIDQueueDevice( IOHIDDeviceRef inIOHIDDeviceRef ) { IOReturn result = kIOReturnSuccess; // error checking if ( !inIOHIDDeviceRef ) { HIDReportError( "Device does not exist, cannot queue device." ); return kIOReturnBadArgument; } if ( !inIOHIDDeviceRef ) { // must have interface HIDReportError( "Device does not have hid device ref, cannot queue device." ); return kIOReturnError; } IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue( inIOHIDDeviceRef ); if ( !tIOHIDQueueRef ) { // if no queue create queue result = HIDCreateQueue( inIOHIDDeviceRef ); if ( kIOReturnSuccess == result ) { tIOHIDQueueRef = IOHIDDevice_GetQueue( inIOHIDDeviceRef ); } } if ( ( kIOReturnSuccess != result ) || ( !tIOHIDQueueRef ) ) { HIDReportErrorNum( "Could not queue device due to problem creating queue.", result ); if ( kIOReturnSuccess != result ) { return result; } else { return kIOReturnError; } } // stop queue IOHIDQueueStop( tIOHIDQueueRef ); // queue element IOHIDElementRef tIOHIDElementRef = HIDGetFirstDeviceElement( inIOHIDDeviceRef, kHIDElementTypeIO ); while ( tIOHIDElementRef ) { if ( !IOHIDQueueContainsElement( tIOHIDQueueRef, tIOHIDElementRef ) ) { IOHIDQueueAddElement( tIOHIDQueueRef, tIOHIDElementRef ); } tIOHIDElementRef = HIDGetNextDeviceElement( tIOHIDElementRef, kHIDElementTypeIO ); } // restart queue IOHIDQueueStart( tIOHIDQueueRef ); return result; } /* HIDQueueDevice */
pRecElement PsychHIDGetCollectionRecordFromDeviceRecordAndCollectionIndex(pRecDevice deviceRecord, int elementIndex) { int i; pRecElement currentElement; PsychHIDVerifyInit(); i=1; for(currentElement=HIDGetFirstDeviceElement(deviceRecord, kHIDElementTypeCollection); currentElement != NULL; currentElement=HIDGetNextDeviceElement (currentElement, kHIDElementTypeCollection)) { if(i==elementIndex) return(currentElement); ++i; } PsychErrorExitMsg(PsychError_internal, "Invalid collection index specified. Has a device has been unplugged? Try rebuilding the device list"); return(NULL); //make the compiler happy. }
/* PsychHIDGetIndexFromRecord() The inverse of PsychHIDGetDeviceRecordPtrFromIndex. This O(n) where n is the number of device elements. We could make it O(1) if we modified the element structure in the HID Utilities library to include a field specifying the index of the element or collection. Note that if PsychHIDGetIndexFromRecord() is O(n) then its caller, PsychHIDGetCollections, is O(n^2) for each device, whereas if PsychHIDGetIndexFromRecord() is O(1) then psychHIDGetCollections becomes O(n) for each device. */ int PsychHIDGetIndexFromRecord(pRecDevice deviceRecord, pRecElement elementRecord, HIDElementTypeMask typeMask) { int elementIndex; pRecElement currentElement; if (elementRecord == NULL) return(0); elementIndex = 1; for (currentElement = HIDGetFirstDeviceElement(deviceRecord, typeMask); currentElement != elementRecord && currentElement != NULL; currentElement = HIDGetNextDeviceElement(currentElement, typeMask)) ++elementIndex; if (currentElement == elementRecord) return elementIndex; else { PsychErrorExitMsg(PsychError_internal, "Element record not found within device record"); return 0; //make the compiler happy } }
// --------------------------------- // completely removes all elements from queue and releases queue and closes device interface // does not release device interfaces, application must call ReleaseHIDDeviceList on exit int HIDDequeueDevice( IOHIDDeviceRef inIOHIDDeviceRef ) { IOReturn result = kIOReturnSuccess; // error checking if ( !inIOHIDDeviceRef ) { HIDReportError( "Device does not exist, cannot queue device." ); return kIOReturnBadArgument; } if ( !inIOHIDDeviceRef ) { // must have interface HIDReportError( "Device does not have hid device ref, cannot queue device." ); return kIOReturnError; } IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue( inIOHIDDeviceRef ); if ( tIOHIDQueueRef ) { // iterate through elements and if queued, remove IOHIDElementRef tIOHIDElementRef = HIDGetFirstDeviceElement( inIOHIDDeviceRef, kHIDElementTypeIO ); while ( tIOHIDElementRef ) { // de-queue element if ( IOHIDQueueContainsElement( tIOHIDQueueRef, tIOHIDElementRef ) ) { IOHIDQueueRemoveElement( tIOHIDQueueRef, tIOHIDElementRef ); } tIOHIDElementRef = HIDGetNextDeviceElement( tIOHIDElementRef, kHIDElementTypeIO ); } // ensure queue is disposed and released result = HIDDisposeReleaseQueue( inIOHIDDeviceRef ); if ( kIOReturnSuccess != result ) { HIDReportErrorNum( "Failed to dispose and release queue.", result ); } } else { HIDReportError( "No queue for device passed to HIDDequeueElement." ); if ( kIOReturnSuccess == result ) { result = kIOReturnError; } } return result; } /* HIDDequeueDevice */
// --------------------------------- // returns true if queue is empty false otherwise // error if no device, empty if no queue static unsigned char HIDIsDeviceQueueEmpty( IOHIDDeviceRef inIOHIDDeviceRef ) { if ( inIOHIDDeviceRef ) { // need device and queue assert( IOHIDDeviceGetTypeID() == CFGetTypeID( inIOHIDDeviceRef ) ); IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue( inIOHIDDeviceRef ); if ( tIOHIDQueueRef ) { IOHIDElementRef tIOHIDElementRef = HIDGetFirstDeviceElement( inIOHIDDeviceRef, kHIDElementTypeIO ); while ( tIOHIDElementRef ) { if ( IOHIDQueueContainsElement( tIOHIDQueueRef, tIOHIDElementRef ) ) { return false; } tIOHIDElementRef = HIDGetNextDeviceElement( tIOHIDElementRef, kHIDElementTypeIO ); } } else { HIDReportError( "NULL device passed to HIDIsDeviceQueueEmpty." ); } } else { HIDReportError( "NULL device passed to HIDIsDeviceQueueEmpty." ); } return true; } /* HIDIsDeviceQueueEmpty */
PsychError PsychHIDOSKbQueueCreate(int deviceIndex, int numScankeys, int* scanKeys) { pRecDevice deviceRecord; // Valid number of keys? if (scanKeys && (numScankeys != 256)) { PsychErrorExitMsg(PsychError_user, "Second argument to KbQueueCreate must be a vector with 256 elements."); } // Do we finally have a valid keyboard or other suitable input device? // PsychHIDOSGetKbQueueDevice() will error out if no suitable device // for deviceIndex can be found. Otherwise it will return the HID // device record and remapped deviceIndex for use with our KbQueues: deviceIndex = PsychHIDOSGetKbQueueDevice(deviceIndex, &deviceRecord); // Keyboard queue for this deviceIndex already created? if (psychHIDKbQueueFirstPress[deviceIndex]) { // Yep. Release it, so we can start from scratch: PsychHIDOSKbQueueRelease(deviceIndex); } // Allocate and zero-init memory for tracking key presses and key releases: psychHIDKbQueueFirstPress[deviceIndex] = calloc(256, sizeof(double)); psychHIDKbQueueFirstRelease[deviceIndex] = calloc(256, sizeof(double)); psychHIDKbQueueLastPress[deviceIndex] = calloc(256, sizeof(double)); psychHIDKbQueueLastRelease[deviceIndex] = calloc(256, sizeof(double)); psychHIDKbQueueScanKeys[deviceIndex] = calloc(256, sizeof(int)); // Assign scanKeys vector, if any: if (scanKeys) { // Copy it: memcpy(psychHIDKbQueueScanKeys[deviceIndex], scanKeys, 256 * sizeof(int)); } else { // None provided. Enable all keys by default: memset(psychHIDKbQueueScanKeys[deviceIndex], 1, 256 * sizeof(int)); } // Create HIDQueue for device: queue[deviceIndex] = IOHIDQueueCreate(kCFAllocatorDefault, deviceRecord, 30, 0); if (NULL == queue[deviceIndex]) PsychErrorExitMsg(PsychError_system, "Failed to create event queue for detecting key press."); // Mark as a non-keyboard device, to start with: queueIsAKeyboard[deviceIndex] = FALSE; // Parse HID device to add all detected and selected keys: { // Add deviceRecord's elements to our queue, filtering unwanted keys via 'scanList'. // This code is almost identical to the enumeration code in PsychHIDKbCheck, to make sure we get // matching performance and behaviour and hopefully that it works on the latest problematic Apple // hardware, e.g., late 2013 MacBookAir and OSX 10.9: { uint32_t usage, usagePage; pRecElement currentElement, lastElement = NULL; // Step through the elements of the device and add matching ones: for (currentElement = HIDGetFirstDeviceElement(deviceRecord, kHIDElementTypeInput | kHIDElementTypeCollection); (currentElement != NULL) && (currentElement != lastElement); currentElement = HIDGetNextDeviceElement(currentElement, kHIDElementTypeInput | kHIDElementTypeCollection)) { // Keep track of last queried element: lastElement = currentElement; usage = IOHIDElementGetUsage(currentElement); usagePage = IOHIDElementGetUsagePage(currentElement); if (getenv("PSYCHHID_TELLME")) { printf("PTB-DEBUG: [KbQueueCreate]: ce %p page %d usage: %d isArray: %d\n", currentElement, usagePage, usage, IOHIDElementIsArray(currentElement)); } if (IOHIDElementGetType(currentElement) == kIOHIDElementTypeCollection) { CFArrayRef children = IOHIDElementGetChildren(currentElement); if (!children) continue; CFIndex idx, cnt = CFArrayGetCount(children); for (idx = 0; idx < cnt; idx++) { IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(children, idx); if (tIOHIDElementRef && ((IOHIDElementGetType(tIOHIDElementRef) == kIOHIDElementTypeInput_Button) || (IOHIDElementGetType(tIOHIDElementRef) == kIOHIDElementTypeInput_ScanCodes))) { usage = IOHIDElementGetUsage(tIOHIDElementRef); if ((usage <= 256) && (usage >= 1) && ( (scanKeys == NULL) || (scanKeys[usage - 1] > 0) )) { // Add it for use in keyboard queue: PsychHIDOSKbElementAdd(tIOHIDElementRef, queue[deviceIndex], deviceIndex); } } } // Done with this currentElement, which was a collection of buttons/keys. // Iterate to next currentElement: continue; } // Classic path for non-collection elements: if(((usagePage == kHIDPage_KeyboardOrKeypad) || (usagePage == kHIDPage_Button)) && (usage <= 256) && (usage >= 1) && ( (scanKeys == NULL) || (scanKeys[usage - 1] > 0) ) ) { // Add it for use in keyboard queue: PsychHIDOSKbElementAdd(currentElement, queue[deviceIndex], deviceIndex); } } } } // Register "queue empty -> non-empty transition" callback: TODO Replace queue by reference to our keyboard queue struct: IOHIDQueueRegisterValueAvailableCallback(queue[deviceIndex], (IOHIDCallback) PsychHIDKbQueueCallbackFunction, (void*) (long) deviceIndex); // Create event buffer: PsychHIDCreateEventBuffer(deviceIndex); // Start the processing thread for this queue: PsychLockMutex(&KbQueueMutex); if (PsychCreateThread(&KbQueueThread[deviceIndex], NULL, KbQueueWorkerThreadMain, (void*) (long) deviceIndex)) { // We are so screwed: // Cleanup the mess: psychHIDKbQueueActive[deviceIndex] = FALSE; PsychUnlockMutex(&KbQueueMutex); // Whine a little bit: printf("PsychHID-ERROR: Start of keyboard queue processing for deviceIndex %i failed!\n", deviceIndex); PsychErrorExitMsg(PsychError_system, "Creation of keyboard queue background processing thread failed!"); } PsychUnlockMutex(&KbQueueMutex); // Ready to use this keybord queue. return(PsychError_none); }
/* PsychHIDGetDeviceListByUsage() */ void PsychHIDGetDeviceListByUsage(long usagePage, long usage, int *numDeviceIndices, int *deviceIndices, pRecDevice *deviceRecords) { pRecDevice currentDevice; int currentDeviceIndex; PsychHIDVerifyInit(); currentDeviceIndex=0; *numDeviceIndices=0; for(currentDevice=HIDGetFirstDevice(); currentDevice != NULL; currentDevice=HIDGetNextDevice(currentDevice)){ ++currentDeviceIndex; #ifndef __LP64__ if(currentDevice->usagePage==usagePage && currentDevice->usage==usage){ #else if(IOHIDDevice_GetUsagePage(currentDevice) == usagePage && IOHIDDevice_GetUsage(currentDevice) == usage){ #endif deviceRecords[*numDeviceIndices]=currentDevice; deviceIndices[*numDeviceIndices]=currentDeviceIndex; //the array is 0-indexed, devices are 1-indexed. ++(*numDeviceIndices); } } } /* PsychHIDGetDeviceListByUsages() */ void PsychHIDGetDeviceListByUsages(int numUsages, long *usagePages, long *usages, int *numDeviceIndices, int *deviceIndices, pRecDevice *deviceRecords) { pRecDevice currentDevice; int currentDeviceIndex; int currentUsage; long *usagePage; long *usage; PsychHIDVerifyInit(); *numDeviceIndices=0; for(usagePage=usagePages, usage=usages, currentUsage=0; currentUsage<numUsages; usagePage++, usage++, currentUsage++){ currentDeviceIndex=0; for(currentDevice=HIDGetFirstDevice(); currentDevice != NULL; currentDevice=HIDGetNextDevice(currentDevice)){ ++currentDeviceIndex; #ifndef __LP64__ if(currentDevice->usagePage==*usagePage && currentDevice->usage==*usage){ #else if(IOHIDDevice_GetPrimaryUsagePage(currentDevice) == *usagePage && IOHIDDevice_GetPrimaryUsage(currentDevice) == *usage){ #endif deviceRecords[*numDeviceIndices]=currentDevice; deviceIndices[*numDeviceIndices]=currentDeviceIndex; //the array is 0-indexed, devices are 1-indexed. ++(*numDeviceIndices); } } } } /* PsychHIDGetIndexFromRecord() The inverse of PsychHIDGetDeviceRecordPtrFromIndex. This O(n) where n is the number of device elements. We could make it O(1) if we modified the element structure in the HID Utilities library to include a field specifying the index of the element or collection. Note that if PsychHIDGetIndexFromRecord() is O(n) then its caller, PsychHIDGetCollections, is O(n^2) for each device, whereas if PsychHIDGetIndexFromRecord() is O(1) then psychHIDGetCollections becomes O(n) for each device. */ int PsychHIDGetIndexFromRecord(pRecDevice deviceRecord, pRecElement elementRecord, HIDElementTypeMask typeMask) { int elementIndex; pRecElement currentElement; if(elementRecord==NULL) return(0); elementIndex=1; for(currentElement=HIDGetFirstDeviceElement(deviceRecord, typeMask); currentElement != elementRecord && currentElement != NULL; currentElement=HIDGetNextDeviceElement(currentElement, typeMask)) ++elementIndex; if(currentElement==elementRecord) return(elementIndex); else{ PsychErrorExitMsg(PsychError_internal, "Element record not found within device record"); return(0); //make the compiler happy } }
long HIDRestoreElementConfig (FILE * fileRef, pRecDevice * ppDevice, pRecElement * ppElement) { // Device: serial,vendorID, productID, location, usagePage, usage // Element: cookie, usagePage, usage, pRecDevice pDevice, pFoundDevice = NULL; pRecElement pElement, pFoundElement = NULL; recSaveHID restoreRec; fread ((void *) &restoreRec, 1, sizeof (recSaveHID), fileRef); // compare to current device list for matches // look for device if (restoreRec.locID && restoreRec.vendorID && restoreRec.productID) { // look for specific device type plug in to same port pDevice = HIDGetFirstDevice (); while (pDevice) { if ((restoreRec.locID == pDevice->locID) && (restoreRec.vendorID == pDevice->vendorID) && (restoreRec.productID == pDevice->productID)) pFoundDevice = pDevice; if (pFoundDevice) break; pDevice = HIDGetNextDevice (pDevice); } if (pFoundDevice) { pElement = HIDGetFirstDeviceElement (pFoundDevice, kHIDElementTypeIO); while (pElement) { if (restoreRec.cookie == pElement->cookie) pFoundElement = pElement; if (pFoundElement) break; pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); } // if no cookie match (should NOT occur) match on usage pElement = HIDGetFirstDeviceElement (pFoundDevice, kHIDElementTypeIO); while (pElement) { if ((restoreRec.usageE == pElement->usage) && (restoreRec.usagePageE == pElement->usagePage)) pFoundElement = pElement; if (pFoundElement) break; pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); } } } // if we have not found a match, look at just vendor and product if ((NULL == pFoundDevice) && (restoreRec.vendorID && restoreRec.productID)) { pDevice = HIDGetFirstDevice (); while (pDevice) { if ((restoreRec.vendorID == pDevice->vendorID) && (restoreRec.productID == pDevice->productID)) pFoundDevice = pDevice; if (pFoundDevice) break; pDevice = HIDGetNextDevice (pDevice); } // match elements by cookie since same device type if (pFoundDevice) { pElement = HIDGetFirstDeviceElement (pFoundDevice, kHIDElementTypeIO); while (pElement) { if (restoreRec.cookie == pElement->cookie) pFoundElement = pElement; if (pFoundElement) break; pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); } // if no cookie match (should NOT occur) match on usage pElement = HIDGetFirstDeviceElement (pFoundDevice, kHIDElementTypeIO); while (pElement) { if ((restoreRec.usageE == pElement->usage) && (restoreRec.usagePageE == pElement->usagePage)) pFoundElement = pElement; if (pFoundElement) break; pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); } } } // if we have not found a match look for just same type of device if ((NULL == pFoundDevice) && (restoreRec.usage && restoreRec.usagePage)) { pDevice = HIDGetFirstDevice (); while (pDevice) { if ((restoreRec.usage == pDevice->usage) && (restoreRec.usagePage == pDevice->usagePage)) pFoundDevice = pDevice; if (pFoundDevice) break; pDevice = HIDGetNextDevice (pDevice); } // match elements by type if (pFoundDevice) { pElement = HIDGetFirstDeviceElement (pFoundDevice, kHIDElementTypeIO); while (pElement) { if ((restoreRec.usageE == pElement->usage) && (restoreRec.usagePageE == pElement->usagePage)) pFoundElement = pElement; if (pFoundElement) break; pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); } } } // if still not found just get first device if (NULL == pFoundDevice) { pFoundDevice = HIDGetFirstDevice (); // match elements by type if (pFoundDevice) { pElement = HIDGetFirstDeviceElement (pFoundDevice, kHIDElementTypeIO); while (pElement) { if ((restoreRec.usageE == pElement->usage) && (restoreRec.usagePageE == pElement->usagePage)) pFoundElement = pElement; if (pFoundElement) break; pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); } } } if ((NULL == pFoundDevice) || (NULL == pFoundElement)) { // no HID device *ppDevice = NULL; *ppElement = NULL; return restoreRec.actionCookie; } else { // no HID device *ppDevice = pFoundDevice; *ppElement = pFoundElement; return restoreRec.actionCookie; } }
static Boolean GetInputElements (pRecDevice pDevice) { short i; pRecElement pElement = NULL; if (pDevice) { // if we have found a device set up elements // prefer correct elements, then try any // look for x axis pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO); // get first element while (pElement) { // for each element if ((kHIDPage_GenericDesktop == pElement->usagePage) && (kHIDUsage_GD_X == pElement->usage)) { // if it is the x axis gActionArray [kActionXAxis].pDevice = pDevice; gActionArray [kActionXAxis].pElement = pElement; break; } pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); // get next element } // look for y axis pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO); // get first element while (pElement) { // for each element if ((kHIDPage_GenericDesktop == pElement->usagePage) && (kHIDUsage_GD_Y == pElement->usage)) { // if it is the y axis gActionArray [kActionYAxis].pDevice = pDevice; gActionArray [kActionYAxis].pElement = pElement; break; } pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); // get next element } // // look for z axis // pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO); // get first element // while (pElement) { // for each element // if ((kHIDPage_GenericDesktop == pElement->usagePage) && (kHIDUsage_GD_Z == pElement->usage)) { // if it is the y axis // gActionArray [kActionZAxis].pDevice = pDevice; // gActionArray [kActionZAxis].pElement = pElement; // break; // } // pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); // get next element // } // // look for x rotation // pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO); // get first element // while (pElement) { // for each element // if ((kHIDPage_GenericDesktop == pElement->usagePage) && (kHIDUsage_GD_Rx == pElement->usage)) { // if it is the x axis // gActionArray [kActionXRot].pDevice = pDevice; // gActionArray [kActionXRot].pElement = pElement; // break; // } // pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); // get next element // } // // look for y rotation // pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO); // get first element // while (pElement) { // for each element // if ((kHIDPage_GenericDesktop == pElement->usagePage) && (kHIDUsage_GD_Ry == pElement->usage)) { // if it is the y axis // gActionArray [kActionYRot].pDevice = pDevice; // gActionArray [kActionYRot].pElement = pElement; // break; // } // pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); // get next element // } // // look for z rotation // pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO); // get first element // while (pElement) { // for each element // if ((kHIDPage_GenericDesktop == pElement->usagePage) && (kHIDUsage_GD_Rz == pElement->usage)) { // if it is the y axis // gActionArray [kActionZRot].pDevice = pDevice; // gActionArray [kActionZRot].pElement = pElement; // break; // } // pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); // get next element // } } // set device limits for (i = 0; i < kNumActions; i++) { #if 0 if (!gActionArray [i].pElement) { // check to ensure we have valid elements InitHIDInputArray (); return false; } #endif if (gActionArray[i].pElement) { (gActionArray[i].pElement)->userMin = -100; (gActionArray[i].pElement)->userMax = 100; } } return true; }
void Controller::Setup() { #if defined(WIN32) ZeroMemory( &_currentControllerRawState, sizeof(XINPUT_STATE)); _dwResult = XInputGetState(_controllerID, &_currentControllerRawState); if (_dwResult == ERROR_SUCCESS) { sysLog.Printf("Controller %d connected!", _controllerID+1); _connected = true; } else { sysLog.Printf("Controller %d not present...", _controllerID+1); ZeroMemory( &_currentControllerRawState, sizeof(XINPUT_STATE)); _currentControllerInput.LeftThumbstickX = _currentControllerInput.LeftThumbstickY = _currentControllerInput.RightThumbstickX = _currentControllerInput.RightThumbstickY = _currentControllerInput.LeftTriggerValue = _currentControllerInput.RightTriggerValue = _currentControllerInput.Buttons = 0; _connected = false; } #elif defined(__APPLE__) unsigned long usagePage = 0; unsigned long usage = 0; if (!HIDHaveDeviceList()) { HIDBuildDeviceList(usagePage, usage); } _device = HIDGetFirstDevice(); while (_device != NULL) { //is this device already taken by another controller? bool breakIt = false; for (int i=0; i < MAX_CONTROLLERS; i++) { Controller* check = &theControllerManager.GetController(i); if ((check != this) && (check->_device == _device)) { _device = HIDGetNextDevice(_device); if (_device == NULL) { breakIt = true; } } } if (breakIt) { break; } std::string manufacturer = _device->manufacturer; std::string product = _device->product; if (manufacturer.length() > 0) manufacturer = manufacturer.substr(1, manufacturer.length()-1).c_str(); //trimming off the initial copyright symbol so matching won't be dumb if ( ((manufacturer == "Microsoft Corporation") && (product == "Controller")) || ((manufacturer == "icrosoft") && (product == "Wireless 360 Controller")) ) { sysLog.Printf("Controller %d connected!", _controllerID+1); _connected = true; break; } _device = HIDGetNextDevice(_device); } if (_device == NULL) { sysLog.Printf("Controller %d not present...", _controllerID+1); _connected = false; } else { pRecElement current_element = HIDGetFirstDeviceElement(_device, kHIDElementTypeIO); while (current_element != NULL) { _elements[(unsigned int)current_element->cookie] = current_element; current_element = HIDGetNextDeviceElement(current_element, kHIDElementTypeIO); } } #elif defined(__linux__) _currentControllerInput.LeftThumbstickX = _currentControllerInput.LeftThumbstickY = _currentControllerInput.RightThumbstickX = _currentControllerInput.RightThumbstickY = _currentControllerInput.LeftTriggerValue = _currentControllerInput.RightTriggerValue = _currentControllerInput.Buttons = 0; char* devicePath; if (_controllerID == 0) devicePath = LINUX_CONTROLLER_1_PATH; else devicePath = LINUX_CONTROLLER_2_PATH; _deviceFD = open(devicePath, O_RDONLY | O_NONBLOCK); if (_deviceFD < 0) { sysLog.Printf("Controller %d not present...", _controllerID+1); _connected = false; } else { sysLog.Printf("Controller %d connected!", _controllerID+1); _connected = true; } // Discover the force feedback device. bool foundFirstController = false; _ffFD = -1; for (int i = 0; i < MAX_LINUX_EVENT_INTERFACES; i++) { std::stringstream ss; ss << i; String eventDev = LINUX_EVENT_INTERFACE + ss.str(); int fd = open(eventDev.c_str(), O_RDWR); if (fd >= 0) { char name[256] = "Unknown"; ioctl(fd, EVIOCGNAME(sizeof(name)), name); if (strcmp(name, "Microsoft X-Box 360 pad") == 0) { if (_controllerID == 0) { _ffFD = fd; break; } else { if (foundFirstController) { _ffFD = fd; break; } else { foundFirstController = true; close(fd); } } } else { close(fd); } } } if (_ffFD < 0) { sysLog.Printf("Error opening Force Feedback device for controller %d!", _controllerID+1); } else { _ffEffect.type = FF_RUMBLE; _ffEffect.id = -1; _ffEffect.u.rumble.strong_magnitude = 0; _ffEffect.u.rumble.weak_magnitude = 0; _ffEffect.replay.length = 0x7fff; _ffEffect.replay.delay = 0; _ffPlay.type = EV_FF; _ffPlay.value = 1; } #endif }
PsychError PSYCHHIDGetElements(void) { pRecDevice specDevice=NULL; UInt32 numDeviceElements; const char *elementFieldNames[]={"typeMaskName", "name", "deviceIndex", "elementIndex", "typeValue", "typeName", "usagePageValue", "usageValue", "usageName", "dataSize", "rangeMin", "rangeMax", "scaledRangeMin", "scaledRangeMax", "relative", "wrapping", "nonLinear", "preferredState", "nullState", "calMin", "calMax", "scalingMin", "scalingMax"}; int numElementStructElements, numElementStructFieldNames=23, elementIndex, deviceIndex; PsychGenericScriptType *elementStruct; pRecElement currentElement; char elementTypeName[PSYCH_HID_MAX_DEVICE_ELEMENT_TYPE_NAME_LENGTH]; char usageName[PSYCH_HID_MAX_DEVICE_ELEMENT_USAGE_NAME_LENGTH]; char *typeMaskName; HIDElementTypeMask typeMask; //all subfunctions should have these two lines PsychPushHelp(useString, synopsisString, seeAlsoString); if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);}; PsychErrorExit(PsychCapNumOutputArgs(1)); PsychErrorExit(PsychCapNumInputArgs(1)); PsychCopyInIntegerArg(1, TRUE, &deviceIndex); PsychHIDVerifyInit(); specDevice= PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex); PsychHIDVerifyOpenDeviceInterfaceFromDeviceRecordPtr(specDevice); numDeviceElements= HIDCountDeviceElements(specDevice, kHIDElementTypeIO); numElementStructElements = (int)numDeviceElements; PsychAllocOutStructArray(1, FALSE, numElementStructElements, numElementStructFieldNames, elementFieldNames, &elementStruct); elementIndex=0; for(currentElement=HIDGetFirstDeviceElement(specDevice,kHIDElementTypeIO); currentElement != NULL; currentElement=HIDGetNextDeviceElement(currentElement, kHIDElementTypeIO)) { typeMask=HIDConvertElementTypeToMask (currentElement->type); PsychHIDGetTypeMaskStringFromTypeMask(typeMask, &typeMaskName); PsychSetStructArrayStringElement("typeMaskName", elementIndex, typeMaskName, elementStruct); PsychSetStructArrayStringElement("name", elementIndex, currentElement->name, elementStruct); PsychSetStructArrayDoubleElement("deviceIndex", elementIndex, (double)deviceIndex, elementStruct); PsychSetStructArrayDoubleElement("elementIndex", elementIndex, (double)elementIndex+1, elementStruct); PsychSetStructArrayDoubleElement("typeValue", elementIndex, (double)currentElement->type, elementStruct); HIDGetTypeName(currentElement->type, elementTypeName); PsychSetStructArrayStringElement("typeName", elementIndex, elementTypeName, elementStruct); PsychSetStructArrayDoubleElement("usagePageValue", elementIndex, (double)currentElement->usagePage, elementStruct); PsychSetStructArrayDoubleElement("usageValue", elementIndex, (double)currentElement->usage, elementStruct); HIDGetUsageName (currentElement->usagePage, currentElement->usage, usageName); PsychSetStructArrayStringElement("usageName", elementIndex, usageName, elementStruct); PsychSetStructArrayDoubleElement("dataSize", elementIndex, (double)currentElement->size, elementStruct); PsychSetStructArrayDoubleElement("rangeMin", elementIndex, (double)currentElement->min, elementStruct); PsychSetStructArrayDoubleElement("rangeMax", elementIndex, (double)currentElement->max, elementStruct); PsychSetStructArrayDoubleElement("scaledRangeMin", elementIndex, (double)currentElement->scaledMin, elementStruct); PsychSetStructArrayDoubleElement("scaledRangeMax", elementIndex, (double)currentElement->scaledMax, elementStruct); PsychSetStructArrayDoubleElement("relative", elementIndex, (double)currentElement->relative, elementStruct); //psych_bool flag PsychSetStructArrayDoubleElement("wrapping", elementIndex, (double)currentElement->wrapping, elementStruct); //psych_bool flag PsychSetStructArrayDoubleElement("nonLinear", elementIndex, (double)currentElement->nonLinear, elementStruct); //psych_bool flag PsychSetStructArrayDoubleElement("preferredState", elementIndex, (double)currentElement->preferredState, elementStruct); //psych_bool flag PsychSetStructArrayDoubleElement("nullState", elementIndex, (double)currentElement->nullState, elementStruct); //psych_bool flag PsychSetStructArrayDoubleElement("calMin", elementIndex, (double)currentElement->calMin, elementStruct); PsychSetStructArrayDoubleElement("calMax", elementIndex, (double)currentElement->calMax, elementStruct); PsychSetStructArrayDoubleElement("scalingMin", elementIndex, (double)currentElement->userMin, elementStruct); PsychSetStructArrayDoubleElement("scalingMax", elementIndex, (double)currentElement->userMax, elementStruct); ++elementIndex; } return(PsychError_none); }
PsychError PSYCHHIDKbCheck(void) { pRecDevice deviceRecord; pRecElement currentElement; int i, deviceIndex, numDeviceIndices; long KeysUsagePage=7; long KbDeviceUsagePage= 1, KbDeviceUsage=6; int deviceIndices[PSYCH_HID_MAX_KEYBOARD_DEVICES]; pRecDevice deviceRecords[PSYCH_HID_MAX_KEYBOARD_DEVICES]; boolean isDeviceSpecified, foundUserSpecifiedDevice, isKeyArgPresent, isTimeArgPresent; double *timeValueOutput, *isKeyDownOutput; PsychNativeBooleanType *keyArrayOutput; PsychPushHelp(useString, synopsisString, seeAlsoString); if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);}; PsychErrorExit(PsychCapNumOutputArgs(3)); PsychErrorExit(PsychCapNumInputArgs(1)); //Specifies the number of the keyboard to scan. PsychHIDVerifyInit(); //Choose the device index and its record PsychHIDGetDeviceListByUsage(KbDeviceUsagePage, KbDeviceUsage, &numDeviceIndices, deviceIndices, deviceRecords); isDeviceSpecified=PsychCopyInIntegerArg(1, FALSE, &deviceIndex); if(isDeviceSpecified){ //make sure that the device number provided by the user is really a keyboard. for(i=0;i<numDeviceIndices;i++){ if(foundUserSpecifiedDevice=(deviceIndices[i]==deviceIndex)) break; } if(!foundUserSpecifiedDevice) PsychErrorExitMsg(PsychError_user, "Specified device number is not a keyboard device."); }else{ // set the keyboard device to be the first keyboard device i=0; if(numDeviceIndices==0) PsychErrorExitMsg(PsychError_user, "No keyboard devices detected."); else{ deviceIndex=deviceIndices[i]; } } deviceRecord=deviceRecords[i]; //Allocate and init out return arguments. isKeyArgPresent = PsychAllocOutBooleanMatArg(3, FALSE, 1, 256, 1, &keyArrayOutput); isTimeArgPresent = PsychAllocOutDoubleArg(2, FALSE, &timeValueOutput); PsychGetPrecisionTimerSeconds(timeValueOutput); PsychAllocOutDoubleArg(1, FALSE, &isKeyDownOutput); *isKeyDownOutput=(double)FALSE; //step through the elements of the device. Set flags in the return array for down keys. for(currentElement=HIDGetFirstDeviceElement(deviceRecord, kHIDElementTypeInput); currentElement != NULL; currentElement=HIDGetNextDeviceElement(currentElement, kHIDElementTypeInput)) { if(currentElement->usagePage==KeysUsagePage && currentElement->usage <= 256 && currentElement->usage >=1){ //printf("usage: %x value: %d \n", currentElement->usage, HIDGetElementValue(deviceRecord, currentElement)); keyArrayOutput[currentElement->usage - 1]=(PsychNativeBooleanType)(HIDGetElementValue(deviceRecord, currentElement) || keyArrayOutput[currentElement->usage - 1]); *isKeyDownOutput= keyArrayOutput[currentElement->usage - 1] || *isKeyDownOutput; } } return(PsychError_none); }
// Get matching element from config record // takes a pre-allocated and filled out config record // search for matching device // return pDevice, pElement and cookie for action long HIDGetElementConfig (pRecSaveHID pConfigRec, pRecDevice * ppDevice, pRecElement * ppElement) { if (!pConfigRec->locID && !pConfigRec->vendorID && !pConfigRec->productID && !pConfigRec->usage && !pConfigRec->usagePage) { // early out *ppDevice = NULL; *ppElement = NULL; return pConfigRec->actionCookie; } pRecDevice pDevice, pFoundDevice = NULL; pRecElement pElement, pFoundElement = NULL; // compare to current device list for matches // look for device if (pConfigRec->locID && pConfigRec->vendorID && pConfigRec->productID) { // look for specific device type plug in to same port pDevice = HIDGetFirstDevice (); while (pDevice) { if ((pConfigRec->locID == pDevice->locID) && (pConfigRec->vendorID == pDevice->vendorID) && (pConfigRec->productID == pDevice->productID)) pFoundDevice = pDevice; if (pFoundDevice) break; pDevice = HIDGetNextDevice (pDevice); } if (pFoundDevice) { pElement = HIDGetFirstDeviceElement (pFoundDevice, kHIDElementTypeIO); while (pElement) { if (pConfigRec->cookie == pElement->cookie) pFoundElement = pElement; if (pFoundElement) break; pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); } // if no cookie match (should NOT occur) match on usage pElement = HIDGetFirstDeviceElement (pFoundDevice, kHIDElementTypeIO); while (pElement) { if ((pConfigRec->usageE == pElement->usage) && (pConfigRec->usagePageE == pElement->usagePage)) pFoundElement = pElement; if (pFoundElement) break; pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); } if (pElement) { // set min and max values if same device pElement->minReport = pConfigRec->minReport; pElement->maxReport = pConfigRec->maxReport; } } } // if we have not found a match, look at just vendor and product if ((NULL == pFoundDevice) && (pConfigRec->vendorID && pConfigRec->productID)) { pDevice = HIDGetFirstDevice (); while (pDevice) { if ((pConfigRec->vendorID == pDevice->vendorID) && (pConfigRec->productID == pDevice->productID)) pFoundDevice = pDevice; if (pFoundDevice) break; pDevice = HIDGetNextDevice (pDevice); } // match elements by cookie since same device type if (pFoundDevice) { pElement = HIDGetFirstDeviceElement (pFoundDevice, kHIDElementTypeIO); while (pElement) { if (pConfigRec->cookie == pElement->cookie) pFoundElement = pElement; if (pFoundElement) break; pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); } // if no cookie match (should NOT occur) match on usage pElement = HIDGetFirstDeviceElement (pFoundDevice, kHIDElementTypeIO); while (pElement) { if ((pConfigRec->usageE == pElement->usage) && (pConfigRec->usagePageE == pElement->usagePage)) pFoundElement = pElement; if (pFoundElement) break; pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); } if (pElement) { // set min and max values if same device pElement->minReport = pConfigRec->minReport; pElement->maxReport = pConfigRec->maxReport; } } } // can't find matching device return NULL, do not return first device if ((NULL == pFoundDevice) || (NULL == pFoundElement)) { // no HID device *ppDevice = NULL; *ppElement = NULL; return pConfigRec->actionCookie; } else { // HID device *ppDevice = pFoundDevice; *ppElement = pFoundElement; return pConfigRec->actionCookie; } }
PsychError PsychHIDOSKbCheck(int deviceIndex, double* scanList) { pRecDevice deviceRecord; pRecElement currentElement, lastElement = NULL; int i, debuglevel = 0; static int numDeviceIndices = -1; int numDeviceUsages=NUMDEVICEUSAGES; long KbDeviceUsagePages[NUMDEVICEUSAGES]= {kHIDPage_GenericDesktop, kHIDPage_GenericDesktop, kHIDPage_GenericDesktop, kHIDPage_GenericDesktop, kHIDPage_GenericDesktop, kHIDPage_GenericDesktop, kHIDPage_GenericDesktop}; long KbDeviceUsages[NUMDEVICEUSAGES]={kHIDUsage_GD_Keyboard, kHIDUsage_GD_Keypad, kHIDUsage_GD_Mouse, kHIDUsage_GD_Pointer, kHIDUsage_GD_Joystick, kHIDUsage_GD_GamePad, kHIDUsage_GD_MultiAxisController}; static int deviceIndices[PSYCH_HID_MAX_KEYBOARD_DEVICES]; static pRecDevice deviceRecords[PSYCH_HID_MAX_KEYBOARD_DEVICES]; psych_bool isDeviceSpecified, foundUserSpecifiedDevice; double *timeValueOutput, *isKeyDownOutput, *keyArrayOutput; int m, n, p, nout; double dummyKeyDown; double dummykeyArrayOutput[256]; uint32_t usage, usagePage; int value; // We query keyboard and keypad devices only on first invocation, then cache and recycle the data: if (numDeviceIndices == -1) { PsychHIDVerifyInit(); PsychHIDGetDeviceListByUsages(numDeviceUsages, KbDeviceUsagePages, KbDeviceUsages, &numDeviceIndices, deviceIndices, deviceRecords); } // Choose the device index and its record isDeviceSpecified = (deviceIndex != INT_MAX); if(isDeviceSpecified){ //make sure that the device number provided by the user is really a keyboard or keypad. if (deviceIndex < 0) { debuglevel = 1; deviceIndex = -deviceIndex; } for(i=0;i<numDeviceIndices;i++){ if ((foundUserSpecifiedDevice=(deviceIndices[i]==deviceIndex))) break; } if(!foundUserSpecifiedDevice) PsychErrorExitMsg(PsychError_user, "Specified device number is not a keyboard or keypad device."); } else { // set the keyboard or keypad device to be the first keyboard device or, if no keyboard, the first keypad i=0; if(numDeviceIndices==0) PsychErrorExitMsg(PsychError_user, "No keyboard or keypad devices detected."); else{ deviceIndex=deviceIndices[i]; } } deviceRecord=deviceRecords[i]; // Allocate and init out return arguments. // Either alloc out the arguments, or redirect to // internal dummy variables. This to avoid mxMalloc() call overhead // inside the PsychAllocOutXXX() routines: nout = PsychGetNumNamedOutputArgs(); // keyDown flag: if (nout >= 1) { PsychAllocOutDoubleArg(1, FALSE, &isKeyDownOutput); } else { isKeyDownOutput = &dummyKeyDown; } *isKeyDownOutput= (double) FALSE; // key state vector: if (nout >= 3) { PsychAllocOutDoubleMatArg(3, FALSE, 1, 256, 1, &keyArrayOutput); } else { keyArrayOutput = &dummykeyArrayOutput[0]; } memset((void*) keyArrayOutput, 0, sizeof(double) * 256); // Query timestamp: if (nout >= 2) { PsychAllocOutDoubleArg(2, FALSE, &timeValueOutput); // Get query timestamp: PsychGetPrecisionTimerSeconds(timeValueOutput); } // Make sure our keyboard query mechanism is not blocked for security reasons, e.g., // secure password entry field active in another process, i.e., EnableSecureEventInput() active. if (PsychHIDWarnInputDisabled("PsychHID('KbCheck')")) return(PsychError_none); //step through the elements of the device. Set flags in the return array for down keys. for(currentElement=HIDGetFirstDeviceElement(deviceRecord, kHIDElementTypeInput | kHIDElementTypeCollection); (currentElement != NULL) && (currentElement != lastElement); currentElement=HIDGetNextDeviceElement(currentElement, kHIDElementTypeInput | kHIDElementTypeCollection)) { // Keep track of last queried element: lastElement = currentElement; #ifndef __LP64__ usage = currentElement->usage; usagePage = currentElement->usagePage; #else usage = IOHIDElementGetUsage(currentElement); usagePage = IOHIDElementGetUsagePage(currentElement); // printf("PTB-DEBUG: [KbCheck]: ce %p page %d usage: %d isArray: %d\n", currentElement, usagePage, usage, IOHIDElementIsArray(currentElement)); if (IOHIDElementGetType(currentElement) == kIOHIDElementTypeCollection) { CFArrayRef children = IOHIDElementGetChildren(currentElement); if (!children) continue; CFIndex idx, cnt = CFArrayGetCount(children); for ( idx = 0; idx < cnt; idx++ ) { IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(children, idx); if (tIOHIDElementRef && ((IOHIDElementGetType(tIOHIDElementRef) == kIOHIDElementTypeInput_Button) || (IOHIDElementGetType(tIOHIDElementRef) == kIOHIDElementTypeInput_ScanCodes))) { usage = IOHIDElementGetUsage(tIOHIDElementRef); if ((usage <= 256) && (usage >= 1) && ( (scanList == NULL) || (scanList[usage - 1] > 0) )) { value = (int) IOHIDElement_GetValue(tIOHIDElementRef, kIOHIDValueScaleTypePhysical); if (debuglevel > 0) printf("PTB-DEBUG: [KbCheck]: usage: %x value: %d \n", usage, value); keyArrayOutput[usage - 1] = (value || (int) keyArrayOutput[usage - 1]); *isKeyDownOutput = keyArrayOutput[usage - 1] || *isKeyDownOutput; } } } // Done with this currentElement, which was a collection of buttons/keys. // Iterate to next currentElement: continue; } #endif // Classic path, or 64-Bit path for non-collection elements: if(((usagePage == kHIDPage_KeyboardOrKeypad) || (usagePage == kHIDPage_Button)) && (usage <= 256) && (usage >= 1) && ( (scanList == NULL) || (scanList[usage - 1] > 0) ) ) { #ifndef __LP64__ value = (int) HIDGetElementValue(deviceRecord, currentElement); #else value = (int) IOHIDElement_GetValue(currentElement, kIOHIDValueScaleTypePhysical); #endif if (debuglevel > 0) printf("PTB-DEBUG: [KbCheck]: usage: %x value: %d \n", usage, value); keyArrayOutput[usage - 1]=(value || (int) keyArrayOutput[usage - 1]); *isKeyDownOutput= keyArrayOutput[usage - 1] || *isKeyDownOutput; } } return(PsychError_none); }
unsigned char HIDConfigureAction (pRecDevice * ppDevice, pRecElement * ppElement, float timeout) { unsigned long devices, maxElements = 0; long * saveValueArray; pRecDevice pDevice = NULL; pRecElement pElement = NULL; short deviceNum = 0; unsigned char found = 0, done = 0; clock_t start = clock (), end; unsigned long i; if (0 == HIDHaveDeviceList ()) // if we do not have a device list if (0 == HIDBuildDeviceList (0, 0)) // if we could not build anorther list (use generic usage and page) return 0; // return 0 // build list of device and elements to save current values devices = HIDCountDevices (); pDevice = HIDGetFirstDevice (); while (pDevice) { if (HIDCountDeviceElements (pDevice, kHIDElementTypeIO) > maxElements) maxElements = HIDCountDeviceElements (pDevice, kHIDElementTypeIO); pDevice = HIDGetNextDevice (pDevice); } saveValueArray = (long *) malloc (sizeof (long) * devices * maxElements); // 2D array to save values for (i = 0; i < devices * maxElements; i++) // clear array *(saveValueArray + i) = 0x00000000; // store current values deviceNum = 0; pDevice = HIDGetFirstDevice (); while (pDevice) { short elementNum = 0; pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO); while (pElement) { *(saveValueArray + (deviceNum * maxElements) + elementNum) = HIDGetElementValue (pDevice, pElement); pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); elementNum++; } pDevice = HIDGetNextDevice (pDevice); deviceNum++; } // poll all devices and elements, compare current value to save +/- kPercentMove while ((!found) && (!done)) { double secs; // are we done? end = clock(); secs = (double)(end - start) / CLOCKS_PER_SEC; if (secs > timeout) done = 1; deviceNum = 0; pDevice = HIDGetFirstDevice (); while (pDevice) { short elementNum = 0; pElement = HIDGetFirstDeviceElement (pDevice, kHIDElementTypeIO); while (pElement) { long initialValue = *(saveValueArray + (deviceNum * maxElements) + elementNum); long value = HIDGetElementValue (pDevice, pElement); long delta = (float)(pElement->max - pElement->min) * kPercentMove * 0.01; if (((initialValue + delta) < value) || ((initialValue - delta) > value)) { found = 1; break; } pElement = HIDGetNextDeviceElement (pElement, kHIDElementTypeIO); elementNum++; } if (found) break; pDevice = HIDGetNextDevice (pDevice); deviceNum++; } } // return device and element moved if (found) { *ppDevice = pDevice; *ppElement = pElement; return 1; } else { *ppDevice = NULL; *ppElement = NULL; return 0; } }
PsychError PSYCHHIDGetCollections(void) { pRecDevice specDevice=NULL; UInt32 numDeviceElements; const char *elementFieldNames[]={"typeMaskName", "name", "deviceIndex", "collectionIndex", "typeValue", "typeName", "usagePageValue", "usageValue", "usageName", "memberCollectionIndices", "memberElementIndices"}; int i, numElementStructElements, numElementStructFieldNames=11, elementIndex, deviceIndex; PsychGenericScriptType *elementStruct, *memberCollectionIndicesMat, *memberIOElementIndicesMat; pRecElement currentElement; char elementTypeName[PSYCH_HID_MAX_DEVICE_ELEMENT_TYPE_NAME_LENGTH]; char usageName[PSYCH_HID_MAX_DEVICE_ELEMENT_USAGE_NAME_LENGTH]; char *typeMaskName; HIDElementTypeMask typeMask; pRecElement *memberCollectionRecords, *memberIOElementRecords; double *memberCollectionIndices, *memberIOElementIndices; int numSubCollections, numSubIOElements; PsychPushHelp(useString, synopsisString, seeAlsoString); if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);}; PsychErrorExit(PsychCapNumOutputArgs(1)); PsychErrorExit(PsychCapNumInputArgs(1)); PsychCopyInIntegerArg(1, TRUE, &deviceIndex); PsychHIDVerifyInit(); specDevice= PsychHIDGetDeviceRecordPtrFromIndex(deviceIndex); PsychHIDVerifyOpenDeviceInterfaceFromDeviceRecordPtr(specDevice); numDeviceElements= HIDCountDeviceElements(specDevice, kHIDElementTypeCollection); numElementStructElements = (int)numDeviceElements; PsychAllocOutStructArray(1, FALSE, numElementStructElements, numElementStructFieldNames, elementFieldNames, &elementStruct); elementIndex=0; for(currentElement=HIDGetFirstDeviceElement(specDevice,kHIDElementTypeCollection); currentElement != NULL; currentElement=HIDGetNextDeviceElement(currentElement, kHIDElementTypeCollection)) { typeMask=HIDConvertElementTypeToMask (currentElement->type); PsychHIDGetTypeMaskStringFromTypeMask(typeMask, &typeMaskName); PsychSetStructArrayStringElement("typeMaskName", elementIndex, typeMaskName, elementStruct); PsychSetStructArrayStringElement("name", elementIndex, currentElement->name, elementStruct); PsychSetStructArrayDoubleElement("deviceIndex", elementIndex, (double)deviceIndex, elementStruct); PsychSetStructArrayDoubleElement("collectionIndex", elementIndex, (double)elementIndex+1, elementStruct); PsychSetStructArrayDoubleElement("typeValue", elementIndex, (double)currentElement->type, elementStruct); HIDGetTypeName(currentElement->type, elementTypeName); PsychSetStructArrayStringElement("typeName", elementIndex, elementTypeName, elementStruct); PsychSetStructArrayDoubleElement("usagePageValue", elementIndex, (double)currentElement->usagePage, elementStruct); PsychSetStructArrayDoubleElement("usageValue", elementIndex, (double)currentElement->usage, elementStruct); HIDGetUsageName (currentElement->usagePage, currentElement->usage, usageName); PsychSetStructArrayStringElement("usageName", elementIndex, usageName, elementStruct); //find and return the indices of this collection's member collections and indices numSubCollections=PsychHIDCountCollectionElements(currentElement, kHIDElementTypeCollection); numSubIOElements=PsychHIDCountCollectionElements(currentElement, kHIDElementTypeIO); memberCollectionRecords=(pRecElement*)PsychMallocTemp(sizeof(pRecElement) * numSubCollections); memberIOElementRecords=(pRecElement*)PsychMallocTemp(sizeof(pRecElement) * numSubIOElements); PsychHIDFindCollectionElements(currentElement, kHIDElementTypeCollection, memberCollectionRecords, numSubCollections); PsychHIDFindCollectionElements(currentElement, kHIDElementTypeIO, memberIOElementRecords, numSubIOElements); memberCollectionIndices=NULL; PsychAllocateNativeDoubleMat(1, numSubCollections, 1, &memberCollectionIndices, &memberCollectionIndicesMat); memberIOElementIndices=NULL; PsychAllocateNativeDoubleMat(1, numSubIOElements, 1, &memberIOElementIndices, &memberIOElementIndicesMat); for(i=0;i<numSubCollections;i++) memberCollectionIndices[i]=PsychHIDGetIndexFromRecord(specDevice, memberCollectionRecords[i], kHIDElementTypeCollection); for(i=0;i<numSubIOElements;i++) memberIOElementIndices[i]=PsychHIDGetIndexFromRecord(specDevice, memberIOElementRecords[i], kHIDElementTypeIO); PsychFreeTemp(memberCollectionRecords); PsychFreeTemp(memberIOElementRecords); PsychSetStructArrayNativeElement("memberCollectionIndices", elementIndex, memberCollectionIndicesMat, elementStruct); PsychSetStructArrayNativeElement("memberElementIndices", elementIndex, memberIOElementIndicesMat, elementStruct); ++elementIndex; } return(PsychError_none); }