lots of HID implementation (OS X only for now)

This commit is contained in:
Jack Andersen 2015-04-20 18:02:43 -10:00
parent 03a325b8ac
commit edaebc5e50
17 changed files with 443 additions and 18 deletions

View File

@ -1,16 +1,21 @@
#ifndef BOO_HPP
#define BOO_HPP
#include "IGraphicsContext.hpp"
#if defined(_WIN32)
#error "No support for WGL"
#elif defined(__APPLE__)
#include "mac/CCGLContext.hpp"
typedef CCGLContext CGraphicsContext;
#elif defined(__GNUC__) || defined(__clang__)
#include "x11/CGLXContext.hpp"
typedef CGLXContext CGraphicsContext;
#endif
#include "IGraphicsContext.hpp"
#include "inputdev/CDeviceFinder.hpp"
#endif // BOO_HPP

View File

@ -1,13 +1,18 @@
#ifndef CDEVICEBASE
#define CDEVICEBASE
#include "CDeviceToken.hpp"
class CDeviceToken;
class IHIDDevice;
class CDeviceBase
{
CDeviceToken* m_token;
IHIDDevice* m_hidDev;
public:
inline CDeviceBase(CDeviceToken* token, IHIDDevice* hidDev)
: m_token(token), m_hidDev(hidDev) {}
void _deviceDisconnected();
virtual void deviceDisconnected()=0;
};
#endif // CDEVICEBASE

View File

@ -1,5 +1,131 @@
#ifndef CDEVICEFINDER_HPP
#define CDEVICEFINDER_HPP
#include <set>
#include <mutex>
#include <stdexcept>
#include "CDeviceToken.hpp"
#include "IHIDListener.hpp"
#include "DeviceClasses.hpp"
static class CDeviceFinder* skDevFinder = NULL;
class CDeviceFinder
{
public:
friend class CHIDListenerIOKit;
friend class CHIDListenerUdev;
friend class CHIDListenerWin32;
static inline CDeviceFinder* instance() {return skDevFinder;}
private:
/* Types this finder is interested in (immutable) */
EDeviceMask m_types;
/* Platform-specific USB event registration
* (for auto-scanning, NULL if not registered) */
IHIDListener* m_listener;
/* Set of presently-connected device tokens */
TDeviceTokens m_tokens;
std::mutex m_tokensLock;
/* Friend methods for platform-listener to find/insert/remove
* tokens with type-filtering */
inline bool _hasToken(TDeviceHandle handle)
{
auto preCheck = m_tokens.find(handle);
if (preCheck != m_tokens.end())
return true;
return false;
}
inline void _insertToken(CDeviceToken&& token)
{
if (BooDeviceMatchToken(token, m_types)) {
m_tokensLock.lock();
m_tokens.insert(std::make_pair(token.getDeviceHandle(), token));
m_tokensLock.unlock();
}
}
inline void _removeToken(TDeviceHandle handle)
{
auto preCheck = m_tokens.find(handle);
if (preCheck != m_tokens.end())
{
CDeviceToken& tok = preCheck->second;
tok._deviceClose();
m_tokensLock.lock();
m_tokens.erase(preCheck);
m_tokensLock.unlock();
}
}
public:
class CDeviceTokensHandle
{
CDeviceFinder& m_finder;
public:
inline CDeviceTokensHandle(CDeviceFinder& finder) : m_finder(finder)
{m_finder.m_tokensLock.lock();}
inline ~CDeviceTokensHandle() {m_finder.m_tokensLock.unlock();}
inline TDeviceTokens::iterator begin() {return m_finder.m_tokens.begin();}
inline TDeviceTokens::iterator end() {return m_finder.m_tokens.end();}
};
/* Application must specify its interested device-types */
CDeviceFinder(EDeviceMask types, bool autoScan=true)
: m_types(types), m_listener(NULL)
{
if (skDevFinder)
throw std::runtime_error("only one instance of CDeviceFinder may be constructed");
skDevFinder = this;
if (autoScan)
startScanning();
}
~CDeviceFinder()
{
if (m_listener)
m_listener->stopScanning();
delete m_listener;
skDevFinder = NULL;
}
/* Get interested device-type mask */
inline EDeviceMask getTypes() const {return m_types;}
/* Iterable set of tokens */
inline CDeviceTokensHandle getTokens() {return CDeviceTokensHandle(*this);}
/* Automatic device scanning */
inline bool startScanning()
{
if (!m_listener)
m_listener = IHIDListenerNew(*this);
if (m_listener)
return m_listener->startScanning();
return false;
}
inline bool stopScanning()
{
if (!m_listener)
m_listener = IHIDListenerNew(*this);
if (m_listener)
return m_listener->stopScanning();
return false;
}
/* Manual device scanning */
inline bool scanNow()
{
if (!m_listener)
m_listener = IHIDListenerNew(*this);
if (m_listener)
return m_listener->scanNow();
return false;
}
};
#endif // CDEVICEFINDER_HPP

