]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CIrrDeviceOSX.mm
Merging r6194 from trunk to ogl-es branch.
[irrlicht.git] / source / Irrlicht / CIrrDeviceOSX.mm
1 // Copyright (C) 2005-2006 Etienne Petitjean
2 // Copyright (C) 2007-2012 Christian Stehno
3 // Copyright (C) 2013-2015 Patryk Nadrowski
4 // This file is part of the "Irrlicht Engine".
5 // For conditions of distribution and use, see copyright notice in Irrlicht.h
6
7 #include "IrrCompileConfig.h"
8
9 #ifdef _IRR_COMPILE_WITH_OSX_DEVICE_
10
11 #import <Cocoa/Cocoa.h>
12 #import <OpenGL/gl.h>
13 #ifndef __MAC_10_6
14 #import <Carbon/Carbon.h>
15 #endif
16
17 #include "CIrrDeviceOSX.h"
18
19 #include "IEventReceiver.h"
20 #include "irrList.h"
21 #include "os.h"
22 #include "CTimer.h"
23 #include "irrString.h"
24 #include "Keycodes.h"
25 #include <stdio.h>
26 #include <sys/utsname.h>
27 #include "COSOperator.h"
28 #include "CColorConverter.h"
29 #include "irrlicht.h"
30 #include <algorithm>
31
32 #include <wchar.h>
33 #include <time.h>
34
35 #include "CNSOGLManager.h"
36
37 #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
38
39 #include <IOKit/IOKitLib.h>
40 #include <IOKit/IOCFPlugIn.h>
41 #ifdef MACOS_10_0_4
42 #include <IOKit/hidsystem/IOHIDUsageTables.h>
43 #else
44 /* The header was moved here in Mac OS X 10.1 */
45 #include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
46 #endif
47 #include <IOKit/hid/IOHIDLib.h>
48 #include <IOKit/hid/IOHIDKeys.h>
49
50 struct JoystickComponent
51 {
52         IOHIDElementCookie cookie; // unique value which identifies element, will NOT change
53         long min; // reported min value possible
54         long max; // reported max value possible
55
56         long minRead; //min read value
57         long maxRead; //max read value
58
59         JoystickComponent() : min(0), minRead(0), max(0), maxRead(0)
60         {
61         }
62 };
63
64 struct JoystickInfo
65 {
66         irr::core::array <JoystickComponent> axisComp;
67         irr::core::array <JoystickComponent> buttonComp;
68         irr::core::array <JoystickComponent> hatComp;
69
70         int hats;
71         int axes;
72         int buttons;
73         int numActiveJoysticks;
74
75         irr::SEvent persistentData;
76
77         IOHIDDeviceInterface ** interface;
78         bool removed;
79         char joystickName[256];
80         long usage; // usage page from IOUSBHID Parser.h which defines general usage
81         long usagePage; // usage within above page from IOUSBHID Parser.h which defines specific usage
82
83         JoystickInfo() : hats(0), axes(0), buttons(0), interface(0), removed(false), usage(0), usagePage(0), numActiveJoysticks(0)
84         {
85                 interface = NULL;
86                 memset(joystickName, '\0', 256);
87                 axisComp.clear();
88                 buttonComp.clear();
89                 hatComp.clear();
90
91                 persistentData.EventType = irr::EET_JOYSTICK_INPUT_EVENT;
92                 persistentData.JoystickEvent.POV = 65535;
93                 persistentData.JoystickEvent.ButtonStates = 0;
94         }
95 };
96 irr::core::array<JoystickInfo> ActiveJoysticks;
97
98 //helper functions for init joystick
99 static IOReturn closeJoystickDevice (JoystickInfo* joyInfo)
100 {
101         IOReturn result = kIOReturnSuccess;
102         if (joyInfo && joyInfo->interface)
103         {
104                 /* close the interface */
105                 result = (*(joyInfo->interface))->close (joyInfo->interface);
106                 if (kIOReturnNotOpen == result)
107                 {
108                         /* do nothing as device was not opened, thus can't be closed */
109                 }
110                 else if (kIOReturnSuccess != result)
111                         irr::os::Printer::log("IOHIDDeviceInterface failed to close", irr::ELL_ERROR);
112                 /* release the interface */
113                 result = (*(joyInfo->interface))->Release (joyInfo->interface);
114                 if (kIOReturnSuccess != result)
115                         irr::os::Printer::log("IOHIDDeviceInterface failed to release", irr::ELL_ERROR);
116                 joyInfo->interface = NULL;
117         }
118         return result;
119 }
120
121 static void addComponentInfo (CFTypeRef refElement, JoystickComponent *pComponent, int numActiveJoysticks)
122 {
123         long number;
124         CFTypeRef refType;
125
126         refType = CFDictionaryGetValue ((CFDictionaryRef)refElement, CFSTR(kIOHIDElementCookieKey));
127         if (refType && CFNumberGetValue ((CFNumberRef)refType, kCFNumberLongType, &number))
128                 pComponent->cookie = (IOHIDElementCookie) number;
129         refType = CFDictionaryGetValue ((CFDictionaryRef)refElement, CFSTR(kIOHIDElementMinKey));
130         if (refType && CFNumberGetValue ((CFNumberRef)refType, kCFNumberLongType, &number))
131                 pComponent->minRead = pComponent->min = number;
132         refType = CFDictionaryGetValue ((CFDictionaryRef)refElement, CFSTR(kIOHIDElementMaxKey));
133         if (refType && CFNumberGetValue ((CFNumberRef)refType, kCFNumberLongType, &number))
134                 pComponent->maxRead = pComponent->max = number;
135 }
136
137 static void getJoystickComponentArrayHandler (const void * value, void * parameter);
138
139 static void addJoystickComponent (CFTypeRef refElement, JoystickInfo* joyInfo)
140 {
141         long elementType, usagePage, usage;
142         CFTypeRef refElementType = CFDictionaryGetValue ((CFDictionaryRef)refElement, CFSTR(kIOHIDElementTypeKey));
143         CFTypeRef refUsagePage = CFDictionaryGetValue ((CFDictionaryRef)refElement, CFSTR(kIOHIDElementUsagePageKey));
144         CFTypeRef refUsage = CFDictionaryGetValue ((CFDictionaryRef)refElement, CFSTR(kIOHIDElementUsageKey));
145
146         if ((refElementType) && (CFNumberGetValue ((CFNumberRef)refElementType, kCFNumberLongType, &elementType)))
147         {
148                 /* look at types of interest */
149                 if ((elementType == kIOHIDElementTypeInput_Misc) || (elementType == kIOHIDElementTypeInput_Button) ||
150                         (elementType == kIOHIDElementTypeInput_Axis))
151                 {
152                         if (refUsagePage && CFNumberGetValue ((CFNumberRef)refUsagePage, kCFNumberLongType, &usagePage) &&
153                                 refUsage && CFNumberGetValue ((CFNumberRef)refUsage, kCFNumberLongType, &usage))
154                         {
155                                 switch (usagePage) /* only interested in kHIDPage_GenericDesktop and kHIDPage_Button */
156                                 {
157                                         case kHIDPage_GenericDesktop:
158                                         {
159                                                 switch (usage) /* look at usage to determine function */
160                                                 {
161                                                         case kHIDUsage_GD_X:
162                                                         case kHIDUsage_GD_Y:
163                                                         case kHIDUsage_GD_Z:
164                                                         case kHIDUsage_GD_Rx:
165                                                         case kHIDUsage_GD_Ry:
166                                                         case kHIDUsage_GD_Rz:
167                                                         case kHIDUsage_GD_Slider:
168                                                         case kHIDUsage_GD_Dial:
169                                                         case kHIDUsage_GD_Wheel:
170                                                         {
171                                                                 joyInfo->axes++;
172                                                                 JoystickComponent newComponent;
173                                                                 addComponentInfo(refElement, &newComponent, joyInfo->numActiveJoysticks);
174                                                                 joyInfo->axisComp.push_back(newComponent);
175                                                         }
176                                                         break;
177                                                         case kHIDUsage_GD_Hatswitch:
178                                                         {
179                                                                 joyInfo->hats++;
180                                                                 JoystickComponent newComponent;
181                                                                 addComponentInfo(refElement, &newComponent, joyInfo->numActiveJoysticks);
182                                                                 joyInfo->hatComp.push_back(newComponent);
183                                                         }
184                                                         break;
185                                                 }
186                                         }
187                                                 break;
188                                         case kHIDPage_Button:
189                                         {
190                                                 joyInfo->buttons++;
191                                                 JoystickComponent newComponent;
192                                                 addComponentInfo(refElement, &newComponent, joyInfo->numActiveJoysticks);
193                                                 joyInfo->buttonComp.push_back(newComponent);
194                                         }
195                                                 break;
196                                         default:
197                                                 break;
198                                 }
199                         }
200                 }
201                 else if (kIOHIDElementTypeCollection == elementType)
202                 {
203                         //get elements
204                         CFTypeRef refElementTop = CFDictionaryGetValue ((CFMutableDictionaryRef) refElement, CFSTR(kIOHIDElementKey));
205                         if (refElementTop)
206                         {
207                                 CFTypeID type = CFGetTypeID (refElementTop);
208                                 if (type == CFArrayGetTypeID())
209                                 {
210                                         CFRange range = {0, CFArrayGetCount ((CFArrayRef)refElementTop)};
211                                         CFArrayApplyFunction ((CFArrayRef)refElementTop, range, getJoystickComponentArrayHandler, joyInfo);
212                                 }
213                         }
214                 }
215         }
216 }
217
218 static void getJoystickComponentArrayHandler (const void * value, void * parameter)
219 {
220         if (CFGetTypeID (value) == CFDictionaryGetTypeID ())
221                 addJoystickComponent ((CFTypeRef) value, (JoystickInfo *) parameter);
222 }
223
224 static void joystickTopLevelElementHandler (const void * value, void * parameter)
225 {
226         CFTypeRef refCF = 0;
227         if (CFGetTypeID (value) != CFDictionaryGetTypeID ())
228                 return;
229         refCF = CFDictionaryGetValue ((CFDictionaryRef)value, CFSTR(kIOHIDElementUsagePageKey));
230         if (!CFNumberGetValue ((CFNumberRef)refCF, kCFNumberLongType, &((JoystickInfo *) parameter)->usagePage))
231                 irr::os::Printer::log("CFNumberGetValue error retrieving JoystickInfo->usagePage", irr::ELL_ERROR);
232         refCF = CFDictionaryGetValue ((CFDictionaryRef)value, CFSTR(kIOHIDElementUsageKey));
233         if (!CFNumberGetValue ((CFNumberRef)refCF, kCFNumberLongType, &((JoystickInfo *) parameter)->usage))
234                 irr::os::Printer::log("CFNumberGetValue error retrieving JoystickInfo->usage", irr::ELL_ERROR);
235 }
236
237 static void getJoystickDeviceInfo (io_object_t hidDevice, CFMutableDictionaryRef hidProperties, JoystickInfo *joyInfo)
238 {
239         CFMutableDictionaryRef usbProperties = 0;
240         io_registry_entry_t parent1, parent2;
241
242         /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
243         * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
244         */
245         if ((KERN_SUCCESS == IORegistryEntryGetParentEntry (hidDevice, kIOServicePlane, &parent1)) &&
246                 (KERN_SUCCESS == IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2)) &&
247                 (KERN_SUCCESS == IORegistryEntryCreateCFProperties (parent2, &usbProperties, kCFAllocatorDefault, kNilOptions)))
248         {
249                 if (usbProperties)
250                 {
251                         CFTypeRef refCF = 0;
252                         /* get device info
253                         * try hid dictionary first, if fail then go to usb dictionary
254                         */
255
256                         /* get joystickName name */
257                         refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDProductKey));
258                         if (!refCF)
259                                 refCF = CFDictionaryGetValue (usbProperties, CFSTR("USB Product Name"));
260                         if (refCF)
261                         {
262                                 if (!CFStringGetCString ((CFStringRef)refCF, joyInfo->joystickName, 256, CFStringGetSystemEncoding ()))
263                                         irr::os::Printer::log("CFStringGetCString error getting joyInfo->joystickName", irr::ELL_ERROR);
264                         }
265
266                         /* get usage page and usage */
267                         refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDPrimaryUsagePageKey));
268                         if (refCF)
269                         {
270                                 if (!CFNumberGetValue ((CFNumberRef)refCF, kCFNumberLongType, &joyInfo->usagePage))
271                                         irr::os::Printer::log("CFNumberGetValue error getting joyInfo->usagePage", irr::ELL_ERROR);
272                                 refCF = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDPrimaryUsageKey));
273                                 if (refCF)
274                                         if (!CFNumberGetValue ((CFNumberRef)refCF, kCFNumberLongType, &joyInfo->usage))
275                                                 irr::os::Printer::log("CFNumberGetValue error getting joyInfo->usage", irr::ELL_ERROR);
276                         }
277
278                         if (NULL == refCF) /* get top level element HID usage page or usage */
279                         {
280                                 /* use top level element instead */
281                                 CFTypeRef refCFTopElement = 0;
282                                 refCFTopElement = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDElementKey));
283                                 {
284                                         /* refCFTopElement points to an array of element dictionaries */
285                                         CFRange range = {0, CFArrayGetCount ((CFArrayRef)refCFTopElement)};
286                                         CFArrayApplyFunction ((CFArrayRef)refCFTopElement, range, joystickTopLevelElementHandler, joyInfo);
287                                 }
288                         }
289
290                         CFRelease (usbProperties);
291                 }
292                 else
293                         irr::os::Printer::log("IORegistryEntryCreateCFProperties failed to create usbProperties", irr::ELL_ERROR);
294
295                 if (kIOReturnSuccess != IOObjectRelease (parent2))
296                         irr::os::Printer::log("IOObjectRelease failed to release parent2", irr::ELL_ERROR);
297                 if (kIOReturnSuccess != IOObjectRelease (parent1))
298                         irr::os::Printer::log("IOObjectRelease failed to release parent1", irr::ELL_ERROR);
299         }
300 }
301
302 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
303
304 // only OSX 10.5 seems to not need these defines...
305 #if !defined(__MAC_10_5) || defined(__MAC_10_6)
306 // Contents from Events.h from Carbon/HIToolbox but we need it with Cocoa too
307 // and for some reason no Cocoa equivalent of these constants seems provided.
308 // So I'm doing like everyone else and using copy-and-paste.
309
310 /*
311  *  Summary:
312  *      Virtual keycodes
313  *
314  *  Discussion:
315  *      These constants are the virtual keycodes defined originally in
316  *      Inside Mac Volume V, pg. V-191. They identify physical keys on a
317  *      keyboard. Those constants with "ANSI" in the name are labeled
318  *      according to the key position on an ANSI-standard US keyboard.
319  *      For example, kVK_ANSI_A indicates the virtual keycode for the key
320  *      with the letter 'A' in the US keyboard layout. Other keyboard
321  *      layouts may have the 'A' key label on a different physical key;
322  *      in this case, pressing 'A' will generate a different virtual
323  *      keycode.
324  */
325 enum {
326         kVK_ANSI_A              = 0x00,
327         kVK_ANSI_S              = 0x01,
328         kVK_ANSI_D              = 0x02,
329         kVK_ANSI_F              = 0x03,
330         kVK_ANSI_H              = 0x04,
331         kVK_ANSI_G              = 0x05,
332         kVK_ANSI_Z              = 0x06,
333         kVK_ANSI_X              = 0x07,
334         kVK_ANSI_C              = 0x08,
335         kVK_ANSI_V              = 0x09,
336         kVK_ANSI_B              = 0x0B,
337         kVK_ANSI_Q              = 0x0C,
338         kVK_ANSI_W              = 0x0D,
339         kVK_ANSI_E              = 0x0E,
340         kVK_ANSI_R              = 0x0F,
341         kVK_ANSI_Y              = 0x10,
342         kVK_ANSI_T              = 0x11,
343         kVK_ANSI_1              = 0x12,
344         kVK_ANSI_2              = 0x13,
345         kVK_ANSI_3              = 0x14,
346         kVK_ANSI_4              = 0x15,
347         kVK_ANSI_6              = 0x16,
348         kVK_ANSI_5              = 0x17,
349         kVK_ANSI_Equal          = 0x18,
350         kVK_ANSI_9              = 0x19,
351         kVK_ANSI_7              = 0x1A,
352         kVK_ANSI_Minus          = 0x1B,
353         kVK_ANSI_8              = 0x1C,
354         kVK_ANSI_0              = 0x1D,
355         kVK_ANSI_RightBracket   = 0x1E,
356         kVK_ANSI_O              = 0x1F,
357         kVK_ANSI_U              = 0x20,
358         kVK_ANSI_LeftBracket    = 0x21,
359         kVK_ANSI_I              = 0x22,
360         kVK_ANSI_P              = 0x23,
361         kVK_ANSI_L              = 0x25,
362         kVK_ANSI_J              = 0x26,
363         kVK_ANSI_Quote          = 0x27,
364         kVK_ANSI_K              = 0x28,
365         kVK_ANSI_Semicolon      = 0x29,
366         kVK_ANSI_Backslash      = 0x2A,
367         kVK_ANSI_Comma          = 0x2B,
368         kVK_ANSI_Slash          = 0x2C,
369         kVK_ANSI_N              = 0x2D,
370         kVK_ANSI_M              = 0x2E,
371         kVK_ANSI_Period         = 0x2F,
372         kVK_ANSI_Grave          = 0x32,
373         kVK_ANSI_KeypadDecimal  = 0x41,
374         kVK_ANSI_KeypadMultiply = 0x43,
375         kVK_ANSI_KeypadPlus     = 0x45,
376         kVK_ANSI_KeypadClear    = 0x47,
377         kVK_ANSI_KeypadDivide   = 0x4B,
378         kVK_ANSI_KeypadEnter    = 0x4C,
379         kVK_ANSI_KeypadMinus    = 0x4E,
380         kVK_ANSI_KeypadEquals   = 0x51,
381         kVK_ANSI_Keypad0        = 0x52,
382         kVK_ANSI_Keypad1        = 0x53,
383         kVK_ANSI_Keypad2        = 0x54,
384         kVK_ANSI_Keypad3        = 0x55,
385         kVK_ANSI_Keypad4        = 0x56,
386         kVK_ANSI_Keypad5        = 0x57,
387         kVK_ANSI_Keypad6        = 0x58,
388         kVK_ANSI_Keypad7        = 0x59,
389         kVK_ANSI_Keypad8        = 0x5B,
390         kVK_ANSI_Keypad9        = 0x5C
391 };
392
393 /* keycodes for keys that are independent of keyboard layout*/
394 enum {
395         kVK_Return              = 0x24,
396         kVK_Tab                 = 0x30,
397         kVK_Space               = 0x31,
398         kVK_Delete              = 0x33,
399         kVK_Escape              = 0x35,
400         kVK_Command             = 0x37,
401         kVK_Shift               = 0x38,
402         kVK_CapsLock            = 0x39,
403         kVK_Option              = 0x3A,
404         kVK_Control             = 0x3B,
405         kVK_RightShift          = 0x3C,
406         kVK_RightOption         = 0x3D,
407         kVK_RightControl        = 0x3E,
408         kVK_Function            = 0x3F,
409         kVK_F17                 = 0x40,
410         kVK_VolumeUp            = 0x48,
411         kVK_VolumeDown          = 0x49,
412         kVK_Mute                = 0x4A,
413         kVK_F18                 = 0x4F,
414         kVK_F19                 = 0x50,
415         kVK_F20                 = 0x5A,
416         kVK_F5                  = 0x60,
417         kVK_F6                  = 0x61,
418         kVK_F7                  = 0x62,
419         kVK_F3                  = 0x63,
420         kVK_F8                  = 0x64,
421         kVK_F9                  = 0x65,
422         kVK_F11                 = 0x67,
423         kVK_F13                 = 0x69,
424         kVK_F16                 = 0x6A,
425         kVK_F14                 = 0x6B,
426         kVK_F10                 = 0x6D,
427         kVK_F12                 = 0x6F,
428         kVK_F15                 = 0x71,
429         kVK_Help                = 0x72,
430         kVK_Home                = 0x73,
431         kVK_PageUp              = 0x74,
432         kVK_ForwardDelete       = 0x75,
433         kVK_F4                  = 0x76,
434         kVK_End                 = 0x77,
435         kVK_F2                  = 0x78,
436         kVK_PageDown            = 0x79,
437         kVK_F1                  = 0x7A,
438         kVK_LeftArrow           = 0x7B,
439         kVK_RightArrow          = 0x7C,
440         kVK_DownArrow           = 0x7D,
441         kVK_UpArrow             = 0x7E
442 };
443 #endif
444
445 //------------------------------------------------------------------------------------------
446 Boolean GetDictionaryBoolean(CFDictionaryRef theDict, const void* key)
447 {
448         // get a boolean from the dictionary
449         Boolean value = false;
450         CFBooleanRef boolRef;
451         boolRef = (CFBooleanRef)CFDictionaryGetValue(theDict, key);
452         if (boolRef != NULL)
453                 value = CFBooleanGetValue(boolRef);
454         return value;
455 }
456 //------------------------------------------------------------------------------------------
457 long GetDictionaryLong(CFDictionaryRef theDict, const void* key)
458 {
459         // get a long from the dictionary
460         long value = 0;
461         CFNumberRef numRef;
462         numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key);
463         if (numRef != NULL)
464                 CFNumberGetValue(numRef, kCFNumberLongType, &value);
465         return value;
466 }
467
468 namespace irr
469 {
470         namespace video
471         {
472                 IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& param, io::IFileSystem* io, IContextManager* contextManager);
473         }
474 } // end namespace irr
475
476 static bool firstLaunch = true;
477
478 @implementation CIrrDelegateOSX
479 {
480     irr::CIrrDeviceMacOSX* Device;
481     bool Quit;
482 }
483
484 - (id)initWithDevice:(irr::CIrrDeviceMacOSX*)device
485 {
486     self = [super init];
487     
488     if (self)
489         Device = device;
490     
491     Quit = false;
492     
493     return (self);
494 }
495
496 - (void)applicationDidFinishLaunching:(NSNotification*)notification
497 {
498     Quit = false;
499 }
500
501 - (void)orderFrontStandardAboutPanel:(id)sender
502 {
503     [NSApp orderFrontStandardAboutPanel:sender];
504 }
505
506 - (void)unhideAllApplications:(id)sender
507 {
508     [NSApp unhideAllApplications:sender];
509 }
510
511 - (void)hide:(id)sender
512 {
513     [NSApp hide:sender];
514 }
515
516 - (void)hideOtherApplications:(id)sender
517 {
518     [NSApp hideOtherApplications:sender];
519 }
520
521 - (void)terminate:(id)sender
522 {
523     Quit = true;
524 }
525
526 - (void)windowWillClose:(id)sender
527 {
528     Device->setWindow(nil);
529     Quit = true;
530 }
531
532 - (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize
533 {
534     if (Device->isResizable())
535         return proposedFrameSize;
536     else
537         return [window frame].size;
538 }
539
540 - (void)windowDidResize:(NSNotification *)aNotification
541 {
542     NSWindow    *window;
543     NSRect              frame;
544     
545     window = [aNotification object];
546     frame = [window frame];
547     Device->setResize((int)frame.size.width,(int)frame.size.height);
548 }
549
550 - (BOOL)isQuit
551 {
552     return (Quit);
553 }
554
555 @end
556
557 namespace irr
558 {
559 //! constructor
560 CIrrDeviceMacOSX::CIrrDeviceMacOSX(const SIrrlichtCreationParameters& param)
561         : CIrrDeviceStub(param), Window(NULL), Display(NULL),
562         SoftwareDriverTarget(0), DeviceWidth(0), DeviceHeight(0),
563         ScreenWidth(0), ScreenHeight(0), MouseButtonStates(0), SoftwareRendererType(0),
564         IsActive(true), IsFullscreen(false), IsShiftDown(false), IsControlDown(false), IsResizable(false)
565 {
566         struct utsname name;
567         NSString *path;
568
569 #ifdef _DEBUG
570         setDebugName("CIrrDeviceMacOSX");
571 #endif
572
573         if (firstLaunch)
574         {
575                 firstLaunch = false;
576
577                 if (!CreationParams.WindowId)
578                 {
579                         [[NSAutoreleasePool alloc] init];
580                         [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
581                         [NSApp setDelegate:(id<NSApplicationDelegate>)[[[CIrrDelegateOSX alloc] initWithDevice:this] autorelease]];
582             
583             // Create menu
584             
585             NSString* bundleName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
586             
587             NSMenu* mainMenu = [[[NSMenu alloc] initWithTitle:@"MainMenu"] autorelease];
588             NSMenu* menu = [[[NSMenu alloc] initWithTitle:bundleName] autorelease];
589             NSMenuItem* menuItem = [mainMenu addItemWithTitle:bundleName action:nil keyEquivalent:@""];
590             [mainMenu setSubmenu:menu forItem:menuItem];
591             menuItem = [menu addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"];
592             [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
593             
594             [NSApp setMainMenu:mainMenu];
595
596             [NSApp finishLaunching];
597                 }
598
599                 path = [[NSBundle mainBundle] bundlePath];
600         path = [path stringByAppendingString:@"/Contents/Resources"];
601                 chdir([path fileSystemRepresentation]);
602         [path release];
603         }
604
605         uname(&name);
606         Operator = new COSOperator(name.version);
607         os::Printer::log(name.version,ELL_INFORMATION);
608
609         initKeycodes();
610
611         VideoModeList->setDesktop(CreationParams.Bits, core::dimension2d<u32>([[NSScreen mainScreen] frame].size.width, [[NSScreen mainScreen] frame].size.height));
612
613         bool success = true;
614
615         if (CreationParams.DriverType != video::EDT_NULL)
616                 success = createWindow();
617
618         // in case of failure, one can check VideoDriver for initialization
619         if (!success)
620                 return;
621
622         setResizable(false);
623         CursorControl = new CCursorControl(CreationParams.WindowSize, this);
624
625         createDriver();
626         createGUIAndScene();
627 }
628
629 CIrrDeviceMacOSX::~CIrrDeviceMacOSX()
630 {
631         [SoftwareDriverTarget release];
632 #ifdef __MAC_10_6
633         [NSApp setPresentationOptions:(NSApplicationPresentationDefault)];
634 #else
635         SetSystemUIMode(kUIModeNormal, kUIOptionAutoShowMenuBar);
636 #endif
637         closeDevice();
638 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
639         for (u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
640         {
641                 if (ActiveJoysticks[joystick].interface)
642                         closeJoystickDevice(&ActiveJoysticks[joystick]);
643         }
644 #endif
645 }
646
647 void CIrrDeviceMacOSX::closeDevice()
648 {
649         if (Window != nil)
650         {
651                 [Window setIsVisible:FALSE];
652                 [Window setReleasedWhenClosed:TRUE];
653                 [Window release];
654                 Window = nil;
655         }
656     
657     if (IsFullscreen)
658         CGReleaseAllDisplays();
659
660         IsFullscreen = false;
661         IsActive = false;
662 }
663
664 bool CIrrDeviceMacOSX::createWindow()
665 {
666     CGDisplayErr error;
667     bool result = false;
668     Display = CGMainDisplayID();
669     
670     CGRect displayRect;
671 #ifdef __MAC_10_6
672     CGDisplayModeRef displaymode, olddisplaymode;
673 #else
674     CFDictionaryRef displaymode, olddisplaymode;
675 #endif
676     
677     ScreenWidth = (int)CGDisplayPixelsWide(Display);
678     ScreenHeight = (int)CGDisplayPixelsHigh(Display);
679     
680     const NSBackingStoreType type = (CreationParams.DriverType == video::EDT_OPENGL) ? NSBackingStoreBuffered : NSBackingStoreNonretained;
681     
682     if (!CreationParams.Fullscreen)
683     {
684         if (!CreationParams.WindowId) //create another window when WindowId is null
685         {
686             int x = (CreationParams.WindowPosition.X > 0) ? CreationParams.WindowPosition.X : 0;
687             int y = (CreationParams.WindowPosition.Y > 0) ? CreationParams.WindowPosition.Y : 0;
688             
689             if (CreationParams.WindowPosition.Y > -1)
690             {
691                 int screenHeight = [[[NSScreen screens] objectAtIndex:0] frame].size.height;
692                 y = screenHeight - y - CreationParams.WindowSize.Height;
693             }
694             
695             Window = [[NSWindow alloc] initWithContentRect:NSMakeRect(x, y, CreationParams.WindowSize.Width,CreationParams.WindowSize.Height) styleMask:NSTitledWindowMask+NSClosableWindowMask+NSResizableWindowMask backing:type defer:FALSE];
696
697             if (CreationParams.WindowPosition.X == -1 && CreationParams.WindowPosition.Y == -1)
698                 [Window center];
699         }
700         
701         DeviceWidth = CreationParams.WindowSize.Width;
702         DeviceHeight = CreationParams.WindowSize.Height;
703         
704         result = true;
705     }
706     else
707     {
708         IsFullscreen = true;
709         
710 #ifdef __MAC_10_6
711         displaymode = CGDisplayCopyDisplayMode(Display);
712         
713         CFArrayRef Modes = CGDisplayCopyAllDisplayModes(Display, NULL);
714         
715         for(int i = 0; i < CFArrayGetCount(Modes); ++i)
716         {
717             CGDisplayModeRef CurrentMode = (CGDisplayModeRef)CFArrayGetValueAtIndex(Modes, i);
718             
719             u8 Depth = 0;
720             
721             CFStringRef pixEnc = CGDisplayModeCopyPixelEncoding(CurrentMode);
722             
723             if (CFStringCompare(pixEnc, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
724                 Depth = 32;
725             else if(CFStringCompare(pixEnc, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
726                 Depth = 16;
727             else if(CFStringCompare(pixEnc, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
728                 Depth = 8;
729             
730             if(Depth == CreationParams.Bits)
731                 if((CGDisplayModeGetWidth(CurrentMode) == CreationParams.WindowSize.Width) && (CGDisplayModeGetHeight(CurrentMode) == CreationParams.WindowSize.Height))
732                 {
733                     displaymode = CurrentMode;
734                     break;
735                 }
736         }
737 #else
738         displaymode = CGDisplayBestModeForParameters(Display,CreationParams.Bits,CreationParams.WindowSize.Width,CreationParams.WindowSize.Height,NULL);
739 #endif
740         
741         if (displaymode != NULL)
742         {
743 #ifdef __MAC_10_6
744             olddisplaymode = CGDisplayCopyDisplayMode(Display);
745 #else
746             olddisplaymode = CGDisplayCurrentMode(Display);
747 #endif
748             
749             error = CGCaptureAllDisplays();
750             if (error == CGDisplayNoErr)
751             {
752 #ifdef __MAC_10_6
753                 error = CGDisplaySetDisplayMode(Display, displaymode, NULL);
754 #else
755                 error = CGDisplaySwitchToMode(Display, displaymode);
756 #endif
757                 
758                 if (error == CGDisplayNoErr)
759                 {
760                     Window = [[NSWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame] styleMask:NSBorderlessWindowMask backing:type defer:FALSE screen:[NSScreen mainScreen]];
761                     
762                     [Window setLevel: CGShieldingWindowLevel()];
763                     [Window setBackgroundColor:[NSColor blackColor]];
764                     
765                     displayRect = CGDisplayBounds(Display);
766                     ScreenWidth = DeviceWidth = (int)displayRect.size.width;
767                     ScreenHeight = DeviceHeight = (int)displayRect.size.height;
768                     CreationParams.WindowSize.set(ScreenWidth, ScreenHeight);
769                     
770                     result = true;
771                 }
772                 
773                 if (!result)
774                     CGReleaseAllDisplays();
775             }
776         }
777     }
778     
779     if (result)
780     {
781         if (Window)
782         {
783             [Window setDelegate:(id<NSWindowDelegate>)[NSApp delegate]];
784             [Window setAcceptsMouseMovedEvents:TRUE];
785             [Window setIsVisible:TRUE];
786             [Window makeKeyAndOrderFront:nil];
787         }
788         
789         if (IsFullscreen) //hide menus in fullscreen mode only
790         {
791 #ifdef __MAC_10_6
792             [NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
793 #else
794             SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
795 #endif
796         }
797     }
798     
799     return result;
800 }
801
802 void CIrrDeviceMacOSX::setResize(int width, int height)
803 {
804         // set new window size
805         DeviceWidth = width;
806         DeviceHeight = height;
807
808 #if defined(_IRR_COMPILE_WITH_OPENGL_)
809         // update the size of the opengl rendering context
810         if (CreationParams.DriverType == video::EDT_OPENGL)
811     {
812         NSOpenGLContext* Context = (NSOpenGLContext*)ContextManager->getContext().OpenGLOSX.Context;
813         
814         if (Context)
815             [Context update];
816     }
817 #endif
818
819         // resize the driver to the inner pane size
820         if (Window)
821         {
822                 NSRect driverFrame = [Window contentRectForFrameRect:[Window frame]];
823                 getVideoDriver()->OnResize(core::dimension2d<u32>( (s32)driverFrame.size.width, (s32)driverFrame.size.height));
824         }
825         else
826                 getVideoDriver()->OnResize(core::dimension2d<u32>( (s32)width, (s32)height));
827 }
828
829
830 void CIrrDeviceMacOSX::createDriver()
831 {
832         switch (CreationParams.DriverType)
833         {
834                 case video::EDT_SOFTWARE:
835 #ifdef _IRR_COMPILE_WITH_SOFTWARE_
836                         VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this);
837                         SoftwareRendererType = 2;
838 #else
839                         os::Printer::log("No Software driver support compiled in.", ELL_ERROR);
840 #endif
841                         break;
842
843                 case video::EDT_BURNINGSVIDEO:
844 #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
845                         VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this);
846                         SoftwareRendererType = 1;
847 #else
848                         os::Printer::log("Burning's video driver was not compiled in.", ELL_ERROR);
849 #endif
850                         break;
851
852                 case video::EDT_OPENGL:
853 #ifdef _IRR_COMPILE_WITH_OPENGL_
854             {
855                 video::SExposedVideoData data;
856                 data.OpenGLOSX.Window = Window;
857                 ContextManager = new video::CNSOGLManager();
858                 ContextManager->initialize(CreationParams, data);
859                 VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager);
860                 if (!VideoDriver)
861                 {
862                     os::Printer::log("Could not create OpenGL driver.", ELL_ERROR);
863                 }
864                 
865                                 if (Window) 
866                                 {
867                                         [[Window contentView] setWantsBestResolutionOpenGLSurface:NO];
868                                         [(NSOpenGLContext*)ContextManager->getContext().OpenGLOSX.Context setView:[Window contentView]];
869                                 }
870                                 else 
871                                 {
872                                         [(NSView*)CreationParams.WindowId setWantsBestResolutionOpenGLSurface:NO];
873                                         [(NSOpenGLContext*)ContextManager->getContext().OpenGLOSX.Context setView:(NSView*)CreationParams.WindowId];
874                                 }
875
876 #ifndef __MAC_10_6
877                 CGLContextObj CGLContext = (CGLContextObj)[(NSOpenGLContext*)ContextManager->getContext().OpenGLOSX.Context CGLContextObj];
878                 CGLSetFullScreen(CGLContext);
879 #endif
880             }
881 #else
882                         os::Printer::log("No OpenGL support compiled in.", ELL_ERROR);
883 #endif
884                         break;
885
886                 case video::DEPRECATED_EDT_DIRECT3D8_NO_LONGER_EXISTS:
887                 case video::EDT_DIRECT3D9:
888                 case video::EDT_OGLES1:
889                 case video::EDT_OGLES2:
890                         os::Printer::log("This driver is not available in OSX. Try OpenGL or Software renderer.", ELL_ERROR);
891                         break;
892
893                 case video::EDT_NULL:
894                         VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);
895                         break;
896
897                 default:
898                         os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR);
899                         break;
900         }
901 }
902
903 bool CIrrDeviceMacOSX::run()
904 {
905         NSAutoreleasePool* Pool = [[NSAutoreleasePool alloc] init];
906
907         NSEvent *event;
908         irr::SEvent     ievent;
909
910         os::Timer::tick();
911         storeMouseLocation();
912
913         event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES];
914         if (event != nil)
915         {
916                 bzero(&ievent,sizeof(ievent));
917
918                 switch([(NSEvent *)event type])
919                 {
920                         case NSKeyDown:
921                                 postKeyEvent(event,ievent,true);
922                                 break;
923
924                         case NSKeyUp:
925                                 postKeyEvent(event,ievent,false);
926                                 break;
927
928                         case NSFlagsChanged:
929                                 ievent.EventType = irr::EET_KEY_INPUT_EVENT;
930                                 ievent.KeyInput.Shift = ([(NSEvent *)event modifierFlags] & NSShiftKeyMask) != 0;
931                                 ievent.KeyInput.Control = ([(NSEvent *)event modifierFlags] & NSControlKeyMask) != 0;
932
933                                 if (IsShiftDown != ievent.KeyInput.Shift)
934                                 {
935                                         ievent.KeyInput.Char = irr::KEY_SHIFT;
936                                         ievent.KeyInput.Key = irr::KEY_SHIFT;
937                                         ievent.KeyInput.PressedDown = ievent.KeyInput.Shift;
938
939                                         IsShiftDown = ievent.KeyInput.Shift;
940
941                                         postEventFromUser(ievent);
942                                 }
943
944                                 if (IsControlDown != ievent.KeyInput.Control)
945                                 {
946                                         ievent.KeyInput.Char = irr::KEY_CONTROL;
947                                         ievent.KeyInput.Key = irr::KEY_CONTROL;
948                                         ievent.KeyInput.PressedDown = ievent.KeyInput.Control;
949
950                                         IsControlDown = ievent.KeyInput.Control;
951
952                                         postEventFromUser(ievent);
953                                 }
954
955                                 [NSApp sendEvent:event];
956                                 break;
957
958                         case NSLeftMouseDown:
959                                 ievent.EventType = irr::EET_MOUSE_INPUT_EVENT;
960                                 ievent.MouseInput.Event = irr::EMIE_LMOUSE_PRESSED_DOWN;
961                                 MouseButtonStates |= irr::EMBSM_LEFT;
962                                 ievent.MouseInput.ButtonStates = MouseButtonStates;
963                                 postMouseEvent(event,ievent);
964                                 break;
965
966                         case NSLeftMouseUp:
967                                 ievent.EventType = irr::EET_MOUSE_INPUT_EVENT;
968                                 MouseButtonStates &= !irr::EMBSM_LEFT;
969                                 ievent.MouseInput.ButtonStates = MouseButtonStates;
970                                 ievent.MouseInput.Event = irr::EMIE_LMOUSE_LEFT_UP;
971                                 postMouseEvent(event,ievent);
972                                 break;
973
974                         case NSOtherMouseDown:
975                                 ievent.EventType = irr::EET_MOUSE_INPUT_EVENT;
976                                 ievent.MouseInput.Event = irr::EMIE_MMOUSE_PRESSED_DOWN;
977                                 MouseButtonStates |= irr::EMBSM_MIDDLE;
978                                 ievent.MouseInput.ButtonStates = MouseButtonStates;
979                                 postMouseEvent(event,ievent);
980                                 break;
981
982                         case NSOtherMouseUp:
983                                 ievent.EventType = irr::EET_MOUSE_INPUT_EVENT;
984                                 MouseButtonStates &= !irr::EMBSM_MIDDLE;
985                                 ievent.MouseInput.ButtonStates = MouseButtonStates;
986                                 ievent.MouseInput.Event = irr::EMIE_MMOUSE_LEFT_UP;
987                                 postMouseEvent(event,ievent);
988                                 break;
989
990                         case NSMouseMoved:
991                         case NSLeftMouseDragged:
992                         case NSRightMouseDragged:
993                         case NSOtherMouseDragged:
994                                 ievent.EventType = irr::EET_MOUSE_INPUT_EVENT;
995                                 ievent.MouseInput.Event = irr::EMIE_MOUSE_MOVED;
996                                 ievent.MouseInput.ButtonStates = MouseButtonStates;
997                                 postMouseEvent(event,ievent);
998                                 break;
999
1000                         case NSRightMouseDown:
1001                                 ievent.EventType = irr::EET_MOUSE_INPUT_EVENT;
1002                                 ievent.MouseInput.Event = irr::EMIE_RMOUSE_PRESSED_DOWN;
1003                                 MouseButtonStates |= irr::EMBSM_RIGHT;
1004                                 ievent.MouseInput.ButtonStates = MouseButtonStates;
1005                                 postMouseEvent(event,ievent);
1006                                 break;
1007
1008                         case NSRightMouseUp:
1009                                 ievent.EventType = irr::EET_MOUSE_INPUT_EVENT;
1010                                 ievent.MouseInput.Event = irr::EMIE_RMOUSE_LEFT_UP;
1011                                 MouseButtonStates &= !irr::EMBSM_RIGHT;
1012                                 ievent.MouseInput.ButtonStates = MouseButtonStates;
1013                                 postMouseEvent(event,ievent);
1014                                 break;
1015
1016                         case NSScrollWheel:
1017                                 ievent.EventType = irr::EET_MOUSE_INPUT_EVENT;
1018                                 ievent.MouseInput.Event = irr::EMIE_MOUSE_WHEEL;
1019                                 ievent.MouseInput.Wheel = [(NSEvent *)event deltaY];
1020                                 if (ievent.MouseInput.Wheel < 1.0f)
1021                                         ievent.MouseInput.Wheel *= 10.0f;
1022                                 else
1023                                         ievent.MouseInput.Wheel *= 5.0f;
1024                                 postMouseEvent(event,ievent);
1025                                 break;
1026
1027                         default:
1028                                 [NSApp sendEvent:event];
1029                                 break;
1030                 }
1031         }
1032
1033         pollJoysticks();
1034
1035         [Pool release];
1036
1037         return (![[NSApp delegate] isQuit] && IsActive);
1038 }
1039
1040
1041 //! Pause the current process for the minimum time allowed only to allow other processes to execute
1042 void CIrrDeviceMacOSX::yield()
1043 {
1044         struct timespec ts = {0,0};
1045         nanosleep(&ts, NULL);
1046 }
1047
1048
1049 //! Pause execution and let other processes to run for a specified amount of time.
1050 void CIrrDeviceMacOSX::sleep(u32 timeMs, bool pauseTimer=false)
1051 {
1052         bool wasStopped = Timer ? Timer->isStopped() : true;
1053
1054         struct timespec ts;
1055         ts.tv_sec = (time_t) (timeMs / 1000);
1056         ts.tv_nsec = (long) (timeMs % 1000) * 1000000;
1057
1058         if (pauseTimer && !wasStopped)
1059                 Timer->stop();
1060
1061         nanosleep(&ts, NULL);
1062
1063         if (pauseTimer && !wasStopped)
1064                 Timer->start();
1065 }
1066
1067
1068 void CIrrDeviceMacOSX::setWindowCaption(const wchar_t* text)
1069 {
1070         if (Window != NULL)
1071         {
1072                 if ( text )
1073                 {
1074                         size_t numBytes = wcslen(text) * sizeof(wchar_t);
1075
1076 #ifdef __BIG_ENDIAN__
1077                         NSStringEncoding encode = sizeof(wchar_t) == 4 ? NSUTF32BigEndianStringEncoding : NSUTF16BigEndianStringEncoding;
1078 #else
1079                         NSStringEncoding encode = sizeof(wchar_t) == 4 ? NSUTF32LittleEndianStringEncoding : NSUTF16LittleEndianStringEncoding;
1080 #endif
1081                         NSString* name = [[NSString alloc] initWithBytes:text length:numBytes encoding:encode];
1082                         if ( name )
1083                         {
1084                                 [Window setTitle:name];
1085                                 [name release];
1086                         }
1087                 }
1088                 else
1089                 {
1090                         [Window setTitle:@""];
1091                 }
1092         }
1093 }
1094
1095
1096 bool CIrrDeviceMacOSX::isWindowActive() const
1097 {
1098         return (IsActive);
1099 }
1100
1101
1102 bool CIrrDeviceMacOSX::isWindowFocused() const
1103 {
1104         if (Window != NULL)
1105                 return [Window isKeyWindow];
1106         return false;
1107 }
1108
1109
1110 bool CIrrDeviceMacOSX::isWindowMinimized() const
1111 {
1112         if (Window != NULL)
1113                 return [Window isMiniaturized];
1114         return false;
1115 }
1116
1117
1118 void CIrrDeviceMacOSX::postKeyEvent(void *event,irr::SEvent &ievent,bool pressed)
1119 {
1120         NSString *str;
1121         std::map<int,int>::const_iterator iter;
1122         unsigned int c,mkey,mchar;
1123         const unsigned char *cStr;
1124         BOOL skipCommand;
1125
1126         str = [(NSEvent *)event characters];
1127         if ((str != nil) && ([str length] > 0))
1128         {
1129                 mkey = mchar = 0;
1130                 skipCommand = false;
1131                 c = [str characterAtIndex:0];
1132                 mchar = c;
1133
1134                 iter = KeyCodes.find([(NSEvent *)event keyCode]);
1135                 if (iter != KeyCodes.end())
1136                         mkey = (*iter).second;
1137                 else if ((iter = KeyCodes.find(c))  != KeyCodes.end())
1138                         mkey = (*iter).second;
1139                 else
1140                 {
1141                         // workaround for period character
1142                         if (c == 0x2E)
1143                         {
1144                                 mkey = irr::KEY_PERIOD;
1145                                 mchar = '.';
1146                         }
1147                         else
1148                         {
1149                                 cStr = (unsigned char *)[str cStringUsingEncoding:NSWindowsCP1252StringEncoding];
1150                                 if (cStr != NULL && strlen((char*)cStr) > 0)
1151                                 {
1152                                         mchar = cStr[0];
1153                                         mkey = toupper(mchar);
1154                                         if ([(NSEvent *)event modifierFlags] & NSCommandKeyMask)
1155                                         {
1156                                                 if (mkey == 'C' || mkey == 'V' || mkey == 'X')
1157                                                 {
1158                                                         mchar = 0;
1159                                                         skipCommand = true;
1160                                                 }
1161                                         }
1162                                 }
1163                         }
1164                 }
1165
1166                 ievent.EventType = irr::EET_KEY_INPUT_EVENT;
1167                 ievent.KeyInput.Key = (irr::EKEY_CODE)mkey;
1168                 ievent.KeyInput.PressedDown = pressed;
1169                 ievent.KeyInput.Shift = ([(NSEvent *)event modifierFlags] & NSShiftKeyMask) != 0;
1170                 ievent.KeyInput.Control = ([(NSEvent *)event modifierFlags] & NSControlKeyMask) != 0;
1171                 ievent.KeyInput.Char = mchar;
1172
1173                 if (skipCommand)
1174                         ievent.KeyInput.Control = true;
1175                 else if ([(NSEvent *)event modifierFlags] & NSCommandKeyMask)
1176                         [NSApp sendEvent:(NSEvent *)event];
1177
1178                 postEventFromUser(ievent);
1179         }
1180 }
1181
1182
1183 void CIrrDeviceMacOSX::postMouseEvent(void *event,irr::SEvent &ievent)
1184 {
1185         bool post = true;
1186
1187         if (Window != NULL)
1188         {
1189                 ievent.MouseInput.X = (int)[(NSEvent *)event locationInWindow].x;
1190                 ievent.MouseInput.Y = DeviceHeight - (int)[(NSEvent *)event locationInWindow].y;
1191
1192                 if (ievent.MouseInput.Y < 0)
1193                         post = false;
1194         }
1195         else
1196         {
1197                 CGEventRef ourEvent = CGEventCreate(NULL);
1198                 CGPoint point = CGEventGetLocation(ourEvent);
1199                 CFRelease(ourEvent);
1200
1201                 ievent.MouseInput.X = (int)point.x;
1202                 ievent.MouseInput.Y = (int)point.y;
1203
1204                 if (ievent.MouseInput.Y < 0)
1205                         post = false;
1206         }
1207
1208         if (post)
1209         {
1210                 ievent.MouseInput.Shift = ([(NSEvent *)event modifierFlags] & NSShiftKeyMask) != 0;
1211                 ievent.MouseInput.Control = ([(NSEvent *)event modifierFlags] & NSControlKeyMask) != 0;
1212                 
1213                 postEventFromUser(ievent);
1214         }
1215
1216         [NSApp sendEvent:(NSEvent *)event];
1217 }
1218
1219
1220 void CIrrDeviceMacOSX::storeMouseLocation()
1221 {
1222         int x,y;
1223
1224         if (Window != NULL)
1225         {
1226                 NSPoint p;
1227                 p = [NSEvent mouseLocation];
1228                 p = [Window convertScreenToBase:p];
1229                 x = (int)p.x;
1230                 y = DeviceHeight - (int)p.y;
1231         }
1232         else
1233         {
1234                 CGEventRef ourEvent = CGEventCreate(NULL);
1235                 CGPoint point = CGEventGetLocation(ourEvent);
1236                 CFRelease(ourEvent);
1237
1238                 x = (int)point.x;
1239                 y = (int)point.y;
1240
1241                 const core::position2di& curr = ((CCursorControl *)CursorControl)->getPosition(true);
1242                 if (curr.X != x || curr.Y != y)
1243                 {
1244                         // In fullscreen mode, events are not sent regularly so rely on polling
1245                         irr::SEvent ievent;
1246                         ievent.EventType = irr::EET_MOUSE_INPUT_EVENT;
1247                         ievent.MouseInput.Event = irr::EMIE_MOUSE_MOVED;
1248                         ievent.MouseInput.X = x;
1249                         ievent.MouseInput.Y = y;
1250                         postEventFromUser(ievent);
1251                 }
1252         }
1253
1254         ((CCursorControl *)CursorControl)->updateInternalCursorPosition(x,y);
1255 }
1256
1257
1258 void CIrrDeviceMacOSX::setMouseLocation(int x,int y)
1259 {
1260         NSPoint p;
1261         CGPoint c;
1262
1263         if (Window != NULL)
1264         {
1265                 // Irrlicht window exists
1266                 p.x = (float) x;
1267                 p.y = (float) (DeviceHeight - y);
1268                 p = [Window convertBaseToScreen:p];
1269                 p.y = ScreenHeight - p.y;
1270         }
1271         else
1272         {
1273                 p.x = (float) x;
1274                 p.y = (float) y + (ScreenHeight - DeviceHeight);
1275         }
1276
1277         c.x = p.x;
1278         c.y = p.y;
1279
1280 #ifdef __MAC_10_6
1281     CGEventRef ev = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, c, kCGMouseButtonLeft);
1282     CGEventPost(kCGHIDEventTap, ev);
1283     CFRelease(ev);
1284 #else
1285     CGSetLocalEventsSuppressionInterval(0);
1286     CGWarpMouseCursorPosition(c);
1287 #endif
1288 }
1289
1290
1291 void CIrrDeviceMacOSX::setCursorVisible(bool visible)
1292 {
1293         if (visible)
1294                 CGDisplayShowCursor(CGMainDisplayID());
1295         else
1296                 CGDisplayHideCursor(CGMainDisplayID());
1297 }
1298     
1299     
1300 void CIrrDeviceMacOSX::setWindow(NSWindow* window)
1301 {
1302     Window = window;
1303 }
1304
1305
1306 void CIrrDeviceMacOSX::initKeycodes()
1307 {
1308         KeyCodes[kVK_UpArrow] = irr::KEY_UP;
1309         KeyCodes[kVK_DownArrow] = irr::KEY_DOWN;
1310         KeyCodes[kVK_LeftArrow] = irr::KEY_LEFT;
1311         KeyCodes[kVK_RightArrow] = irr::KEY_RIGHT;
1312         KeyCodes[kVK_F1]        = irr::KEY_F1;
1313         KeyCodes[kVK_F2]        = irr::KEY_F2;
1314         KeyCodes[kVK_F3]        = irr::KEY_F3;
1315         KeyCodes[kVK_F4]        = irr::KEY_F4;
1316         KeyCodes[kVK_F5]        = irr::KEY_F5;
1317         KeyCodes[kVK_F6]        = irr::KEY_F6;
1318         KeyCodes[kVK_F7]        = irr::KEY_F7;
1319         KeyCodes[kVK_F8]        = irr::KEY_F8;
1320         KeyCodes[kVK_F9]        = irr::KEY_F9;
1321         KeyCodes[kVK_F10]       = irr::KEY_F10;
1322         KeyCodes[kVK_F11]       = irr::KEY_F11;
1323         KeyCodes[kVK_F12]       = irr::KEY_F12;
1324         KeyCodes[kVK_F13]       = irr::KEY_F13;
1325         KeyCodes[kVK_F14]       = irr::KEY_F14;
1326         KeyCodes[kVK_F15]       = irr::KEY_F15;
1327         KeyCodes[kVK_F16]       = irr::KEY_F16;
1328         KeyCodes[kVK_F17]       = irr::KEY_F17;
1329         KeyCodes[kVK_F18]       = irr::KEY_F18;
1330         KeyCodes[kVK_F19]       = irr::KEY_F19;
1331         KeyCodes[kVK_F20]       = irr::KEY_F20;
1332         KeyCodes[kVK_Home]      = irr::KEY_HOME;
1333         KeyCodes[kVK_End]       = irr::KEY_END;
1334         KeyCodes[NSInsertFunctionKey] = irr::KEY_INSERT;
1335         KeyCodes[kVK_ForwardDelete] = irr::KEY_DELETE;
1336         KeyCodes[kVK_Help] = irr::KEY_HELP;
1337         KeyCodes[NSSelectFunctionKey] = irr::KEY_SELECT;
1338         KeyCodes[NSPrintFunctionKey] = irr::KEY_PRINT;
1339         KeyCodes[NSExecuteFunctionKey] = irr::KEY_EXECUT;
1340         KeyCodes[NSPrintScreenFunctionKey] = irr::KEY_SNAPSHOT;
1341         KeyCodes[NSPauseFunctionKey] = irr::KEY_PAUSE;
1342         KeyCodes[NSScrollLockFunctionKey] = irr::KEY_SCROLL;
1343         KeyCodes[kVK_Delete] = irr::KEY_BACK;
1344         KeyCodes[kVK_Tab] = irr::KEY_TAB;
1345         KeyCodes[kVK_Return] = irr::KEY_RETURN;
1346         KeyCodes[kVK_Escape] = irr::KEY_ESCAPE;
1347         KeyCodes[kVK_Control] = irr::KEY_CONTROL;
1348         KeyCodes[kVK_RightControl] = irr::KEY_RCONTROL;
1349         KeyCodes[kVK_Command] = irr::KEY_MENU;
1350         KeyCodes[kVK_Shift] = irr::KEY_SHIFT;
1351         KeyCodes[kVK_RightShift] = irr::KEY_RSHIFT;
1352         KeyCodes[kVK_Space] = irr::KEY_SPACE;
1353
1354         KeyCodes[kVK_ANSI_A] = irr::KEY_KEY_A;
1355         KeyCodes[kVK_ANSI_B] = irr::KEY_KEY_B;
1356         KeyCodes[kVK_ANSI_C] = irr::KEY_KEY_C;
1357         KeyCodes[kVK_ANSI_D] = irr::KEY_KEY_D;
1358         KeyCodes[kVK_ANSI_E] = irr::KEY_KEY_E;
1359         KeyCodes[kVK_ANSI_F] = irr::KEY_KEY_F;
1360         KeyCodes[kVK_ANSI_G] = irr::KEY_KEY_G;
1361         KeyCodes[kVK_ANSI_H] = irr::KEY_KEY_H;
1362         KeyCodes[kVK_ANSI_I] = irr::KEY_KEY_I;
1363         KeyCodes[kVK_ANSI_J] = irr::KEY_KEY_J;
1364         KeyCodes[kVK_ANSI_K] = irr::KEY_KEY_K;
1365         KeyCodes[kVK_ANSI_L] = irr::KEY_KEY_L;
1366         KeyCodes[kVK_ANSI_M] = irr::KEY_KEY_M;
1367         KeyCodes[kVK_ANSI_N] = irr::KEY_KEY_N;
1368         KeyCodes[kVK_ANSI_O] = irr::KEY_KEY_O;
1369         KeyCodes[kVK_ANSI_P] = irr::KEY_KEY_P;
1370         KeyCodes[kVK_ANSI_Q] = irr::KEY_KEY_Q;
1371         KeyCodes[kVK_ANSI_R] = irr::KEY_KEY_R;
1372         KeyCodes[kVK_ANSI_S] = irr::KEY_KEY_S;
1373         KeyCodes[kVK_ANSI_T] = irr::KEY_KEY_T;
1374         KeyCodes[kVK_ANSI_U] = irr::KEY_KEY_U;
1375         KeyCodes[kVK_ANSI_V] = irr::KEY_KEY_V;
1376         KeyCodes[kVK_ANSI_W] = irr::KEY_KEY_W;
1377         KeyCodes[kVK_ANSI_X] = irr::KEY_KEY_X;
1378         KeyCodes[kVK_ANSI_X] = irr::KEY_KEY_X;
1379         KeyCodes[kVK_ANSI_Y] = irr::KEY_KEY_Y;
1380         KeyCodes[kVK_ANSI_Z] = irr::KEY_KEY_Z;
1381
1382         KeyCodes[kVK_ANSI_0] = irr::KEY_KEY_0;
1383         KeyCodes[kVK_ANSI_1] = irr::KEY_KEY_1;
1384         KeyCodes[kVK_ANSI_2] = irr::KEY_KEY_2;
1385         KeyCodes[kVK_ANSI_3] = irr::KEY_KEY_3;
1386         KeyCodes[kVK_ANSI_4] = irr::KEY_KEY_4;
1387         KeyCodes[kVK_ANSI_5] = irr::KEY_KEY_5;
1388         KeyCodes[kVK_ANSI_6] = irr::KEY_KEY_6;
1389         KeyCodes[kVK_ANSI_7] = irr::KEY_KEY_7;
1390         KeyCodes[kVK_ANSI_8] = irr::KEY_KEY_8;
1391         KeyCodes[kVK_ANSI_9] = irr::KEY_KEY_9;
1392
1393         KeyCodes[kVK_ANSI_Slash] = irr::KEY_DIVIDE;
1394         KeyCodes[kVK_ANSI_Comma] = irr::KEY_COMMA;
1395         KeyCodes[kVK_ANSI_Period] = irr::KEY_PERIOD;
1396         KeyCodes[kVK_PageUp] = irr::KEY_PRIOR;
1397         KeyCodes[kVK_PageDown] = irr::KEY_NEXT;
1398
1399         KeyCodes[kVK_ANSI_Keypad0] = irr::KEY_NUMPAD0;
1400         KeyCodes[kVK_ANSI_Keypad1] = irr::KEY_NUMPAD1;
1401         KeyCodes[kVK_ANSI_Keypad2] = irr::KEY_NUMPAD2;
1402         KeyCodes[kVK_ANSI_Keypad3] = irr::KEY_NUMPAD3;
1403         KeyCodes[kVK_ANSI_Keypad4] = irr::KEY_NUMPAD4;
1404         KeyCodes[kVK_ANSI_Keypad5] = irr::KEY_NUMPAD5;
1405         KeyCodes[kVK_ANSI_Keypad6] = irr::KEY_NUMPAD6;
1406         KeyCodes[kVK_ANSI_Keypad7] = irr::KEY_NUMPAD7;
1407         KeyCodes[kVK_ANSI_Keypad8] = irr::KEY_NUMPAD8;
1408         KeyCodes[kVK_ANSI_Keypad9] = irr::KEY_NUMPAD9;
1409
1410         KeyCodes[kVK_ANSI_KeypadDecimal] = irr::KEY_DECIMAL;
1411         KeyCodes[kVK_ANSI_KeypadMultiply] = irr::KEY_MULTIPLY;
1412         KeyCodes[kVK_ANSI_KeypadPlus] = irr::KEY_PLUS;
1413         KeyCodes[kVK_ANSI_KeypadClear] = irr::KEY_OEM_CLEAR;
1414         KeyCodes[kVK_ANSI_KeypadDivide] = irr::KEY_DIVIDE;
1415         KeyCodes[kVK_ANSI_KeypadEnter] = irr::KEY_RETURN;
1416         KeyCodes[kVK_ANSI_KeypadMinus] = irr::KEY_SUBTRACT;
1417
1418         KeyCodes[kVK_ANSI_LeftBracket] = irr::KEY_OEM_4;
1419         KeyCodes[kVK_ANSI_Backslash] = irr::KEY_OEM_5;
1420         KeyCodes[kVK_ANSI_RightBracket] = irr::KEY_OEM_6;
1421 }
1422
1423
1424 //! Sets if the window should be resizable in windowed mode.
1425 void CIrrDeviceMacOSX::setResizable(bool resize)
1426 {
1427         IsResizable = resize;
1428 #if 0
1429         if (resize)
1430                 [Window setStyleMask:NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask];
1431         else
1432                 [Window setStyleMask:NSTitledWindowMask|NSClosableWindowMask];
1433 #endif
1434 }
1435
1436
1437 bool CIrrDeviceMacOSX::isResizable() const
1438 {
1439         return IsResizable;
1440 }
1441
1442
1443 void CIrrDeviceMacOSX::minimizeWindow()
1444 {
1445         if (Window != NULL)
1446                 [Window miniaturize:[NSApp self]];
1447 }
1448
1449
1450 //! Maximizes the window if possible.
1451 void CIrrDeviceMacOSX::maximizeWindow()
1452 {
1453         // todo: implement
1454 }
1455
1456
1457 //! get the window to normal size if possible.
1458 void CIrrDeviceMacOSX::restoreWindow()
1459 {
1460         [Window deminiaturize:[NSApp self]];
1461 }
1462     
1463 //! Get the position of this window on screen
1464 core::position2di CIrrDeviceMacOSX::getWindowPosition()
1465 {
1466         NSRect rect = [Window frame];
1467         int screenHeight = [[[NSScreen screens] objectAtIndex:0] frame].size.height;
1468         return core::position2di(rect.origin.x, screenHeight - rect.origin.y - rect.size.height);
1469 }
1470
1471
1472
1473 bool CIrrDeviceMacOSX::present(video::IImage* surface, void* windowId, core::rect<s32>* src )
1474 {
1475         // todo: implement window ID and src rectangle
1476
1477         if (!surface)
1478                 return false;
1479
1480         if (SoftwareRendererType > 0)
1481         {
1482                 const u32 colorSamples=3;
1483                 // do we need to change the size?
1484                 const bool updateSize = !SoftwareDriverTarget ||
1485                                 s32([SoftwareDriverTarget size].width) != surface->getDimension().Width ||
1486                                 s32([SoftwareDriverTarget size].height) != surface->getDimension().Height;
1487
1488                 NSRect areaRect = NSMakeRect(0.0, 0.0, surface->getDimension().Width, surface->getDimension().Height);
1489                 const u32 destPitch = (colorSamples * areaRect.size.width);
1490
1491                 // create / update the target
1492                 if (updateSize)
1493                 {
1494                         [SoftwareDriverTarget release];
1495                         // allocate target for IImage
1496                         SoftwareDriverTarget = [[NSBitmapImageRep alloc]
1497                                         initWithBitmapDataPlanes: nil
1498                                         pixelsWide: areaRect.size.width
1499                                         pixelsHigh: areaRect.size.height
1500                                         bitsPerSample: 8
1501                                         samplesPerPixel: colorSamples
1502                                         hasAlpha: NO
1503                                         isPlanar: NO
1504                                         colorSpaceName: NSCalibratedRGBColorSpace
1505                                         bytesPerRow: destPitch
1506                                         bitsPerPixel: 8*colorSamples];
1507                 }
1508
1509                 if (SoftwareDriverTarget==nil)
1510                         return false;
1511
1512                 // get pointer to image data
1513                 unsigned char* imgData = (unsigned char*)surface->getData();
1514
1515                 u8* srcdata = reinterpret_cast<u8*>(imgData);
1516                 u8* destData = reinterpret_cast<u8*>([SoftwareDriverTarget bitmapData]);
1517                 const u32 srcheight = core::min_(surface->getDimension().Height, (u32)areaRect.size.height);
1518                 const u32 srcPitch = surface->getPitch();
1519                 const u32 minWidth = core::min_(surface->getDimension().Width, (u32)areaRect.size.width);
1520                 for (u32 y=0; y!=srcheight; ++y)
1521                 {
1522                         if(SoftwareRendererType == 2)
1523                         {
1524                                 if (surface->getColorFormat() == video::ECF_A8R8G8B8)
1525                                         video::CColorConverter::convert_A8R8G8B8toB8G8R8(srcdata, minWidth, destData);
1526                                 else if (surface->getColorFormat() == video::ECF_A1R5G5B5)
1527                                         video::CColorConverter::convert_A1R5G5B5toB8G8R8(srcdata, minWidth, destData);
1528                                 else
1529                                         video::CColorConverter::convert_viaFormat(srcdata, surface->getColorFormat(), minWidth, destData, video::ECF_R8G8B8);
1530                         }
1531                         else
1532                         {
1533                                 if (surface->getColorFormat() == video::ECF_A8R8G8B8)
1534                                         video::CColorConverter::convert_A8R8G8B8toR8G8B8(srcdata, minWidth, destData);
1535                                 else if (surface->getColorFormat() == video::ECF_A1R5G5B5)
1536                                         video::CColorConverter::convert_A1R5G5B5toR8G8B8(srcdata, minWidth, destData);
1537                                 else
1538                                         video::CColorConverter::convert_viaFormat(srcdata, surface->getColorFormat(), minWidth, destData, video::ECF_R8G8B8);
1539                         }
1540
1541                         srcdata += srcPitch;
1542                         destData += destPitch;
1543                 }
1544
1545                 // todo: draw properly into a sub-view
1546                 [SoftwareDriverTarget draw];
1547         }
1548
1549         return false;
1550 }
1551
1552
1553 #if defined (_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
1554 static void joystickRemovalCallback(void * target,
1555                 IOReturn result, void * refcon, void * sender)
1556 {
1557         JoystickInfo *joy = (JoystickInfo *) refcon;
1558         joy->removed = 1;
1559 }
1560 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
1561
1562
1563 bool CIrrDeviceMacOSX::activateJoysticks(core::array<SJoystickInfo> & joystickInfo)
1564 {
1565 #if defined (_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
1566         ActiveJoysticks.clear();
1567         joystickInfo.clear();
1568
1569         io_object_t hidObject = 0;
1570         io_iterator_t hidIterator = 0;
1571         IOReturn result = kIOReturnSuccess;
1572         mach_port_t masterPort = 0;
1573         CFMutableDictionaryRef hidDictionaryRef = NULL;
1574
1575         result = IOMasterPort (bootstrap_port, &masterPort);
1576         if (kIOReturnSuccess != result)
1577         {
1578                 os::Printer::log("initialiseJoysticks IOMasterPort failed", ELL_ERROR);
1579                 return false;
1580         }
1581
1582         hidDictionaryRef = IOServiceMatching (kIOHIDDeviceKey);
1583         if (!hidDictionaryRef)
1584         {
1585                 os::Printer::log("initialiseJoysticks IOServiceMatching failed", ELL_ERROR);
1586                 return false;
1587         }
1588         result = IOServiceGetMatchingServices (masterPort, hidDictionaryRef, &hidIterator);
1589
1590         if (kIOReturnSuccess != result)
1591         {
1592                 os::Printer::log("initialiseJoysticks IOServiceGetMatchingServices failed", ELL_ERROR);
1593                 return false;
1594         }
1595
1596         //no joysticks just return
1597         if (!hidIterator)
1598                 return false;
1599
1600         u32 jindex = 0u;
1601         while ((hidObject = IOIteratorNext (hidIterator)))
1602         {
1603                 JoystickInfo info;
1604
1605                 // get dictionary for HID properties
1606                 CFMutableDictionaryRef hidProperties = 0;
1607
1608                 kern_return_t kern_result = IORegistryEntryCreateCFProperties (hidObject, &hidProperties, kCFAllocatorDefault, kNilOptions);
1609                 if ((kern_result == KERN_SUCCESS) && hidProperties)
1610                 {
1611                         HRESULT plugInResult = S_OK;
1612                         SInt32 score = 0;
1613                         IOCFPlugInInterface ** ppPlugInInterface = NULL;
1614                         result = IOCreatePlugInInterfaceForService (hidObject, kIOHIDDeviceUserClientTypeID,
1615                                                                                                         kIOCFPlugInInterfaceID, &ppPlugInInterface, &score);
1616                         if (kIOReturnSuccess == result)
1617                         {
1618                                 plugInResult = (*ppPlugInInterface)->QueryInterface (ppPlugInInterface,
1619                                                                         CFUUIDGetUUIDBytes (kIOHIDDeviceInterfaceID), (void **) &(info.interface));
1620                                 if (plugInResult != S_OK)
1621                                         os::Printer::log("initialiseJoysticks query HID class device interface failed", ELL_ERROR);
1622                                 (*ppPlugInInterface)->Release(ppPlugInInterface);
1623                         }
1624                         else
1625                                 continue;
1626
1627                         if (info.interface != NULL)
1628                         {
1629                                 result = (*(info.interface))->open (info.interface, 0);
1630                                 if (result == kIOReturnSuccess)
1631                                 {
1632                                         (*(info.interface))->setRemovalCallback (info.interface, joystickRemovalCallback, &info, &info);
1633                                         getJoystickDeviceInfo(hidObject, hidProperties, &info);
1634
1635                                         // get elements
1636                                         CFTypeRef refElementTop = CFDictionaryGetValue (hidProperties, CFSTR(kIOHIDElementKey));
1637                                         if (refElementTop)
1638                                         {
1639                                                 CFTypeID type = CFGetTypeID (refElementTop);
1640                                                 if (type == CFArrayGetTypeID())
1641                                                 {
1642                                                         CFRange range = {0, CFArrayGetCount ((CFArrayRef)refElementTop)};
1643                                                         info.numActiveJoysticks = ActiveJoysticks.size();
1644                                                         CFArrayApplyFunction ((CFArrayRef)refElementTop, range, getJoystickComponentArrayHandler, &info);
1645                                                 }
1646                                         }
1647                                 }
1648                                 else
1649                                 {
1650                                         CFRelease (hidProperties);
1651                                         os::Printer::log("initialiseJoysticks Open interface failed", ELL_ERROR);
1652                                         continue;
1653                                 }
1654
1655                                 CFRelease (hidProperties);
1656
1657                                 result = IOObjectRelease (hidObject);
1658
1659                                 if ( (info.usagePage != kHIDPage_GenericDesktop) ||
1660                                         ((info.usage != kHIDUsage_GD_Joystick &&
1661                                         info.usage != kHIDUsage_GD_GamePad &&
1662                                         info.usage != kHIDUsage_GD_MultiAxisController)) )
1663                                 {
1664                                         closeJoystickDevice (&info);
1665                                         continue;
1666                                 }
1667
1668                                 for (u32 i = 0; i < 6; ++i)
1669                                         info.persistentData.JoystickEvent.Axis[i] = 0;
1670
1671                                 ActiveJoysticks.push_back(info);
1672
1673                                 SJoystickInfo returnInfo;
1674                                 returnInfo.Joystick = jindex;
1675                                 returnInfo.Axes = info.axes;
1676                                 //returnInfo.Hats = info.hats;
1677                                 returnInfo.Buttons = info.buttons;
1678                                 returnInfo.Name = info.joystickName;
1679                                 returnInfo.PovHat = SJoystickInfo::POV_HAT_UNKNOWN;
1680                                 ++ jindex;
1681
1682                                 //if (info.hatComp.size())
1683                                 //      returnInfo.PovHat = SJoystickInfo::POV_HAT_PRESENT;
1684                                 //else
1685                                 //      returnInfo.PovHat = SJoystickInfo::POV_HAT_ABSENT;
1686
1687                                 joystickInfo.push_back(returnInfo);
1688                         }
1689
1690                 }
1691                 else
1692                 {
1693                         continue;
1694                 }
1695         }
1696         result = IOObjectRelease (hidIterator);
1697
1698         return true;
1699 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
1700
1701         return false;
1702 }
1703
1704 void CIrrDeviceMacOSX::pollJoysticks()
1705 {
1706 #if defined (_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
1707         if(0 == ActiveJoysticks.size())
1708                 return;
1709
1710         u32 joystick;
1711         for (joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
1712         {
1713                 if (ActiveJoysticks[joystick].removed)
1714                         continue;
1715
1716                 bool found = false;
1717                 ActiveJoysticks[joystick].persistentData.JoystickEvent.Joystick = joystick;
1718
1719                 if (ActiveJoysticks[joystick].interface)
1720                 {
1721                         for (u32 n = 0; n < ActiveJoysticks[joystick].axisComp.size(); n++)
1722                         {
1723                                 IOReturn result = kIOReturnSuccess;
1724                                 IOHIDEventStruct hidEvent;
1725                                 hidEvent.value = 0;
1726                                 result = (*(ActiveJoysticks[joystick].interface))->getElementValue(ActiveJoysticks[joystick].interface, ActiveJoysticks[joystick].axisComp[n].cookie, &hidEvent);
1727                                 if (kIOReturnSuccess == result)
1728                                 {
1729                                         const f32 min = -32768.0f;
1730                                         const f32 max = 32767.0f;
1731                                         const f32 deviceScale = max - min;
1732                                         const f32 readScale = (f32)ActiveJoysticks[joystick].axisComp[n].maxRead - (f32)ActiveJoysticks[joystick].axisComp[n].minRead;
1733
1734                                         if (hidEvent.value < ActiveJoysticks[joystick].axisComp[n].minRead)
1735                                                 ActiveJoysticks[joystick].axisComp[n].minRead = hidEvent.value;
1736                                         if (hidEvent.value > ActiveJoysticks[joystick].axisComp[n].maxRead)
1737                                                 ActiveJoysticks[joystick].axisComp[n].maxRead = hidEvent.value;
1738
1739                                         if (readScale != 0.0f)
1740                                                 hidEvent.value = (int)(((f32)((f32)hidEvent.value - (f32)ActiveJoysticks[joystick].axisComp[n].minRead) * deviceScale / readScale) + min);
1741
1742                                         if (ActiveJoysticks[joystick].persistentData.JoystickEvent.Axis[n] != (s16)hidEvent.value)
1743                                                 found = true;
1744                                         ActiveJoysticks[joystick].persistentData.JoystickEvent.Axis[n] = (s16)hidEvent.value;
1745                                 }
1746                         }//axis check
1747
1748                         for (u32 n = 0; n < ActiveJoysticks[joystick].buttonComp.size(); n++)
1749                         {
1750                                 IOReturn result = kIOReturnSuccess;
1751                                 IOHIDEventStruct hidEvent;
1752                                 hidEvent.value = 0;
1753                                 result = (*(ActiveJoysticks[joystick].interface))->getElementValue(ActiveJoysticks[joystick].interface, ActiveJoysticks[joystick].buttonComp[n].cookie, &hidEvent);
1754                                 if (kIOReturnSuccess == result)
1755                                 {
1756                                         if (hidEvent.value && !((ActiveJoysticks[joystick].persistentData.JoystickEvent.ButtonStates & (1 << n)) ? true : false) )
1757                                                         found = true;
1758                                         else if (!hidEvent.value && ((ActiveJoysticks[joystick].persistentData.JoystickEvent.ButtonStates & (1 << n)) ? true : false))
1759                                                         found = true;
1760
1761                                         if (hidEvent.value)
1762                                                         ActiveJoysticks[joystick].persistentData.JoystickEvent.ButtonStates |= (1 << n);
1763                                         else
1764                                                         ActiveJoysticks[joystick].persistentData.JoystickEvent.ButtonStates &= ~(1 << n);
1765                                 }
1766                         }//button check
1767                         //still ToDo..will be done soon :)
1768 /*
1769                         for (u32 n = 0; n < ActiveJoysticks[joystick].hatComp.size(); n++)
1770                         {
1771                                 IOReturn result = kIOReturnSuccess;
1772                                 IOHIDEventStruct hidEvent;
1773                                 hidEvent.value = 0;
1774                                 result = (*(ActiveJoysticks[joystick].interface))->getElementValue(ActiveJoysticks[joystick].interface, ActiveJoysticks[joystick].hatComp[n].cookie, &hidEvent);
1775                                 if (kIOReturnSuccess == result)
1776                                 {
1777                                         if (ActiveJoysticks[joystick].persistentData.JoystickEvent.POV != hidEvent.value)
1778                                                 found = true;
1779                                         ActiveJoysticks[joystick].persistentData.JoystickEvent.POV = hidEvent.value;
1780                                 }
1781                         }//hat check
1782 */
1783                 }
1784
1785                 if (found)
1786                         postEventFromUser(ActiveJoysticks[joystick].persistentData);
1787         }
1788 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
1789 }
1790
1791 video::IVideoModeList* CIrrDeviceMacOSX::getVideoModeList()
1792 {
1793         if (!VideoModeList->getVideoModeCount())
1794         {
1795                 CGDirectDisplayID display;
1796                 display = CGMainDisplayID();
1797
1798 #ifdef __MAC_10_6
1799                 CFArrayRef Modes = CGDisplayCopyAllDisplayModes(display, NULL);
1800
1801                 for(int i = 0; i < CFArrayGetCount(Modes); ++i)
1802                 {
1803                         CGDisplayModeRef CurrentMode = (CGDisplayModeRef)CFArrayGetValueAtIndex(Modes, i);
1804
1805                         u8 Depth = 0;
1806
1807                         CFStringRef pixEnc = CGDisplayModeCopyPixelEncoding(CurrentMode);
1808
1809                         if(CFStringCompare(pixEnc, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
1810                                 Depth = 32;
1811                         else
1812                         if(CFStringCompare(pixEnc, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
1813                                 Depth = 16;
1814                         else
1815                         if(CFStringCompare(pixEnc, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
1816                                 Depth = 8;
1817
1818                         if(Depth)
1819                         {
1820                                 unsigned int Width = CGDisplayModeGetWidth(CurrentMode);
1821                                 unsigned int Height = CGDisplayModeGetHeight(CurrentMode);
1822
1823                                 VideoModeList->addMode(core::dimension2d<u32>(Width, Height), Depth);
1824                         }
1825                 }
1826 #else
1827                 CFArrayRef availableModes = CGDisplayAvailableModes(display);
1828                 unsigned int numberOfAvailableModes = CFArrayGetCount(availableModes);
1829                 for (u32 i= 0; i<numberOfAvailableModes; ++i)
1830                 {
1831                         // look at each mode in the available list
1832                         CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex(availableModes, i);
1833                         long bitsPerPixel = GetDictionaryLong(mode, kCGDisplayBitsPerPixel);
1834                         Boolean safeForHardware = GetDictionaryBoolean(mode, kCGDisplayModeIsSafeForHardware);
1835                         Boolean stretched = GetDictionaryBoolean(mode, kCGDisplayModeIsStretched);
1836
1837                         if (!safeForHardware)
1838                                 continue;
1839
1840                         long width = GetDictionaryLong(mode, kCGDisplayWidth);
1841                         long height = GetDictionaryLong(mode, kCGDisplayHeight);
1842                         // long refresh = GetDictionaryLong((mode), kCGDisplayRefreshRate);
1843                         VideoModeList.addMode(core::dimension2d<u32>(width, height),
1844                                 bitsPerPixel);
1845                 }
1846 #endif
1847         }
1848         return VideoModeList;
1849 }
1850
1851 } // end namespace
1852
1853 #endif // _IRR_COMPILE_WITH_OSX_DEVICE_
1854