]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/hid.cpp
927341fff0e6962fd7f1fcc6c4aa968add76ffaa
[wxWidgets.git] / src / mac / carbon / hid.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: hid.cpp
3 // Purpose: DARWIN HID layer for WX Implementation
4 // Author: Ryan Norton
5 // Modified by:
6 // Created: 11/11/2003
7 // RCS-ID: $Id$
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/defs.h"
13
14 //DARWIN _ONLY_
15 #ifdef __DARWIN__
16
17 #include "wx/mac/carbon/private/hid.h"
18 #include "wx/string.h"
19 #include "wx/log.h"
20
21 #define wxFORCECHECK_MSG(arg, msg) \
22 {\
23 if (arg) \
24 {\
25 wxLogSysError(wxString::Format(wxT("Message:%s\nHID: %s failed!"), wxT(msg), wxT(#arg)));\
26 return false;\
27 }\
28 }
29 #define wxIOCHECK(arg, msg) wxFORCECHECK_MSG(arg != kIOReturnSuccess, msg)
30 #define wxKERNCHECK(arg, msg) wxFORCECHECK_MSG(arg != KERN_SUCCESS, msg)
31 #define wxSCHECK(arg, msg) wxFORCECHECK_MSG(arg != S_OK, msg)
32
33 #ifdef __WXDEBUG___
34 # define wxVERIFY(arg) wxASSERT(arg)
35 #else
36 # define wxVERIFY(arg) arg
37 #endif
38
39 /*
40 void CFShowTypeIDDescription(CFTypeRef pData)
41 {
42 if(!pData)
43 {
44 wxASSERT(false);
45 return;
46 }
47
48 wxMessageBox(
49 CFStringGetCStringPtr(
50 CFCopyTypeIDDescription(CFGetTypeID(pData)),CFStringGetSystemEncoding()
51 )
52 );
53 }
54 */
55
56 // ============================================================================
57 // implementation
58 // ============================================================================
59
60
61 bool wxHIDDevice::Create (const int& nClass, const int& nType)
62 {
63 //Create the mach port
64 wxIOCHECK(IOMasterPort(bootstrap_port, &m_pPort), "Could not create mach port");
65
66 //Dictionary that will hold first
67 //the matching dictionary for determining which kind of devices we want,
68 //then later some registry properties from an iterator (see below)
69 CFMutableDictionaryRef pDictionary;
70
71 //Create a dictionary
72 //The call to IOServiceMatching filters down the
73 //the services we want to hid services (and also eats the
74 //dictionary up for us (consumes one reference))
75 wxVERIFY((pDictionary = IOServiceMatching(kIOHIDDeviceKey)) != NULL );
76
77 //Here we'll filter down the services to what we want
78 if (nType != -1)
79 {
80 CFNumberRef pType = CFNumberCreate(kCFAllocatorDefault,
81 kCFNumberIntType, &nType);
82 CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsageKey), pType);
83 CFRelease(pType);
84 }
85 if (nClass != -1)
86 {
87 CFNumberRef pClass = CFNumberCreate(kCFAllocatorDefault,
88 kCFNumberIntType, &nClass);
89 CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsagePageKey), pClass);
90 CFRelease(pClass);
91 }
92
93 //Now get the maching services
94 io_iterator_t pIterator;
95 wxIOCHECK(IOServiceGetMatchingServices(m_pPort, pDictionary, &pIterator), "No Matching HID Services");
96 wxASSERT(pIterator != NULL);
97
98 //Now we iterate through them
99 io_object_t pObject;
100 while ( (pObject = IOIteratorNext(pIterator)) != NULL)
101 {
102 wxVERIFY(IORegistryEntryCreateCFProperties(pObject, &pDictionary,
103 kCFAllocatorDefault, kNilOptions) == KERN_SUCCESS);
104
105 //Just for sanity :)
106 wxASSERT(CFGetTypeID(CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey))) == CFStringGetTypeID());
107
108 //Get [product] name
109 m_szName = CFStringGetCStringPtr (
110 (CFStringRef) CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey)),
111 CFStringGetSystemEncoding()
112 );
113
114 //
115 //Now the hard part - in order to scan things we need "cookies" -
116 //
117 wxCFArray CookieArray = CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDElementKey));
118 BuildCookies(CookieArray);
119 if (m_ppQueue != NULL)
120 wxVERIFY((*m_ppQueue)->start(m_ppQueue) == S_OK);
121
122 //Create the interface (good grief - long function names!)
123 SInt32 nScore;
124 IOCFPlugInInterface** ppPlugin;
125 wxIOCHECK(IOCreatePlugInInterfaceForService(pObject, kIOHIDDeviceUserClientTypeID,
126 kIOCFPlugInInterfaceID, &ppPlugin, &nScore), "");
127
128 //Now, the final thing we can check before we fall back to asserts
129 //(because the dtor only checks if the device is ok, so if anything
130 //fails from now on the dtor will delete the device anyway, so we can't break from this).
131
132 //Get the HID interface from the plugin to the mach port
133 wxSCHECK((*ppPlugin)->QueryInterface(ppPlugin,
134 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (void**) &m_ppDevice), "");
135
136 //release the plugin
137 (*ppPlugin)->Release(ppPlugin);
138
139 //open the HID interface...
140 wxVERIFY((*m_ppDevice)->open(m_ppDevice, 0) == S_OK);
141
142 //cleanup
143 CFRelease(pDictionary);
144 IOObjectRelease(pObject);
145 break;
146 }
147 //iterator cleanup
148 IOObjectRelease(pIterator);
149
150 return true;
151 }//end Create()
152
153 void wxHIDDevice::AddCookie(CFTypeRef Data, const int& i)
154 {
155 CFNumberGetValue(
156 (CFNumberRef) CFDictionaryGetValue ( (CFDictionaryRef) Data
157 , CFSTR(kIOHIDElementCookieKey)
158 ),
159 kCFNumberIntType,
160 &m_pCookies[i]
161 );
162 }
163
164 void wxHIDDevice::AddCookieInQueue(CFTypeRef Data, const int& i)
165 {
166 AddCookie(Data, i);
167 wxVERIFY((*m_ppQueue)->addElement(m_ppQueue, m_pCookies[i], 0) == S_OK);//3rd Param flags (none yet)
168 }
169
170 void wxHIDDevice::InitCookies(const size_t& dwSize, bool bQueue)
171 {
172 m_pCookies = new IOHIDElementCookie[dwSize];
173 if (bQueue)
174 {
175 wxASSERT( m_ppQueue != NULL);
176 wxVERIFY( (m_ppQueue = (*m_ppDevice)->allocQueue(m_ppDevice)) != NULL);
177 wxVERIFY( (*m_ppQueue)->create(m_ppQueue, 0, 512) == S_OK); //Param 2, flags, none yet
178 }
179 }
180
181 bool wxHIDDevice::IsActive(const int& nIndex)
182 {
183 wxASSERT(m_pCookies[nIndex] != NULL);
184 IOHIDEventStruct Event;
185 (*m_ppDevice)->getElementValue(m_ppDevice, m_pCookies[nIndex], &Event);
186 return !!Event.value;
187 }
188
189
190 wxHIDDevice::~wxHIDDevice()
191 {
192 if (m_ppDevice != NULL)
193 {
194 (*m_ppDevice)->close(m_ppDevice);
195 (*m_ppDevice)->Release(m_ppDevice);
196 mach_port_deallocate(mach_task_self(), m_pPort);
197 }
198
199 if (m_pCookies != NULL)
200 {
201 delete [] m_pCookies;
202 if (m_ppQueue != NULL)
203 {
204 (*m_ppQueue)->stop(m_ppQueue);
205 (*m_ppQueue)->dispose(m_ppQueue);
206 (*m_ppQueue)->Release(m_ppQueue);
207 }
208 }
209 }
210
211 enum
212 {
213 WXK_RSHIFT = 400,
214 WXK_RALT,
215 WXK_RCONTROL,
216 WXK_RMENU
217
218 };
219
220 bool wxHIDKeyboard::Create()
221 {
222 return wxHIDDevice::Create(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard);
223 }
224
225 void wxHIDKeyboard::BuildCookies(wxCFArray& Array)
226 {
227 Array = CFDictionaryGetValue((CFDictionaryRef)Array[0], CFSTR(kIOHIDElementKey));
228 InitCookies(500);
229 int i,
230 nUsage;
231 for (i = 0; i < Array.Count(); ++i)
232 {
233 CFNumberGetValue(
234 (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) Array[i], CFSTR(kIOHIDElementUsageKey)),
235 kCFNumberLongType, &nUsage);
236
237 if (nUsage >= kHIDUsage_KeyboardA && nUsage <= kHIDUsage_KeyboardZ)
238 AddCookie(Array[i], 'A' + (nUsage - kHIDUsage_KeyboardA) );
239 else if (nUsage >= kHIDUsage_Keyboard1 && nUsage <= kHIDUsage_Keyboard9)
240 AddCookie(Array[i], '1' + (nUsage - kHIDUsage_Keyboard1) );
241 else if (nUsage >= kHIDUsage_KeyboardF1 && nUsage <= kHIDUsage_KeyboardF12)
242 AddCookie(Array[i], WXK_F1 + (nUsage - kHIDUsage_KeyboardF1) );
243 else if (nUsage >= kHIDUsage_KeyboardF13 && nUsage <= kHIDUsage_KeyboardF24)
244 AddCookie(Array[i], WXK_F13 + (nUsage - kHIDUsage_KeyboardF13) );
245 else if (nUsage >= kHIDUsage_Keypad1 && nUsage <= kHIDUsage_Keypad9)
246 AddCookie(Array[i], WXK_NUMPAD1 + (nUsage - kHIDUsage_Keypad1) );
247 else switch (nUsage)
248 {
249 //0's (wx & ascii go 0-9, but HID goes 1-0)
250 case kHIDUsage_Keyboard0:
251 AddCookie(Array[i],'0');
252 break;
253 case kHIDUsage_Keypad0:
254 AddCookie(Array[i],WXK_NUMPAD0);
255 break;
256
257 //Basic
258 case kHIDUsage_KeyboardReturnOrEnter:
259 AddCookie(Array[i], WXK_RETURN);
260 break;
261 case kHIDUsage_KeyboardEscape:
262 AddCookie(Array[i], WXK_ESCAPE);
263 break;
264 case kHIDUsage_KeyboardDeleteOrBackspace:
265 AddCookie(Array[i], WXK_BACK);
266 break;
267 case kHIDUsage_KeyboardTab:
268 AddCookie(Array[i], WXK_TAB);
269 break;
270 case kHIDUsage_KeyboardSpacebar:
271 AddCookie(Array[i], WXK_SPACE);
272 break;
273 case kHIDUsage_KeyboardPageUp:
274 AddCookie(Array[i], WXK_PRIOR);
275 break;
276 case kHIDUsage_KeyboardEnd:
277 AddCookie(Array[i], WXK_END);
278 break;
279 case kHIDUsage_KeyboardPageDown:
280 AddCookie(Array[i], WXK_NEXT);
281 break;
282 case kHIDUsage_KeyboardRightArrow:
283 AddCookie(Array[i], WXK_RIGHT);
284 break;
285 case kHIDUsage_KeyboardLeftArrow:
286 AddCookie(Array[i], WXK_LEFT);
287 break;
288 case kHIDUsage_KeyboardDownArrow:
289 AddCookie(Array[i], WXK_DOWN);
290 break;
291 case kHIDUsage_KeyboardUpArrow:
292 AddCookie(Array[i], WXK_UP);
293 break;
294
295 //LEDS
296 case kHIDUsage_KeyboardCapsLock:
297 AddCookie(Array[i],WXK_CAPITAL);
298 break;
299 case kHIDUsage_KeypadNumLock:
300 AddCookie(Array[i],WXK_NUMLOCK);
301 break;
302 case kHIDUsage_KeyboardScrollLock:
303 AddCookie(Array[i],WXK_SCROLL);
304 break;
305
306 //Menu keys, Shift, other specials
307 case kHIDUsage_KeyboardLeftControl:
308 AddCookie(Array[i],WXK_CONTROL);
309 break;
310 case kHIDUsage_KeyboardLeftShift:
311 AddCookie(Array[i],WXK_SHIFT);
312 break;
313 case kHIDUsage_KeyboardLeftAlt:
314 AddCookie(Array[i],WXK_ALT);
315 break;
316 case kHIDUsage_KeyboardLeftGUI:
317 AddCookie(Array[i],WXK_MENU);
318 break;
319 case kHIDUsage_KeyboardRightControl:
320 AddCookie(Array[i],WXK_RCONTROL);
321 break;
322 case kHIDUsage_KeyboardRightShift:
323 AddCookie(Array[i],WXK_RSHIFT);
324 break;
325 case kHIDUsage_KeyboardRightAlt:
326 AddCookie(Array[i],WXK_RALT);
327 break;
328 case kHIDUsage_KeyboardRightGUI:
329 AddCookie(Array[i],WXK_RMENU);
330 break;
331
332 //Default
333 default:
334 //not in wx keycodes - do nothing....
335 break;
336 }
337 }
338 }//end buildcookies
339
340 #endif //__DARWIN__