/* PSYCHHIDCheckInit() Check to see if we need to create the USB-HID device list. If it has not been created then create it. */ void PsychHIDVerifyInit(void) { psych_bool success = TRUE; // Build HID device list if it doesn't already exist: if (!HIDHaveDeviceList()) success = (psych_bool) HIDBuildDeviceList(0, 0); // This check can only be made against the 64-Bit HID Utilities, as the older 32-Bit // version is even more crappy and can't report meaningful error status: #if defined(__LP64__) if (!success) { printf("PsychHID-ERROR: Could not enumerate HID devices (HIDBuildDeviceList() failed)! There can be various reasons,\n"); printf("PsychHID-ERROR: ranging from bugs in Apples HID software to a buggy HID device driver for some connected device,\n"); printf("PsychHID-ERROR: to general operating system malfunction. A reboot or device driver update for 3rd party HID devices\n"); printf("PsychHID-ERROR: maybe could help. Check the OSX system log for possible HID related error messages or hints. Aborting...\n"); PsychErrorExitMsg(PsychError_system, "HID device enumeration failed due to malfunction in the OSX 64 Bit Apple HID Utilities framework."); } #endif // Double-Check to protect against pathetic Apple software: if (!HIDHaveDeviceList()) { printf("PsychHID-ERROR: Could not enumerate HID devices (HIDBuildDeviceList() success, but HIDHaveDeviceList() still failed)!\n"); printf("PsychHID-ERROR: Reasons can be ranging from bugs in Apples HID software to a buggy HID device driver for some connected device,\n"); printf("PsychHID-ERROR: to general operating system malfunction. A reboot or device driver update for 3rd party HID devices\n"); printf("PsychHID-ERROR: maybe could help. Check the OSX system log for possible HID related error messages or hints. Aborting...\n"); PsychErrorExitMsg(PsychError_system, "HID device enumeration failed due to malfunction in the OSX Apple HID Utilities framework (II)."); } // Verify no security sensitive application is blocking our low-level access to HID devices: PsychHIDWarnInputDisabled(NULL); }
/* PSYCHHIDCheckInit() Check to see if we need to create the USB-HID device list. If it has not been created then create it. */ void PsychHIDVerifyInit(void) { psych_bool success = TRUE; // Build HID device list if it doesn't already exist: if (!HIDHaveDeviceList()) success = (psych_bool) HIDBuildDeviceList(0, 0); // This check can only be made against the 64-Bit HID Utilities, as the older 32-Bit // version is even more crappy and can't report meaningful error status: #if defined(__LP64__) if (!success) { printf("PsychHID-ERROR: Could not enumerate HID devices (HIDBuildDeviceList() failed)! There can be various reasons,\n"); printf("PsychHID-ERROR: ranging from bugs in Apples HID software to a buggy HID device driver for some connected device,\n"); printf("PsychHID-ERROR: to general operating system malfunction. A reboot or device driver update for 3rd party HID devices\n"); printf("PsychHID-ERROR: maybe could help. Check the OSX system log for possible HID related error messages or hints. Aborting...\n"); PsychErrorExitMsg(PsychError_system, "HID device enumeration failed due to malfunction in the OSX 64 Bit Apple HID Utilities framework."); } #endif // Double-Check to protect against pathetic Apple software: if (!HIDHaveDeviceList()) { printf("PsychHID-ERROR: Could not enumerate HID devices (HIDBuildDeviceList() success, but HIDHaveDeviceList() still failed)!\n"); printf("PsychHID-ERROR: Reasons can be ranging from bugs in Apples HID software to a buggy HID device driver for some connected device,\n"); printf("PsychHID-ERROR: to general operating system malfunction. A reboot or device driver update for 3rd party HID devices\n"); printf("PsychHID-ERROR: maybe could help. Check the OSX system log for possible HID related error messages or hints. Aborting...\n"); PsychErrorExitMsg(PsychError_system, "HID device enumeration failed due to malfunction in the OSX Apple HID Utilities framework (II)."); } // Verify no security sensitive application is blocking our low-level access to HID devices: PsychHIDWarnInputDisabled(NULL); #if defined(__LP64__) // Try to load all bundles from Psychtoolbox/PsychHardware/ // This loads the HID_Utilities.framework bundle if it is present. The whole point of it is // to allow our statically compiled-in version of the library to find the location of // the XML file with the database of (vendorId, productId) -> (VendorName, ProductName) and // (usagePage, usage) -> (usageName) mappings. // // In practice, the XML file only serves as a fallback, and one that doesn't contain much // useful info for mainstream products, only for a few niche products. Given its limited // value, i think we can refrain from shipping the framework as part of Psychtoolbox and // just provide the option to use it (== its XML file) if users decide to install it themselves. char tmpString[1024]; sprintf(tmpString, "%sPsychHardware/", PsychRuntimeGetPsychtoolboxRoot(FALSE)); CFStringRef urlString = CFStringCreateWithCString(kCFAllocatorDefault, tmpString, kCFStringEncodingASCII); CFURLRef directoryURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, urlString, kCFURLPOSIXPathStyle, false); CFRelease(urlString); CFArrayRef bundleArray = CFBundleCreateBundlesFromDirectory(kCFAllocatorDefault, directoryURL, NULL); CFRelease(directoryURL); CFRelease(bundleArray); #endif }
/* PSYCHHIDCheckInit() Check to see if we need to create the USB-HID device list. If it has not been created then create it. */ void PsychHIDVerifyInit(void) { // GenericDesktop for mice, keyboards, gamepads etc. vendor defined for things like MCC USB-DAQ boxes... UInt32 inUsagePages[2] = {kHIDPage_GenericDesktop, kHIDPage_VendorDefinedStart}; UInt32 inUsages[2] = {0, 0}; int inNumDeviceTypes = 2; psych_bool success = TRUE; // Build HID device list if it doesn't already exist: if (!HIDHaveDeviceList()) success = (psych_bool)HIDBuildDeviceList(0, 0); // This check can only be made against the 64-Bit HID Utilities, as the older 32-Bit // version is even more crappy and can't report meaningful error status: if (!success) { printf("PsychHID-ERROR: Could not enumerate and attach to all HID devices (HIDBuildDeviceList(0,0) failed)!\n"); printf("PsychHID-ERROR: One reason could be that some HID devices are already exclusively claimed by some 3rd party device drivers\n"); printf("PsychHID-ERROR: or applications. I will now retry to only claim control of a hopefully safe subset of devices like standard\n"); printf("PsychHID-ERROR: keyboards, mice, gamepads and supported USB-DAQ devices and other vendor defined devices and hope this goes better...\n"); // User override for special devices provided? if (getenv("PSYCHHID_HIDPAGEOVERRIDE")) { // Override via environment variable provided: Use it in addition to the generic desktop input devices: inUsagePages[1] = atoi(getenv("PSYCHHID_HIDPAGEOVERRIDE")); inUsages[1] = atoi(getenv("PSYCHHID_HIDUSAGEOVERRIDE")); printf("PsychHID-INFO: User override: Generic desktop page devices + usagePage 0x%x and usage value 0x%x ...\n", inUsagePages[1], inUsages[1]); } success = (psych_bool)HIDBuildMultiDeviceList(inUsagePages, inUsages, inNumDeviceTypes); if (!success) { printf("PsychHID-ERROR: Nope. Excluding everything but a few known USB-DAQ devices and standard mice, keyboards etc. Retrying ...\n"); inUsagePages[1] = kHIDPage_VendorDefinedStart; inUsages[1] = 1; // Known combo is usagepage 0xff00 + usage 0x1 for MCC USB 1208-FS USB HID-DAQ device. success = (psych_bool)HIDBuildMultiDeviceList(inUsagePages, inUsages, inNumDeviceTypes); } if (!success) { printf("PsychHID-ERROR: Nope. Excluding everything but standard mice, keyboards etc. Retrying ...\n"); success = (psych_bool)HIDBuildMultiDeviceList(inUsagePages, inUsages, 1); if (!success) { printf("PsychHID-ERROR: Could not enumerate any HID devices (HIDBuildDeviceList() still failed even for standard generic desktop input devices)!\n"); printf("PsychHID-ERROR: Reasons can be ranging from bugs in Apples HID software to a buggy HID device driver for some connected device,\n"); printf("PsychHID-ERROR: to general operating system malfunction. A reboot or device driver update for 3rd party HID devices\n"); printf("PsychHID-ERROR: maybe could help. Check the OSX system log for possible HID related error messages or hints. Aborting...\n"); PsychErrorExitMsg(PsychError_system, "HID device enumeration failed due to malfunction in the OSX 64 Bit Apple HID Utilities framework."); } } else { printf("PsychHID-INFO: That worked. A subset of regular mouse, keyboard etc. input devices and maybe some vendor defined devices will be available at least.\n"); } } // Double-Check to protect against pathetic Apple software: if (!HIDHaveDeviceList()) { printf("PsychHID-ERROR: Could not enumerate HID devices (HIDBuildDeviceList() success, but HIDHaveDeviceList() still failed)!\n"); printf("PsychHID-ERROR: Reasons can be ranging from bugs in Apples HID software to a buggy HID device driver for some connected device,\n"); printf("PsychHID-ERROR: to general operating system malfunction. A reboot or device driver update for 3rd party HID devices\n"); printf("PsychHID-ERROR: maybe could help. Check the OSX system log for possible HID related error messages or hints. Aborting...\n"); PsychErrorExitMsg(PsychError_system, "HID device enumeration failed due to malfunction in the OSX Apple HID Utilities framework (II)."); } // Verify no security sensitive application is blocking our low-level access to HID devices: PsychHIDWarnInputDisabled(NULL); }
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); }