View File

@ -2,21 +2,65 @@
#define CDEVICETOKEN
#include <string>
#include <IOKit/hid/IOHIDDevice.h>
#include "CDeviceBase.hpp"
#include "DeviceClasses.hpp"
#if __APPLE__
#include <IOKit/hid/IOHIDLib.h>
typedef IOHIDDeviceRef TDeviceHandle;
#elif _WIN32
#elif __linux__
#endif
class CDeviceBase;
class CDeviceToken
{
std::string m_name;
#if __APPLE__
unsigned m_vendorId;
unsigned m_productId;
std::string m_vendorName;
std::string m_productName;
TDeviceHandle m_devHandle;
friend CDeviceBase;
CDeviceBase* m_connectedDev;
#elif _WIN32
#elif __linux__
#endif
public:
const std::string& getName() const;
CDeviceBase* getDevice() const;
inline CDeviceToken(unsigned vid, unsigned pid, const char* vname, const char* pname, TDeviceHandle handle)
: m_vendorId(vid), m_productId(pid), m_devHandle(handle), m_connectedDev(NULL)
{
if (vname)
m_vendorName = vname;
if (pname)
m_productName = pname;
}
inline unsigned getVendorId() const {return m_vendorId;}
inline unsigned getProductId() const {return m_productId;}
inline const std::string& getVendorName() const {return m_vendorName;}
inline const std::string& getProductName() const {return m_productName;}
inline TDeviceHandle getDeviceHandle() const {return m_devHandle;}
inline bool isDeviceOpen() const {return m_connectedDev;}
inline CDeviceBase* openAndGetDevice()
{
if (!m_connectedDev)
m_connectedDev = BooDeviceNew(this);
return m_connectedDev;
}
inline void _deviceClose()
{
if (m_connectedDev)
m_connectedDev->deviceDisconnected();
m_connectedDev = NULL;
}
inline CDeviceToken operator =(const CDeviceToken& other)
{return CDeviceToken(other);}
inline bool operator ==(const CDeviceToken& rhs) const
{return m_devHandle == rhs.m_devHandle;}
inline bool operator <(const CDeviceToken& rhs) const
{return m_devHandle < rhs.m_devHandle;}
};
#endif // CDEVICETOKEN

View File

@ -1,5 +1,17 @@
#ifndef CDOLPHINSMASHADAPTER_HPP
#define CDOLPHINSMASHADAPTER_HPP
#include "CDeviceBase.hpp"
class CDolphinSmashAdapter final : public CDeviceBase
{
void deviceDisconnected();
public:
CDolphinSmashAdapter(CDeviceToken* token, IHIDDevice* hidDev)
: CDeviceBase(token, hidDev)
{
}
};
#endif // CDOLPHINSMASHADAPTER_HPP

View File

@ -0,0 +1,24 @@
#ifndef CDEVICECLASSES_HPP
#define CDEVICECLASSES_HPP
#include "CDolphinSmashAdapter.hpp"
#include "CRevolutionPad.hpp"
#include "CCafeProPad.hpp"
#include "CDualshockPad.hpp"
#include "CGenericPad.hpp"
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

