1
0
Fork 0

Tatsuhiro Nishioka:

Fixed: wrong event name for abs-hat0-y
Modified: let AxisElement to generate normalized input (-1.0 to 1.0).
                  This can be temporal and can be removed when AxisEvent normalizes its value.
Modified: clean up code
Added: some comments so other Mac developers can see what's going on
This commit is contained in:
torsten 2009-09-03 08:45:43 +00:00 committed by Tim Moore
parent 80a6317ab6
commit a26ca9f3e3
2 changed files with 136 additions and 111 deletions

View file

@ -93,6 +93,10 @@ struct HIDTypes HID_PAGE_TABLE[] = {
#define CON_USAGE(USAGE) USAGE_KEY(kHIDPage_Consumer, USAGE) #define CON_USAGE(USAGE) USAGE_KEY(kHIDPage_Consumer, USAGE)
// HID Element Usage <-> FGEventData convertion data // HID Element Usage <-> FGEventData convertion data
// See http://www.usb.org/developers/devclass_docs/Hut1_12.pdf for detail on HID pages and usages
// Note
// kHIDUsageAxis is FG specific type of DV since it is needed to be normalized into -1.0 to 1.0
// kHIDUsageHat also is FG specific type of DV. it's value is converted into two axis events
struct HIDTypes HID_USAGE_TABLE[] = { struct HIDTypes HID_USAGE_TABLE[] = {
// Generic Desktop Page // Generic Desktop Page
{GD_USAGE(kHIDUsage_GD_X), kHIDUsageAxis, "x-translate"}, {GD_USAGE(kHIDUsage_GD_X), kHIDUsageAxis, "x-translate"},
@ -306,7 +310,7 @@ HIDElement::HIDElement(CFDictionaryRef element, long page, long usage) :
name = hidUsageByID.getName(USAGE_KEY(page, usage)); name = hidUsageByID.getName(USAGE_KEY(page, usage));
} }
float HIDElement::readStatus(IOHIDDeviceInterface **interface) long HIDElement::read(IOHIDDeviceInterface **interface)
{ {
IOHIDEventStruct event; IOHIDEventStruct event;
lastValue = value; lastValue = value;
@ -314,10 +318,10 @@ float HIDElement::readStatus(IOHIDDeviceInterface **interface)
if (ret == kIOReturnSuccess) { if (ret == kIOReturnSuccess) {
value = event.value; value = event.value;
// SG_LOG(SG_INPUT, SG_BULK, "Element: " << name << "; value = " << value); // SG_LOG(SG_INPUT, SG_BULK, "Element: " << name << "; value = " << value);
return (float)event.value; return event.value;
} else { } else {
SG_LOG(SG_INPUT, SG_ALERT, "Failed reading value for HID Element: " << name); SG_LOG(SG_INPUT, SG_WARN, "Failed reading value for HID Element: " << name);
return 0.0; return 0;
} }
} }
@ -329,45 +333,49 @@ bool HIDElement::isUpdated()
void HIDElement::generateEvent(FGMacOSXInputDevice *device, double dt, int modifiers) void HIDElement::generateEvent(FGMacOSXInputDevice *device, double dt, int modifiers)
{ {
SG_LOG(SG_INPUT, SG_DEBUG, "Generating Input Event: " << name << "=" << value); SG_LOG(SG_INPUT, SG_DEBUG, "Generating Input Event: " << name << "=" << value);
FGMacOSXEventData eventData(name, value, dt, modifiers); FGMacOSXEventData eventData(name, (float)value, dt, modifiers);
device->HandleEvent(eventData); device->HandleEvent(eventData);
} }
AxisElement::AxisElement(CFDictionaryRef element, long page, long usage) : AxisElement::AxisElement(CFDictionaryRef element, long page, long usage) :
HIDElement(element, page, usage), dead_band(0.00), saturate(1.0) HIDElement(element, page, usage), dead_band(0.00), saturate(1.0)
{ {
// long scaledmin, scaledmax;
min = GetHIDElementLongValue(element, kIOHIDElementMinKey); min = GetHIDElementLongValue(element, kIOHIDElementMinKey);
max = GetHIDElementLongValue(element, kIOHIDElementMaxKey); max = GetHIDElementLongValue(element, kIOHIDElementMaxKey);
isRelative = GetHIDElementBooleanValue(element, kIOHIDElementIsRelativeKey); isRelative = GetHIDElementBooleanValue(element, kIOHIDElementIsRelativeKey);
isWrapping = GetHIDElementBooleanValue(element, kIOHIDElementIsWrappingKey); isWrapping = GetHIDElementBooleanValue(element, kIOHIDElementIsWrappingKey);
isNonLinear = GetHIDElementBooleanValue(element, kIOHIDElementIsNonLinearKey); isNonLinear = GetHIDElementBooleanValue(element, kIOHIDElementIsNonLinearKey);
cout << "isRelative=" << isRelative << ", isWrapping=" << isWrapping << ", isNonLinear=" << isNonLinear << endl;
name = ((isRelative == true) ? "rel-" : "abs-") + name; name = ((isRelative == true) ? "rel-" : "abs-") + name;
center = min + (max - min) / 2; center = min + (max - abs(min)) * 0.5;
SG_LOG(SG_INPUT, SG_DEBUG, "HID Axis Element; " << name << " min: " << min << " max:" << max << " center: " << center); SG_LOG(SG_INPUT, SG_DEBUG, "HID Axis Element; " << name << " min: " << min << " max:" << max << " center: " << center);
SG_LOG(SG_INPUT, SG_DEBUG, "isRelative=" << isRelative << ", isWrapping=" << isWrapping << ", isNonLinear=" << isNonLinear);
} }
float AxisElement::readStatus(IOHIDDeviceInterface **interface) long AxisElement::read(IOHIDDeviceInterface **interface)
{ {
lastValue = value; lastValue = value;
value = HIDElement::readStatus(interface); return HIDElement::read(interface);
return value;
/*
if (!isRelative) {
value = (value - (float)center) / (float)(max - center);
if (fabs(value) < dead_band)
value = 0.0;
}
*/
} }
// FIXME: This can be removed when AxisInputEvent can normalize its value
void AxisElement::generateEvent(FGMacOSXInputDevice *device, double dt, int modifiers)
{
float normalizedValue = (float)value;
if (!isRelative) {
normalizedValue = (value - (float)center) / (float)(max - center);
if (fabs(normalizedValue) < dead_band)
normalizedValue = 0.0;
}
SG_LOG(SG_INPUT, SG_DEBUG, "Generating Input Event: " << name << "=" << normalizedValue);
FGMacOSXEventData eventData(name, normalizedValue, dt, modifiers);
device->HandleEvent(eventData);
}
ButtonElement::ButtonElement(CFDictionaryRef element, long page, long usage) : ButtonElement::ButtonElement(CFDictionaryRef element, long page, long usage) :
HIDElement(element, page, usage) HIDElement(element, page, usage)
{ {
if (name == "") { if (name == "") {
stringstream ss; stringstream ss;
@ -386,20 +394,18 @@ HatElement::HatElement(CFDictionaryRef element, long page, long usage, int id) :
void HatElement::generateEvent(FGMacOSXInputDevice *device, double dt, int modifiers) void HatElement::generateEvent(FGMacOSXInputDevice *device, double dt, int modifiers)
{ {
// Hat Value is from 0 to 8, representing: // Hat value is from 0 to 8, representing:
// 0:N, 1:NE, 2:E, 3:SE, 4:S, 5:SW, 6:W, 7:NW, 8:N // 0:N, 1:NE, 2:E, 3:SE, 4:S, 5:SW, 6:W, 7:NW, 8:Neutral
// FG can't bind hat directly, so need to convert its value to two axis events
static float xvalues[] = {0, 1, 1, 1, 0, -1, -1, -1, 0}; static float xvalues[] = {0, 1, 1, 1, 0, -1, -1, -1, 0};
static float yvalues[] = {1, 1, 0, -1, -1, -1, 0, 1, 0}; static float yvalues[] = {1, 1, 0, -1, -1, -1, 0, 1, 0};
stringstream ss; stringstream ss1, ss2;
string eventName; ss1 << "abs-hat" << id << "-x";
ss << "abs-hat" << id << "-x"; SG_LOG(SG_INPUT, SG_BULK, "Generating Input Event: " << ss1.str() << "=" << xvalues[(int)value]);
ss >> eventName; FGMacOSXEventData eventDataX(ss1.str(), xvalues[(int)value], dt, modifiers);
SG_LOG(SG_INPUT, SG_BULK, "Generating Input Event: " << eventName << "=" << xvalues[(int)value]); ss2 << "abs-hat" << id << "-y";
FGMacOSXEventData eventDataX(eventName, xvalues[(int)value], dt, modifiers); SG_LOG(SG_INPUT, SG_BULK, "Generating Input Event: " << ss2.str() << "=" << yvalues[(int)value]);
ss << "abs-hat" << id << "-y"; FGMacOSXEventData eventDataY(ss2.str(), yvalues[(int)value], dt, modifiers);
ss >> eventName;
SG_LOG(SG_INPUT, SG_BULK, "Generating Input Event: " << eventName << "=" << yvalues[(int)value]);
FGMacOSXEventData eventDataY(eventName, yvalues[(int)value], dt, modifiers);
device->HandleEvent((FGEventData &)eventDataX); device->HandleEvent((FGEventData &)eventDataX);
device->HandleEvent((FGEventData &)eventDataY); device->HandleEvent((FGEventData &)eventDataY);
} }
@ -436,17 +442,16 @@ FeatureElement::FeatureElement(CFDictionaryRef element, long page, long usage, i
} }
} }
float FeatureElement::readStatus(IOHIDDeviceInterface **interface) { long FeatureElement::read(IOHIDDeviceInterface **interface) {
IOHIDEventStruct event; IOHIDEventStruct event;
IOReturn ret = (*interface)->queryElementValue(interface, cookie, &event, 0, NULL, NULL, NULL); IOReturn ret = (*interface)->queryElementValue(interface, cookie, &event, 0, NULL, NULL, NULL);
if (ret != kIOReturnSuccess) { if (ret != kIOReturnSuccess) {
ret = (*interface)->getElementValue(interface, cookie, &event); ret = (*interface)->getElementValue(interface, cookie, &event);
if (ret != kIOReturnSuccess) { if (ret != kIOReturnSuccess) {
SG_LOG(SG_INPUT, SG_ALERT, "Can't get element value for feature element: " << getName()); SG_LOG(SG_INPUT, SG_WARN, "Can't get element value for feature element: " << getName());
return 0.0; return 0;
} }
} }
cout << getName() << "=" << event.value << endl;
return event.value; return event.value;
} }
@ -481,9 +486,9 @@ void HIDElementFactory::parseElement(CFDictionaryRef element, FGMacOSXInputDevic
if (type == kIOHIDElementTypeCollection) { if (type == kIOHIDElementTypeCollection) {
id = 0; id = 0;
cout << "Collection: " << hidTypeByID.getName(type) << "(" << type << ")" SG_LOG(SG_INPUT, SG_DEBUG, "Collection: " << hidTypeByID.getName(type) << "(" << type << ")"
<<":" << hidPageByID.getName(page) << "(" << page << ")" << ":" << hidPageByID.getName(page) << "(" << page << ")"
<< ":" << hidUsageByID.getName(USAGE_KEY(page, usage)) << "(" << usage << ")" << endl; << ":" << hidUsageByID.getName(USAGE_KEY(page, usage)) << "(" << usage << ")");
HIDElementFactory::create(CFDictionaryGetValue(element, CFSTR(kIOHIDElementKey)), inputDevice); HIDElementFactory::create(CFDictionaryGetValue(element, CFSTR(kIOHIDElementKey)), inputDevice);
} else { } else {
HIDUsageType usageType = hidUsageByID.getType(USAGE_KEY(page, usage)); HIDUsageType usageType = hidUsageByID.getType(USAGE_KEY(page, usage));
@ -516,14 +521,15 @@ void HIDElementFactory::parseElement(CFDictionaryRef element, FGMacOSXInputDevic
inputDevice->addElement(new ButtonElement(element, page, usage)); inputDevice->addElement(new ButtonElement(element, page, usage));
} else if (page == kHIDPage_LEDs && usage > 0) { } else if (page == kHIDPage_LEDs && usage > 0) {
inputDevice->addElement(new LEDElement(element, page, usage)); inputDevice->addElement(new LEDElement(element, page, usage));
/* /* Feature elements are not fully tested yet
} else if (type == kIOHIDElementTypeFeature) { } else if (type == kIOHIDElementTypeFeature) {
// just for testing feature elements // just for testing feature elements
inputDevice->addElement(new FeatureElement(element, page, usage, elementCount[inputDevice][USAGE_KEY(page, usage)])); inputDevice->addElement(new FeatureElement(element, page, usage, elementCount[inputDevice][USAGE_KEY(page, usage)]));
*/ */
} else { } else {
cout << "HID Element Page/Usage is not supported: type=" << hidTypeByID.getName(type) << "(" << type << ")" SG_LOG(SG_INPUT, SG_INFO, "HID Element Page/Usage is not supported: type=" << hidTypeByID.getName(type)
<< ", page=" << hidPageByID.getName(page) << "(" << page << ")" << ", usage=" << usage << endl; << "(" << type << ")" << ", page=" << hidPageByID.getName(page) << "(" << page << ")"
<< ", usage=" << usage);
} }
} }
} }
@ -552,13 +558,16 @@ const char *FGMacOSXInputDevice::TranslateEventName(FGEventData &eventData)
} }
//
// Outputs value to an writable element (like LEDElement)
//
void FGMacOSXInputDevice::Send(const char *eventName, double value) void FGMacOSXInputDevice::Send(const char *eventName, double value)
{ {
HIDElement *element = elements[eventName]; HIDElement *element = elements[eventName];
if (element) { if (element) {
element->write(devInterface, value); element->write(devInterface, value);
} else { } else {
cout << "No element to handle event: " << eventName << endl; SG_LOG(SG_INPUT, SG_WARN, "No element to handle event: " << eventName);
} }
} }
@ -577,7 +586,11 @@ CFDictionaryRef FGMacOSXInputDevice::getProperties(io_object_t device)
return properties; return properties;
} }
//
// Adds HID element to FGMacOSXInputDevice.
// On Mac OS X, update() will read value of each HID element.
// Thus, FGMacOSXInputDevice needs all supported elements when a device is opened
//
void FGMacOSXInputDevice::addElement(HIDElement *element) void FGMacOSXInputDevice::addElement(HIDElement *element)
{ {
elements[element->getName()] = element; elements[element->getName()] = element;
@ -608,7 +621,7 @@ void FGMacOSXInputDevice::Open() {
(LPVOID*)&devInterface ); (LPVOID*)&devInterface );
if (result != S_OK) if (result != S_OK)
SG_LOG(SG_INPUT, SG_ALERT, "Failed Querying HID plugin interface: " << GetName()); SG_LOG(SG_INPUT, SG_WARN, "Failed Querying HID plugin interface: " << GetName());
(*plugin)->Release(plugin); // don't leak a ref (*plugin)->Release(plugin); // don't leak a ref
if (devInterface == NULL) { if (devInterface == NULL) {
@ -625,9 +638,8 @@ void FGMacOSXInputDevice::Open() {
} }
CFDictionaryRef props = getProperties(); CFDictionaryRef props = getProperties();
// recursively enumerate all the bits (buttons, axes, hats, ...) // recursively adds all supported HID elements to FGMacOSXInputDevice
CFTypeRef topLevelElement = CFTypeRef topLevelElement = CFDictionaryGetValue (props, CFSTR(kIOHIDElementKey));
CFDictionaryGetValue (props, CFSTR(kIOHIDElementKey));
HIDElementFactory::create(topLevelElement, this); HIDElementFactory::create(topLevelElement, this);
CFRelease(props); CFRelease(props);
} }
@ -646,12 +658,15 @@ void FGMacOSXInputDevice::Close() {
elements.clear(); elements.clear();
} }
//
// Reads values of assigned HIDElement and generates events
//
void FGMacOSXInputDevice::update(double dt) void FGMacOSXInputDevice::update(double dt)
{ {
map<string, HIDElement *>::iterator it; map<string, HIDElement *>::iterator it;
for (it = elements.begin(); it != elements.end(); it++) { for (it = elements.begin(); it != elements.end(); it++) {
(*it).second->readStatus(devInterface); (*it).second->read(devInterface);
if ((*it).second->isUpdated()) { if ((*it).second->isUpdated()) { // Is this needed?
int modifiers = fgGetKeyModifiers(); int modifiers = fgGetKeyModifiers();
(*it).second->generateEvent(this, dt, modifiers); (*it).second->generateEvent(this, dt, modifiers);
} }
@ -661,25 +676,7 @@ void FGMacOSXInputDevice::update(double dt)
// //
// FGMacOSXEventInput implementation // FGMacOSXEventInput implementation
// //
FGMacOSXEventInput *FGMacOSXEventInput::_instance=NULL;
FGMacOSXEventInput &FGMacOSXEventInput::instance()
{
if (!FGMacOSXEventInput::_instance) {
SG_LOG(SG_INPUT, SG_ALERT, "FGMacOSXEventInput is not created but its instance is referred.");
}
return *FGMacOSXEventInput::_instance;
}
FGMacOSXEventInput::~FGMacOSXEventInput() { FGMacOSXEventInput::~FGMacOSXEventInput() {
/*
// inputDevice will be deleted in FGEventInput
map<io_object_t, FGMacOSXInputDevice *>::iterator deviceIterator;
for (deviceIterator = inputDevices.begin(); deviceIterator != inputDevices.end(); deviceIterator++) {
FGMacOSXInputDevice *inputDevice = (*deviceIterator).second;
// inputDevice->Close();
// delete inputDevice;
}
*/
deviceIndices.clear(); deviceIndices.clear();
} }
@ -695,17 +692,18 @@ void FGMacOSXEventInput::init()
matchingDictionary = (CFMutableDictionaryRef) CFRetain(matchingDictionary); matchingDictionary = (CFMutableDictionaryRef) CFRetain(matchingDictionary);
matchingDictionary = (CFMutableDictionaryRef) CFRetain(matchingDictionary); matchingDictionary = (CFMutableDictionaryRef) CFRetain(matchingDictionary);
// Registers Hotplug notification for plug and play.
notifyPort = IONotificationPortCreate(kIOMasterPortDefault); notifyPort = IONotificationPortCreate(kIOMasterPortDefault);
runLoopSource = IONotificationPortGetRunLoopSource(notifyPort); runLoopSource = IONotificationPortGetRunLoopSource(notifyPort);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode); CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
ret = IOServiceAddMatchingNotification(notifyPort, kIOFirstMatchNotification, ret = IOServiceAddMatchingNotification(notifyPort, kIOFirstMatchNotification,
matchingDictionary, FGMacOSXEventInput::deviceAttached, this, &addedIterator); matchingDictionary, FGMacOSXEventInput::deviceAttached, (void *)this, &addedIterator);
ret = IOServiceAddMatchingNotification(notifyPort, kIOTerminatedNotification, ret = IOServiceAddMatchingNotification(notifyPort, kIOTerminatedNotification,
matchingDictionary, FGMacOSXEventInput::deviceDetached, this, &removedIterator); matchingDictionary, FGMacOSXEventInput::deviceDetached, (void *)this, &removedIterator);
// prepare for notification by calling these callback funcs to remove existing HID device iterators // prepare for notification by calling these callback funcs to remove existing HID device iterators
FGMacOSXEventInput::deviceAttached(NULL, addedIterator); FGMacOSXEventInput::deviceAttached((void *)this, addedIterator);
FGMacOSXEventInput::deviceDetached(NULL, removedIterator); FGMacOSXEventInput::deviceDetached((void *)this, removedIterator);
} }
@ -718,8 +716,10 @@ void FGMacOSXEventInput::attachDevice(io_iterator_t iterator)
if (inputDevice) { if (inputDevice) {
SG_LOG(SG_INPUT, SG_INFO, "HID Device Atached: " << inputDevice->GetName()); SG_LOG(SG_INPUT, SG_INFO, "HID Device Atached: " << inputDevice->GetName());
unsigned index = AddDevice(inputDevice); unsigned index = AddDevice(inputDevice);
// Needs to check if AddDevice closed the device due to lack to config file // Needs to check if AddDevice closed the device due to lack of config file
if (index != FGEventInput::INVALID_DEVICE_INDEX) { if (index != FGEventInput::INVALID_DEVICE_INDEX) {
// maps device with FG device index.
// This map is needed in detachDevice to tell FGEventInput which deivce ID is to be removed
deviceIndices[device] = index; deviceIndices[device] = index;
} }
} }
@ -735,10 +735,14 @@ void FGMacOSXEventInput::detachDevice(io_iterator_t iterator)
while ((device = IOIteratorNext(iterator))) { while ((device = IOIteratorNext(iterator))) {
unsigned index = deviceIndices[device]; unsigned index = deviceIndices[device];
if (index != FGEventInput::INVALID_DEVICE_INDEX) { if (index != FGEventInput::INVALID_DEVICE_INDEX) {
FGMacOSXInputDevice *inputDevice = (FGMacOSXInputDevice *)input_devices[index]; FGMacOSXInputDevice *inputDevice = dynamic_cast<FGMacOSXInputDevice *>(input_devices[index]);
SG_LOG(SG_INPUT, SG_INFO, "HID Device Detached: " << inputDevice->GetName()); if (inputDevice) {
RemoveDevice(index); SG_LOG(SG_INPUT, SG_INFO, "HID Device Detached: " << inputDevice->GetName());
deviceIndices.erase(device); RemoveDevice(index);
deviceIndices.erase(device);
} else {
SG_LOG(SG_INPUT, SG_WARN, "Invalid device index:" << index << ". Detach failed.");
}
} else { } else {
SG_LOG(SG_INPUT, SG_INFO, "Device ID unmatched: " << (int)device << " No HID deivce is detached since it is not supported by FG."); SG_LOG(SG_INPUT, SG_INFO, "Device ID unmatched: " << (int)device << " No HID deivce is detached since it is not supported by FG.");
} }
@ -746,6 +750,9 @@ void FGMacOSXEventInput::detachDevice(io_iterator_t iterator)
} }
} }
//
// read all elements in each input device
//
void FGMacOSXEventInput::update(double dt) void FGMacOSXEventInput::update(double dt)
{ {
FGEventInput::update(dt); FGEventInput::update(dt);
@ -753,8 +760,12 @@ void FGMacOSXEventInput::update(double dt)
map<int, FGInputDevice*>::const_iterator it; map<int, FGInputDevice*>::const_iterator it;
for (it = input_devices.begin(); it != input_devices.end(); it++) { for (it = input_devices.begin(); it != input_devices.end(); it++) {
if ((*it).second) { if ((*it).second) {
FGMacOSXInputDevice *inputDevice = (FGMacOSXInputDevice *)((*it).second); FGMacOSXInputDevice *inputDevice = dynamic_cast<FGMacOSXInputDevice *>((*it).second);
inputDevice->update(dt); if (inputDevice) {
inputDevice->update(dt);
} else {
SG_LOG(SG_INPUT, SG_WARN, "Invalid device. Update failed.");
}
} }
} }
} }

