]> git.mxchange.org Git - flightgear.git/blob - src/Input/FGMacOSXEventInput.hxx
Merge branch 'next' of 10.101.2.62:~/FlightGear/fg-osg/FlightGear into next
[flightgear.git] / src / Input / FGMacOSXEventInput.hxx
1 // FGMacOSXEventInput.hxx -- handle event driven input devices for Mac OS X
2 //
3 // Written by Tatsuhiro Nishioka, started Aug. 2009.
4 //
5 // Copyright (C) 2009 Tasuhiro Nishioka, tat <dot> fgmacosx <at> gmail <dot> com
6 //
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.
11 //
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.
16 //
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.
20 //
21 // $Id$
22
23 #ifndef __FGMACOSXEVENTINPUT_HXX_
24 #define __FGMACOSXEVENTINPUT_HXX_
25
26 #include <iostream>
27 #include <string>
28 #include <vector>
29 #include <map>
30 #include <sstream>
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>
39
40 #ifndef _TEST
41 #include "FGEventInput.hxx"
42 #endif
43
44 //
45 // HID Usage type
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
49 //
50 typedef enum {
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?
63   // FG specific types
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 
66 } HIDUsageType;
67   
68
69 class HIDElement;
70 struct FGMacOSXEventData : public FGEventData {
71   FGMacOSXEventData(string name, double value, double dt, int modifiers) : 
72     FGEventData(value, dt, modifiers), name(name) {}
73   string name;
74 };
75
76 //
77 // For mapping HID element page/usage, usage type, and event names
78 //
79 struct HIDTypes {
80   long key;
81   HIDUsageType type;
82   const char *eventName;
83 };
84
85 class FGMacOSXInputDevice;
86
87 //
88 // Generic HIDElement for DV, DF types
89 // 
90 class HIDElement {
91 public:
92   HIDElement(CFDictionaryRef element, long page, long usage);
93   virtual ~HIDElement() {}
94   bool isUpdated();
95   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);
100   }
101 protected:
102   IOHIDElementCookie cookie;
103   long type;
104   long page;
105   long usage;
106   float value;
107   float lastValue;
108
109   string name;
110 };
111
112 class AxisElement : public HIDElement {
113 public:
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);
118 private:
119   long min;
120   long max;
121   float dead_band;
122   float saturate;
123   long center;
124   bool isRelative;
125   bool isWrapping;
126   bool isNonLinear;
127 };
128
129 class ButtonElement : public HIDElement {
130 public:
131   ButtonElement(CFDictionaryRef element, long page, long usage);
132   virtual ~ButtonElement() {}
133 private:
134 };
135
136 class HatElement : public HIDElement {
137 public:
138   HatElement(CFDictionaryRef element, long page, long usage, int id);
139   virtual ~HatElement() {}
140   virtual void generateEvent(FGMacOSXInputDevice *device, double dt, int modifiers);
141 private:
142   int id;
143   long min;
144   long max;
145 };
146
147 class LEDElement : public HIDElement {
148 public:
149   LEDElement(CFDictionaryRef element, long page, long usage);
150   virtual ~LEDElement() {}
151   virtual void write(IOHIDDeviceInterface **interface, double value);
152 };
153
154 class FeatureElement : public HIDElement {
155 public:
156   FeatureElement(CFDictionaryRef element, long page, long usage, int count);
157   virtual ~FeatureElement() {}
158   virtual long read(IOHIDDeviceInterface **inerface);
159 };
160
161 //
162 // FGMacOSXInputDevice
163 // Mac OS X specific FGInputDevice
164 //
165 class FGMacOSXInputDevice : public FGInputDevice {
166 public:
167   FGMacOSXInputDevice(io_object_t device);
168   virtual ~FGMacOSXInputDevice() { Close(); }
169   void Open();
170   void Close();
171   virtual void update(double dt);
172   virtual const char *TranslateEventName(FGEventData &eventData);
173   void Send( const char *eventName, double value);
174
175   // Mac OS X specific methods
176   CFDictionaryRef getProperties() {
177     return FGMacOSXInputDevice::getProperties(device); 
178   }
179   static CFDictionaryRef getProperties(io_object_t device); 
180   void addElement(HIDElement *element);
181
182 private:
183   io_object_t device;
184   IOHIDDeviceInterface **devInterface;
185   map<string, HIDElement *> elements; // maps eventName and its relevant element for Send()
186 };
187
188 //
189 // HID element factory that iteratively parses and creates 
190 // HIDElement instances and add these to FGMacOSXDeviceInput
191 //
192 class HIDElementFactory {
193 public:
194   static void create(CFTypeRef element, FGMacOSXInputDevice *inputDevice);
195   static void elementEnumerator( const void *element, void *inputDevice); 
196   static void parseElement(CFDictionaryRef element, FGMacOSXInputDevice *device);
197 };
198
199 //
200 // Mac OS X specific FGEventInput
201 //
202 class FGMacOSXEventInput : public FGEventInput {
203 public:
204   FGMacOSXEventInput() : FGEventInput() { SG_LOG(SG_INPUT, SG_DEBUG, "FGMacOSXEventInput created"); }
205   virtual ~FGMacOSXEventInput();
206   virtual void update(double dt);
207   virtual void init();
208
209   // Mac OS X specific methods
210   static void deviceAttached(void *device, io_iterator_t iterator) {
211     static_cast<FGMacOSXEventInput *>(device)->attachDevice(iterator); 
212   }
213
214   static void deviceDetached(void *device, io_iterator_t iterator) { 
215     static_cast<FGMacOSXEventInput *>(device)->detachDevice(iterator); 
216   }
217
218   void attachDevice(io_iterator_t iterator);
219   void detachDevice(io_iterator_t iterator);
220
221 private:
222   IONotificationPortRef notifyPort;
223   CFRunLoopSourceRef runLoopSource;
224   io_iterator_t addedIterator; 
225   io_iterator_t removedIterator;
226
227   // maps FG device property ID (i.e. /input/events/device[ID]) with io_object for detaching devices
228   map<io_object_t, unsigned> deviceIndices; 
229 };
230
231
232 //
233 // For obtaining event name and type from both HID element page and usage
234 // 
235 class HIDTypeByID : public map<long, pair<HIDUsageType, const char *>*> {
236 public:
237   HIDTypeByID(struct HIDTypes *table) {
238     for( int i = 0; table[i].key!= -1; i++ )
239       (*this)[table[i].key] = new pair<HIDUsageType, const char *>(table[i].type, table[i].eventName);
240   }
241
242   ~HIDTypeByID() {
243     map<long, pair<HIDUsageType, const char *>*>::iterator it;
244     for (it = this->begin(); it != this->end(); it++) {
245       delete (*it).second;
246     }
247     clear();
248   }
249
250   // key = (HID_element_page) << 16 | HID_element_usage)
251   const char *getName(long key) {
252     pair<HIDUsageType, const char *> *usageType = (*this)[key];
253     if (usageType == NULL) {
254       return "";
255     } else {
256       return usageType->second;
257     }
258   }
259
260   const HIDUsageType getType(long key) {
261     pair<HIDUsageType, const char *> *usageType = (*this)[key];
262     if (usageType == NULL) {
263       return kHIDUsageNotSupported;
264     } else {
265       return usageType->first;
266     }
267   }
268 };
269
270 #endif