@ -17,6 +17,7 @@ HEADERS += \
$$PWD/include/inputdev/CDeviceFinder.hpp \
$$PWD/include/inputdev/CDeviceToken.hpp \
$$PWD/include/inputdev/CDeviceBase.hpp \
$$PWD/include/inputdev/DeviceClasses.hpp \
$$PWD/src/inputdev/IHIDDevice.hpp \
$$PWD/src/inputdev/IHIDListener.hpp
@ -39,8 +40,8 @@ SOURCES += \
$$PWD/src/inputdev/CCafeProPad.cpp \
$$PWD/src/inputdev/CDualshockPad.cpp \
$$PWD/src/inputdev/CGenericPad.cpp \
$$PWD/src/inputdev/CDeviceFinder.cpp \
$$PWD/src/inputdev/CDeviceBase.cpp
$$PWD/src/inputdev/CDeviceBase.cpp \
$$PWD/src/inputdev/DeviceClasses.cpp
unix:!macx:SOURCES += \
$$PWD/src/x11/CGLXContext.cpp \

View File

@ -1,3 +1,15 @@
#include "inputdev/CDeviceBase.hpp"
#include "inputdev/CDeviceToken.hpp"
#include "IHIDDevice.hpp"
void CDeviceBase::_deviceDisconnected()
{
m_token->m_connectedDev = NULL;
m_token = NULL;
m_hidDev->deviceDisconnected();
m_hidDev = NULL;
}

View File

@ -1 +0,0 @@
#include "inputdev/CDeviceFinder.hpp"

View File

@ -1 +1,6 @@
#include "inputdev/CDolphinSmashAdapter.hpp"
void CDolphinSmashAdapter::deviceDisconnected()
{
}

View File

@ -1 +1,30 @@
#include "IHIDDevice.hpp"
#include "inputdev/CDeviceToken.hpp"
#include <IOKit/hid/IOHIDLib.h>
class CHIDDeviceIOKit final : public IHIDDevice
{
IOHIDDeviceRef m_dev;
public:
CHIDDeviceIOKit(CDeviceToken* token)
: m_dev(token->getDeviceHandle())
{
IOHIDDeviceOpen(m_dev, kIOHIDOptionsTypeNone);
}
CHIDDeviceIOKit()
{
IOHIDDeviceClose(m_dev, kIOHIDOptionsTypeNone);
}
void deviceDisconnected()
{
IOHIDDeviceClose(m_dev, kIOHIDOptionsTypeNone);
}
};
IHIDDevice* IHIDDeviceNew(CDeviceToken* token)
{
return new CHIDDeviceIOKit(token);
}

View File

@ -0,0 +1,114 @@
#include "IHIDListener.hpp"
#include "inputdev/CDeviceFinder.hpp"
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hid/IOHIDLib.h>
class CHIDListenerIOKit final : public IHIDListener
{
CDeviceFinder& m_finder;
IOHIDManagerRef m_hidManager;
bool m_scanningEnabled;
static void deviceConnected(CHIDListenerIOKit* listener,
IOReturn,
void*,
IOHIDDeviceRef device)
{
if (!listener->m_scanningEnabled)
return;
if (listener->m_finder._hasToken(device))
return;
CFIndex vid, pid;
CFNumberGetValue((CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey)), kCFNumberCFIndexType, &vid);
CFNumberGetValue((CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey)), kCFNumberCFIndexType, &pid);
CFStringRef manuf = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDManufacturerKey));
CFStringRef product = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
listener->m_finder._insertToken(CDeviceToken(vid, pid,
CFStringGetCStringPtr(manuf, kCFStringEncodingUTF8),
CFStringGetCStringPtr(product, kCFStringEncodingUTF8),
device));
}
static void deviceDisconnected(CHIDListenerIOKit* listener,
IOReturn,
void*,
IOHIDDeviceRef device)
{listener->m_finder._removeToken(device);}
static void applyDevice(IOHIDDeviceRef device, CHIDListenerIOKit* listener)
{
auto preCheck = listener->m_finder.m_tokens.find(device);
if (preCheck != listener->m_finder.m_tokens.end())
return;
CFIndex vid, pid;
CFNumberGetValue((CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey)), kCFNumberCFIndexType, &vid);
CFNumberGetValue((CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey)), kCFNumberCFIndexType, &pid);
CFStringRef manuf = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDManufacturerKey));
CFStringRef product = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
listener->m_finder.m_tokens.insert(std::make_pair(device,
CDeviceToken(vid, pid,
CFStringGetCStringPtr(manuf, kCFStringEncodingUTF8),
CFStringGetCStringPtr(product, kCFStringEncodingUTF8),
device)));
}
public:
CHIDListenerIOKit(CDeviceFinder& finder)
: m_finder(finder)
{
/* Register HID Manager */
m_hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDManagerOptionNone);
IOHIDManagerSetDeviceMatching(m_hidManager, NULL);
IOHIDManagerRegisterDeviceMatchingCallback(m_hidManager, (IOHIDDeviceCallback)deviceConnected, this);
IOHIDManagerRegisterDeviceRemovalCallback(m_hidManager, (IOHIDDeviceCallback)deviceDisconnected, this);
IOHIDManagerScheduleWithRunLoop(m_hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
IOReturn ret = IOHIDManagerOpen(m_hidManager, kIOHIDManagerOptionNone);
if (ret != kIOReturnSuccess)
throw std::runtime_error("error establishing IOHIDManager");
/* Initial Device Add */
m_scanningEnabled = true;
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
m_scanningEnabled = false;
}
~CHIDListenerIOKit()
{
IOHIDManagerUnscheduleFromRunLoop(m_hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
IOHIDManagerClose(m_hidManager, kIOHIDManagerOptionNone);
CFRelease(m_hidManager);
}
/* Automatic device scanning */
bool startScanning()
{
m_scanningEnabled = true;
return true;
}
bool stopScanning()
{
m_scanningEnabled = false;
return true;
}
/* Manual device scanning */
bool scanNow()
{
CFSetRef devs = IOHIDManagerCopyDevices(m_hidManager);
m_finder.m_tokensLock.lock();
CFSetApplyFunction(devs, (CFSetApplierFunction)applyDevice, this);
m_finder.m_tokensLock.unlock();
CFRelease(devs);
return true;
}
};
IHIDListener* IHIDListenerNew(CDeviceFinder& finder)
{
return new CHIDListenerIOKit(finder);
}