View file

@ -41,6 +41,12 @@
#include "FGEventInput.hxx" #include "FGEventInput.hxx"
#endif #endif
//
// HID Usage type
// HIDElementFactory will create a proper HIDElement subclass
// depending on the usage type of a detected HID element
// See http://www.usb.org/developers/devclass_docs/Hut1_12.pdf for detail
//
typedef enum { typedef enum {
kHIDUsageNotSupported = -1, // Debug use kHIDUsageNotSupported = -1, // Debug use
kHIDElementType = 0, // Debug use kHIDElementType = 0, // Debug use
@ -62,12 +68,14 @@ typedef enum {
class HIDElement; class HIDElement;
struct FGMacOSXEventData : public FGEventData { struct FGMacOSXEventData : public FGEventData {
FGMacOSXEventData(std::string name, double value, double dt, int modifiers) : FGMacOSXEventData(string name, double value, double dt, int modifiers) :
FGEventData(value, dt, modifiers), name(name) {} FGEventData(value, dt, modifiers), name(name) {}
std::string name; string name;
}; };
//
// For mapping HID element page/usage, usage type, and event names
//
struct HIDTypes { struct HIDTypes {
long key; long key;
HIDUsageType type; HIDUsageType type;
@ -77,18 +85,18 @@ struct HIDTypes {
class FGMacOSXInputDevice; class FGMacOSXInputDevice;
// //
// Generic HIDElement that might work for DV, DF types // Generic HIDElement for DV, DF types
// //
class HIDElement { class HIDElement {
public: public:
HIDElement(CFDictionaryRef element, long page, long usage); HIDElement(CFDictionaryRef element, long page, long usage);
virtual ~HIDElement() {} virtual ~HIDElement() {}
virtual float readStatus(IOHIDDeviceInterface **interface);
bool isUpdated(); bool isUpdated();
string getName() { return name; }
virtual void generateEvent(FGMacOSXInputDevice *device, double dt, int modifiers); virtual void generateEvent(FGMacOSXInputDevice *device, double dt, int modifiers);
std::string getName() { return name; } virtual long read(IOHIDDeviceInterface **interface);
virtual void write(IOHIDDeviceInterface **interface, double value) { virtual void write(IOHIDDeviceInterface **interface, double value) {
std::cout << "writing is not implemented on this device: " << name << std::endl; SG_LOG(SG_INPUT, SG_WARN, "writing is not implemented on this device: " << name);
} }
protected: protected:
IOHIDElementCookie cookie; IOHIDElementCookie cookie;
@ -98,14 +106,15 @@ protected:
float value; float value;
float lastValue; float lastValue;
std::string name; string name;
}; };
class AxisElement : public HIDElement { class AxisElement : public HIDElement {
public: public:
AxisElement(CFDictionaryRef element, long page, long usage); AxisElement(CFDictionaryRef element, long page, long usage);
virtual ~AxisElement() {} virtual ~AxisElement() {}
virtual float readStatus(IOHIDDeviceInterface **interface); virtual long read(IOHIDDeviceInterface **interface);
virtual void generateEvent(FGMacOSXInputDevice *device, double dt, int modifiers);
private: private:
long min; long min;
long max; long max;
@ -121,6 +130,7 @@ class ButtonElement : public HIDElement {
public: public:
ButtonElement(CFDictionaryRef element, long page, long usage); ButtonElement(CFDictionaryRef element, long page, long usage);
virtual ~ButtonElement() {} virtual ~ButtonElement() {}
private:
}; };
class HatElement : public HIDElement { class HatElement : public HIDElement {
@ -145,11 +155,12 @@ class FeatureElement : public HIDElement {
public: public:
FeatureElement(CFDictionaryRef element, long page, long usage, int count); FeatureElement(CFDictionaryRef element, long page, long usage, int count);
virtual ~FeatureElement() {} virtual ~FeatureElement() {}
virtual float readStatus(IOHIDDeviceInterface **inerface); virtual long read(IOHIDDeviceInterface **inerface);
}; };
// //
// FGMacOSXInputDevice // FGMacOSXInputDevice
// Mac OS X specific FGInputDevice
// //
class FGMacOSXInputDevice : public FGInputDevice { class FGMacOSXInputDevice : public FGInputDevice {
public: public:
@ -157,25 +168,26 @@ public:
virtual ~FGMacOSXInputDevice() { Close(); } virtual ~FGMacOSXInputDevice() { Close(); }
void Open(); void Open();
void Close(); void Close();
void readStatus();
virtual void update(double dt); virtual void update(double dt);
virtual const char *TranslateEventName(FGEventData &eventData); virtual const char *TranslateEventName(FGEventData &eventData);
void Send( const char *eventName, double value);
// Mac OS X specific methods
CFDictionaryRef getProperties() { CFDictionaryRef getProperties() {
return FGMacOSXInputDevice::getProperties(device); return FGMacOSXInputDevice::getProperties(device);
} }
static CFDictionaryRef getProperties(io_object_t device); static CFDictionaryRef getProperties(io_object_t device);
void addElement(HIDElement *element); void addElement(HIDElement *element);
void Send( const char *eventName, double value);
private: private:
io_object_t device; io_object_t device;
IOHIDDeviceInterface **devInterface; IOHIDDeviceInterface **devInterface;
std::map<std::string, HIDElement *> elements; map<string, HIDElement *> elements; // maps eventName and its relevant element for Send()
}; };
// //
// HID element parser // HID element factory that iteratively parses and creates
// HIDElement instances and add these to FGMacOSXDeviceInput
// //
class HIDElementFactory { class HIDElementFactory {
public: public:
@ -185,57 +197,59 @@ public:
}; };
// //
// // Mac OS X specific FGEventInput
// //
class FGMacOSXEventInput : public FGEventInput { class FGMacOSXEventInput : public FGEventInput {
public: public:
FGMacOSXEventInput() : FGEventInput() { FGMacOSXEventInput::_instance = this; SG_LOG(SG_INPUT, SG_ALERT, "FGMacOSXEventInput created"); } FGMacOSXEventInput() : FGEventInput() { SG_LOG(SG_INPUT, SG_DEBUG, "FGMacOSXEventInput created"); }
virtual ~FGMacOSXEventInput(); virtual ~FGMacOSXEventInput();
static void deviceAttached(void *ref, io_iterator_t iterator) { virtual void update(double dt);
FGMacOSXEventInput::instance().attachDevice(iterator); virtual void init();
// Mac OS X specific methods
static void deviceAttached(void *device, io_iterator_t iterator) {
static_cast<FGMacOSXEventInput *>(device)->attachDevice(iterator);
} }
static void deviceDetached(void *ref, io_iterator_t iterator) {
FGMacOSXEventInput::instance().detachDevice(iterator); static void deviceDetached(void *device, io_iterator_t iterator) {
static_cast<FGMacOSXEventInput *>(device)->detachDevice(iterator);
} }
static FGMacOSXEventInput &instance();
void attachDevice(io_iterator_t iterator); void attachDevice(io_iterator_t iterator);
void detachDevice(io_iterator_t iterator); void detachDevice(io_iterator_t iterator);
virtual void update(double dt);
virtual void init();
static FGMacOSXEventInput *_instance;
private: private:
IONotificationPortRef notifyPort; IONotificationPortRef notifyPort;
CFRunLoopSourceRef runLoopSource; CFRunLoopSourceRef runLoopSource;
io_iterator_t addedIterator; io_iterator_t addedIterator;
io_iterator_t removedIterator; io_iterator_t removedIterator;
std::map<io_object_t, unsigned> deviceIndices; // maps FG device property ID (i.e. /input/events/device[ID]) with io_object for detaching devices
map<io_object_t, unsigned> deviceIndices;
}; };
// //
// For debug and warnings // For obtaining event name and type from both HID element page and usage
// //
class HIDTypeByID : public std::map<long, std::pair<HIDUsageType, const char *>*> { class HIDTypeByID : public map<long, pair<HIDUsageType, const char *>*> {
public: public:
HIDTypeByID(struct HIDTypes *table) { HIDTypeByID(struct HIDTypes *table) {
for( int i = 0; table[i].key!= -1; i++ ) for( int i = 0; table[i].key!= -1; i++ )
(*this)[table[i].key] = new std::pair<HIDUsageType, const char *>(table[i].type, table[i].eventName); (*this)[table[i].key] = new pair<HIDUsageType, const char *>(table[i].type, table[i].eventName);
} }
~HIDTypeByID() { ~HIDTypeByID() {
std::map<long, std::pair<HIDUsageType, const char *>*>::iterator it; map<long, pair<HIDUsageType, const char *>*>::iterator it;
for (it = this->begin(); it != this->end(); it++) { for (it = this->begin(); it != this->end(); it++) {
delete (*it).second; delete (*it).second;
} }
clear(); clear();
} }
// key = (HID_element_page) << 16 | HID_element_usage)
const char *getName(long key) { const char *getName(long key) {
std::pair<HIDUsageType, const char *> *usageType = (*this)[key]; pair<HIDUsageType, const char *> *usageType = (*this)[key];
if (usageType == NULL) { if (usageType == NULL) {
return ""; return "";
} else { } else {
@ -244,7 +258,7 @@ public:
} }
const HIDUsageType getType(long key) { const HIDUsageType getType(long key) {
std::pair<HIDUsageType, const char *> *usageType = (*this)[key]; pair<HIDUsageType, const char *> *usageType = (*this)[key];
if (usageType == NULL) { if (usageType == NULL) {
return kHIDUsageNotSupported; return kHIDUsageNotSupported;
} else { } else {