]> git.saurik.com Git - wxWidgets.git/blob - src/mac/corefoundation/hid.cpp
Common code for the same handling of wxSL_INVERSE.
[wxWidgets.git] / src / mac / corefoundation / 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 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "hid.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 //DARWIN _ONLY_
32 #ifdef __DARWIN__
33
34 #include "wx/mac/corefoundation/hid.h"
35 #include "wx/string.h"
36 #include "wx/log.h"
37
38
39 // ---------------------------------------------------------------------------
40 // assertion macros
41 // ---------------------------------------------------------------------------
42
43 #define wxFORCECHECK_MSG(arg, msg) \
44 {\
45 if (arg) \
46 {\
47 wxLogSysError(wxString::Format(wxT("Message:%s\nHID: %s failed!"), wxT(msg), wxT(#arg)));\
48 return false;\
49 }\
50 }
51 #define wxIOCHECK(arg, msg) wxFORCECHECK_MSG(arg != kIOReturnSuccess, msg)
52 #define wxKERNCHECK(arg, msg) wxFORCECHECK_MSG(arg != KERN_SUCCESS, msg)
53 #define wxSCHECK(arg, msg) wxFORCECHECK_MSG(arg != S_OK, msg)
54
55 #ifdef __WXDEBUG___
56 # define wxVERIFY(arg) wxASSERT(arg)
57 #else
58 # define wxVERIFY(arg) arg
59 #endif
60
61 /*
62 void CFShowTypeIDDescription(CFTypeRef pData)
63 {
64 if(!pData)
65 {
66 wxASSERT(false);
67 return;
68 }
69
70 wxMessageBox(
71 CFStringGetCStringPtr(
72 CFCopyTypeIDDescription(CFGetTypeID(pData)),CFStringGetSystemEncoding()
73 )
74 );
75 }
76 */
77
78 // ============================================================================
79 // implementation
80 // ============================================================================
81
82 // ---------------------------------------------------------------------------
83 // wxHIDDevice
84 // ---------------------------------------------------------------------------
85
86 bool wxHIDDevice::Create (int nClass, int nType, int nDev)
87 {
88 //Create the mach port
89 wxIOCHECK(IOMasterPort(bootstrap_port, &m_pPort), "Could not create mach port");
90
91 //Dictionary that will hold first
92 //the matching dictionary for determining which kind of devices we want,
93 //then later some registry properties from an iterator (see below)
94 CFMutableDictionaryRef pDictionary;
95
96 //Create a dictionary
97 //The call to IOServiceMatching filters down the
98 //the services we want to hid services (and also eats the
99 //dictionary up for us (consumes one reference))
100 wxVERIFY((pDictionary = IOServiceMatching(kIOHIDDeviceKey)) != NULL );
101
102 //Here we'll filter down the services to what we want
103 if (nType != -1)
104 {
105 CFNumberRef pType = CFNumberCreate(kCFAllocatorDefault,
106 kCFNumberIntType, &nType);
107 CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsageKey), pType);
108 CFRelease(pType);
109 }
110 if (nClass != -1)
111 {
112 CFNumberRef pClass = CFNumberCreate(kCFAllocatorDefault,
113 kCFNumberIntType, &nClass);
114 CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsagePageKey), pClass);
115 CFRelease(pClass);
116 }
117
118 //Now get the maching services
119 io_iterator_t pIterator;
120 wxIOCHECK(IOServiceGetMatchingServices(m_pPort, pDictionary, &pIterator), "No Matching HID Services");
121 wxASSERT(pIterator != 0);
122
123 //Now we iterate through them
124 io_object_t pObject;
125 while ( (pObject = IOIteratorNext(pIterator)) != 0)
126 {
127 if(--nDev != 0)
128 continue;
129
130 wxVERIFY(IORegistryEntryCreateCFProperties(pObject, &pDictionary,
131 kCFAllocatorDefault, kNilOptions) == KERN_SUCCESS);
132
133 //Just for sanity :)
134 wxASSERT(CFGetTypeID(CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey))) == CFStringGetTypeID());
135
136 //Get [product] name
137 m_szName = CFStringGetCStringPtr (
138 (CFStringRef) CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey)),
139 CFStringGetSystemEncoding()
140 );
141
142 //Create the interface (good grief - long function names!)
143 SInt32 nScore;
144 IOCFPlugInInterface** ppPlugin;
145 wxIOCHECK(IOCreatePlugInInterfaceForService(pObject, kIOHIDDeviceUserClientTypeID,
146 kIOCFPlugInInterfaceID, &ppPlugin, &nScore), "");
147
148 //Now, the final thing we can check before we fall back to asserts
149 //(because the dtor only checks if the device is ok, so if anything
150 //fails from now on the dtor will delete the device anyway, so we can't break from this).
151
152 //Get the HID interface from the plugin to the mach port
153 wxSCHECK((*ppPlugin)->QueryInterface(ppPlugin,
154 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (void**) &m_ppDevice), "");
155
156 //release the plugin
157 (*ppPlugin)->Release(ppPlugin);
158
159 //open the HID interface...
160 wxVERIFY((*m_ppDevice)->open(m_ppDevice, 0) == S_OK);
161
162 //
163 //Now the hard part - in order to scan things we need "cookies" -
164 //
165 wxCFArray CookieArray = CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDElementKey));
166 BuildCookies(CookieArray);
167 if (m_ppQueue != NULL)
168 wxVERIFY((*m_ppQueue)->start(m_ppQueue) == S_OK);
169
170 //cleanup
171 CFRelease(pDictionary);
172 IOObjectRelease(pObject);
173 break;
174 }
175 //iterator cleanup
176 IOObjectRelease(pIterator);
177
178 return true;
179 }//end Create()
180
181 int wxHIDDevice::GetCount (int nClass, int nType)
182 {
183 mach_port_t m_pPort;
184
185 //Create the mach port
186 wxIOCHECK(IOMasterPort(bootstrap_port, &m_pPort), "Could not create mach port");
187
188 //Dictionary that will hold first
189 //the matching dictionary for determining which kind of devices we want,
190 //then later some registry properties from an iterator (see below)
191 CFMutableDictionaryRef pDictionary;
192
193 //Create a dictionary
194 //The call to IOServiceMatching filters down the
195 //the services we want to hid services (and also eats the
196 //dictionary up for us (consumes one reference))
197 wxVERIFY((pDictionary = IOServiceMatching(kIOHIDDeviceKey)) != NULL );
198
199 //Here we'll filter down the services to what we want
200 if (nType != -1)
201 {
202 CFNumberRef pType = CFNumberCreate(kCFAllocatorDefault,
203 kCFNumberIntType, &nType);
204 CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsageKey), pType);
205 CFRelease(pType);
206 }
207 if (nClass != -1)
208 {
209 CFNumberRef pClass = CFNumberCreate(kCFAllocatorDefault,
210 kCFNumberIntType, &nClass);
211 CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsagePageKey), pClass);
212 CFRelease(pClass);
213 }
214
215 //Now get the maching services
216 io_iterator_t pIterator;
217 wxIOCHECK(IOServiceGetMatchingServices(m_pPort, pDictionary, &pIterator), "No Matching HID Services");
218 wxASSERT(pIterator != 0);
219
220 //Now we iterate through them
221 io_object_t pObject;
222
223 int nCount = 0;
224
225 while ( (pObject = IOIteratorNext(pIterator)) != 0)
226 ++nCount;
227
228 //iterator cleanup
229 IOObjectRelease(pIterator);
230
231 return nCount;
232 }//end Create()
233
234 void wxHIDDevice::AddCookie(CFTypeRef Data, int i)
235 {
236 CFNumberGetValue(
237 (CFNumberRef) CFDictionaryGetValue ( (CFDictionaryRef) Data
238 , CFSTR(kIOHIDElementCookieKey)
239 ),
240 kCFNumberIntType,
241 &m_pCookies[i]
242 );
243 }
244
245 void wxHIDDevice::AddCookieInQueue(CFTypeRef Data, int i)
246 {
247 AddCookie(Data, i);
248 wxVERIFY((*m_ppQueue)->addElement(m_ppQueue, m_pCookies[i], 0) == S_OK);//3rd Param flags (none yet)
249 }
250
251 void wxHIDDevice::InitCookies(size_t dwSize, bool bQueue)
252 {
253 m_pCookies = new IOHIDElementCookie[dwSize];
254 if (bQueue)
255 {
256 wxASSERT( m_ppQueue == NULL);
257 wxVERIFY( (m_ppQueue = (*m_ppDevice)->allocQueue(m_ppDevice)) != NULL);
258 wxVERIFY( (*m_ppQueue)->create(m_ppQueue, 0, 512) == S_OK); //Param 2, flags, none yet
259 }
260 }
261
262 bool wxHIDDevice::IsActive(int nIndex)
263 {
264 wxASSERT(m_pCookies[nIndex] != NULL);
265 IOHIDEventStruct Event;
266 (*m_ppDevice)->getElementValue(m_ppDevice, m_pCookies[nIndex], &Event);
267 return !!Event.value;
268 }
269
270 bool wxHIDDevice::HasElement(int nIndex)
271 {
272 return m_pCookies[nIndex] != NULL;
273 }
274
275 wxHIDDevice::~wxHIDDevice()
276 {
277 if (m_ppDevice != NULL)
278 {
279 if (m_ppQueue != NULL)
280 {
281 (*m_ppQueue)->stop(m_ppQueue);
282 (*m_ppQueue)->dispose(m_ppQueue);
283 (*m_ppQueue)->Release(m_ppQueue);
284 }
285 (*m_ppDevice)->close(m_ppDevice);
286 (*m_ppDevice)->Release(m_ppDevice);
287 mach_port_deallocate(mach_task_self(), m_pPort);
288 }
289
290 if (m_pCookies != NULL)
291 {
292 delete [] m_pCookies;
293 }
294 }
295
296 // ---------------------------------------------------------------------------
297 // wxHIDKeyboard
298 // ---------------------------------------------------------------------------
299
300 enum
301 {
302 WXK_RSHIFT = 400,
303 WXK_RALT,
304 WXK_RCONTROL,
305 WXK_RMENU
306
307 };
308
309 bool wxHIDKeyboard::Create()
310 {
311 return wxHIDDevice::Create(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard);
312 }
313
314 void wxHIDKeyboard::BuildCookies(wxCFArray& Array)
315 {
316 Array = CFDictionaryGetValue((CFDictionaryRef)Array[0], CFSTR(kIOHIDElementKey));
317 InitCookies(500);
318 int i,
319 nUsage;
320 for (i = 0; i < Array.Count(); ++i)
321 {
322 CFNumberGetValue(
323 (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) Array[i], CFSTR(kIOHIDElementUsageKey)),
324 kCFNumberLongType, &nUsage);
325
326 if (nUsage >= kHIDUsage_KeyboardA && nUsage <= kHIDUsage_KeyboardZ)
327 AddCookie(Array[i], 'A' + (nUsage - kHIDUsage_KeyboardA) );
328 else if (nUsage >= kHIDUsage_Keyboard1 && nUsage <= kHIDUsage_Keyboard9)
329 AddCookie(Array[i], '1' + (nUsage - kHIDUsage_Keyboard1) );
330 else if (nUsage >= kHIDUsage_KeyboardF1 && nUsage <= kHIDUsage_KeyboardF12)
331 AddCookie(Array[i], WXK_F1 + (nUsage - kHIDUsage_KeyboardF1) );
332 else if (nUsage >= kHIDUsage_KeyboardF13 && nUsage <= kHIDUsage_KeyboardF24)
333 AddCookie(Array[i], WXK_F13 + (nUsage - kHIDUsage_KeyboardF13) );
334 else if (nUsage >= kHIDUsage_Keypad1 && nUsage <= kHIDUsage_Keypad9)
335 AddCookie(Array[i], WXK_NUMPAD1 + (nUsage - kHIDUsage_Keypad1) );
336 else switch (nUsage)
337 {
338 //0's (wx & ascii go 0-9, but HID goes 1-0)
339 case kHIDUsage_Keyboard0:
340 AddCookie(Array[i],'0');
341 break;
342 case kHIDUsage_Keypad0:
343 AddCookie(Array[i],WXK_NUMPAD0);
344 break;
345
346 //Basic
347 case kHIDUsage_KeyboardReturnOrEnter:
348 AddCookie(Array[i], WXK_RETURN);
349 break;
350 case kHIDUsage_KeyboardEscape:
351 AddCookie(Array[i], WXK_ESCAPE);
352 break;
353 case kHIDUsage_KeyboardDeleteOrBackspace:
354 AddCookie(Array[i], WXK_BACK);
355 break;
356 case kHIDUsage_KeyboardTab:
357 AddCookie(Array[i], WXK_TAB);
358 break;
359 case kHIDUsage_KeyboardSpacebar:
360 AddCookie(Array[i], WXK_SPACE);
361 break;
362 case kHIDUsage_KeyboardPageUp:
363 AddCookie(Array[i], WXK_PRIOR);
364 break;
365 case kHIDUsage_KeyboardEnd:
366 AddCookie(Array[i], WXK_END);
367 break;
368 case kHIDUsage_KeyboardPageDown:
369 AddCookie(Array[i], WXK_NEXT);
370 break;
371 case kHIDUsage_KeyboardRightArrow:
372 AddCookie(Array[i], WXK_RIGHT);
373 break;
374 case kHIDUsage_KeyboardLeftArrow:
375 AddCookie(Array[i], WXK_LEFT);
376 break;
377 case kHIDUsage_KeyboardDownArrow:
378 AddCookie(Array[i], WXK_DOWN);
379 break;
380 case kHIDUsage_KeyboardUpArrow:
381 AddCookie(Array[i], WXK_UP);
382 break;
383
384 //LEDS
385 case kHIDUsage_KeyboardCapsLock:
386 AddCookie(Array[i],WXK_CAPITAL);
387 break;
388 case kHIDUsage_KeypadNumLock:
389 AddCookie(Array[i],WXK_NUMLOCK);
390 break;
391 case kHIDUsage_KeyboardScrollLock:
392 AddCookie(Array[i],WXK_SCROLL);
393 break;
394
395 //Menu keys, Shift, other specials
396 case kHIDUsage_KeyboardLeftControl:
397 AddCookie(Array[i],WXK_CONTROL);
398 break;
399 case kHIDUsage_KeyboardLeftShift:
400 AddCookie(Array[i],WXK_SHIFT);
401 break;
402 case kHIDUsage_KeyboardLeftAlt:
403 AddCookie(Array[i],WXK_ALT);
404 break;
405 case kHIDUsage_KeyboardLeftGUI:
406 AddCookie(Array[i],WXK_MENU);
407 break;
408 case kHIDUsage_KeyboardRightControl:
409 AddCookie(Array[i],WXK_RCONTROL);
410 break;
411 case kHIDUsage_KeyboardRightShift:
412 AddCookie(Array[i],WXK_RSHIFT);
413 break;
414 case kHIDUsage_KeyboardRightAlt:
415 AddCookie(Array[i],WXK_RALT);
416 break;
417 case kHIDUsage_KeyboardRightGUI:
418 AddCookie(Array[i],WXK_RMENU);
419 break;
420
421 //Default
422 default:
423 //not in wx keycodes - do nothing....
424 break;
425 }
426 }
427 }//end buildcookies
428
429 //
430 // wxGetKeyState
431 //
432
433 #include "wx/utils.h"
434 #include "wx/module.h"
435
436 class wxHIDModule : public wxModule
437 {
438 DECLARE_DYNAMIC_CLASS(wxHIDModule)
439
440 public:
441 static wxHIDKeyboard* sm_keyboard;
442
443 virtual bool OnInit()
444 {
445 sm_keyboard = NULL;
446 return true;
447 }
448 virtual void OnExit()
449 {
450 if (sm_keyboard)
451 delete sm_keyboard;
452 }
453 };
454
455 IMPLEMENT_DYNAMIC_CLASS(wxHIDModule, wxModule)
456
457 wxHIDKeyboard* wxHIDModule::sm_keyboard;
458
459 bool wxGetKeyState (wxKeyCode key)
460 {
461 if (!wxHIDModule::sm_keyboard)
462 {
463 wxHIDModule::sm_keyboard = new wxHIDKeyboard();
464 bool bOK = wxHIDModule::sm_keyboard->Create();
465 wxASSERT(bOK);
466 if(!bOK)
467 {
468 delete wxHIDModule::sm_keyboard;
469 wxHIDModule::sm_keyboard = NULL;
470 return false;
471 }
472 }
473
474 return wxHIDModule::sm_keyboard->IsActive(key);
475 }
476
477 #endif //__DARWIN__