void PsychHIDOSKbQueueRelease(int deviceIndex) { if (deviceIndex < 0) { deviceIndex = PsychHIDGetDefaultKbQueueDevice(); // Ok, deviceIndex now contains our default keyboard to use - The first suitable keyboard. } if ((deviceIndex < 0) || (deviceIndex >= ndevices)) { // Out of range index: PsychErrorExitMsg(PsychError_user, "Invalid 'deviceIndex' specified. No such device!"); } // Keyboard queue for this deviceIndex already exists? if (NULL == psychHIDKbQueueFirstPress[deviceIndex]) { // No. Nothing to do then. return; } // Ok, we have a keyboard queue. Stop any operation on it first: PsychHIDOSKbQueueStop(deviceIndex); // Release its data structures: free(psychHIDKbQueueFirstPress[deviceIndex]); psychHIDKbQueueFirstPress[deviceIndex] = NULL; free(psychHIDKbQueueFirstRelease[deviceIndex]); psychHIDKbQueueFirstRelease[deviceIndex] = NULL; free(psychHIDKbQueueLastPress[deviceIndex]); psychHIDKbQueueLastPress[deviceIndex] = NULL; free(psychHIDKbQueueLastRelease[deviceIndex]); psychHIDKbQueueLastRelease[deviceIndex] = NULL; free(psychHIDKbQueueScanKeys[deviceIndex]); psychHIDKbQueueScanKeys[deviceIndex] = NULL; // Release kbqueue event buffer: PsychHIDDeleteEventBuffer(deviceIndex); // Done. return; }
void PsychHIDOSKbQueueRelease(int deviceIndex) { // Get true keyboardqueue index assigned to deviceIndex from original user provided deviceIndex: deviceIndex = PsychHIDOSGetKbQueueDevice(deviceIndex, NULL); // Keyboard queue for this deviceIndex already exists? if (NULL == psychHIDKbQueueFirstPress[deviceIndex]) { // No. Nothing to do then. return; } // Ok, we have a keyboard queue. Stop any operation on it first: PsychHIDOSKbQueueStop(deviceIndex); // The mutex will be automatically unlocked and destroyed by the CFRunLoop thread // so it isn't even declared in this routine if (psychHIDKbQueueCFRunLoopRef[deviceIndex]) { // Shutdown the processing thread for this queue: PsychLockMutex(&KbQueueMutex); // Stop the CFRunLoop, which will allow its associated thread to exit: CFRunLoopStop(psychHIDKbQueueCFRunLoopRef[deviceIndex]); // Done. PsychUnlockMutex(&KbQueueMutex); // Shutdown the thread, wait for its termination: PsychDeleteThread(&KbQueueThread[deviceIndex]); KbQueueThread[deviceIndex] = NULL; // Release the CFRunLoop for this queue: CFRelease(psychHIDKbQueueCFRunLoopRef[deviceIndex]); psychHIDKbQueueCFRunLoopRef[deviceIndex] = NULL; // Release queue object: CFRelease(queue[deviceIndex]); queue[deviceIndex] = NULL; } // Release its data structures: free(psychHIDKbQueueFirstPress[deviceIndex]); psychHIDKbQueueFirstPress[deviceIndex] = NULL; free(psychHIDKbQueueFirstRelease[deviceIndex]); psychHIDKbQueueFirstRelease[deviceIndex] = NULL; free(psychHIDKbQueueLastPress[deviceIndex]); psychHIDKbQueueLastPress[deviceIndex] = NULL; free(psychHIDKbQueueLastRelease[deviceIndex]); psychHIDKbQueueLastRelease[deviceIndex] = NULL; free(psychHIDKbQueueScanKeys[deviceIndex]); psychHIDKbQueueScanKeys[deviceIndex] = NULL; // Release kbqueue event buffer: PsychHIDDeleteEventBuffer(deviceIndex); // Done. return; }
PsychError PSYCHHIDKbQueueStop(void) { int deviceIndex; PsychPushHelp(useString, synopsisString, seeAlsoString); if(PsychIsGiveHelp()) { PsychGiveHelp(); return(PsychError_none); }; PsychErrorExit(PsychCapNumOutputArgs(0)); PsychErrorExit(PsychCapNumInputArgs(1)); deviceIndex = -1; PsychCopyInIntegerArg(1, kPsychArgOptional, &deviceIndex); PsychHIDOSKbQueueStop(deviceIndex); return(PsychError_none); }
void PsychHIDOSKbTriggerWait(int deviceIndex, int numScankeys, int* scanKeys) { int keyMask[256]; int i; double t, tc; if (deviceIndex < 0) { deviceIndex = PsychHIDGetDefaultKbQueueDevice(); // Ok, deviceIndex now contains our default keyboard to use - The first suitable keyboard. } if ((deviceIndex < 0) || (deviceIndex >= ndevices)) { // Out of range index: PsychErrorExitMsg(PsychError_user, "Invalid 'deviceIndex' specified. No such device!"); } if(psychHIDKbQueueFirstPress[deviceIndex]) PsychErrorExitMsg(PsychError_user, "A queue for this device is already running, you must call KbQueueRelease() before invoking KbTriggerWait."); // Create a keyboard queue for this deviceIndex: memset(&keyMask[0], 0, sizeof(keyMask)); for (i = 0; i < numScankeys; i++) { if (scanKeys[i] < 1 || scanKeys[i] > 256) PsychErrorExitMsg(PsychError_user, "Invalid entry for triggerKey specified. Not in valid range 1 - 256!"); keyMask[scanKeys[i] - 1] = 1; } // Create keyboard queue with proper mask: PsychHIDOSKbQueueCreate(deviceIndex, 256, &keyMask[0]); PsychHIDOSKbQueueStart(deviceIndex); PsychLockMutex(&KbQueueMutex); // Scan for trigger key: while (1) { // Wait until something changes in a keyboard queue: PsychWaitCondition(&KbQueueCondition, &KbQueueMutex); // Check if our queue had one of the dedicated trigger keys pressed: for (i = 0; i < numScankeys; i++) { // Break out of scan loop if key pressed: if (psychHIDKbQueueFirstPress[deviceIndex][scanKeys[i] - 1] != 0) break; } // Triggerkey pressed? if ((i < numScankeys) && (psychHIDKbQueueFirstPress[deviceIndex][scanKeys[i] - 1] != 0)) break; // No change for our trigger keys. Repeat scan loop. } // If we reach this point, we know some triggerkey has been pressed. As we aborted // the scan on detection of the first pressed key, we can't be certain we caught the // key with the earliest key press, maybe one of the untested keys was pressed even // earlier. Therefore do another pass over all keys to find the pressed one with the // earliest (minimum) pressed time: t = DBL_MAX; for (i = 0; i < numScankeys; i++) { tc = psychHIDKbQueueFirstPress[deviceIndex][scanKeys[i] - 1]; if ((tc != 0) && (tc <= t)) t = tc; } // Done. Release the lock: PsychUnlockMutex(&KbQueueMutex); // Stop and release the queue: PsychHIDOSKbQueueStop(deviceIndex); PsychHIDOSKbQueueRelease(deviceIndex); // Return timestamp: PsychCopyOutDoubleArg(1, kPsychArgOptional, t); return; }