#import #import #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // USB Gamepad code, likely to be moved somewhere else later. // This is Frankencode until the Input redesign happens. namespace { using namespace std; using namespace Gosu; using boost::shared_ptr; template void checkTrue(Negatable cond, const char* message = "work") { if (!cond) throw runtime_error(string("HID system failed to ") + message); } void checkIO(IOReturn val, const char* message = "work") { checkTrue(val == kIOReturnSuccess, message); } class IOScope : boost::noncopyable { io_object_t ref; public: IOScope(io_object_t ref) : ref(ref) { } ~IOScope() { IOObjectRelease(ref); } }; string getDictString(CFMutableDictionaryRef dict, CFStringRef key, const char* what) { char buf[256]; CFStringRef str = (CFStringRef)CFDictionaryGetValue(dict, key); checkTrue(str && CFStringGetCString(str, buf, sizeof buf, CFStringGetSystemEncoding()), what); return buf; } SInt32 getDictSInt32(CFMutableDictionaryRef dict, CFStringRef key, const char* what) { SInt32 value; CFNumberRef number = (CFNumberRef)CFDictionaryGetValue(dict, key); checkTrue(number && CFNumberGetValue(number, kCFNumberSInt32Type, &value), what); return value; } struct Axis { IOHIDElementCookie cookie; long min, max; enum Role { mainX, mainY } role; // Some devices report more axis than they have, with random constant values. // An axis has to go into, and out of the neutral zone so it will be reported. bool wasNeutralOnce; Axis(CFMutableDictionaryRef dict, Role role) : role(role), wasNeutralOnce(false) { cookie = (IOHIDElementCookie)getDictSInt32(dict, CFSTR(kIOHIDElementCookieKey), "get an element cookie"); min = getDictSInt32(dict, CFSTR(kIOHIDElementMinKey), "get a min value"); max = getDictSInt32(dict, CFSTR(kIOHIDElementMaxKey), "get a max value"); } }; struct Hat { IOHIDElementCookie cookie; enum { fourWay, eightWay, unknown } kind; long min; Hat(CFMutableDictionaryRef dict) { cookie = (IOHIDElementCookie)getDictSInt32(dict, CFSTR(kIOHIDElementCookieKey), "an element cookie"); min = getDictSInt32(dict, CFSTR(kIOHIDElementMinKey), "a min value"); SInt32 max = getDictSInt32(dict, CFSTR(kIOHIDElementMaxKey), "a max value"); if ((max - min) == 3) kind = fourWay; else if ((max - min) == 7) kind = eightWay; else kind = unknown; } }; struct Button { IOHIDElementCookie cookie; Button(CFMutableDictionaryRef dict) { cookie = (IOHIDElementCookie)getDictSInt32(dict, CFSTR(kIOHIDElementCookieKey), "get an element cookie"); } }; struct Device { shared_ptr interface; std::string name; vector axis; vector hats; vector