PsychError PSYCHHIDKbQueueStart(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); PsychHIDOSKbQueueStart(deviceIndex); return(PsychError_none); }
PsychError PsychHIDOSKbCheck(int deviceIndex, double* scanList) { psych_uint8 keys[1024]; LPDIRECTINPUTDEVICE8 kb; unsigned int i, j; double* buttonStates; int keysdown; double timestamp; DWORD cbSize; if (deviceIndex == INT_MAX) { 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!"); } // Get DirectInput keyboard device: kb = GetXDevice(deviceIndex); // Keyboard queue for this deviceIndex already exists? if (NULL == psychHIDKbQueueFirstPress[deviceIndex]) { // No. Create one which accepts all keys: PsychHIDOSKbQueueCreate(deviceIndex, 0, NULL); } // Keyboard queue for this device active? If not, we need // to start it: if (!psychHIDKbQueueActive[deviceIndex]) { // Keyboard idle: Need to start it: PsychHIDOSKbQueueStart(deviceIndex); // Startup to first key delivery takes time. Wait for // 50 msecs to be on the safe side: PsychYieldIntervalSeconds(0.050); } // Size of state structure is device dependent: switch (info[deviceIndex].dwDevType & 0xff) { case DI8DEVTYPE_KEYBOARD: cbSize = 256; break; case DI8DEVTYPE_MOUSE: case DI8DEVTYPE_SCREENPOINTER: cbSize = sizeof(DIMOUSESTATE2); break; case DI8DEVTYPE_JOYSTICK: cbSize = sizeof(DIJOYSTATE2); break; default: // Unkown device. Fail. cbSize = 0; } // Query current state snapshot of keyboard: memset(keys, 0, sizeof(keys)); if (DI_OK != kb->GetDeviceState(cbSize, (LPVOID) &keys[0])) { printf("PsychHID-ERROR: KbCheck for deviceIndex %i failed, because query of device failed!\n", deviceIndex); PsychErrorExitMsg(PsychError_user, "KbCheck failed!"); } // Request current time of query: PsychGetAdjustedPrecisionTimerSeconds(×tamp); // Reset overall key state to "none pressed": keysdown = 0; // Copy out timestamp: PsychCopyOutDoubleArg(2, kPsychArgOptional, timestamp); // Copy keyboard state: PsychAllocOutDoubleMatArg(3, kPsychArgOptional, 1, 256, 1, &buttonStates); for (i = 0; i < 256; i++) buttonStates[i] = 0; // Keyboard? if (cbSize == 256) { // Copy button state to output vector, apply scanlist mask, compute // resulting overall keysdown state. We ignore keyboard scancode zero and // start with 1 instead. We also ignore code 255. These are borderline codes // which may do weird things... for (i = 1; i < 255; i++) { // Compute target key slot for this scancode i: j = PsychHIDOSMapKey(i); // This key down? buttonStates[j] += (keys[i] > 0) ? 1 : 0; // Apply scanList mask, if any provided: if (scanList && (scanList[j] <= 0)) buttonStates[j] = 0; keysdown += (unsigned int) buttonStates[j]; } } // Joystick? if (cbSize == sizeof(DIJOYSTATE2)) { // Copy button state to output vector, apply scanlist mask, compute // resulting overall keysdown state. There are 128 buttons at an offset: for (i = (8 * sizeof(LONG) + 4 * sizeof(DWORD)); i < (8 * sizeof(LONG) + 4 * sizeof(DWORD)) + 128; i++) { // Compute target key slot for this scancode i: j = i - (8 * sizeof(LONG) + 4 * sizeof(DWORD)); // This key down? buttonStates[j] += (keys[i] > 0) ? 1 : 0; // Apply scanList mask, if any provided: if (scanList && (scanList[j] <= 0)) buttonStates[j] = 0; keysdown += (unsigned int) buttonStates[j]; } } // Mouse? if (cbSize == sizeof(DIMOUSESTATE2)) { // Copy button state to output vector, apply scanlist mask, compute // resulting overall keysdown state. There are 8 buttons at an offset: for (i = (3 * sizeof(LONG)); i < (3 * sizeof(LONG)) + 8; i++) { // Compute target key slot for this scancode i: j = i - (3 * sizeof(LONG)); // This key down? buttonStates[j] += (keys[i] > 0) ? 1 : 0; // Apply scanList mask, if any provided: if (scanList && (scanList[j] <= 0)) buttonStates[j] = 0; keysdown += (unsigned int) buttonStates[j]; } } // Copy out overall keystate: PsychCopyOutDoubleArg(1, kPsychArgOptional, (keysdown > 0) ? 1 : 0); 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; }