1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
|
/*
PsychToolbox3/Source/Common/PsychHID/PsychHIDKbCheck.c
PROJECTS: PsychHID only.
PLATFORMS: All.
AUTHORS:
Allen.Ingling@nyu.edu awi
mario.kleiner@tuebingen.mpg.de mk
HISTORY:
5/12/03 awi Created.
12/17/09 rpw Added keypad support
07/28/11 mk Refactored for multi-os support.
TO DO:
*/
#include "PsychHID.h"
static char useString[]= "[keyIsDown,secs,keyCode]=PsychHID('KbCheck' [, deviceNumber][, scanList])";
static char synopsisString[] =
"Scan a keyboard, keypad, or other HID device with buttons, and return a vector of logical values indicating the "
"state of each key.\n"
"By default the first keyboard device (the one with the lowest device number) is "
"scanned. If no keyboard is found, the first keypad device is scanned, followed by other "
"devices, e.g., mice. Optionally, the 'deviceNumber' of any keyboard or HID device may be specified.\n"
"As checking all potentially 256 keys on a HID device is a time consuming process, "
"which can easily take up to 1 msec on modern hardware, you can restrict the scan to a subset of "
"the 256 keys by providing the optional 'scanList' parameter: 'scanList' must be a vector of 256 "
"doubles, where the i'th element corresponds to the i'th key and a zero value means: Ignore this "
"key during scan, whereas a positive non-zero value means: Scan this key.\n"
"The PsychHID('KbCheck') implements the KbCheck command as provided by the OS 9 Psychtoolbox. "
"KbCheck is defined in the OS X Psychtoolbox and invokes PsychHID('KbCheck'). "
"Always use KbCheck instead of directly calling PsychHID('KbCheck'), unless you have very good "
"reasons to do otherwise and really know what you're doing!";
static char seeAlsoString[] = "";
PsychError PSYCHHIDKbCheck(void)
{
int deviceIndex, debuglevel = 0;
int m, n, p;
double *scanList = NULL;
psych_bool isDeviceSpecified;
PsychPushHelp(useString, synopsisString, seeAlsoString);
if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);};
PsychErrorExit(PsychCapNumOutputArgs(3));
PsychErrorExit(PsychCapNumInputArgs(2));
// Choose the device index and its record
isDeviceSpecified=PsychCopyInIntegerArg(1, FALSE, &deviceIndex);
if (isDeviceSpecified) {
if (deviceIndex < 0) {
debuglevel = 1;
deviceIndex = -deviceIndex;
}
}else { // set the keyboard or keypad device to be the first keyboard device or, if no keyboard, the first keypad
deviceIndex = INT_MAX;
}
// Optional 2nd argument 'scanlist' provided?
if (PsychAllocInDoubleMatArg(2, FALSE, &m, &n, &p, &scanList)) {
// Yep. Matching size?
if (p!=1 || m * n != 256) PsychErrorExitMsg(PsychError_user, "Provided 'scanList' parameter is not a vector of 256 doubles, as required!");
}
return(PsychHIDOSKbCheck(deviceIndex, scanList));
}
#if PSYCH_SYSTEM == PSYCH_OSX
#define NUMDEVICEUSAGES 7
PsychError PsychHIDOSKbCheck(int deviceIndex, double* scanList)
{
pRecDevice deviceRecord;
pRecElement currentElement;
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];
// 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);
currentElement != NULL;
currentElement=HIDGetNextDeviceElement(currentElement, kHIDElementTypeInput))
{
if(((currentElement->usagePage == kHIDPage_KeyboardOrKeypad) || (currentElement->usagePage == kHIDPage_Button)) && (currentElement->usage <= 256) && (currentElement->usage >= 1) &&
( (scanList == NULL) || (scanList[currentElement->usage - 1] > 0) ) ) {
if (debuglevel > 0) printf("PTB-DEBUG: [KbCheck]: usage: %x value: %d \n", currentElement->usage, HIDGetElementValue(deviceRecord, currentElement));
keyArrayOutput[currentElement->usage - 1]=((int) HIDGetElementValue(deviceRecord, currentElement) || (int) keyArrayOutput[currentElement->usage - 1]);
*isKeyDownOutput= keyArrayOutput[currentElement->usage - 1] || *isKeyDownOutput;
}
}
return(PsychError_none);
}
#endif
|