]> git.mxchange.org Git - flightgear.git/blob - src/Input/FGMacOSXEventInput.hxx
Document that property write-protection is not a security measure
[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(std::string name, double value, double dt, int modifiers) : 
72     FGEventData(value, dt, modifiers), name(name) {}
73   std::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   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);
100   }
101 protected:
102   IOHIDElementCookie cookie;
103   long type;
104   long page;
105   long usage;
106   float value;
107   float lastValue;
108
109   std::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   long center;
123   bool isRelative;
124   bool isWrapping;
125   bool isNonLinear;
126 };
127
128 class ButtonElement : public HIDElement {
129 public:
130   ButtonElement(CFDictionaryRef element, long page, long usage);
131   virtual ~ButtonElement() {}
132 private:
133 };
134
135 class HatElement : public HIDElement {
136 public:
137   HatElement(CFDictionaryRef element, long page, long usage, int id);
138   virtual ~HatElement() {}
139   virtual void generateEvent(FGMacOSXInputDevice *device, double dt, int modifiers);
140 private:
141   int id;
142   long min;
143   long max;
144 };
145
146 class LEDElement : public HIDElement {
147 public:
148   LEDElement(CFDictionaryRef element, long page, long usage);
149   virtual ~LEDElement() {}
150   virtual void write(IOHIDDeviceInterface **interface, double value);
151 };
152
153 class FeatureElement : public HIDElement {
154 public:
155   FeatureElement(CFDictionaryRef element, long page, long usage, int count);
156   virtual ~FeatureElement() {}
157   virtual long read(IOHIDDeviceInterface **inerface);
158 };
159
160 //
161 // FGMacOSXInputDevice
162 // Mac OS X specific FGInputDevice
163 //
164 class FGMacOSXInputDevice : public FGInputDevice {
165 public:
166   FGMacOSXInputDevice(io_object_t device);
167   virtual ~FGMacOSXInputDevice() { Close(); }
168   void Open();
169   void Close();
170   virtual void update(double dt);
171   virtual const char *TranslateEventName(FGEventData &eventData);
172   void Send( const char *eventName, double value);
173
174   // Mac OS X specific methods
175   CFDictionaryRef getProperties() {
176     return FGMacOSXInputDevice::getProperties(device); 
177   }
178   static CFDictionaryRef getProperties(io_object_t device); 
179   void addElement(HIDElement *element);
180
181 private:
182   io_object_t device;
183   IOHIDDeviceInterface **devInterface;
184   std::map<std::string, HIDElement *> elements; // maps eventName and its relevant element for Send()
185 };
186
187 //
188 // HID element factory that iteratively parses and creates 
189 // HIDElement instances and add these to FGMacOSXDeviceInput
190 //
191 class HIDElementFactory {
192 public:
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);
196 };
197
198 //
199 // Mac OS X specific FGEventInput
200 //
201 class FGMacOSXEventInput : public FGEventInput {
202 public:
203   FGMacOSXEventInput() : FGEventInput() { SG_LOG(SG_INPUT, SG_DEBUG, "FGMacOSXEventInput created"); }
204   virtual ~FGMacOSXEventInput();
205   virtual void update(double dt);
206   virtual void init();
207
208   // Mac OS X specific methods
209   static void deviceAttached(void *device, io_iterator_t iterator) {
210     static_cast<FGMacOSXEventInput *>(device)->attachDevice(iterator); 
211   }
212
213   static void deviceDetached(void *device, io_iterator_t iterator) { 
214     static_cast<FGMacOSXEventInput *>(device)->detachDevice(iterator); 
215   }
216
217   void attachDevice(io_iterator_t iterator);
218   void detachDevice(io_iterator_t iterator);
219
220 private:
221   IONotificationPortRef notifyPort;
222   CFRunLoopSourceRef runLoopSource;
223   io_iterator_t addedIterator; 
224   io_iterator_t removedIterator;
225
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; 
228 };
229
230
231 //
232 // For obtaining event name and type from both HID element page and usage
233 // 
234 class HIDTypeByID : public std::map<long, std::pair<HIDUsageType, const char *>*> {
235 public:
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);
239   }
240
241   ~HIDTypeByID() {
242     std::map<long, std::pair<HIDUsageType, const char *>*>::iterator it;
243     for (it = this->begin(); it != this->end(); it++) {
244       delete (*it).second;
245     }
246     clear();
247   }
248
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) {
253       return "";
254     } else {
255       return usageType->second;
256     }
257   }
258
259   const HIDUsageType getType(long key) {
260     std::pair<HIDUsageType, const char *> *usageType = (*this)[key];
261     if (usageType == NULL) {
262       return kHIDUsageNotSupported;
263     } else {
264       return usageType->first;
265     }
266   }
267 };
268
269 #endif