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