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:
parent
80a6317ab6
commit
a26ca9f3e3
2 changed files with 136 additions and 111 deletions
|
@ -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,42 +333,46 @@ 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;
|
}
|
||||||
/*
|
|
||||||
|
// 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) {
|
if (!isRelative) {
|
||||||
value = (value - (float)center) / (float)(max - center);
|
normalizedValue = (value - (float)center) / (float)(max - center);
|
||||||
if (fabs(value) < dead_band)
|
if (fabs(normalizedValue) < dead_band)
|
||||||
value = 0.0;
|
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)
|
||||||
|
@ -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]);
|
||||||
|
if (inputDevice) {
|
||||||
SG_LOG(SG_INPUT, SG_INFO, "HID Device Detached: " << inputDevice->GetName());
|
SG_LOG(SG_INPUT, SG_INFO, "HID Device Detached: " << inputDevice->GetName());
|
||||||
RemoveDevice(index);
|
RemoveDevice(index);
|
||||||
deviceIndices.erase(device);
|
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);
|
||||||
|
if (inputDevice) {
|
||||||
inputDevice->update(dt);
|
inputDevice->update(dt);
|
||||||
|
} else {
|
||||||
|
SG_LOG(SG_INPUT, SG_WARN, "Invalid device. Update failed.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue