Factor out HIDDevice.

This commit is contained in:
Steve Checkoway
2006-01-23 03:48:03 +00:00
parent 6e03ec1998
commit bab07ebf58
7 changed files with 786 additions and 713 deletions
@@ -0,0 +1,239 @@
#include "global.h"
#include "HIDDevice.h"
#include "RageUtil.h"
HIDDevice::HIDDevice() : m_Interface( NULL ), m_Queue( NULL ), m_bRunning( false )
{
}
HIDDevice::~HIDDevice()
{
if( m_Queue )
{
CFRunLoopSourceRef runLoopSource;
if( m_bRunning )
CALL( m_Queue, stop );
if( (runLoopSource = CALL(m_Queue, getAsyncEventSource)) )
{
mach_port_deallocate( mach_task_self(), CALL(m_Queue, getAsyncPort) );
CFRunLoopSourceInvalidate( runLoopSource );
CFRelease( runLoopSource );
}
CALL( m_Queue, dispose );
CALL( m_Queue, Release );
}
if( m_Interface )
{
CALL( m_Interface, close );
CALL( m_Interface, Release );
}
}
bool HIDDevice::Open( io_object_t device )
{
IOReturn ret;
CFMutableDictionaryRef properties;
kern_return_t result;
result = IORegistryEntryCreateCFProperties( device, &properties, kCFAllocatorDefault, kNilOptions );
if ( result != KERN_SUCCESS || !properties )
{
LOG->Warn( "Couldn't get properties." );
return false;
}
CFStringRef productRef = (CFStringRef)CFDictionaryGetValue( properties, CFSTR(kIOHIDProductKey) );
if( productRef )
{
m_sDescription = CFStringGetCStringPtr( productRef, CFStringGetSystemEncoding() );
}
else
{
CFTypeRef vidRef = (CFTypeRef)CFDictionaryGetValue( properties, CFSTR(kIOHIDVendorIDKey) );
CFTypeRef pidRef = (CFTypeRef)CFDictionaryGetValue( properties, CFSTR(kIOHIDProductIDKey) );
int vid, pid;
if( vidRef && !IntValue(vidRef, &vid) )
vid = 0;
if( pidRef && !IntValue(pidRef, &pid) )
pid = 0;
m_sDescription = ssprintf( "%04x:%04x", vid, pid );
}
CFArrayRef logicalDevices;
if ( !(logicalDevices = (CFArrayRef)CFDictionaryGetValue(properties, CFSTR(kIOHIDElementKey))) )
{
CFRelease( properties );
return false;
}
CFRange r = { 0, CFArrayGetCount(logicalDevices) };
CFArrayApplyFunction( logicalDevices, r, HIDDevice::AddLogicalDevice, this );
CFRelease( properties );
// Create the interface
IOCFPlugInInterface **plugInInterface;
HRESULT hresult;
SInt32 score;
ret = IOCreatePlugInInterfaceForService( device, kIOHIDDeviceUserClientTypeID,
kIOCFPlugInInterfaceID, &plugInInterface, &score );
if( ret != kIOReturnSuccess )
{
PrintIOErr( ret, "Failed to create plugin interface." );
return false;
}
// Call a method of the plugin to create the device interface
CFUUIDBytes bytes = CFUUIDGetUUIDBytes( kIOHIDDeviceInterfaceID );
hresult = CALL( plugInInterface, QueryInterface, bytes, (void **)&m_Interface );
CALL( plugInInterface, Release );
if( hresult != S_OK )
{
LOG->Warn( "Couldn't get device interface from plugin interface." );
m_Interface = NULL;
return false;
}
// open the interface
if( (ret = CALL(m_Interface, open, 0)) != kIOReturnSuccess )
{
PrintIOErr( ret, "Failed to open the interface." );
CALL( m_Interface, Release );
m_Interface = NULL;
return false;
}
// alloc/create queue
m_Queue = CALL( m_Interface, allocQueue );
if( !m_Queue )
{
LOG->Warn( "Couldn't allocate a queue." );
return false;
}
if( (ret = CALL(m_Queue, create, 0, 32)) != kIOReturnSuccess )
{
PrintIOErr( ret, "Failed to create the queue." );
CALL( m_Queue, Release );
m_Queue = NULL;
return false;
}
Open();
return true;
}
void HIDDevice::StartQueue( CFRunLoopRef loopRef, IOHIDCallbackFunction callback, void *target, int refCon )
{
CFRunLoopSourceRef runLoopSource;
// This creates a run loop source and a mach port. They are released in the dtor.
IOReturn ret = CALL( m_Queue, createAsyncEventSource, &runLoopSource );
if( ret != kIOReturnSuccess )
{
PrintIOErr( ret, "Failed to create async event source." );
return;
}
if( !CFRunLoopContainsSource(loopRef, runLoopSource, kCFRunLoopDefaultMode) )
CFRunLoopAddSource( loopRef, runLoopSource, kCFRunLoopDefaultMode );
CALL( m_Queue, setEventCallout, callback, target, (void *)refCon );
if( ret != kIOReturnSuccess )
{
PrintIOErr( ret, "Failed to set the call back." );
return;
}
// start the queue
ret = CALL( m_Queue, start );
if( ret != kIOReturnSuccess )
{
PrintIOErr( ret, "Failed to start the queue." );
return;
}
m_bRunning = true;
}
void HIDDevice::AddLogicalDevice( const void *value, void *context )
{
if( CFGetTypeID(CFTypeRef(value)) != CFDictionaryGetTypeID() )
return;
CFDictionaryRef dict = CFDictionaryRef( value );
HIDDevice *This = (HIDDevice *)context;
CFArrayRef elements;
CFTypeRef object;
int usage, usagePage;
CFTypeID numID = CFNumberGetTypeID();
// Get usage page
object = CFDictionaryGetValue( dict, CFSTR(kIOHIDElementUsagePageKey) );
if( !object || CFGetTypeID(object) != numID || !IntValue(object, &usagePage) )
return;
// Get usage
object = CFDictionaryGetValue( dict, CFSTR(kIOHIDElementUsageKey) );
if( !object || CFGetTypeID(object) != numID || !IntValue(object, &usage) )
return;
if( !(elements = (CFArrayRef)CFDictionaryGetValue( dict, CFSTR(kIOHIDElementKey))) )
return;
if( !This->AddLogicalDevice(usagePage, usage) )
return;
CFRange r = { 0, CFArrayGetCount(elements) };
CFArrayApplyFunction( elements, r, HIDDevice::AddElement, This );
}
void HIDDevice::AddElement( const void *value, void *context )
{
if( CFGetTypeID(CFTypeRef(value)) != CFDictionaryGetTypeID() )
return;
CFDictionaryRef dict = CFDictionaryRef( value );
HIDDevice *This = (HIDDevice *)context;
CFTypeRef object;
CFTypeID numID = CFNumberGetTypeID();
int cookie, usage, usagePage;
CFArrayRef elements;
// Recursively add elements
if( (elements = (CFArrayRef)CFDictionaryGetValue(dict, CFSTR(kIOHIDElementKey))) )
{
CFRange r = { 0, CFArrayGetCount(elements) };
CFArrayApplyFunction( elements, r, AddElement, context );
}
// Get usage page
object = CFDictionaryGetValue( dict, CFSTR(kIOHIDElementUsagePageKey) );
if( !object || CFGetTypeID(object) != numID || !IntValue(object, &usagePage) )
return;
// Get usage
object = CFDictionaryGetValue( dict, CFSTR(kIOHIDElementUsageKey) );
if( !object || CFGetTypeID(object) != numID || !IntValue(object, &usage) )
return;
// Get cookie
object = CFDictionaryGetValue( dict, CFSTR(kIOHIDElementCookieKey) );
if( !object || CFGetTypeID(object) != numID || !IntValue(object, &cookie) )
return;
This->AddElement( usagePage, usage, cookie, dict );
}
@@ -0,0 +1,86 @@
#ifndef HIDDEVICE_H
#define HIDDEVICE_H
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hid/IOHIDLib.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/hid/IOHIDUsageTables.h>
#include <IOKit/usb/USB.h>
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <vector>
#include <utility>
#include "RageLog.h"
#include "RageInputDevice.h"
/* A few helper functions. */
// The result needs to be released.
static inline CFNumberRef CFInt( int n )
{
return CFNumberCreate( kCFAllocatorDefault, kCFNumberIntType, &n );
}
static inline void PrintIOErr( IOReturn err, const char *s )
{
LOG->Warn( "%s - %s(%x,%d)", s, mach_error_string(err), err, err & 0xFFFFFF );
}
static inline Boolean IntValue( const void *o, int *n )
{
return CFNumberGetValue( CFNumberRef(o), kCFNumberIntType, n );
}
/*
* This is just awful, these aren't objects, treating them as such leads
* to: (*object)->function(object [, argument]...)
* Instead, do: CALL(object, function [, argument]...)
*/
#define CALL(o,f,...) (*(o))->f((o), ## __VA_ARGS__)
class HIDDevice
{
private:
IOHIDDeviceInterface **m_Interface;
IOHIDQueueInterface **m_Queue;
bool m_bRunning;
RString m_sDescription;
static void AddLogicalDevice( const void *value, void *context );
static void AddElement( const void *value, void *context );
protected:
virtual bool AddLogicalDevice( int usagePage, int usage ) = 0;
virtual void AddElement( int usagePage, int usage, int cookie, const CFDictionaryRef dict ) = 0;
virtual void Open() = 0;
inline void AddElementToQueue( int cookie )
{
CALL( m_Queue, addElement, IOHIDElementCookie(cookie), 0 );
}
public:
HIDDevice();
virtual ~HIDDevice();
bool Open( io_object_t device );
void StartQueue( CFRunLoopRef loopRef, IOHIDCallbackFunction callback, void *target, int refCon );
inline const RString& GetDescription() const { return m_sDescription; }
virtual void GetButtonPresses( vector<pair<DeviceInput, bool> >& vPresses, int cookie,
int value, const RageTimer& now ) const = 0;
/*
* Returns the number of IDs assigned starting from startID. This is not meaningful for devices like
* keyboards that all share the same InputDevice id.
*/
virtual int AssignIDs( InputDevice startID ) { return 0; }
virtual void GetDevicesAndDescriptions( vector<InputDevice>& dev, vector<RString>& desc ) const = 0;
};
#endif
@@ -0,0 +1,184 @@
#include "global.h"
#include "JoystickDevice.h"
#include "Foreach.h"
#include "EnumHelper.h"
#include "RageUtil.h"
using namespace std;
using __gnu_cxx::hash_map;
Joystick::Joystick() : id( DEVICE_NONE ),
x_axis( DeviceButton_Invalid ),
y_axis( DeviceButton_Invalid ),
z_axis( DeviceButton_Invalid ),
x_min( 0 ), y_min( 0 ), z_min( 0 ),
x_max( 0 ), y_max( 0 ), z_max( 0 )
{
}
bool JoystickDevice::AddLogicalDevice( int usagePage, int usage )
{
if( usagePage != kHIDPage_GenericDesktop || usage != kHIDUsage_GD_Joystick )
return false;
m_vSticks.push_back( Joystick() );
return true;
}
void JoystickDevice::AddElement( int usagePage, int usage, int cookie, const CFDictionaryRef dict )
{
CFTypeRef object;
CFTypeID numID = CFNumberGetTypeID();
Joystick& js = m_vSticks.back();
switch( usagePage )
{
case kHIDPage_GenericDesktop:
{
int min = 0;
int max = 0;
object = CFDictionaryGetValue( dict, CFSTR(kIOHIDElementMinKey) );
if( object && CFGetTypeID(object) == numID )
IntValue( object, &min );
object = CFDictionaryGetValue( dict, CFSTR(kIOHIDElementMaxKey) );
if( object && CFGetTypeID(object) == numID )
IntValue( object, &max );
switch( usage )
{
case kHIDUsage_GD_X:
js.x_axis = cookie;
js.x_min = min;
js.x_max = max;
break;
case kHIDUsage_GD_Y:
js.y_axis = cookie;
js.y_min = min;
js.y_max = max;
break;
case kHIDUsage_GD_Z:
js.z_axis = cookie;
js.z_min = min;
js.z_max = max;
break;
case kHIDUsage_GD_DPadUp:
js.mapping[cookie] = JOY_UP;
break;
case kHIDUsage_GD_DPadDown:
js.mapping[cookie] = JOY_DOWN;
break;
case kHIDUsage_GD_DPadRight:
js.mapping[cookie] = JOY_RIGHT;
break;
case kHIDUsage_GD_DPadLeft:
js.mapping[cookie] = JOY_LEFT;
break;
default:
return;
}
break;
}
case kHIDPage_Button:
{
// button n has usage = n, subtract 1 to ensure
// button 1 = JOY_BUTTON_1
const DeviceButton buttonID = enum_add2( JOY_BUTTON_1, usage - 1 );
if( buttonID <= JOY_BUTTON_32 )
js.mapping[cookie] = buttonID;
break;
}
default:
return;
} // end switch (usagePage)
}
void JoystickDevice::Open()
{
// Add elements to the queue for each Joystick
FOREACH_CONST( Joystick, m_vSticks, i )
{
const Joystick& js = *i;
if( js.x_axis )
AddElementToQueue( js.x_axis );
if( js.y_axis )
AddElementToQueue( js.y_axis );
if( js.z_axis )
AddElementToQueue( js.z_axis );
for( hash_map<int,DeviceButton>::const_iterator j = js.mapping.begin(); j != js.mapping.end(); ++j )
AddElementToQueue( j->first );
}
}
void JoystickDevice::GetButtonPresses( vector<pair<DeviceInput, bool> >& vPresses, int cookie,
int value, const RageTimer& now ) const
{
typedef pair<DeviceInput, bool> dib;
FOREACH_CONST( Joystick, m_vSticks, i )
{
const Joystick& js = *i;
if( js.x_axis == cookie )
{
float level = SCALE( value, js.x_min, js.x_max, -1.0f, 1.0f );
vPresses.push_back( dib(DeviceInput(js.id, JOY_LEFT, max(-level, 0.0f), now), level < -0.5f) );
vPresses.push_back( dib(DeviceInput(js.id, JOY_RIGHT, max(level, 0.0f), now), level > 0.5f) );
break;
}
else if( js.y_axis == cookie )
{
float level = SCALE( value, js.y_min, js.y_max, -1.0f, 1.0f );
vPresses.push_back( dib(DeviceInput(js.id, JOY_UP, max(-level, 0.0f), now), level < -0.5f) );
vPresses.push_back( dib(DeviceInput(js.id, JOY_DOWN, max(level, 0.0f), now), level > 0.5f) );
break;
}
else if( js.z_axis == cookie )
{
float level = SCALE( value, js.z_min, js.z_max, -1.0f, 1.0f );
vPresses.push_back( dib(DeviceInput(js.id, JOY_Z_UP, max(-level, 0.0f), now), level < -0.5f) );
vPresses.push_back( dib(DeviceInput(js.id, JOY_Z_DOWN, max(level, 0.0f), now), level > 0.5f) );
break;
}
else
{
// hash_map<T,U>::operator[] is not const
hash_map<int, DeviceButton>::const_iterator iter;
iter = js.mapping.find( cookie );
if( iter != js.mapping.end() )
{
vPresses.push_back( dib(DeviceInput(js.id, iter->second, value, now), value) );
break;
}
}
}
}
int JoystickDevice::AssignIDs( InputDevice startID )
{
FOREACH( Joystick, m_vSticks, i )
{
i->id = InputDevice( startID );
enum_add( startID, 1 );
}
return m_vSticks.size();
}
void JoystickDevice::GetDevicesAndDescriptions( vector<InputDevice>& dev, vector<RString>& desc ) const
{
FOREACH_CONST( Joystick, m_vSticks, i )
{
dev.push_back( i->id );
desc.push_back( GetDescription() );
}
}
@@ -0,0 +1,37 @@
#ifndef JOYSTICK_DEVICE_H
#define JOYSTICK_DEVICE_H
#include "HIDDevice.h"
#include <ext/hash_map>
struct Joystick
{
InputDevice id;
// map cookie to button
__gnu_cxx::hash_map<int, DeviceButton> mapping;
int x_axis, y_axis, z_axis;
int x_min, y_min, z_min;
int x_max, y_max, z_max;
Joystick();
};
class JoystickDevice : public HIDDevice
{
private:
vector<Joystick> m_vSticks;
protected:
bool AddLogicalDevice( int usagePage, int usage );
void AddElement( int usagePage, int usage, int cookie, const CFDictionaryRef dict );
void Open();
public:
void GetButtonPresses( vector<pair<DeviceInput, bool> >& vPresses, int cookie,
int value, const RageTimer& now ) const;
int AssignIDs( InputDevice startID );
void GetDevicesAndDescriptions( vector<InputDevice>& dev, vector<RString>& desc ) const;
};
#endif
@@ -0,0 +1,176 @@
#include "global.h"
#include "KeyboardDevice.h"
using namespace __gnu_cxx;
bool KeyboardDevice::AddLogicalDevice( int usagePage, int usage )
{
return usagePage == kHIDPage_GenericDesktop && usage == kHIDUsage_GD_Keyboard;
}
void KeyboardDevice::AddElement( int usagePage, int usage, int cookie, const CFDictionaryRef dict )
{
if( usagePage != kHIDPage_KeyboardOrKeypad )
return;
if( usage < kHIDUsage_KeyboardA )
return;
if( usage <= kHIDUsage_KeyboardZ )
{
m_Mapping[cookie] = enum_add2( KEY_Ca, usage - kHIDUsage_KeyboardA );
return;
}
// KEY_C0 = KEY_C1 - 1, kHIDUsage_Keyboard0 = kHIDUsage_Keyboard9 + 1
if( usage <= kHIDUsage_Keyboard9 )
{
m_Mapping[cookie] = enum_add2( KEY_C1, usage - kHIDUsage_Keyboard1 );
return;
}
if( usage >= kHIDUsage_KeyboardF1 && usage <= kHIDUsage_KeyboardF12 )
{
m_Mapping[cookie] = enum_add2( KEY_F1, usage - kHIDUsage_KeyboardF1 );
return;
}
if( usage >= kHIDUsage_KeyboardF13 && usage <= kHIDUsage_KeyboardF16 )
{
m_Mapping[cookie] = enum_add2( KEY_F13, usage - kHIDUsage_KeyboardF13 );
return;
}
// keypad 0 is again backward
if( usage >= kHIDUsage_Keypad1 && usage <= kHIDUsage_Keypad9 )
{
m_Mapping[cookie] = enum_add2( KEY_KP_C1, usage - kHIDUsage_Keypad1 );
return;
}
#define OTHER(n) (enum_add2(KEY_OTHER_0, (n)))
// [0, 8]
if( usage >= kHIDUsage_KeyboardF17 && usage <= kHIDUsage_KeyboardExecute )
{
m_Mapping[cookie] = OTHER( 0 + usage - kHIDUsage_KeyboardF17 );
return;
}
// [9, 19]
if( usage >= kHIDUsage_KeyboardSelect && usage <= kHIDUsage_KeyboardVolumeDown )
{
m_Mapping[cookie] = OTHER( 9 + usage - kHIDUsage_KeyboardSelect );
return;
}
// [20, 31]
if( usage >= kHIDUsage_KeypadEqualSignAS400 && usage <= kHIDUsage_KeyboardCancel )
{
m_Mapping[cookie] = OTHER( 20 + usage - kHIDUsage_KeypadEqualSignAS400 );
return;
}
// [32, 37]
// XXX kHIDUsage_KeyboardClearOrAgain
if( usage >= kHIDUsage_KeyboardSeparator && usage <= kHIDUsage_KeyboardExSel )
{
m_Mapping[cookie] = OTHER( 32 + usage - kHIDUsage_KeyboardSeparator );
return;
}
#define X(x,y) case x: m_Mapping[cookie] = y; return
// Time for the special cases
switch( usage )
{
X( kHIDUsage_Keyboard0, KEY_C0 );
X( kHIDUsage_Keypad0, KEY_KP_C0 );
X( kHIDUsage_KeyboardReturnOrEnter, KEY_ENTER );
X( kHIDUsage_KeyboardEscape, KEY_ESC );
X( kHIDUsage_KeyboardDeleteOrBackspace, KEY_BACK );
X( kHIDUsage_KeyboardTab, KEY_TAB );
X( kHIDUsage_KeyboardSpacebar, KEY_SPACE );
X( kHIDUsage_KeyboardHyphen, KEY_HYPHEN );
X( kHIDUsage_KeyboardEqualSign, KEY_EQUAL );
X( kHIDUsage_KeyboardOpenBracket, KEY_LBRACKET );
X( kHIDUsage_KeyboardCloseBracket, KEY_RBRACKET );
X( kHIDUsage_KeyboardBackslash, KEY_BACKSLASH );
X( kHIDUsage_KeyboardNonUSPound, KEY_HASH );
X( kHIDUsage_KeyboardSemicolon, KEY_SEMICOLON );
X( kHIDUsage_KeyboardQuote, KEY_SQUOTE );
X( kHIDUsage_KeyboardGraveAccentAndTilde, KEY_ACCENT );
X( kHIDUsage_KeyboardComma, KEY_COMMA );
X( kHIDUsage_KeyboardPeriod, KEY_PERIOD );
X( kHIDUsage_KeyboardSlash, KEY_SLASH );
X( kHIDUsage_KeyboardCapsLock, KEY_CAPSLOCK );
X( kHIDUsage_KeyboardPrintScreen, KEY_PRTSC );
X( kHIDUsage_KeyboardScrollLock, KEY_SCRLLOCK );
X( kHIDUsage_KeyboardPause, OTHER(38) );
X( kHIDUsage_KeyboardInsert, KEY_INSERT );
X( kHIDUsage_KeyboardHome, KEY_HOME );
X( kHIDUsage_KeyboardPageUp, KEY_PGUP );
X( kHIDUsage_KeyboardDeleteForward, KEY_DEL );
X( kHIDUsage_KeyboardEnd, KEY_END );
X( kHIDUsage_KeyboardPageDown, KEY_PGDN );
X( kHIDUsage_KeyboardRightArrow, KEY_RIGHT );
X( kHIDUsage_KeyboardLeftArrow, KEY_LEFT );
X( kHIDUsage_KeyboardDownArrow, KEY_DOWN );
X( kHIDUsage_KeyboardUpArrow, KEY_UP );
X( kHIDUsage_KeypadNumLock, KEY_NUMLOCK );
X( kHIDUsage_KeypadSlash, KEY_KP_SLASH );
X( kHIDUsage_KeypadEqualSign, KEY_KP_EQUAL );
X( kHIDUsage_KeypadAsterisk, KEY_KP_ASTERISK );
X( kHIDUsage_KeypadHyphen, KEY_KP_HYPHEN );
X( kHIDUsage_KeypadPlus, KEY_KP_PLUS );
X( kHIDUsage_KeypadEnter, KEY_KP_ENTER );
X( kHIDUsage_KeypadPeriod, KEY_KP_PERIOD );
X( kHIDUsage_KeyboardNonUSBackslash, OTHER(39) );
X( kHIDUsage_KeyboardApplication, OTHER(40) );
X( kHIDUsage_KeyboardClear, KEY_NUMLOCK ); // XXX
X( kHIDUsage_KeyboardHelp, KEY_INSERT );
X( kHIDUsage_KeyboardMenu, KEY_MENU );
// XXX kHIDUsage_KeyboardLockingCapsLock
// XXX kHIDUsage_KeyboardLockingNumLock
// XXX kHIDUsage_KeyboardLockingScrollLock
X( kHIDUsage_KeypadComma, KEY_KP_PERIOD ); // XXX
X( kHIDUsage_KeyboardReturn, KEY_ENTER );
X( kHIDUsage_KeyboardPrior, OTHER(41) );
X( kHIDUsage_KeyboardLeftControl, KEY_LCTRL );
X( kHIDUsage_KeyboardLeftShift, KEY_LSHIFT );
X( kHIDUsage_KeyboardLeftAlt, KEY_LALT );
X( kHIDUsage_KeyboardLeftGUI, KEY_LMETA );
X( kHIDUsage_KeyboardRightControl, KEY_RCTRL );
X( kHIDUsage_KeyboardRightShift, KEY_RSHIFT );
X( kHIDUsage_KeyboardRightAlt, KEY_RALT );
X( kHIDUsage_KeyboardRightGUI, KEY_RMETA );
}
#undef X
#undef OTHER
}
void KeyboardDevice::Open()
{
for( hash_map<int,DeviceButton>::const_iterator i = m_Mapping.begin(); i != m_Mapping.end(); ++i )
AddElementToQueue( i->first );
}
void KeyboardDevice::GetButtonPresses( vector<pair<DeviceInput, bool> >& vPresses, int cookie,
int value, const RageTimer& now ) const
{
hash_map<int, DeviceButton>::const_iterator iter = m_Mapping.find( cookie );
if( iter != m_Mapping.end() )
vPresses.push_back( pair<DeviceInput, bool>(DeviceInput(DEVICE_KEYBOARD, iter->second, value, now), value) );
}
void KeyboardDevice::GetDevicesAndDescriptions( vector<InputDevice>& dev, vector<RString>& desc ) const
{
if( dev.size() && dev[0] == DEVICE_KEYBOARD )
return;
dev.insert( dev.begin(), DEVICE_KEYBOARD );
desc.insert( desc.begin(), "Keyboard" );
}
@@ -0,0 +1,24 @@
#ifndef KEYBOARD_DEVICE_H
#define KEYBOARD_DEVICE_H
#include "HIDDevice.h"
#include <ext/hash_map>
class KeyboardDevice : public HIDDevice
{
private:
__gnu_cxx::hash_map<int, DeviceButton> m_Mapping;
protected:
bool AddLogicalDevice( int usagePage, int usage );
void AddElement( int usagePage, int usage, int cookie, const CFDictionaryRef dict );
void Open();
public:
void GetButtonPresses( vector<pair<DeviceInput, bool> >& vPresses, int cookie,
int value, const RageTimer& now ) const;
void GetDevicesAndDescriptions( vector<InputDevice>& dev, vector<RString>& desc ) const;
};
#endif