]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/hid.cpp
Patch by David Brinegar to fix menubar updating after modal dialog shown
[wxWidgets.git] / src / mac / carbon / 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
34#include "wx/mac/carbon/private/hid.h"
35#include "wx/string.h"
36#include "wx/log.h"
7f71c4c8 37
1553abf4
RN
38
39// ---------------------------------------------------------------------------
40// assertion macros
41// ---------------------------------------------------------------------------
42
7f71c4c8
RN
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
ec8bd392
RN
55#ifdef __WXDEBUG___
56# define wxVERIFY(arg) wxASSERT(arg)
57#else
58# define wxVERIFY(arg) arg
59#endif
60
61/*
7f71c4c8
RN
62void CFShowTypeIDDescription(CFTypeRef pData)
63{
64 if(!pData)
65 {
ec8bd392 66 wxASSERT(false);
7f71c4c8
RN
67 return;
68 }
69
70 wxMessageBox(
71 CFStringGetCStringPtr(
72 CFCopyTypeIDDescription(CFGetTypeID(pData)),CFStringGetSystemEncoding()
73 )
74 );
75}
ec8bd392 76*/
7f71c4c8
RN
77
78// ============================================================================
79// implementation
80// ============================================================================
81
1553abf4
RN
82// ---------------------------------------------------------------------------
83// wxHIDDevice
84// ---------------------------------------------------------------------------
7f71c4c8
RN
85
86bool wxHIDDevice::Create (const int& nClass, const int& nType)
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))
ec8bd392 100 wxVERIFY((pDictionary = IOServiceMatching(kIOHIDDeviceKey)) != NULL );
7f71c4c8
RN
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");
b409fa19 121 wxASSERT(pIterator != 0);
7f71c4c8
RN
122
123 //Now we iterate through them
124 io_object_t pObject;
b409fa19 125 while ( (pObject = IOIteratorNext(pIterator)) != 0)
7f71c4c8 126 {
ec8bd392 127 wxVERIFY(IORegistryEntryCreateCFProperties(pObject, &pDictionary,
7f71c4c8
RN
128 kCFAllocatorDefault, kNilOptions) == KERN_SUCCESS);
129
130 //Just for sanity :)
342689c8 131 wxASSERT(CFGetTypeID(CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey))) == CFStringGetTypeID());
7f71c4c8
RN
132
133 //Get [product] name
134 m_szName = CFStringGetCStringPtr (
135 (CFStringRef) CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDProductKey)),
136 CFStringGetSystemEncoding()
137 );
138
139 //
140 //Now the hard part - in order to scan things we need "cookies" -
141 //
142 wxCFArray CookieArray = CFDictionaryGetValue(pDictionary, CFSTR(kIOHIDElementKey));
143 BuildCookies(CookieArray);
144 if (m_ppQueue != NULL)
ec8bd392 145 wxVERIFY((*m_ppQueue)->start(m_ppQueue) == S_OK);
7f71c4c8
RN
146
147 //Create the interface (good grief - long function names!)
148 SInt32 nScore;
149 IOCFPlugInInterface** ppPlugin;
150 wxIOCHECK(IOCreatePlugInInterfaceForService(pObject, kIOHIDDeviceUserClientTypeID,
151 kIOCFPlugInInterfaceID, &ppPlugin, &nScore), "");
152
153 //Now, the final thing we can check before we fall back to asserts
154 //(because the dtor only checks if the device is ok, so if anything
155 //fails from now on the dtor will delete the device anyway, so we can't break from this).
156
157 //Get the HID interface from the plugin to the mach port
158 wxSCHECK((*ppPlugin)->QueryInterface(ppPlugin,
159 CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (void**) &m_ppDevice), "");
160
161 //release the plugin
162 (*ppPlugin)->Release(ppPlugin);
163
164 //open the HID interface...
ec8bd392 165 wxVERIFY((*m_ppDevice)->open(m_ppDevice, 0) == S_OK);
7f71c4c8
RN
166
167 //cleanup
168 CFRelease(pDictionary);
169 IOObjectRelease(pObject);
170 break;
171 }
172 //iterator cleanup
173 IOObjectRelease(pIterator);
174
175 return true;
176}//end Create()
177
178void wxHIDDevice::AddCookie(CFTypeRef Data, const int& i)
179{
180 CFNumberGetValue(
181 (CFNumberRef) CFDictionaryGetValue ( (CFDictionaryRef) Data
182 , CFSTR(kIOHIDElementCookieKey)
183 ),
184 kCFNumberIntType,
185 &m_pCookies[i]
186 );
187}
188
189void wxHIDDevice::AddCookieInQueue(CFTypeRef Data, const int& i)
190{
191 AddCookie(Data, i);
ec8bd392 192 wxVERIFY((*m_ppQueue)->addElement(m_ppQueue, m_pCookies[i], 0) == S_OK);//3rd Param flags (none yet)
7f71c4c8
RN
193}
194
195void wxHIDDevice::InitCookies(const size_t& dwSize, bool bQueue)
196{
197 m_pCookies = new IOHIDElementCookie[dwSize];
198 if (bQueue)
199 {
200 wxASSERT( m_ppQueue != NULL);
ec8bd392
RN
201 wxVERIFY( (m_ppQueue = (*m_ppDevice)->allocQueue(m_ppDevice)) != NULL);
202 wxVERIFY( (*m_ppQueue)->create(m_ppQueue, 0, 512) == S_OK); //Param 2, flags, none yet
7f71c4c8
RN
203 }
204}
205
206bool wxHIDDevice::IsActive(const int& nIndex)
207{
208 wxASSERT(m_pCookies[nIndex] != NULL);
209 IOHIDEventStruct Event;
210 (*m_ppDevice)->getElementValue(m_ppDevice, m_pCookies[nIndex], &Event);
211 return !!Event.value;
212}
213
214
215wxHIDDevice::~wxHIDDevice()
216{
217 if (m_ppDevice != NULL)
218 {
219 (*m_ppDevice)->close(m_ppDevice);
220 (*m_ppDevice)->Release(m_ppDevice);
221 mach_port_deallocate(mach_task_self(), m_pPort);
222 }
223
224 if (m_pCookies != NULL)
225 {
226 delete [] m_pCookies;
227 if (m_ppQueue != NULL)
228 {
229 (*m_ppQueue)->stop(m_ppQueue);
230 (*m_ppQueue)->dispose(m_ppQueue);
231 (*m_ppQueue)->Release(m_ppQueue);
232 }
233 }
234}
7f71c4c8 235
1553abf4
RN
236// ---------------------------------------------------------------------------
237// wxHIDKeyboard
238// ---------------------------------------------------------------------------
239
7f71c4c8
RN
240enum
241{
242 WXK_RSHIFT = 400,
243 WXK_RALT,
244 WXK_RCONTROL,
245 WXK_RMENU
246
247};
248
249bool wxHIDKeyboard::Create()
250{
251 return wxHIDDevice::Create(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard);
252}
253
254void wxHIDKeyboard::BuildCookies(wxCFArray& Array)
255{
256 Array = CFDictionaryGetValue((CFDictionaryRef)Array[0], CFSTR(kIOHIDElementKey));
257 InitCookies(500);
258 int i,
259 nUsage;
260 for (i = 0; i < Array.Count(); ++i)
261 {
262 CFNumberGetValue(
263 (CFNumberRef) CFDictionaryGetValue((CFDictionaryRef) Array[i], CFSTR(kIOHIDElementUsageKey)),
264 kCFNumberLongType, &nUsage);
265
266 if (nUsage >= kHIDUsage_KeyboardA && nUsage <= kHIDUsage_KeyboardZ)
267 AddCookie(Array[i], 'A' + (nUsage - kHIDUsage_KeyboardA) );
268 else if (nUsage >= kHIDUsage_Keyboard1 && nUsage <= kHIDUsage_Keyboard9)
269 AddCookie(Array[i], '1' + (nUsage - kHIDUsage_Keyboard1) );
270 else if (nUsage >= kHIDUsage_KeyboardF1 && nUsage <= kHIDUsage_KeyboardF12)
271 AddCookie(Array[i], WXK_F1 + (nUsage - kHIDUsage_KeyboardF1) );
272 else if (nUsage >= kHIDUsage_KeyboardF13 && nUsage <= kHIDUsage_KeyboardF24)
273 AddCookie(Array[i], WXK_F13 + (nUsage - kHIDUsage_KeyboardF13) );
274 else if (nUsage >= kHIDUsage_Keypad1 && nUsage <= kHIDUsage_Keypad9)
275 AddCookie(Array[i], WXK_NUMPAD1 + (nUsage - kHIDUsage_Keypad1) );
276 else switch (nUsage)
277 {
278 //0's (wx & ascii go 0-9, but HID goes 1-0)
279 case kHIDUsage_Keyboard0:
280 AddCookie(Array[i],'0');
281 break;
282 case kHIDUsage_Keypad0:
283 AddCookie(Array[i],WXK_NUMPAD0);
284 break;
285
286 //Basic
287 case kHIDUsage_KeyboardReturnOrEnter:
288 AddCookie(Array[i], WXK_RETURN);
289 break;
290 case kHIDUsage_KeyboardEscape:
291 AddCookie(Array[i], WXK_ESCAPE);
292 break;
293 case kHIDUsage_KeyboardDeleteOrBackspace:
294 AddCookie(Array[i], WXK_BACK);
295 break;
296 case kHIDUsage_KeyboardTab:
297 AddCookie(Array[i], WXK_TAB);
298 break;
299 case kHIDUsage_KeyboardSpacebar:
300 AddCookie(Array[i], WXK_SPACE);
301 break;
302 case kHIDUsage_KeyboardPageUp:
303 AddCookie(Array[i], WXK_PRIOR);
304 break;
305 case kHIDUsage_KeyboardEnd:
306 AddCookie(Array[i], WXK_END);
307 break;
308 case kHIDUsage_KeyboardPageDown:
309 AddCookie(Array[i], WXK_NEXT);
310 break;
311 case kHIDUsage_KeyboardRightArrow:
312 AddCookie(Array[i], WXK_RIGHT);
313 break;
314 case kHIDUsage_KeyboardLeftArrow:
315 AddCookie(Array[i], WXK_LEFT);
316 break;
317 case kHIDUsage_KeyboardDownArrow:
318 AddCookie(Array[i], WXK_DOWN);
319 break;
320 case kHIDUsage_KeyboardUpArrow:
321 AddCookie(Array[i], WXK_UP);
322 break;
323
324 //LEDS
325 case kHIDUsage_KeyboardCapsLock:
326 AddCookie(Array[i],WXK_CAPITAL);
327 break;
328 case kHIDUsage_KeypadNumLock:
329 AddCookie(Array[i],WXK_NUMLOCK);
330 break;
331 case kHIDUsage_KeyboardScrollLock:
332 AddCookie(Array[i],WXK_SCROLL);
333 break;
334
335 //Menu keys, Shift, other specials
336 case kHIDUsage_KeyboardLeftControl:
337 AddCookie(Array[i],WXK_CONTROL);
338 break;
339 case kHIDUsage_KeyboardLeftShift:
340 AddCookie(Array[i],WXK_SHIFT);
341 break;
342 case kHIDUsage_KeyboardLeftAlt:
343 AddCookie(Array[i],WXK_ALT);
344 break;
345 case kHIDUsage_KeyboardLeftGUI:
346 AddCookie(Array[i],WXK_MENU);
347 break;
348 case kHIDUsage_KeyboardRightControl:
349 AddCookie(Array[i],WXK_RCONTROL);
350 break;
351 case kHIDUsage_KeyboardRightShift:
352 AddCookie(Array[i],WXK_RSHIFT);
353 break;
354 case kHIDUsage_KeyboardRightAlt:
355 AddCookie(Array[i],WXK_RALT);
356 break;
357 case kHIDUsage_KeyboardRightGUI:
358 AddCookie(Array[i],WXK_RMENU);
359 break;
360
361 //Default
362 default:
363 //not in wx keycodes - do nothing....
364 break;
365 }
366 }
367}//end buildcookies
ec8bd392
RN
368
369#endif //__DARWIN__