much better input-device class registration

This commit is contained in:
Jack Andersen 2015-04-29 21:01:55 -10:00
parent d4b1211c24
commit 4b8651b844
19 changed files with 184 additions and 106 deletions

13
InputDeviceClasses.cpp Normal file
View File

@ -0,0 +1,13 @@
#include "inputdev/SDeviceSignature.hpp"
#include "inputdev/CDolphinSmashAdapter.hpp"
namespace boo
{
const SDeviceSignature BOO_DEVICE_SIGS[] =
{
DEVICE_SIG(CDolphinSmashAdapter, 0x57e, 0x337, true),
DEVICE_SIG_SENTINEL()
};
}

View File

@ -11,11 +11,12 @@ namespace boo {typedef CCGLContext CGraphicsContext;}
#elif defined(__GNUC__) || defined(__clang__) #elif defined(__GNUC__) || defined(__clang__)
#include "x11/CGLXContext.hpp" #include "x11/CGLXContext.hpp"
namespace boo {typedef boo::CGLXContext CGraphicsContext;} namespace boo {typedef CGLXContext CGraphicsContext;}
#endif #endif
#include "IGraphicsContext.hpp" #include "IGraphicsContext.hpp"
#include "inputdev/CDeviceFinder.hpp" #include "inputdev/CDeviceFinder.hpp"
#include "inputdev/CDolphinSmashAdapter.hpp"
#endif // BOO_HPP #endif // BOO_HPP

View File

@ -3,6 +3,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
namespace boo namespace boo
{ {
@ -23,16 +24,18 @@ public:
virtual ~CDeviceBase(); virtual ~CDeviceBase();
void closeDevice(); void closeDevice();
virtual void deviceDisconnected()=0; virtual void deviceDisconnected()=0;
virtual void deviceError(const char* error) {fprintf(stderr, "%s\n", error);}
/* Low-Level API */ /* Low-Level API */
bool sendInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length); bool sendInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length);
size_t receiveInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length); size_t receiveInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length);
virtual void transferCycle() {}; virtual void initialCycle() {}
virtual void finalCycle() {}; virtual void transferCycle() {}
virtual void finalCycle() {}
/* High-Level API */ /* High-Level API */
bool sendReport(const uint8_t* data, size_t length); bool sendReport(const uint8_t* data, size_t length);
virtual size_t receiveReport(uint8_t* data, size_t length) {}; virtual size_t receiveReport(uint8_t* data, size_t length) {return 0;}
}; };

View File

@ -6,7 +6,8 @@
#include <stdexcept> #include <stdexcept>
#include "CDeviceToken.hpp" #include "CDeviceToken.hpp"
#include "IHIDListener.hpp" #include "IHIDListener.hpp"
#include "DeviceClasses.hpp" #include "SDeviceSignature.hpp"
#include <string.h>
namespace boo namespace boo
{ {
@ -24,7 +25,7 @@ public:
private: private:
/* Types this finder is interested in (immutable) */ /* Types this finder is interested in (immutable) */
EDeviceMask m_types; SDeviceSignature::TDeviceSignatureSet m_types;
/* Platform-specific USB event registration /* Platform-specific USB event registration
* (for auto-scanning, NULL if not registered) */ * (for auto-scanning, NULL if not registered) */
@ -45,9 +46,10 @@ private:
} }
inline void _insertToken(CDeviceToken&& token) inline void _insertToken(CDeviceToken&& token)
{ {
if (BooDeviceMatchToken(token, m_types)) { if (SDeviceSignature::DeviceMatchToken(token, m_types)) {
m_tokensLock.lock(); m_tokensLock.lock();
TInsertedDeviceToken inseredTok = m_tokens.insert(std::make_pair(token.getDevicePath(), std::move(token))); TInsertedDeviceToken inseredTok =
m_tokens.insert(std::make_pair(token.getDevicePath(), std::move(token)));
m_tokensLock.unlock(); m_tokensLock.unlock();
deviceConnected(inseredTok.first->second); deviceConnected(inseredTok.first->second);
} }
@ -81,12 +83,22 @@ public:
}; };
/* Application must specify its interested device-types */ /* Application must specify its interested device-types */
CDeviceFinder(EDeviceMask types) CDeviceFinder(std::vector<const char*> types)
: m_types(types), m_listener(NULL) : m_listener(NULL)
{ {
if (skDevFinder) if (skDevFinder)
throw std::runtime_error("only one instance of CDeviceFinder may be constructed"); throw std::runtime_error("only one instance of CDeviceFinder may be constructed");
skDevFinder = this; skDevFinder = this;
for (const char* typeName : types)
{
const SDeviceSignature* sigIter = BOO_DEVICE_SIGS;
while (sigIter->m_name)
{
if (!strcmp(sigIter->m_name, typeName))
m_types.push_back(sigIter);
++sigIter;
}
}
} }
~CDeviceFinder() ~CDeviceFinder()
{ {
@ -97,7 +109,7 @@ public:
} }
/* Get interested device-type mask */ /* Get interested device-type mask */
inline EDeviceMask getTypes() const {return m_types;} inline const SDeviceSignature::TDeviceSignatureSet& getTypes() const {return m_types;}
/* Iterable set of tokens */ /* Iterable set of tokens */
inline CDeviceTokensHandle getTokens() {return CDeviceTokensHandle(*this);} inline CDeviceTokensHandle getTokens() {return CDeviceTokensHandle(*this);}

View File

@ -3,7 +3,7 @@
#include <string> #include <string>
#include "CDeviceBase.hpp" #include "CDeviceBase.hpp"
#include "DeviceClasses.hpp" #include "SDeviceSignature.hpp"
namespace boo namespace boo
{ {
@ -48,7 +48,7 @@ public:
inline CDeviceBase* openAndGetDevice() inline CDeviceBase* openAndGetDevice()
{ {
if (!m_connectedDev) if (!m_connectedDev)
m_connectedDev = BooDeviceNew(*this); m_connectedDev = SDeviceSignature::DeviceNew(*this);
return m_connectedDev; return m_connectedDev;
} }

View File

@ -54,6 +54,7 @@ class CDolphinSmashAdapter final : public CDeviceBase
uint8_t m_rumbleState; uint8_t m_rumbleState;
bool m_didHandshake; bool m_didHandshake;
void deviceDisconnected(); void deviceDisconnected();
void initialCycle();
void transferCycle(); void transferCycle();
void finalCycle(); void finalCycle();
public: public:

View File

@ -1,32 +0,0 @@
#ifndef CDEVICECLASSES_HPP
#define CDEVICECLASSES_HPP
#include "CDolphinSmashAdapter.hpp"
#include "CRevolutionPad.hpp"
#include "CCafeProPad.hpp"
#include "CDualshockPad.hpp"
#include "CGenericPad.hpp"
namespace boo
{
#define VID_NINTENDO 0x57e
#define PID_SMASH_ADAPTER 0x337
enum EDeviceMask
{
DEV_NONE = 0,
DEV_DOL_SMASH_ADAPTER = 1<<0,
DEV_RVL_PAD = 1<<1,
DEV_CAFE_PRO_PAD = 1<<2,
DEV_DUALSHOCK_PAD = 1<<3,
DEV_GENERIC_PAD = 1<<4,
DEV_ALL = 0xff
};
bool BooDeviceMatchToken(const CDeviceToken& token, EDeviceMask mask);
CDeviceBase* BooDeviceNew(CDeviceToken& token);
}
#endif // CDEVICECLASSES_HPP

View File

@ -15,7 +15,7 @@ class CDeviceFinder;
class IHIDListener class IHIDListener
{ {
public: public:
virtual ~IHIDListener() {}; virtual ~IHIDListener() {}
/* Automatic device scanning */ /* Automatic device scanning */
virtual bool startScanning()=0; virtual bool startScanning()=0;

View File

@ -0,0 +1,37 @@
#ifndef SDeviceSignature_HPP
#define SDeviceSignature_HPP
#include <vector>
#include <functional>
namespace boo
{
class CDeviceToken;
class CDeviceBase;
struct SDeviceSignature
{
typedef std::vector<const SDeviceSignature*> TDeviceSignatureSet;
typedef std::function<CDeviceBase*(CDeviceToken*)> TFactoryLambda;
const char* m_name;
unsigned m_vid, m_pid;
bool m_lowLevel;
TFactoryLambda m_factory;
SDeviceSignature() : m_name(NULL) {} /* Sentinel constructor */
SDeviceSignature(const char* name, unsigned vid, unsigned pid, bool lowLevel, TFactoryLambda&& factory)
: m_name(name), m_vid(vid), m_pid(pid), m_lowLevel(lowLevel), m_factory(factory) {}
static bool DeviceMatchToken(const CDeviceToken& token, const TDeviceSignatureSet& sigSet);
static CDeviceBase* DeviceNew(CDeviceToken& token);
};
#define DEVICE_SIG(name, vid, pid, lowLevel) \
SDeviceSignature(#name, vid, pid, lowLevel, [](CDeviceToken* tok) -> CDeviceBase* {return new name(tok);})
#define DEVICE_SIG_SENTINEL() SDeviceSignature()
extern const SDeviceSignature BOO_DEVICE_SIGS[];
}
#endif // SDeviceSignature_HPP

View File

@ -15,9 +15,9 @@ HEADERS += \
$$PWD/include/inputdev/CDeviceFinder.hpp \ $$PWD/include/inputdev/CDeviceFinder.hpp \
$$PWD/include/inputdev/CDeviceToken.hpp \ $$PWD/include/inputdev/CDeviceToken.hpp \
$$PWD/include/inputdev/CDeviceBase.hpp \ $$PWD/include/inputdev/CDeviceBase.hpp \
$$PWD/include/inputdev/DeviceClasses.hpp \
$$PWD/include/inputdev/IHIDListener.hpp \ $$PWD/include/inputdev/IHIDListener.hpp \
$$PWD/src/inputdev/IHIDDevice.hpp $$PWD/src/inputdev/IHIDDevice.hpp \
$$PWD/include/inputdev/SDeviceSignature.hpp
unix:!macx:HEADERS += \ unix:!macx:HEADERS += \
$$PWD/include/x11/CGLXContext.hpp $$PWD/include/x11/CGLXContext.hpp
@ -29,6 +29,7 @@ win32:HEADERS += \
$$PWD/include/win/CWGLContext.hpp $$PWD/include/win/CWGLContext.hpp
SOURCES += \ SOURCES += \
$$PWD/InputDeviceClasses.cpp \
$$PWD/src/CSurface.cpp \ $$PWD/src/CSurface.cpp \
$$PWD/src/CRetraceWaiter.cpp \ $$PWD/src/CRetraceWaiter.cpp \
$$PWD/src/CInputRelay.cpp \ $$PWD/src/CInputRelay.cpp \
@ -39,9 +40,9 @@ SOURCES += \
$$PWD/src/inputdev/CDualshockPad.cpp \ $$PWD/src/inputdev/CDualshockPad.cpp \
$$PWD/src/inputdev/CGenericPad.cpp \ $$PWD/src/inputdev/CGenericPad.cpp \
$$PWD/src/inputdev/CDeviceBase.cpp \ $$PWD/src/inputdev/CDeviceBase.cpp \
$$PWD/src/inputdev/DeviceClasses.cpp \
$$PWD/src/inputdev/CHIDListenerUdev.cpp \ $$PWD/src/inputdev/CHIDListenerUdev.cpp \
$$PWD/src/inputdev/CHIDDeviceUdev.cpp $$PWD/src/inputdev/CHIDDeviceUdev.cpp \
$$PWD/src/inputdev/SDeviceSignature.cpp
unix:!macx:SOURCES += \ unix:!macx:SOURCES += \
$$PWD/src/x11/CGLXContext.cpp $$PWD/src/x11/CGLXContext.cpp

View File

@ -1,6 +1,8 @@
CONFIG -= Qt CONFIG -= Qt
#QMAKE_CXXFLAGS -= -std=c++0x #QMAKE_CXXFLAGS -= -std=c++0x
QMAKE_CXXFLAGS += -std=c++11 CONFIG += c++11
QMAKE_CXXFLAGS += -stdlib=libc++
LIBS += -std=c++11 -stdlib=libc++ -lc++abi
#unix:!macx:CONFIG += link_pkgconfig #unix:!macx:CONFIG += link_pkgconfig
#unix:!macx:PKGCONFIG += x11 #unix:!macx:PKGCONFIG += x11

View File

@ -118,7 +118,12 @@ void CDolphinSmashAdapter::transferCycle()
m_rumbleState = rumbleReq; m_rumbleState = rumbleReq;
} }
} }
}; }
void CDolphinSmashAdapter::initialCycle()
{
}
void CDolphinSmashAdapter::finalCycle() void CDolphinSmashAdapter::finalCycle()
{ {
@ -127,7 +132,7 @@ void CDolphinSmashAdapter::finalCycle()
uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0}; uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0};
sendInterruptTransfer(0, rumbleMessage, sizeof(rumbleMessage)); sendInterruptTransfer(0, rumbleMessage, sizeof(rumbleMessage));
} }
}; }
void CDolphinSmashAdapter::deviceDisconnected() void CDolphinSmashAdapter::deviceDisconnected()
{ {

View File

@ -8,6 +8,9 @@
#define MAX_REPORT_SIZE 65536 #define MAX_REPORT_SIZE 65536
namespace boo
{
class CHIDDeviceIOKit final : public IHIDDevice class CHIDDeviceIOKit final : public IHIDDevice
{ {
CDeviceToken& m_token; CDeviceToken& m_token;
@ -253,3 +256,5 @@ IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp, bool lowLeve
{ {
return new CHIDDeviceIOKit(token, devImp, lowLevel); return new CHIDDeviceIOKit(token, devImp, lowLevel);
} }
}

View File

@ -17,7 +17,7 @@
namespace boo namespace boo
{ {
udev* BooGetUdev(); udev* GetUdev();
#define MAX_REPORT_SIZE 65536 #define MAX_REPORT_SIZE 65536
@ -52,7 +52,7 @@ class CHIDDeviceUdev final : public IHIDDevice
(void*)data (void*)data
}; };
int ret = ioctl(m_devFd, USBDEVFS_BULK, &xfer); int ret = ioctl(m_devFd, USBDEVFS_BULK, &xfer);
if (ret != length) if (ret != (int)length)
return false; return false;
return true; return true;
} }
@ -79,12 +79,23 @@ class CHIDDeviceUdev final : public IHIDDevice
{ {
unsigned i; unsigned i;
std::unique_lock<std::mutex> lk(device->m_initMutex); std::unique_lock<std::mutex> lk(device->m_initMutex);
udev_device* hidDev = udev_device_new_from_syspath(BooGetUdev(), device->m_devPath.c_str()); udev_device* hidDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.c_str());
/* Get the HID element's parent (USB interrupt transfer-interface) */ /* Get the HID element's parent (USB interrupt transfer-interface) */
udev_device* usbDev = udev_device_get_parent_with_subsystem_devtype(hidDev, "usb", "usb_device"); udev_device* usbDev = udev_device_get_parent_with_subsystem_devtype(hidDev, "usb", "usb_device");
const char* dp = udev_device_get_devnode(usbDev); const char* dp = udev_device_get_devnode(usbDev);
device->m_devFd = open(dp, O_RDONLY); device->m_devFd = open(dp, O_RDWR);
if (device->m_devFd < 0)
{
char errStr[256];
snprintf(errStr, 256, "Unable to open %s@%s: %s\n",
device->m_token.getProductName().c_str(), dp, strerror(errno));
device->m_devImp.deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
udev_device_unref(hidDev);
return;
}
usb_device_descriptor devDesc = {0}; usb_device_descriptor devDesc = {0};
read(device->m_devFd, &devDesc, 1); read(device->m_devFd, &devDesc, 1);
read(device->m_devFd, &devDesc.bDescriptorType, devDesc.bLength-1); read(device->m_devFd, &devDesc.bDescriptorType, devDesc.bLength-1);
@ -128,13 +139,14 @@ class CHIDDeviceUdev final : public IHIDDevice
device->m_initCond.notify_one(); device->m_initCond.notify_one();
/* Start transfer loop */ /* Start transfer loop */
device->m_devImp.initialCycle();
while (device->m_runningTransferLoop) while (device->m_runningTransferLoop)
device->m_devImp.transferCycle(); device->m_devImp.transferCycle();
device->m_devImp.finalCycle(); device->m_devImp.finalCycle();
/* Cleanup */ /* Cleanup */
close(device->m_devFd); close(device->m_devFd);
device->m_devFd = NULL; device->m_devFd = 0;
udev_device_unref(hidDev); udev_device_unref(hidDev);
} }
@ -173,7 +185,7 @@ public:
~CHIDDeviceUdev() ~CHIDDeviceUdev()
{ {
m_runningTransferLoop = false; m_runningTransferLoop = false;
m_thread->detach(); m_thread->join();
delete m_thread; delete m_thread;
} }

View File

@ -6,6 +6,9 @@
#include <IOKit/usb/IOUSBLib.h> #include <IOKit/usb/IOUSBLib.h>
#include <IOKit/IOCFPlugIn.h> #include <IOKit/IOCFPlugIn.h>
namespace boo
{
/* /*
* Reference: http://oroboro.com/usb-serial-number-osx/ * Reference: http://oroboro.com/usb-serial-number-osx/
*/ */
@ -286,3 +289,4 @@ IHIDListener* IHIDListenerNew(CDeviceFinder& finder)
return new CHIDListenerIOKit(finder); return new CHIDListenerIOKit(finder);
} }
}

