]> git.saurik.com Git - wxWidgets.git/blame - src/mac/corefoundation/hid.cpp
Fix for modal/modeless wizards
[wxWidgets.git] / src / mac / corefoundation / hid.cpp
CommitLineData
ec8bd392
RN
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
1553abf4
RN
12// ===========================================================================
13// declarations
14// ===========================================================================
15
16// ---------------------------------------------------------------------------
17// headers
18// ---------------------------------------------------------------------------
19
3d1a4878 20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
1553abf4
RN
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
ec8bd392
RN
31//DARWIN _ONLY_
32#ifdef __DARWIN__
33
4cb1d3da 34#include "wx/mac/corefoundation/hid.h"
ec8bd392
RN
35#include "wx/string.h"
36#include "wx/log.h"
65442ab6 37#include "wx/mac/corefoundation/cfstring.h"
7f71c4c8 38
1553abf4
RN
39
40// ---------------------------------------------------------------------------
41// assertion macros
42// ---------------------------------------------------------------------------
43
7f71c4c8
RN
44#define wxFORCECHECK_MSG(arg, msg) \
45{\
26dfc728
VZ
46 if (arg) \
47 {\
48 wxLogSysError(wxString::Format(wxT("Message:%s\nHID: %s failed!"), wxT(msg), wxT(#arg)));\
49 return false;\
50 }\
7f71c4c8
RN
51}
52#define wxIOCHECK(arg, msg) wxFORCECHECK_MSG(arg != kIOReturnSuccess, msg)
53#define wxKERNCHECK(arg, msg) wxFORCECHECK_MSG(arg != KERN_SUCCESS, msg)
54#define wxSCHECK(arg, msg) wxFORCECHECK_MSG(arg != S_OK, msg)
55
ec8bd392 56/*
7f71c4c8
RN
57void CFShowTypeIDDescription(CFTypeRef pData)
58{
26dfc728
VZ
59 if(!pData)
60 {
61 wxASSERT(false);
62 return;
63 }
64
65 wxMessageBox(
66 CFStringGetCStringPtr(
67 CFCopyTypeIDDescription(CFGetTypeID(pData)),CFStringGetSystemEncoding()
68 )
69 );
7f71c4c8 70}
ec8bd392 71*/
7f71c4c8
RN
72
73// ============================================================================
74// implementation
75// ============================================================================
76
1553abf4
RN
77// ---------------------------------------------------------------------------
78// wxHIDDevice
79// ---------------------------------------------------------------------------
7f71c4c8 80
4cb1d3da 81bool wxHIDDevice::Create (int nClass, int nType, int nDev)
7f71c4c8 82{
26dfc728
VZ
83 //Create the mach port
84 wxIOCHECK(IOMasterPort(bootstrap_port, &m_pPort), "Could not create mach port");
85
86 //Dictionary that will hold first
87 //the matching dictionary for determining which kind of devices we want,
88 //then later some registry properties from an iterator (see below)
a8ee8060 89 //
26dfc728
VZ
90 //The call to IOServiceMatching filters down the
91 //the services we want to hid services (and also eats the
92 //dictionary up for us (consumes one reference))
a8ee8060
VZ
93 CFMutableDictionaryRef pDictionary = IOServiceMatching(kIOHIDDeviceKey);
94 wxCHECK_MSG( pDictionary, false,
95 _T("IOServiceMatching(kIOHIDDeviceKey) failed") );
96
97 wxASSERT( pDictionary );
26dfc728
VZ
98
99 //Here we'll filter down the services to what we want
100 if (nType != -1)
101 {
102 CFNumberRef pType = CFNumberCreate(kCFAllocatorDefault,
103 kCFNumberIntType, &nType);
104 CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsageKey), pType);
105 CFRelease(pType);
106 }
107 if (nClass != -1)
108 {
109 CFNumberRef pClass = CFNumberCreate(kCFAllocatorDefault,
110 kCFNumberIntType, &nClass);
111 CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsagePageKey), pClass);
112 CFRelease(pClass);
113 }
114
115 //Now get the maching services
116 io_iterator_t pIterator;
117 wxIOCHECK(IOServiceGetMatchingServices(m_pPort, pDictionary, &pIterator), "No Matching HID Services");
118 wxASSERT_MSG(pIterator != 0, wxT("No devices found!"));
119
120 //Now we iterate through them
121 io_object_t pObject;
122 while ( (pObject = IOIteratorNext(pIterator)) != 0)
123 {
4cb1d3da
RN
124 if(--nDev != 0)
125 continue;
7f71c4c8 126
a8ee8060
VZ
127 if ( IORegistryEntryCreateCFProperties
128 (
129 pObject,
130 &pDictionary,
131 kCFAllocatorDefault,
132 kNilOptions
133 ) != KERN_SUCCESS )
134 {
135 wxLogDebug(_T("IORegistryEntryCreateCFProperties failed"));
136 }
26dfc728
VZ
137
138 //Just for sanity :)
139 wxASSERT(CFGetTypeID(CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey))) == CFStringGetTypeID());
140
65442ab6
RN
141/*
142 kIOHIDTransportKey;
143 kIOHIDVendorIDKey;
144 kIOHIDProductIDKey;
145 kIOHIDVersionNumberKey;
146 kIOHIDManufacturerKey;
147 kIOHIDSerialNumberKey;
148 if !kIOHIDLocationIDKey
149 kUSBDevicePropertyLocationID
150 kIOHIDPrimaryUsageKey
151kIOHIDPrimaryUsagePageKey
152idProduct
153idVendor
154USB Product Name
155*/
26dfc728
VZ
156 //Get [product] name
157 m_szProductName = wxMacCFStringHolder( (CFStringRef) CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey)), false ).AsString();
158
2ff29ddf 159 CFNumberRef nref = (CFNumberRef) CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductIDKey));
26dfc728 160
2ff29ddf
RN
161 if (nref)
162 CFNumberGetValue(
26dfc728
VZ
163 nref,
164 kCFNumberIntType,
65442ab6 165 &m_nProductId
26dfc728 166 );
65442ab6 167
2ff29ddf
RN
168 nref = (CFNumberRef) CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDVendorIDKey));
169 if (nref)
26dfc728
VZ
170 CFNumberGetValue(
171 nref,
172 kCFNumberIntType,
65442ab6 173 &m_nManufacturerId
26dfc728
VZ
174 );
175
176 //Create the interface (good grief - long function names!)
177 SInt32 nScore;
178 IOCFPlugInInterface** ppPlugin;
179 wxIOCHECK(IOCreatePlugInInterfaceForService(pObject, kIOHIDDeviceUserClientTypeID,
180 kIOCFPlugInInterfaceID, &ppPlugin, &nScore), "");
181
182 //Now, the final thing we can check before we fall back to asserts
183 //(because the dtor only checks if the device is ok, so if anything
184 //fails from now on the dtor will delete the device anyway, so we can't break from this).
185
186 //Get the HID interface from the plugin to the mach port
187 wxSCHECK((*ppPlugin)->QueryInterface(ppPlugin,
188 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (void**) &m_ppDevice), "");
189
190 //release the plugin
191 (*ppPlugin)->Release(ppPlugin);
192
193 //open the HID interface...
a8ee8060
VZ
194 if ( (*m_ppDevice)->open(m_ppDevice, 0) != S_OK )
195 wxLogDebug(_T("HID device: open failed"));
26dfc728
VZ
196
197 //
198 //Now the hard part - in order to scan things we need "cookies" -
199 //
200 wxCFArray CookieArray = CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDElementKey));
201 BuildCookies(CookieArray);
202
203 //cleanup
204 CFRelease(pDictionary);
205 IOObjectRelease(pObject);
206 break;
207 }
208 //iterator cleanup
209 IOObjectRelease(pIterator);
210
211 return true;
7f71c4c8 212}//end Create()
26dfc728 213
4cb1d3da
RN
214int wxHIDDevice::GetCount (int nClass, int nType)
215{
26dfc728
VZ
216 mach_port_t m_pPort;
217
218 //Create the mach port
219 wxIOCHECK(IOMasterPort(bootstrap_port, &m_pPort), "Could not create mach port");
220
221 //Dictionary that will hold first
222 //the matching dictionary for determining which kind of devices we want,
223 //then later some registry properties from an iterator (see below)
a8ee8060
VZ
224 CFMutableDictionaryRef pDictionary = IOServiceMatching(kIOHIDDeviceKey);
225 wxCHECK_MSG( pDictionary, 0,
226 _T("IOServiceMatching(kIOHIDDeviceKey) failed") );
26dfc728
VZ
227
228 //Here we'll filter down the services to what we want
229 if (nType != -1)
230 {
231 CFNumberRef pType = CFNumberCreate(kCFAllocatorDefault,
232 kCFNumberIntType, &nType);
233 CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsageKey), pType);
234 CFRelease(pType);
235 }
236 if (nClass != -1)
237 {
238 CFNumberRef pClass = CFNumberCreate(kCFAllocatorDefault,
239 kCFNumberIntType, &nClass);
240 CFDictionarySetValue(pDictionary, CFSTR(kIOHIDPrimaryUsagePageKey), pClass);
241 CFRelease(pClass);
242 }
243
244 //Now get the maching services
245 io_iterator_t pIterator;
246 wxIOCHECK(IOServiceGetMatchingServices(m_pPort, pDictionary, &pIterator), "No Matching HID Services");
247
a8ee8060 248 if ( !pIterator )
65442ab6 249 return 0;
4cb1d3da 250
26dfc728
VZ
251 //Now we iterate through them
252 io_object_t pObject;
253
4cb1d3da 254 int nCount = 0;
26dfc728
VZ
255
256 while ( (pObject = IOIteratorNext(pIterator)) != 0)
4cb1d3da 257 ++nCount;
26dfc728 258
4cb1d3da 259 //iterator cleanup
26dfc728
VZ
260 IOObjectRelease(pIterator);
261
262 return nCount;
4cb1d3da
RN
263}//end Create()
264
265void wxHIDDevice::AddCookie(CFTypeRef Data, int i)
7f71c4c8 266{
26dfc728
VZ
267 CFNumberGetValue(
268 (CFNumberRef) CFDictionaryGetValue ( (CFDictionaryRef) Data
269 , CFSTR(kIOHIDElementCookieKey)
270 ),
271 kCFNumberIntType,
272 &m_pCookies[i]
273 );
7f71c4c8
RN
274}
275
4cb1d3da 276void wxHIDDevice::AddCookieInQueue(CFTypeRef Data, int i)
7f71c4c8 277{
a8ee8060 278 //3rd Param flags (none yet)
26dfc728 279 AddCookie(Data, i);
a8ee8060
VZ
280 if ( (*m_ppQueue)->addElement(m_ppQueue, m_pCookies[i], 0) != S_OK )
281 wxLogDebug(_T("HID device: adding element failed"));
7f71c4c8 282}
26dfc728 283
4cb1d3da 284void wxHIDDevice::InitCookies(size_t dwSize, bool bQueue)
7f71c4c8 285{
26dfc728
VZ
286 m_pCookies = new IOHIDElementCookie[dwSize];
287 if (bQueue)
288 {
289 wxASSERT( m_ppQueue == NULL);
a8ee8060
VZ
290 m_ppQueue = (*m_ppDevice)->allocQueue(m_ppDevice);
291 if ( !m_ppQueue )
292 {
293 wxLogDebug(_T("HID device: allocQueue failed"));
294 return;
295 }
296
297 //Param 2, flags, none yet
298 if ( (*m_ppQueue)->create(m_ppQueue, 0, 512) != S_OK )
299 {
300 wxLogDebug(_T("HID device: create failed"));
301 }
26dfc728 302 }
7f71c4c8
RN
303}
304
4cb1d3da 305bool wxHIDDevice::IsActive(int nIndex)
7f71c4c8 306{
26dfc728
VZ
307 wxASSERT(m_pCookies[nIndex] != NULL);
308 IOHIDEventStruct Event;
309 (*m_ppDevice)->getElementValue(m_ppDevice, m_pCookies[nIndex], &Event);
09d27083
RN
310/*
311 wxString ss;
312 ss << _T("[") << (int) m_pCookies[nIndex] << _T("] = ") << Event.value << _T(" SIZE:") << Event.longValueSize;
26dfc728 313
09d27083
RN
314 wxLogDebug(ss);
315*/
26dfc728 316 return !!Event.value;
7f71c4c8 317}
26dfc728 318
4cb1d3da
RN
319bool wxHIDDevice::HasElement(int nIndex)
320{
321 return m_pCookies[nIndex] != NULL;
322}
7f71c4c8
RN
323
324wxHIDDevice::~wxHIDDevice()
325{
26dfc728
VZ
326 if (m_ppDevice != NULL)
327 {
328 if (m_ppQueue != NULL)
329 {
330 (*m_ppQueue)->stop(m_ppQueue);
331 (*m_ppQueue)->dispose(m_ppQueue);
332 (*m_ppQueue)->Release(m_ppQueue);
333 }
334 (*m_ppDevice)->close(m_ppDevice);
335 (*m_ppDevice)->Release(m_ppDevice);
336 mach_port_deallocate(mach_task_self(), m_pPort);
337 }
338
339 if (m_pCookies != NULL)
340 {
341 delete [] m_pCookies;
342 }
7f71c4c8 343}
7f71c4c8 344
1553abf4
RN
345// ---------------------------------------------------------------------------
346// wxHIDKeyboard
347// ---------------------------------------------------------------------------
348
7f71c4c8
RN
349enum
350{
26dfc728
VZ
351 WXK_RSHIFT = 400,
352 WXK_RALT,
353 WXK_RCONTROL,
354 WXK_RMENU
355
7f71c4c8
RN
356};
357
358bool wxHIDKeyboard::Create()
359{
26dfc728 360 return wxHIDDevice::Create(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard);
7f71c4c8
RN
361}
362
363void wxHIDKeyboard::BuildCookies(wxCFArray& Array)
364{
26dfc728
VZ
365 Array = CFDictionaryGetValue((CFDictionaryRef)Array[0], CFSTR(kIOHIDElementKey));
366 InitCookies(500);
367 int i,
368 nUsage;
09d27083 369 bool bEOTriggered = false;
26dfc728
VZ
370 for (i = 0; i < Array.Count(); ++i)
371 {
372 CFNumberGetValue(
373 (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) Array[i], CFSTR(kIOHIDElementUsageKey)),
374 kCFNumberLongType, &nUsage);
375
09d27083 376 //
26dfc728 377 // OK, this is strange - basically this kind of strange -
09d27083
RN
378 // Starting from 0xEO these elements (like shift) appear twice in
379 // the array! The ones at the end are bogus I guess - the funny part
380 // is that besides the fact that the ones at the front have a Unit
381 // and UnitExponent key with a value of 0 and a different cookie value,
26dfc728 382 // there is no discernable difference between the two...
09d27083
RN
383 //
384 // Will the real shift please stand up?
385 //
386 // Something to spend a support request on, if I had one, LOL.
387 //
388 if(nUsage == 0xE0)
389 {
390 if(bEOTriggered)
391 break;
392 bEOTriggered = true;
393 }
394/*
395 wxString msg;
396 int cookie;
26dfc728
VZ
397 CFNumberGetValue(
398 (CFNumberRef) CFDictionaryGetValue ( (CFDictionaryRef) Array[i]
399 , CFSTR(kIOHIDElementCookieKey)
400 ),
401 kCFNumberIntType,
402 &cookie
403 );
09d27083
RN
404
405 msg << wxT("KEY:") << nUsage << wxT("COOKIE:") << cookie;
26dfc728 406 wxLogDebug(msg);
09d27083
RN
407*/
408
26dfc728
VZ
409 if (nUsage >= kHIDUsage_KeyboardA && nUsage <= kHIDUsage_KeyboardZ)
410 AddCookie(Array[i], 'A' + (nUsage - kHIDUsage_KeyboardA) );
411 else if (nUsage >= kHIDUsage_Keyboard1 && nUsage <= kHIDUsage_Keyboard9)
412 AddCookie(Array[i], '1' + (nUsage - kHIDUsage_Keyboard1) );
413 else if (nUsage >= kHIDUsage_KeyboardF1 && nUsage <= kHIDUsage_KeyboardF12)
414 AddCookie(Array[i], WXK_F1 + (nUsage - kHIDUsage_KeyboardF1) );
415 else if (nUsage >= kHIDUsage_KeyboardF13 && nUsage <= kHIDUsage_KeyboardF24)
416 AddCookie(Array[i], WXK_F13 + (nUsage - kHIDUsage_KeyboardF13) );
417 else if (nUsage >= kHIDUsage_Keypad1 && nUsage <= kHIDUsage_Keypad9)
418 AddCookie(Array[i], WXK_NUMPAD1 + (nUsage - kHIDUsage_Keypad1) );
419 else switch (nUsage)
420 {
421 //0's (wx & ascii go 0-9, but HID goes 1-0)
422 case kHIDUsage_Keyboard0:
423 AddCookie(Array[i],'0');
424 break;
425 case kHIDUsage_Keypad0:
426 AddCookie(Array[i],WXK_NUMPAD0);
427 break;
428
429 //Basic
430 case kHIDUsage_KeyboardReturnOrEnter:
431 AddCookie(Array[i], WXK_RETURN);
432 break;
433 case kHIDUsage_KeyboardEscape:
434 AddCookie(Array[i], WXK_ESCAPE);
435 break;
436 case kHIDUsage_KeyboardDeleteOrBackspace:
437 AddCookie(Array[i], WXK_BACK);
438 break;
439 case kHIDUsage_KeyboardTab:
440 AddCookie(Array[i], WXK_TAB);
441 break;
442 case kHIDUsage_KeyboardSpacebar:
443 AddCookie(Array[i], WXK_SPACE);
444 break;
445 case kHIDUsage_KeyboardPageUp:
446 AddCookie(Array[i], WXK_PRIOR);
447 break;
448 case kHIDUsage_KeyboardEnd:
449 AddCookie(Array[i], WXK_END);
450 break;
451 case kHIDUsage_KeyboardPageDown:
452 AddCookie(Array[i], WXK_NEXT);
453 break;
454 case kHIDUsage_KeyboardRightArrow:
455 AddCookie(Array[i], WXK_RIGHT);
456 break;
457 case kHIDUsage_KeyboardLeftArrow:
458 AddCookie(Array[i], WXK_LEFT);
459 break;
460 case kHIDUsage_KeyboardDownArrow:
461 AddCookie(Array[i], WXK_DOWN);
462 break;
463 case kHIDUsage_KeyboardUpArrow:
464 AddCookie(Array[i], WXK_UP);
465 break;
466
467 //LEDS
468 case kHIDUsage_KeyboardCapsLock:
469 AddCookie(Array[i],WXK_CAPITAL);
470 break;
471 case kHIDUsage_KeypadNumLock:
472 AddCookie(Array[i],WXK_NUMLOCK);
473 break;
474 case kHIDUsage_KeyboardScrollLock:
475 AddCookie(Array[i],WXK_SCROLL);
476 break;
477
478 //Menu keys, Shift, other specials
479 case kHIDUsage_KeyboardLeftControl:
480 AddCookie(Array[i],WXK_CONTROL);
481 break;
482 case kHIDUsage_KeyboardLeftShift:
483 AddCookie(Array[i],WXK_SHIFT);
484 break;
485 case kHIDUsage_KeyboardLeftAlt:
486 AddCookie(Array[i],WXK_ALT);
487 break;
488 case kHIDUsage_KeyboardLeftGUI:
489 AddCookie(Array[i],WXK_MENU);
490 break;
491 case kHIDUsage_KeyboardRightControl:
492 AddCookie(Array[i],WXK_RCONTROL);
493 break;
494 case kHIDUsage_KeyboardRightShift:
495 AddCookie(Array[i],WXK_RSHIFT);
496 break;
497 case kHIDUsage_KeyboardRightAlt:
498 AddCookie(Array[i],WXK_RALT);
499 break;
500 case kHIDUsage_KeyboardRightGUI:
501 AddCookie(Array[i],WXK_RMENU);
502 break;
503
504 //Default
505 default:
506 //not in wx keycodes - do nothing....
507 break;
508 }
509 }
7f71c4c8 510}//end buildcookies
ec8bd392 511
4cb1d3da
RN
512//
513// wxGetKeyState
514//
515
516#include "wx/utils.h"
517#include "wx/module.h"
518
519class wxHIDModule : public wxModule
520{
521 DECLARE_DYNAMIC_CLASS(wxHIDModule)
26dfc728 522
4cb1d3da
RN
523 public:
524 static wxHIDKeyboard* sm_keyboard;
26dfc728 525
4cb1d3da
RN
526 virtual bool OnInit()
527 {
528 sm_keyboard = NULL;
529 return true;
530 }
531 virtual void OnExit()
532 {
533 if (sm_keyboard)
534 delete sm_keyboard;
535 }
536};
537
538IMPLEMENT_DYNAMIC_CLASS(wxHIDModule, wxModule)
539
540wxHIDKeyboard* wxHIDModule::sm_keyboard;
541
542bool wxGetKeyState (wxKeyCode key)
543{
44353523
VZ
544 wxASSERT_MSG(key != WXK_LBUTTON && key != WXK_RBUTTON && key !=
545 WXK_MBUTTON, wxT("can't use wxGetKeyState() for mouse buttons"));
546
4cb1d3da
RN
547 if (!wxHIDModule::sm_keyboard)
548 {
549 wxHIDModule::sm_keyboard = new wxHIDKeyboard();
550 bool bOK = wxHIDModule::sm_keyboard->Create();
551 wxASSERT(bOK);
552 if(!bOK)
553 {
554 delete wxHIDModule::sm_keyboard;
555 wxHIDModule::sm_keyboard = NULL;
556 return false;
557 }
558 }
26dfc728 559
09d27083
RN
560 switch(key)
561 {
562 case WXK_SHIFT:
563 return wxHIDModule::sm_keyboard->IsActive(WXK_SHIFT) ||
564 wxHIDModule::sm_keyboard->IsActive(WXK_RSHIFT);
565 break;
26dfc728 566 case WXK_ALT:
09d27083
RN
567 return wxHIDModule::sm_keyboard->IsActive(WXK_ALT) ||
568 wxHIDModule::sm_keyboard->IsActive(WXK_RALT);
569 break;
26dfc728 570 case WXK_CONTROL:
09d27083
RN
571 return wxHIDModule::sm_keyboard->IsActive(WXK_CONTROL) ||
572 wxHIDModule::sm_keyboard->IsActive(WXK_RCONTROL);
573 break;
26dfc728 574 case WXK_MENU:
09d27083
RN
575 return wxHIDModule::sm_keyboard->IsActive(WXK_MENU) ||
576 wxHIDModule::sm_keyboard->IsActive(WXK_RMENU);
577 break;
578 default:
579 return wxHIDModule::sm_keyboard->IsActive(key);
580 break;
581 }
4cb1d3da
RN
582}
583
ec8bd392 584#endif //__DARWIN__