1 // FGMacOSXEventInput.hxx -- handle event driven input devices for Mac OS X
3 // Written by Tatsuhiro Nishioka, started Aug. 2009.
5 // Copyright (C) 2009 Tasuhiro Nishioka, tat <dot> fgmacosx <at> gmail <dot> com
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #ifndef __FGMACOSXEVENTINPUT_HXX_
24 #define __FGMACOSXEVENTINPUT_HXX_
31 #include <mach/mach.h>
32 #include <mach/mach_error.h>
33 #include <IOKit/IOKitLib.h>
34 #include <IOKit/hid/IOHIDLib.h>
35 #include <IOKit/hid/IOHIDKeys.h>
36 #include <IOKit/IOCFPlugIn.h>
37 #include <CoreFoundation/CoreFoundation.h>
38 #include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
41 #include "FGEventInput.hxx"
46 // HIDElementFactory will create a proper HIDElement subclass
47 // depending on the usage type of a detected HID element
48 // See http://www.usb.org/developers/devclass_docs/Hut1_12.pdf for detail
51 kHIDUsageNotSupported = -1, // Debug use
52 kHIDElementType = 0, // Debug use
53 kHIDElementPage, // Debug use
54 kHIDUsageSel, // Selector; Contained in a Named Array - not supported yet
55 kHIDUsageSV, // Static Value; Axis?(Constant, Variable, Absolute) - not supported yet
56 kHIDUsageSF, // Static Flag; Axis?(Constant, Variable, Absolute) - not supported yet
57 kHIDUsageDV, // Dynamic Value; Axis(Data, Variable, Absolute)
58 kHIDUsageDF, // Dynamic Flag; Axis?(Data, Variable, Absolute) - not supported yet
59 kHIDUsageOOC, // On/Off Control; Button?
60 kHIDUsageMC, // Momentary Control; Button
61 kHIDUsageOSC, // One Shot Control; Button
62 kHIDUsageRTC, // Re-trigger Control; Button?
64 kHIDUsageHat, // HatSwitch ; a special usage of DV that generates two FGInputEvent instances
65 kHIDUsageAxis, // Axis; a special usage of DV that has either abs- or rel- prefix
70 struct FGMacOSXEventData : public FGEventData {
71 FGMacOSXEventData(std::string name, double value, double dt, int modifiers) :
72 FGEventData(value, dt, modifiers), name(name) {}
77 // For mapping HID element page/usage, usage type, and event names
82 const char *eventName;
85 class FGMacOSXInputDevice;
88 // Generic HIDElement for DV, DF types
92 HIDElement(CFDictionaryRef element, long page, long usage);
93 virtual ~HIDElement() {}
95 std::string getName() { return name; }
96 virtual void generateEvent(FGMacOSXInputDevice *device, double dt, int modifiers);
97 virtual long read(IOHIDDeviceInterface **interface);
98 virtual void write(IOHIDDeviceInterface **interface, double value) {
99 SG_LOG(SG_INPUT, SG_WARN, "writing is not implemented on this device: " << name);
102 IOHIDElementCookie cookie;
112 class AxisElement : public HIDElement {
114 AxisElement(CFDictionaryRef element, long page, long usage);
115 virtual ~AxisElement() {}
116 virtual long read(IOHIDDeviceInterface **interface);
117 virtual void generateEvent(FGMacOSXInputDevice *device, double dt, int modifiers);
128 class ButtonElement : public HIDElement {
130 ButtonElement(CFDictionaryRef element, long page, long usage);
131 virtual ~ButtonElement() {}
135 class HatElement : public HIDElement {
137 HatElement(CFDictionaryRef element, long page, long usage, int id);
138 virtual ~HatElement() {}
139 virtual void generateEvent(FGMacOSXInputDevice *device, double dt, int modifiers);
146 class LEDElement : public HIDElement {
148 LEDElement(CFDictionaryRef element, long page, long usage);
149 virtual ~LEDElement() {}
150 virtual void write(IOHIDDeviceInterface **interface, double value);
153 class FeatureElement : public HIDElement {
155 FeatureElement(CFDictionaryRef element, long page, long usage, int count);
156 virtual ~FeatureElement() {}
157 virtual long read(IOHIDDeviceInterface **inerface);
161 // FGMacOSXInputDevice
162 // Mac OS X specific FGInputDevice
164 class FGMacOSXInputDevice : public FGInputDevice {
166 FGMacOSXInputDevice(io_object_t device);
167 virtual ~FGMacOSXInputDevice() { Close(); }
170 virtual void update(double dt);
171 virtual const char *TranslateEventName(FGEventData &eventData);
172 void Send( const char *eventName, double value);
174 // Mac OS X specific methods
175 CFDictionaryRef getProperties() {
176 return FGMacOSXInputDevice::getProperties(device);
178 static CFDictionaryRef getProperties(io_object_t device);
179 void addElement(HIDElement *element);
183 IOHIDDeviceInterface **devInterface;
184 std::map<std::string, HIDElement *> elements; // maps eventName and its relevant element for Send()
188 // HID element factory that iteratively parses and creates
189 // HIDElement instances and add these to FGMacOSXDeviceInput
191 class HIDElementFactory {
193 static void create(CFTypeRef element, FGMacOSXInputDevice *inputDevice);
194 static void elementEnumerator( const void *element, void *inputDevice);
195 static void parseElement(CFDictionaryRef element, FGMacOSXInputDevice *device);
199 // Mac OS X specific FGEventInput
201 class FGMacOSXEventInput : public FGEventInput {
203 FGMacOSXEventInput() : FGEventInput() { SG_LOG(SG_INPUT, SG_DEBUG, "FGMacOSXEventInput created"); }
204 virtual ~FGMacOSXEventInput();
205 virtual void update(double dt);
208 // Mac OS X specific methods
209 static void deviceAttached(void *device, io_iterator_t iterator) {
210 static_cast<FGMacOSXEventInput *>(device)->attachDevice(iterator);
213 static void deviceDetached(void *device, io_iterator_t iterator) {
214 static_cast<FGMacOSXEventInput *>(device)->detachDevice(iterator);
217 void attachDevice(io_iterator_t iterator);
218 void detachDevice(io_iterator_t iterator);
221 IONotificationPortRef notifyPort;
222 CFRunLoopSourceRef runLoopSource;
223 io_iterator_t addedIterator;
224 io_iterator_t removedIterator;
226 // maps FG device property ID (i.e. /input/events/device[ID]) with io_object for detaching devices
227 std::map<io_object_t, unsigned> deviceIndices;
232 // For obtaining event name and type from both HID element page and usage
234 class HIDTypeByID : public std::map<long, std::pair<HIDUsageType, const char *>*> {
236 HIDTypeByID(struct HIDTypes *table) {
237 for( int i = 0; table[i].key!= -1; i++ )
238 (*this)[table[i].key] = new std::pair<HIDUsageType, const char *>(table[i].type, table[i].eventName);
242 std::map<long, std::pair<HIDUsageType, const char *>*>::iterator it;
243 for (it = this->begin(); it != this->end(); it++) {
249 // key = (HID_element_page) << 16 | HID_element_usage)
250 const char *getName(long key) {
251 std::pair<HIDUsageType, const char *> *usageType = (*this)[key];
252 if (usageType == NULL) {
255 return usageType->second;
259 const HIDUsageType getType(long key) {
260 std::pair<HIDUsageType, const char *> *usageType = (*this)[key];
261 if (usageType == NULL) {
262 return kHIDUsageNotSupported;
264 return usageType->first;