View File

@ -1 +0,0 @@
#include "IHIDListener.hpp"

View File

@ -0,0 +1,21 @@
#include "inputdev/DeviceClasses.hpp"
#include "inputdev/CDeviceToken.hpp"
bool BooDeviceMatchToken(const CDeviceToken& token, EDeviceMask mask)
{
if (mask & DEV_DOL_SMASH_ADAPTER &&
token.getVendorId() == 0x57e && token.getProductId() == 0x337)
return true;
return false;
}
IHIDDevice* IHIDDeviceNew(CDeviceToken* token);
CDeviceBase* BooDeviceNew(CDeviceToken* token)
{
IHIDDevice* newDev = IHIDDeviceNew(token);
if (token->getVendorId() == 0x57e && token->getProductId() == 0x337)
return new CDolphinSmashAdapter(token, newDev);
return NULL;
}

View File

@ -1,9 +1,13 @@
#ifndef IHIDDEVICE_HPP
#define IHIDDEVICE_HPP
#include "inputdev/CDeviceToken.hpp"
class CDeviceBase;
class IHIDDevice
{
friend CDeviceBase;
virtual void deviceDisconnected()=0;
};
#endif // IHIDDEVICE_HPP

View File

@ -1,9 +1,27 @@
#ifndef IHIDLISTENER_HPP
#define IHIDLISTENER_HPP
#include <map>
#include <mutex>
#include "CDeviceToken.hpp"
typedef std::map<TDeviceHandle, CDeviceToken> TDeviceTokens;
class CDeviceFinder;
class IHIDListener
{
public:
virtual ~IHIDListener() {};
/* Automatic device scanning */
virtual bool startScanning()=0;
virtual bool stopScanning()=0;
/* Manual device scanning */
virtual bool scanNow()=0;
};
/* Platform-specific constructor */
IHIDListener* IHIDListenerNew(CDeviceFinder& finder);
#endif // IHIDLISTENER_HPP

View File

@ -1,15 +1,22 @@
#include <CoreFoundation/CoreFoundation.h>
#include <stdio.h>
#include <boo.hpp>
int main(int argc, char** argv)
{
CDeviceFinder finder(DEV_DOL_SMASH_ADAPTER);
CDeviceToken& smashToken = finder.getTokens().begin()->second;
CDolphinSmashAdapter* smashAdapter = dynamic_cast<CDolphinSmashAdapter*>(smashToken.openAndGetDevice());
IGraphicsContext* ctx = new CGraphicsContext;
if (ctx->create())
{
}
CFRunLoopRun();
delete ctx;
return 0;
}