View File

@ -8,7 +8,7 @@ namespace boo
{ {
static udev* UDEV_INST = NULL; static udev* UDEV_INST = NULL;
udev* BooGetUdev() udev* GetUdev()
{ {
if (!UDEV_INST) if (!UDEV_INST)
UDEV_INST = udev_new(); UDEV_INST = udev_new();
@ -105,7 +105,7 @@ public:
{ {
/* Setup hotplug events */ /* Setup hotplug events */
m_udevMon = udev_monitor_new_from_netlink(BooGetUdev(), "udev"); m_udevMon = udev_monitor_new_from_netlink(GetUdev(), "udev");
if (!m_udevMon) if (!m_udevMon)
throw std::runtime_error("unable to init udev_monitor"); throw std::runtime_error("unable to init udev_monitor");
udev_monitor_filter_add_match_subsystem_devtype(m_udevMon, "hid", NULL); udev_monitor_filter_add_match_subsystem_devtype(m_udevMon, "hid", NULL);
@ -145,7 +145,7 @@ public:
/* Manual device scanning */ /* Manual device scanning */
bool scanNow() bool scanNow()
{ {
udev_enumerate* uenum = udev_enumerate_new(BooGetUdev()); udev_enumerate* uenum = udev_enumerate_new(GetUdev());
udev_enumerate_add_match_subsystem(uenum, "hid"); udev_enumerate_add_match_subsystem(uenum, "hid");
udev_enumerate_scan_devices(uenum); udev_enumerate_scan_devices(uenum);
udev_list_entry* uenumList = udev_enumerate_get_list_entry(uenum); udev_list_entry* uenumList = udev_enumerate_get_list_entry(uenum);

View File

@ -1,43 +0,0 @@
#include "inputdev/DeviceClasses.hpp"
#include "inputdev/CDeviceToken.hpp"
#include "IHIDDevice.hpp"
namespace boo
{
bool BooDeviceMatchToken(const CDeviceToken& token, EDeviceMask mask)
{
if (mask & DEV_DOL_SMASH_ADAPTER &&
token.getVendorId() == VID_NINTENDO && token.getProductId() == PID_SMASH_ADAPTER)
return true;
return false;
}
IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp, bool lowLevel);
CDeviceBase* BooDeviceNew(CDeviceToken& token)
{
CDeviceBase* retval = NULL;
bool lowLevel = false;
if (token.getVendorId() == VID_NINTENDO && token.getProductId() == PID_SMASH_ADAPTER)
{
retval = new CDolphinSmashAdapter(&token);
lowLevel = true;
}
if (!retval)
return NULL;
IHIDDevice* newDev = IHIDDeviceNew(token, *retval, lowLevel);
if (!newDev)
{
delete retval;
return NULL;
}
return retval;
}
}

View File

@ -0,0 +1,57 @@
#include "inputdev/SDeviceSignature.hpp"
#include "inputdev/CDeviceToken.hpp"
#include "IHIDDevice.hpp"
namespace boo
{
extern const SDeviceSignature BOO_DEVICE_SIGS[];
bool SDeviceSignature::DeviceMatchToken(const CDeviceToken& token, const TDeviceSignatureSet& sigSet)
{
for (const SDeviceSignature* sig : sigSet)
{
if (sig->m_vid == token.getVendorId() && sig->m_pid == token.getProductId())
return true;
}
return false;
}
IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp, bool lowLevel);
CDeviceBase* SDeviceSignature::DeviceNew(CDeviceToken& token)
{
CDeviceBase* retval = NULL;
const SDeviceSignature* foundSig = NULL;
const SDeviceSignature* sigIter = BOO_DEVICE_SIGS;
unsigned targetVid = token.getVendorId();
unsigned targetPid = token.getProductId();
while (sigIter->m_name)
{
if (sigIter->m_vid == targetVid && sigIter->m_pid == targetPid)
{
foundSig = sigIter;
break;
}
++sigIter;
}
if (!foundSig)
return NULL;
retval = foundSig->m_factory(&token);
if (!retval)
return NULL;
IHIDDevice* newDev = IHIDDeviceNew(token, *retval, foundSig->m_lowLevel);
if (!newDev)
{
delete retval;
return NULL;
}
return retval;
}
}

View File

@ -33,7 +33,7 @@ class CTestDeviceFinder : public CDeviceFinder
CDolphinSmashAdapterCallback m_cb; CDolphinSmashAdapterCallback m_cb;
public: public:
CTestDeviceFinder() CTestDeviceFinder()
: CDeviceFinder(DEV_DOL_SMASH_ADAPTER) : CDeviceFinder({"CDolphinSmashAdapter"})
{} {}
void deviceConnected(CDeviceToken& tok) void deviceConnected(CDeviceToken& tok)
{ {