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
7 #ifdef _IRR_COMPILE_WITH_OSX_DEVICE_
9 #import <Cocoa/Cocoa.h>
12 #include "CIrrDeviceOSX.h"
14 #include "IEventReceiver.h"
15 #include "IVideoDriver.h"
18 #include "irrString.h"
21 #include <sys/utsname.h>
22 #include "COSOperator.h"
23 #include "CColorConverter.h"
30 #include "CNSOGLManager.h"
32 #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
34 #include <IOKit/IOKitLib.h>
35 #include <IOKit/IOCFPlugIn.h>
36 #include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
37 #include <IOKit/hid/IOHIDLib.h>
38 #include <IOKit/hid/IOHIDKeys.h>
40 struct JoystickComponent
42 IOHIDElementCookie cookie; // unique value which identifies element, will NOT change
43 long min; // reported min value possible
44 long max; // reported max value possible
46 long minRead; // min read value
47 long maxRead; // max read value
50 min(0), minRead(0), max(0), maxRead(0)
57 irr::core::array<JoystickComponent> axisComp;
58 irr::core::array<JoystickComponent> buttonComp;
59 irr::core::array<JoystickComponent> hatComp;
64 int numActiveJoysticks;
66 irr::SEvent persistentData;
68 IOHIDDeviceInterface **interface;
70 char joystickName[256];
71 long usage; // usage page from IOUSBHID Parser.h which defines general usage
72 long usagePage; // usage within above page from IOUSBHID Parser.h which defines specific usage
75 hats(0), axes(0), buttons(0), interface(0), removed(false), usage(0), usagePage(0), numActiveJoysticks(0)
78 memset(joystickName, '\0', 256);
83 persistentData.EventType = irr::EET_JOYSTICK_INPUT_EVENT;
84 persistentData.JoystickEvent.POV = 65535;
85 persistentData.JoystickEvent.ButtonStates = 0;
88 irr::core::array<JoystickInfo> ActiveJoysticks;
90 // helper functions for init joystick
91 static IOReturn closeJoystickDevice(JoystickInfo *joyInfo)
93 IOReturn result = kIOReturnSuccess;
94 if (joyInfo && joyInfo->interface) {
95 /* close the interface */
96 result = (*(joyInfo->interface))->close(joyInfo->interface);
97 if (kIOReturnNotOpen == result) {
98 /* do nothing as device was not opened, thus can't be closed */
99 } else if (kIOReturnSuccess != result)
100 irr::os::Printer::log("IOHIDDeviceInterface failed to close", irr::ELL_ERROR);
101 /* release the interface */
102 result = (*(joyInfo->interface))->Release(joyInfo->interface);
103 if (kIOReturnSuccess != result)
104 irr::os::Printer::log("IOHIDDeviceInterface failed to release", irr::ELL_ERROR);
105 joyInfo->interface = NULL;
110 static void addComponentInfo(CFTypeRef refElement, JoystickComponent *pComponent, int numActiveJoysticks)
115 refType = CFDictionaryGetValue((CFDictionaryRef)refElement, CFSTR(kIOHIDElementCookieKey));
116 if (refType && CFNumberGetValue((CFNumberRef)refType, kCFNumberLongType, &number))
117 pComponent->cookie = (IOHIDElementCookie)number;
118 refType = CFDictionaryGetValue((CFDictionaryRef)refElement, CFSTR(kIOHIDElementMinKey));
119 if (refType && CFNumberGetValue((CFNumberRef)refType, kCFNumberLongType, &number))
120 pComponent->minRead = pComponent->min = number;
121 refType = CFDictionaryGetValue((CFDictionaryRef)refElement, CFSTR(kIOHIDElementMaxKey));
122 if (refType && CFNumberGetValue((CFNumberRef)refType, kCFNumberLongType, &number))
123 pComponent->maxRead = pComponent->max = number;
126 static void getJoystickComponentArrayHandler(const void *value, void *parameter);
128 static void addJoystickComponent(CFTypeRef refElement, JoystickInfo *joyInfo)
130 long elementType, usagePage, usage;
131 CFTypeRef refElementType = CFDictionaryGetValue((CFDictionaryRef)refElement, CFSTR(kIOHIDElementTypeKey));
132 CFTypeRef refUsagePage = CFDictionaryGetValue((CFDictionaryRef)refElement, CFSTR(kIOHIDElementUsagePageKey));
133 CFTypeRef refUsage = CFDictionaryGetValue((CFDictionaryRef)refElement, CFSTR(kIOHIDElementUsageKey));
135 if ((refElementType) && (CFNumberGetValue((CFNumberRef)refElementType, kCFNumberLongType, &elementType))) {
136 /* look at types of interest */
137 if ((elementType == kIOHIDElementTypeInput_Misc) || (elementType == kIOHIDElementTypeInput_Button) ||
138 (elementType == kIOHIDElementTypeInput_Axis)) {
139 if (refUsagePage && CFNumberGetValue((CFNumberRef)refUsagePage, kCFNumberLongType, &usagePage) &&
140 refUsage && CFNumberGetValue((CFNumberRef)refUsage, kCFNumberLongType, &usage)) {
141 switch (usagePage) /* only interested in kHIDPage_GenericDesktop and kHIDPage_Button */
143 case kHIDPage_GenericDesktop: {
144 switch (usage) /* look at usage to determine function */
149 case kHIDUsage_GD_Rx:
150 case kHIDUsage_GD_Ry:
151 case kHIDUsage_GD_Rz:
152 case kHIDUsage_GD_Slider:
153 case kHIDUsage_GD_Dial:
154 case kHIDUsage_GD_Wheel: {
156 JoystickComponent newComponent;
157 addComponentInfo(refElement, &newComponent, joyInfo->numActiveJoysticks);
158 joyInfo->axisComp.push_back(newComponent);
160 case kHIDUsage_GD_Hatswitch: {
162 JoystickComponent newComponent;
163 addComponentInfo(refElement, &newComponent, joyInfo->numActiveJoysticks);
164 joyInfo->hatComp.push_back(newComponent);
168 case kHIDPage_Button: {
170 JoystickComponent newComponent;
171 addComponentInfo(refElement, &newComponent, joyInfo->numActiveJoysticks);
172 joyInfo->buttonComp.push_back(newComponent);
178 } else if (kIOHIDElementTypeCollection == elementType) {
180 CFTypeRef refElementTop = CFDictionaryGetValue((CFMutableDictionaryRef)refElement, CFSTR(kIOHIDElementKey));
182 CFTypeID type = CFGetTypeID(refElementTop);
183 if (type == CFArrayGetTypeID()) {
184 CFRange range = {0, CFArrayGetCount((CFArrayRef)refElementTop)};
185 CFArrayApplyFunction((CFArrayRef)refElementTop, range, getJoystickComponentArrayHandler, joyInfo);
192 static void getJoystickComponentArrayHandler(const void *value, void *parameter)
194 if (CFGetTypeID(value) == CFDictionaryGetTypeID())
195 addJoystickComponent((CFTypeRef)value, (JoystickInfo *)parameter);
198 static void joystickTopLevelElementHandler(const void *value, void *parameter)
201 if (CFGetTypeID(value) != CFDictionaryGetTypeID())
203 refCF = CFDictionaryGetValue((CFDictionaryRef)value, CFSTR(kIOHIDElementUsagePageKey));
204 if (!CFNumberGetValue((CFNumberRef)refCF, kCFNumberLongType, &((JoystickInfo *)parameter)->usagePage))
205 irr::os::Printer::log("CFNumberGetValue error retrieving JoystickInfo->usagePage", irr::ELL_ERROR);
206 refCF = CFDictionaryGetValue((CFDictionaryRef)value, CFSTR(kIOHIDElementUsageKey));
207 if (!CFNumberGetValue((CFNumberRef)refCF, kCFNumberLongType, &((JoystickInfo *)parameter)->usage))
208 irr::os::Printer::log("CFNumberGetValue error retrieving JoystickInfo->usage", irr::ELL_ERROR);
211 static void getJoystickDeviceInfo(io_object_t hidDevice, CFMutableDictionaryRef hidProperties, JoystickInfo *joyInfo)
213 CFMutableDictionaryRef usbProperties = 0;
214 io_registry_entry_t parent1, parent2;
216 /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
217 * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
219 if ((KERN_SUCCESS == IORegistryEntryGetParentEntry(hidDevice, kIOServicePlane, &parent1)) &&
220 (KERN_SUCCESS == IORegistryEntryGetParentEntry(parent1, kIOServicePlane, &parent2)) &&
221 (KERN_SUCCESS == IORegistryEntryCreateCFProperties(parent2, &usbProperties, kCFAllocatorDefault, kNilOptions))) {
225 * try hid dictionary first, if fail then go to usb dictionary
228 /* get joystickName name */
229 refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDProductKey));
231 refCF = CFDictionaryGetValue(usbProperties, CFSTR("USB Product Name"));
233 if (!CFStringGetCString((CFStringRef)refCF, joyInfo->joystickName, 256, CFStringGetSystemEncoding()))
234 irr::os::Printer::log("CFStringGetCString error getting joyInfo->joystickName", irr::ELL_ERROR);
237 /* get usage page and usage */
238 refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDPrimaryUsagePageKey));
240 if (!CFNumberGetValue((CFNumberRef)refCF, kCFNumberLongType, &joyInfo->usagePage))
241 irr::os::Printer::log("CFNumberGetValue error getting joyInfo->usagePage", irr::ELL_ERROR);
242 refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDPrimaryUsageKey));
244 if (!CFNumberGetValue((CFNumberRef)refCF, kCFNumberLongType, &joyInfo->usage))
245 irr::os::Printer::log("CFNumberGetValue error getting joyInfo->usage", irr::ELL_ERROR);
248 if (NULL == refCF) /* get top level element HID usage page or usage */
250 /* use top level element instead */
251 CFTypeRef refCFTopElement = 0;
252 refCFTopElement = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDElementKey));
254 /* refCFTopElement points to an array of element dictionaries */
255 CFRange range = {0, CFArrayGetCount((CFArrayRef)refCFTopElement)};
256 CFArrayApplyFunction((CFArrayRef)refCFTopElement, range, joystickTopLevelElementHandler, joyInfo);
260 CFRelease(usbProperties);
262 irr::os::Printer::log("IORegistryEntryCreateCFProperties failed to create usbProperties", irr::ELL_ERROR);
264 if (kIOReturnSuccess != IOObjectRelease(parent2))
265 irr::os::Printer::log("IOObjectRelease failed to release parent2", irr::ELL_ERROR);
266 if (kIOReturnSuccess != IOObjectRelease(parent1))
267 irr::os::Printer::log("IOObjectRelease failed to release parent1", irr::ELL_ERROR);
271 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
273 // Contents from Events.h from Carbon/HIToolbox but we need it with Cocoa too
274 // and for some reason no Cocoa equivalent of these constants seems provided.
275 // So I'm doing like everyone else and using copy-and-paste.
282 * These constants are the virtual keycodes defined originally in
283 * Inside Mac Volume V, pg. V-191. They identify physical keys on a
284 * keyboard. Those constants with "ANSI" in the name are labeled
285 * according to the key position on an ANSI-standard US keyboard.
286 * For example, kVK_ANSI_A indicates the virtual keycode for the key
287 * with the letter 'A' in the US keyboard layout. Other keyboard
288 * layouts may have the 'A' key label on a different physical key;
289 * in this case, pressing 'A' will generate a different virtual
317 kVK_ANSI_Equal = 0x18,
320 kVK_ANSI_Minus = 0x1B,
323 kVK_ANSI_RightBracket = 0x1E,
326 kVK_ANSI_LeftBracket = 0x21,
331 kVK_ANSI_Quote = 0x27,
333 kVK_ANSI_Semicolon = 0x29,
334 kVK_ANSI_Backslash = 0x2A,
335 kVK_ANSI_Comma = 0x2B,
336 kVK_ANSI_Slash = 0x2C,
339 kVK_ANSI_Period = 0x2F,
340 kVK_ANSI_Grave = 0x32,
341 kVK_ANSI_KeypadDecimal = 0x41,
342 kVK_ANSI_KeypadMultiply = 0x43,
343 kVK_ANSI_KeypadPlus = 0x45,
344 kVK_ANSI_KeypadClear = 0x47,
345 kVK_ANSI_KeypadDivide = 0x4B,
346 kVK_ANSI_KeypadEnter = 0x4C,
347 kVK_ANSI_KeypadMinus = 0x4E,
348 kVK_ANSI_KeypadEquals = 0x51,
349 kVK_ANSI_Keypad0 = 0x52,
350 kVK_ANSI_Keypad1 = 0x53,
351 kVK_ANSI_Keypad2 = 0x54,
352 kVK_ANSI_Keypad3 = 0x55,
353 kVK_ANSI_Keypad4 = 0x56,
354 kVK_ANSI_Keypad5 = 0x57,
355 kVK_ANSI_Keypad6 = 0x58,
356 kVK_ANSI_Keypad7 = 0x59,
357 kVK_ANSI_Keypad8 = 0x5B,
358 kVK_ANSI_Keypad9 = 0x5C
361 /* keycodes for keys that are independent of keyboard layout*/
374 kVK_RightShift = 0x3C,
375 kVK_RightOption = 0x3D,
376 kVK_RightControl = 0x3E,
380 kVK_VolumeDown = 0x49,
401 kVK_ForwardDelete = 0x75,
407 kVK_LeftArrow = 0x7B,
408 kVK_RightArrow = 0x7C,
409 kVK_DownArrow = 0x7D,
413 //------------------------------------------------------------------------------------------
414 Boolean GetDictionaryBoolean(CFDictionaryRef theDict, const void *key)
416 // get a boolean from the dictionary
417 Boolean value = false;
418 CFBooleanRef boolRef;
419 boolRef = (CFBooleanRef)CFDictionaryGetValue(theDict, key);
421 value = CFBooleanGetValue(boolRef);
424 //------------------------------------------------------------------------------------------
425 long GetDictionaryLong(CFDictionaryRef theDict, const void *key)
427 // get a long from the dictionary
430 numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key);
432 CFNumberGetValue(numRef, kCFNumberLongType, &value);
436 static bool firstLaunch = true;
438 @implementation CIrrDelegateOSX {
439 irr::CIrrDeviceMacOSX *Device;
443 - (id)initWithDevice:(irr::CIrrDeviceMacOSX *)device
455 - (void)applicationDidFinishLaunching:(NSNotification *)notification
460 - (void)orderFrontStandardAboutPanel:(id)sender
462 [NSApp orderFrontStandardAboutPanel:sender];
465 - (void)unhideAllApplications:(id)sender
467 [NSApp unhideAllApplications:sender];
470 - (void)hide:(id)sender
475 - (void)hideOtherApplications:(id)sender
477 [NSApp hideOtherApplications:sender];
480 - (void)terminate:(id)sender
485 - (void)windowWillClose:(id)sender
487 Device->setWindow(nil);
491 - (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize
493 if (Device->isResizable())
494 return proposedFrameSize;
496 return [window frame].size;
499 - (void)windowDidResize:(NSNotification *)aNotification
504 window = [aNotification object];
505 frame = [window frame];
506 Device->setResize((int)frame.size.width, (int)frame.size.height);
519 CIrrDeviceMacOSX::CIrrDeviceMacOSX(const SIrrlichtCreationParameters ¶m) :
520 CIrrDeviceStub(param), Window(NULL), Display(NULL),
521 DeviceWidth(0), DeviceHeight(0),
522 ScreenWidth(0), ScreenHeight(0), MouseButtonStates(0),
523 IsActive(true), IsFullscreen(false), IsShiftDown(false), IsControlDown(false), IsResizable(false)
528 setDebugName("CIrrDeviceMacOSX");
534 if (!CreationParams.WindowId) {
535 [[NSAutoreleasePool alloc] init];
536 [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
537 [[NSApplication sharedApplication] setDelegate:[[[CIrrDelegateOSX alloc] initWithDevice:this] autorelease]];
541 NSString *bundleName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
542 if (bundleName == nil)
543 bundleName = @"Irrlicht";
545 NSMenu *mainMenu = [[[NSMenu alloc] initWithTitle:@"MainMenu"] autorelease];
546 NSMenu *menu = [[[NSMenu alloc] initWithTitle:bundleName] autorelease];
547 NSMenuItem *menuItem = [mainMenu addItemWithTitle:bundleName action:nil keyEquivalent:@""];
548 [mainMenu setSubmenu:menu forItem:menuItem];
549 menuItem = [menu addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"];
550 [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
552 [NSApp setMainMenu:mainMenu];
554 [NSApp finishLaunching];
557 NSString *path = [[NSBundle mainBundle] bundlePath];
559 path = [path stringByAppendingString:@"/Contents/Resources"];
560 chdir([path fileSystemRepresentation]);
566 Operator = new COSOperator(name.version);
567 os::Printer::log(name.version, ELL_INFORMATION);
573 if (CreationParams.DriverType != video::EDT_NULL)
574 success = createWindow();
576 // in case of failure, one can check VideoDriver for initialization
581 CursorControl = new CCursorControl(CreationParams.WindowSize, this);
587 CIrrDeviceMacOSX::~CIrrDeviceMacOSX()
589 [NSApp setPresentationOptions:(NSApplicationPresentationDefault)];
591 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
592 for (u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) {
593 if (ActiveJoysticks[joystick].interface)
594 closeJoystickDevice(&ActiveJoysticks[joystick]);
599 void CIrrDeviceMacOSX::closeDevice()
602 [Window setIsVisible:FALSE];
603 [Window setReleasedWhenClosed:TRUE];
608 IsFullscreen = false;
612 bool CIrrDeviceMacOSX::createWindow()
616 Display = CGMainDisplayID();
619 CGDisplayModeRef displaymode, olddisplaymode;
621 ScreenWidth = (int)CGDisplayPixelsWide(Display);
622 ScreenHeight = (int)CGDisplayPixelsHigh(Display);
624 const NSBackingStoreType type = (CreationParams.DriverType == video::EDT_OPENGL) ? NSBackingStoreBuffered : NSBackingStoreNonretained;
627 // if (!CreationParams.Fullscreen)
629 if (!CreationParams.WindowId) { // create another window when WindowId is null
630 int x = (CreationParams.WindowPosition.X > 0) ? CreationParams.WindowPosition.X : 0;
631 int y = (CreationParams.WindowPosition.Y > 0) ? CreationParams.WindowPosition.Y : 0;
633 if (CreationParams.WindowPosition.Y > -1) {
634 int screenHeight = [[[NSScreen screens] objectAtIndex:0] frame].size.height;
635 y = screenHeight - y - CreationParams.WindowSize.Height;
638 Window = [[NSWindow alloc] initWithContentRect:NSMakeRect(x, y, CreationParams.WindowSize.Width, CreationParams.WindowSize.Height) styleMask:NSTitledWindowMask + NSClosableWindowMask + NSResizableWindowMask backing:type defer:FALSE];
640 if (CreationParams.WindowPosition.X == -1 && CreationParams.WindowPosition.Y == -1)
644 DeviceWidth = CreationParams.WindowSize.Width;
645 DeviceHeight = CreationParams.WindowSize.Height;
652 [Window setDelegate:(CIrrDelegateOSX *)[NSApp delegate]];
653 [Window setAcceptsMouseMovedEvents:TRUE];
654 [Window setIsVisible:TRUE];
655 [Window makeKeyAndOrderFront:nil];
662 void CIrrDeviceMacOSX::setResize(int width, int height)
664 // set new window size
666 DeviceHeight = height;
668 #if defined(_IRR_COMPILE_WITH_OPENGL_)
669 // update the size of the opengl rendering context
670 if (CreationParams.DriverType == video::EDT_OPENGL) {
671 NSOpenGLContext *Context = (NSOpenGLContext *)ContextManager->getContext().OpenGLOSX.Context;
678 // resize the driver to the inner pane size
680 NSRect driverFrame = [Window contentRectForFrameRect:[Window frame]];
681 getVideoDriver()->OnResize(core::dimension2d<u32>((s32)driverFrame.size.width, (s32)driverFrame.size.height));
682 DeviceWidth = (s32)driverFrame.size.width;
683 DeviceHeight = (s32)driverFrame.size.height;
685 getVideoDriver()->OnResize(core::dimension2d<u32>((s32)width, (s32)height));
688 void CIrrDeviceMacOSX::createDriver()
690 switch (CreationParams.DriverType) {
691 case video::EDT_OPENGL:
692 #ifdef _IRR_COMPILE_WITH_OPENGL_
694 video::SExposedVideoData data;
695 data.OpenGLOSX.Window = Window;
696 ContextManager = new video::CNSOGLManager();
697 ContextManager->initialize(CreationParams, data);
698 VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager);
700 os::Printer::log("Could not create OpenGL driver.", ELL_ERROR);
704 [[Window contentView] setWantsBestResolutionOpenGLSurface:NO];
705 [(NSOpenGLContext *)ContextManager->getContext().OpenGLOSX.Context setView:[Window contentView]];
707 [(NSView *)CreationParams.WindowId setWantsBestResolutionOpenGLSurface:NO];
708 [(NSOpenGLContext *)ContextManager->getContext().OpenGLOSX.Context setView:(NSView *)CreationParams.WindowId];
712 os::Printer::log("No OpenGL support compiled in.", ELL_ERROR);
716 case video::EDT_OPENGL3:
717 case video::EDT_OGLES2:
718 os::Printer::log("This driver is not available on OSX.", ELL_ERROR);
721 case video::EDT_NULL:
722 VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);
726 os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR);
731 bool CIrrDeviceMacOSX::run()
733 NSAutoreleasePool *Pool = [[NSAutoreleasePool alloc] init];
739 storeMouseLocation();
741 event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES];
743 bzero(&ievent, sizeof(ievent));
745 switch ([(NSEvent *)event type]) {
747 postKeyEvent(event, ievent, true);
751 postKeyEvent(event, ievent, false);
755 ievent.EventType = irr::EET_KEY_INPUT_EVENT;
756 ievent.KeyInput.Shift = ([(NSEvent *)event modifierFlags] & NSShiftKeyMask) != 0;
757 ievent.KeyInput.Control = ([(NSEvent *)event modifierFlags] & NSControlKeyMask) != 0;
759 if (IsShiftDown != ievent.KeyInput.Shift) {
760 ievent.KeyInput.Char = irr::KEY_SHIFT;
761 ievent.KeyInput.Key = irr::KEY_SHIFT;
762 ievent.KeyInput.PressedDown = ievent.KeyInput.Shift;
764 IsShiftDown = ievent.KeyInput.Shift;
766 postEventFromUser(ievent);
769 if (IsControlDown != ievent.KeyInput.Control) {
770 ievent.KeyInput.Char = irr::KEY_CONTROL;
771 ievent.KeyInput.Key = irr::KEY_CONTROL;
772 ievent.KeyInput.PressedDown = ievent.KeyInput.Control;
774 IsControlDown = ievent.KeyInput.Control;
776 postEventFromUser(ievent);
779 [NSApp sendEvent:event];
782 case NSLeftMouseDown:
783 ievent.EventType = irr::EET_MOUSE_INPUT_EVENT;
784 ievent.MouseInput.Event = irr::EMIE_LMOUSE_PRESSED_DOWN;
785 MouseButtonStates |= irr::EMBSM_LEFT;
786 ievent.MouseInput.ButtonStates = MouseButtonStates;
787 postMouseEvent(event, ievent);
791 ievent.EventType = irr::EET_MOUSE_INPUT_EVENT;
792 MouseButtonStates &= !irr::EMBSM_LEFT;
793 ievent.MouseInput.ButtonStates = MouseButtonStates;
794 ievent.MouseInput.Event = irr::EMIE_LMOUSE_LEFT_UP;
795 postMouseEvent(event, ievent);
798 case NSOtherMouseDown:
799 ievent.EventType = irr::EET_MOUSE_INPUT_EVENT;
800 ievent.MouseInput.Event = irr::EMIE_MMOUSE_PRESSED_DOWN;
801 MouseButtonStates |= irr::EMBSM_MIDDLE;
802 ievent.MouseInput.ButtonStates = MouseButtonStates;
803 postMouseEvent(event, ievent);
807 ievent.EventType = irr::EET_MOUSE_INPUT_EVENT;
808 MouseButtonStates &= !irr::EMBSM_MIDDLE;
809 ievent.MouseInput.ButtonStates = MouseButtonStates;
810 ievent.MouseInput.Event = irr::EMIE_MMOUSE_LEFT_UP;
811 postMouseEvent(event, ievent);
815 case NSLeftMouseDragged:
816 case NSRightMouseDragged:
817 case NSOtherMouseDragged:
818 ievent.EventType = irr::EET_MOUSE_INPUT_EVENT;
819 ievent.MouseInput.Event = irr::EMIE_MOUSE_MOVED;
820 ievent.MouseInput.ButtonStates = MouseButtonStates;
821 postMouseEvent(event, ievent);
824 case NSRightMouseDown:
825 ievent.EventType = irr::EET_MOUSE_INPUT_EVENT;
826 ievent.MouseInput.Event = irr::EMIE_RMOUSE_PRESSED_DOWN;
827 MouseButtonStates |= irr::EMBSM_RIGHT;
828 ievent.MouseInput.ButtonStates = MouseButtonStates;
829 postMouseEvent(event, ievent);
833 ievent.EventType = irr::EET_MOUSE_INPUT_EVENT;
834 ievent.MouseInput.Event = irr::EMIE_RMOUSE_LEFT_UP;
835 MouseButtonStates &= !irr::EMBSM_RIGHT;
836 ievent.MouseInput.ButtonStates = MouseButtonStates;
837 postMouseEvent(event, ievent);
841 ievent.EventType = irr::EET_MOUSE_INPUT_EVENT;
842 ievent.MouseInput.Event = irr::EMIE_MOUSE_WHEEL;
843 ievent.MouseInput.Wheel = [(NSEvent *)event deltaY];
844 if (ievent.MouseInput.Wheel < 1.0f)
845 ievent.MouseInput.Wheel *= 10.0f;
847 ievent.MouseInput.Wheel *= 5.0f;
848 ievent.MouseInput.ButtonStates = MouseButtonStates;
849 postMouseEvent(event, ievent);
853 [NSApp sendEvent:event];
862 return (![[NSApp delegate] isQuit] && IsActive);
865 //! Pause the current process for the minimum time allowed only to allow other processes to execute
866 void CIrrDeviceMacOSX::yield()
868 struct timespec ts = {0, 0};
869 nanosleep(&ts, NULL);
872 //! Pause execution and let other processes to run for a specified amount of time.
873 void CIrrDeviceMacOSX::sleep(u32 timeMs, bool pauseTimer = false)
875 bool wasStopped = Timer ? Timer->isStopped() : true;
878 ts.tv_sec = (time_t)(timeMs / 1000);
879 ts.tv_nsec = (long)(timeMs % 1000) * 1000000;
881 if (pauseTimer && !wasStopped)
884 nanosleep(&ts, NULL);
886 if (pauseTimer && !wasStopped)
890 void CIrrDeviceMacOSX::setWindowCaption(const wchar_t *text)
892 if (Window != NULL) {
894 size_t numBytes = wcslen(text) * sizeof(wchar_t);
896 #ifdef __BIG_ENDIAN__
897 NSStringEncoding encode = sizeof(wchar_t) == 4 ? NSUTF32BigEndianStringEncoding : NSUTF16BigEndianStringEncoding;
899 NSStringEncoding encode = sizeof(wchar_t) == 4 ? NSUTF32LittleEndianStringEncoding : NSUTF16LittleEndianStringEncoding;
901 NSString *name = [[NSString alloc] initWithBytes:text length:numBytes encoding:encode];
903 [Window setTitle:name];
907 [Window setTitle:@""];
912 bool CIrrDeviceMacOSX::isWindowActive() const
917 bool CIrrDeviceMacOSX::isWindowFocused() const
920 return [Window isKeyWindow];
924 bool CIrrDeviceMacOSX::isWindowMinimized() const
927 return [Window isMiniaturized];
931 void CIrrDeviceMacOSX::postKeyEvent(void *event, irr::SEvent &ievent, bool pressed)
934 std::map<int, int>::const_iterator iter;
935 unsigned int c, mkey, mchar;
936 const unsigned char *cStr;
939 str = [(NSEvent *)event characters];
940 if ((str != nil) && ([str length] > 0)) {
943 c = [str characterAtIndex:0];
946 iter = KeyCodes.find([(NSEvent *)event keyCode]);
947 if (iter != KeyCodes.end())
948 mkey = (*iter).second;
949 else if ((iter = KeyCodes.find(c)) != KeyCodes.end())
950 mkey = (*iter).second;
952 // workaround for period character
954 mkey = irr::KEY_PERIOD;
957 cStr = (unsigned char *)[str cStringUsingEncoding:NSWindowsCP1252StringEncoding];
958 if (cStr != NULL && strlen((char *)cStr) > 0) {
960 mkey = toupper(mchar);
961 if ([(NSEvent *)event modifierFlags] & NSCommandKeyMask) {
962 if (mkey == 'C' || mkey == 'V' || mkey == 'X') {
971 ievent.EventType = irr::EET_KEY_INPUT_EVENT;
972 ievent.KeyInput.Key = (irr::EKEY_CODE)mkey;
973 ievent.KeyInput.PressedDown = pressed;
974 ievent.KeyInput.Shift = ([(NSEvent *)event modifierFlags] & NSShiftKeyMask) != 0;
975 ievent.KeyInput.Control = ([(NSEvent *)event modifierFlags] & NSControlKeyMask) != 0;
976 ievent.KeyInput.Char = mchar;
979 ievent.KeyInput.Control = true;
980 else if ([(NSEvent *)event modifierFlags] & NSCommandKeyMask)
981 [NSApp sendEvent:(NSEvent *)event];
983 postEventFromUser(ievent);
987 void CIrrDeviceMacOSX::postMouseEvent(void *event, irr::SEvent &ievent)
991 if (Window != NULL) {
992 ievent.MouseInput.X = (int)[(NSEvent *)event locationInWindow].x;
993 ievent.MouseInput.Y = DeviceHeight - (int)[(NSEvent *)event locationInWindow].y;
995 if (ievent.MouseInput.Y < 0)
998 CGEventRef ourEvent = CGEventCreate(NULL);
999 CGPoint point = CGEventGetLocation(ourEvent);
1000 CFRelease(ourEvent);
1002 ievent.MouseInput.X = (int)point.x;
1003 ievent.MouseInput.Y = (int)point.y;
1005 if (ievent.MouseInput.Y < 0)
1010 ievent.MouseInput.Shift = ([(NSEvent *)event modifierFlags] & NSShiftKeyMask) != 0;
1011 ievent.MouseInput.Control = ([(NSEvent *)event modifierFlags] & NSControlKeyMask) != 0;
1013 postEventFromUser(ievent);
1016 [NSApp sendEvent:(NSEvent *)event];
1019 void CIrrDeviceMacOSX::storeMouseLocation()
1023 if (Window != NULL) {
1025 p = [NSEvent mouseLocation];
1026 p = [Window convertScreenToBase:p];
1028 y = DeviceHeight - (int)p.y;
1030 // Do we still need this?
1031 CGEventRef ourEvent = CGEventCreate(NULL);
1032 CGPoint point = CGEventGetLocation(ourEvent);
1033 CFRelease(ourEvent);
1038 const core::position2di &curr = ((CCursorControl *)CursorControl)->getPosition(true);
1039 if (curr.X != x || curr.Y != y) {
1041 ievent.EventType = irr::EET_MOUSE_INPUT_EVENT;
1042 ievent.MouseInput.Event = irr::EMIE_MOUSE_MOVED;
1043 ievent.MouseInput.X = x;
1044 ievent.MouseInput.Y = y;
1045 ievent.MouseInput.ButtonStates = MouseButtonStates;
1046 postEventFromUser(ievent);
1050 ((CCursorControl *)CursorControl)->updateInternalCursorPosition(x, y);
1053 void CIrrDeviceMacOSX::setMouseLocation(int x, int y)
1058 if (Window != NULL) {
1059 // Irrlicht window exists
1061 p.y = (float)(DeviceHeight - y);
1062 p = [Window convertBaseToScreen:p];
1063 p.y = ScreenHeight - p.y;
1066 p.y = (float)y + (ScreenHeight - DeviceHeight);
1072 CGWarpMouseCursorPosition(c);
1073 CGAssociateMouseAndMouseCursorPosition(YES);
1076 void CIrrDeviceMacOSX::setCursorVisible(bool visible)
1079 CGDisplayShowCursor(CGMainDisplayID());
1081 CGDisplayHideCursor(CGMainDisplayID());
1084 void CIrrDeviceMacOSX::setWindow(NSWindow *window)
1089 void CIrrDeviceMacOSX::initKeycodes()
1091 KeyCodes[kVK_UpArrow] = irr::KEY_UP;
1092 KeyCodes[kVK_DownArrow] = irr::KEY_DOWN;
1093 KeyCodes[kVK_LeftArrow] = irr::KEY_LEFT;
1094 KeyCodes[kVK_RightArrow] = irr::KEY_RIGHT;
1095 KeyCodes[kVK_F1] = irr::KEY_F1;
1096 KeyCodes[kVK_F2] = irr::KEY_F2;
1097 KeyCodes[kVK_F3] = irr::KEY_F3;
1098 KeyCodes[kVK_F4] = irr::KEY_F4;
1099 KeyCodes[kVK_F5] = irr::KEY_F5;
1100 KeyCodes[kVK_F6] = irr::KEY_F6;
1101 KeyCodes[kVK_F7] = irr::KEY_F7;
1102 KeyCodes[kVK_F8] = irr::KEY_F8;
1103 KeyCodes[kVK_F9] = irr::KEY_F9;
1104 KeyCodes[kVK_F10] = irr::KEY_F10;
1105 KeyCodes[kVK_F11] = irr::KEY_F11;
1106 KeyCodes[kVK_F12] = irr::KEY_F12;
1107 KeyCodes[kVK_F13] = irr::KEY_F13;
1108 KeyCodes[kVK_F14] = irr::KEY_F14;
1109 KeyCodes[kVK_F15] = irr::KEY_F15;
1110 KeyCodes[kVK_F16] = irr::KEY_F16;
1111 KeyCodes[kVK_F17] = irr::KEY_F17;
1112 KeyCodes[kVK_F18] = irr::KEY_F18;
1113 KeyCodes[kVK_F19] = irr::KEY_F19;
1114 KeyCodes[kVK_F20] = irr::KEY_F20;
1115 KeyCodes[kVK_Home] = irr::KEY_HOME;
1116 KeyCodes[kVK_End] = irr::KEY_END;
1117 KeyCodes[NSInsertFunctionKey] = irr::KEY_INSERT;
1118 KeyCodes[kVK_ForwardDelete] = irr::KEY_DELETE;
1119 KeyCodes[kVK_Help] = irr::KEY_HELP;
1120 KeyCodes[NSSelectFunctionKey] = irr::KEY_SELECT;
1121 KeyCodes[NSPrintFunctionKey] = irr::KEY_PRINT;
1122 KeyCodes[NSExecuteFunctionKey] = irr::KEY_EXECUT;
1123 KeyCodes[NSPrintScreenFunctionKey] = irr::KEY_SNAPSHOT;
1124 KeyCodes[NSPauseFunctionKey] = irr::KEY_PAUSE;
1125 KeyCodes[NSScrollLockFunctionKey] = irr::KEY_SCROLL;
1126 KeyCodes[kVK_Delete] = irr::KEY_BACK;
1127 KeyCodes[kVK_Tab] = irr::KEY_TAB;
1128 KeyCodes[kVK_Return] = irr::KEY_RETURN;
1129 KeyCodes[kVK_Escape] = irr::KEY_ESCAPE;
1130 KeyCodes[kVK_Control] = irr::KEY_CONTROL;
1131 KeyCodes[kVK_RightControl] = irr::KEY_RCONTROL;
1132 KeyCodes[kVK_Command] = irr::KEY_MENU;
1133 KeyCodes[kVK_Shift] = irr::KEY_SHIFT;
1134 KeyCodes[kVK_RightShift] = irr::KEY_RSHIFT;
1135 KeyCodes[kVK_Space] = irr::KEY_SPACE;
1137 KeyCodes[kVK_ANSI_A] = irr::KEY_KEY_A;
1138 KeyCodes[kVK_ANSI_B] = irr::KEY_KEY_B;
1139 KeyCodes[kVK_ANSI_C] = irr::KEY_KEY_C;
1140 KeyCodes[kVK_ANSI_D] = irr::KEY_KEY_D;
1141 KeyCodes[kVK_ANSI_E] = irr::KEY_KEY_E;
1142 KeyCodes[kVK_ANSI_F] = irr::KEY_KEY_F;
1143 KeyCodes[kVK_ANSI_G] = irr::KEY_KEY_G;
1144 KeyCodes[kVK_ANSI_H] = irr::KEY_KEY_H;
1145 KeyCodes[kVK_ANSI_I] = irr::KEY_KEY_I;
1146 KeyCodes[kVK_ANSI_J] = irr::KEY_KEY_J;
1147 KeyCodes[kVK_ANSI_K] = irr::KEY_KEY_K;
1148 KeyCodes[kVK_ANSI_L] = irr::KEY_KEY_L;
1149 KeyCodes[kVK_ANSI_M] = irr::KEY_KEY_M;
1150 KeyCodes[kVK_ANSI_N] = irr::KEY_KEY_N;
1151 KeyCodes[kVK_ANSI_O] = irr::KEY_KEY_O;
1152 KeyCodes[kVK_ANSI_P] = irr::KEY_KEY_P;
1153 KeyCodes[kVK_ANSI_Q] = irr::KEY_KEY_Q;
1154 KeyCodes[kVK_ANSI_R] = irr::KEY_KEY_R;
1155 KeyCodes[kVK_ANSI_S] = irr::KEY_KEY_S;
1156 KeyCodes[kVK_ANSI_T] = irr::KEY_KEY_T;
1157 KeyCodes[kVK_ANSI_U] = irr::KEY_KEY_U;
1158 KeyCodes[kVK_ANSI_V] = irr::KEY_KEY_V;
1159 KeyCodes[kVK_ANSI_W] = irr::KEY_KEY_W;
1160 KeyCodes[kVK_ANSI_X] = irr::KEY_KEY_X;
1161 KeyCodes[kVK_ANSI_X] = irr::KEY_KEY_X;
1162 KeyCodes[kVK_ANSI_Y] = irr::KEY_KEY_Y;
1163 KeyCodes[kVK_ANSI_Z] = irr::KEY_KEY_Z;
1165 KeyCodes[kVK_ANSI_0] = irr::KEY_KEY_0;
1166 KeyCodes[kVK_ANSI_1] = irr::KEY_KEY_1;
1167 KeyCodes[kVK_ANSI_2] = irr::KEY_KEY_2;
1168 KeyCodes[kVK_ANSI_3] = irr::KEY_KEY_3;
1169 KeyCodes[kVK_ANSI_4] = irr::KEY_KEY_4;
1170 KeyCodes[kVK_ANSI_5] = irr::KEY_KEY_5;
1171 KeyCodes[kVK_ANSI_6] = irr::KEY_KEY_6;
1172 KeyCodes[kVK_ANSI_7] = irr::KEY_KEY_7;
1173 KeyCodes[kVK_ANSI_8] = irr::KEY_KEY_8;
1174 KeyCodes[kVK_ANSI_9] = irr::KEY_KEY_9;
1176 KeyCodes[kVK_ANSI_Slash] = irr::KEY_DIVIDE;
1177 KeyCodes[kVK_ANSI_Comma] = irr::KEY_COMMA;
1178 KeyCodes[kVK_ANSI_Period] = irr::KEY_PERIOD;
1179 KeyCodes[kVK_PageUp] = irr::KEY_PRIOR;
1180 KeyCodes[kVK_PageDown] = irr::KEY_NEXT;
1182 KeyCodes[kVK_ANSI_Keypad0] = irr::KEY_NUMPAD0;
1183 KeyCodes[kVK_ANSI_Keypad1] = irr::KEY_NUMPAD1;
1184 KeyCodes[kVK_ANSI_Keypad2] = irr::KEY_NUMPAD2;
1185 KeyCodes[kVK_ANSI_Keypad3] = irr::KEY_NUMPAD3;
1186 KeyCodes[kVK_ANSI_Keypad4] = irr::KEY_NUMPAD4;
1187 KeyCodes[kVK_ANSI_Keypad5] = irr::KEY_NUMPAD5;
1188 KeyCodes[kVK_ANSI_Keypad6] = irr::KEY_NUMPAD6;
1189 KeyCodes[kVK_ANSI_Keypad7] = irr::KEY_NUMPAD7;
1190 KeyCodes[kVK_ANSI_Keypad8] = irr::KEY_NUMPAD8;
1191 KeyCodes[kVK_ANSI_Keypad9] = irr::KEY_NUMPAD9;
1193 KeyCodes[kVK_ANSI_KeypadDecimal] = irr::KEY_DECIMAL;
1194 KeyCodes[kVK_ANSI_KeypadMultiply] = irr::KEY_MULTIPLY;
1195 KeyCodes[kVK_ANSI_KeypadPlus] = irr::KEY_PLUS;
1196 KeyCodes[kVK_ANSI_KeypadClear] = irr::KEY_OEM_CLEAR;
1197 KeyCodes[kVK_ANSI_KeypadDivide] = irr::KEY_DIVIDE;
1198 KeyCodes[kVK_ANSI_KeypadEnter] = irr::KEY_RETURN;
1199 KeyCodes[kVK_ANSI_KeypadMinus] = irr::KEY_SUBTRACT;
1201 KeyCodes[kVK_ANSI_LeftBracket] = irr::KEY_OEM_4;
1202 KeyCodes[kVK_ANSI_Backslash] = irr::KEY_OEM_5;
1203 KeyCodes[kVK_ANSI_RightBracket] = irr::KEY_OEM_6;
1206 //! Sets if the window should be resizable in windowed mode.
1207 void CIrrDeviceMacOSX::setResizable(bool resize)
1209 IsResizable = resize;
1212 [Window setStyleMask:NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask];
1214 [Window setStyleMask:NSTitledWindowMask|NSClosableWindowMask];
1218 bool CIrrDeviceMacOSX::isResizable() const
1223 void CIrrDeviceMacOSX::minimizeWindow()
1226 [Window miniaturize:[NSApp self]];
1229 //! Maximizes the window if possible.
1230 void CIrrDeviceMacOSX::maximizeWindow()
1235 //! get the window to normal size if possible.
1236 void CIrrDeviceMacOSX::restoreWindow()
1238 [Window deminiaturize:[NSApp self]];
1241 //! Get the position of this window on screen
1242 core::position2di CIrrDeviceMacOSX::getWindowPosition()
1244 NSRect rect = [Window frame];
1245 int screenHeight = [[[NSScreen screens] objectAtIndex:0] frame].size.height;
1246 return core::position2di(rect.origin.x, screenHeight - rect.origin.y - rect.size.height);
1249 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
1250 static void joystickRemovalCallback(void *target,
1251 IOReturn result, void *refcon, void *sender)
1253 JoystickInfo *joy = (JoystickInfo *)refcon;
1256 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
1258 bool CIrrDeviceMacOSX::activateJoysticks(core::array<SJoystickInfo> &joystickInfo)
1260 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
1261 ActiveJoysticks.clear();
1262 joystickInfo.clear();
1264 io_object_t hidObject = 0;
1265 io_iterator_t hidIterator = 0;
1266 IOReturn result = kIOReturnSuccess;
1267 mach_port_t masterPort = 0;
1268 CFMutableDictionaryRef hidDictionaryRef = NULL;
1270 result = IOMasterPort(bootstrap_port, &masterPort);
1271 if (kIOReturnSuccess != result) {
1272 os::Printer::log("initialiseJoysticks IOMasterPort failed", ELL_ERROR);
1276 hidDictionaryRef = IOServiceMatching(kIOHIDDeviceKey);
1277 if (!hidDictionaryRef) {
1278 os::Printer::log("initialiseJoysticks IOServiceMatching failed", ELL_ERROR);
1281 result = IOServiceGetMatchingServices(masterPort, hidDictionaryRef, &hidIterator);
1283 if (kIOReturnSuccess != result) {
1284 os::Printer::log("initialiseJoysticks IOServiceGetMatchingServices failed", ELL_ERROR);
1288 // no joysticks just return
1293 while ((hidObject = IOIteratorNext(hidIterator))) {
1296 // get dictionary for HID properties
1297 CFMutableDictionaryRef hidProperties = 0;
1299 kern_return_t kern_result = IORegistryEntryCreateCFProperties(hidObject, &hidProperties, kCFAllocatorDefault, kNilOptions);
1300 if ((kern_result == KERN_SUCCESS) && hidProperties) {
1301 HRESULT plugInResult = S_OK;
1303 IOCFPlugInInterface **ppPlugInInterface = NULL;
1304 result = IOCreatePlugInInterfaceForService(hidObject, kIOHIDDeviceUserClientTypeID,
1305 kIOCFPlugInInterfaceID, &ppPlugInInterface, &score);
1306 if (kIOReturnSuccess == result) {
1307 plugInResult = (*ppPlugInInterface)->QueryInterface(ppPlugInInterface, CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (void **)&(info.interface));
1308 if (plugInResult != S_OK)
1309 os::Printer::log("initialiseJoysticks query HID class device interface failed", ELL_ERROR);
1310 (*ppPlugInInterface)->Release(ppPlugInInterface);
1314 if (info.interface != NULL) {
1315 result = (*(info.interface))->open(info.interface, 0);
1316 if (result == kIOReturnSuccess) {
1317 (*(info.interface))->setRemovalCallback(info.interface, joystickRemovalCallback, &info, &info);
1318 getJoystickDeviceInfo(hidObject, hidProperties, &info);
1321 CFTypeRef refElementTop = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDElementKey));
1322 if (refElementTop) {
1323 CFTypeID type = CFGetTypeID(refElementTop);
1324 if (type == CFArrayGetTypeID()) {
1325 CFRange range = {0, CFArrayGetCount((CFArrayRef)refElementTop)};
1326 info.numActiveJoysticks = ActiveJoysticks.size();
1327 CFArrayApplyFunction((CFArrayRef)refElementTop, range, getJoystickComponentArrayHandler, &info);
1331 CFRelease(hidProperties);
1332 os::Printer::log("initialiseJoysticks Open interface failed", ELL_ERROR);
1336 CFRelease(hidProperties);
1338 result = IOObjectRelease(hidObject);
1340 if ((info.usagePage != kHIDPage_GenericDesktop) ||
1341 ((info.usage != kHIDUsage_GD_Joystick &&
1342 info.usage != kHIDUsage_GD_GamePad &&
1343 info.usage != kHIDUsage_GD_MultiAxisController))) {
1344 closeJoystickDevice(&info);
1348 for (u32 i = 0; i < 6; ++i)
1349 info.persistentData.JoystickEvent.Axis[i] = 0;
1351 ActiveJoysticks.push_back(info);
1353 SJoystickInfo returnInfo;
1354 returnInfo.Joystick = jindex;
1355 returnInfo.Axes = info.axes;
1356 // returnInfo.Hats = info.hats;
1357 returnInfo.Buttons = info.buttons;
1358 returnInfo.Name = info.joystickName;
1359 returnInfo.PovHat = SJoystickInfo::POV_HAT_UNKNOWN;
1362 // if (info.hatComp.size())
1363 // returnInfo.PovHat = SJoystickInfo::POV_HAT_PRESENT;
1365 // returnInfo.PovHat = SJoystickInfo::POV_HAT_ABSENT;
1367 joystickInfo.push_back(returnInfo);
1374 result = IOObjectRelease(hidIterator);
1377 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
1382 void CIrrDeviceMacOSX::pollJoysticks()
1384 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
1385 if (0 == ActiveJoysticks.size())
1389 for (joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) {
1390 if (ActiveJoysticks[joystick].removed)
1394 ActiveJoysticks[joystick].persistentData.JoystickEvent.Joystick = joystick;
1396 if (ActiveJoysticks[joystick].interface) {
1397 for (u32 n = 0; n < ActiveJoysticks[joystick].axisComp.size(); n++) {
1398 IOReturn result = kIOReturnSuccess;
1399 IOHIDEventStruct hidEvent;
1401 result = (*(ActiveJoysticks[joystick].interface))->getElementValue(ActiveJoysticks[joystick].interface, ActiveJoysticks[joystick].axisComp[n].cookie, &hidEvent);
1402 if (kIOReturnSuccess == result) {
1403 const f32 min = -32768.0f;
1404 const f32 max = 32767.0f;
1405 const f32 deviceScale = max - min;
1406 const f32 readScale = (f32)ActiveJoysticks[joystick].axisComp[n].maxRead - (f32)ActiveJoysticks[joystick].axisComp[n].minRead;
1408 if (hidEvent.value < ActiveJoysticks[joystick].axisComp[n].minRead)
1409 ActiveJoysticks[joystick].axisComp[n].minRead = hidEvent.value;
1410 if (hidEvent.value > ActiveJoysticks[joystick].axisComp[n].maxRead)
1411 ActiveJoysticks[joystick].axisComp[n].maxRead = hidEvent.value;
1413 if (readScale != 0.0f)
1414 hidEvent.value = (int)(((f32)((f32)hidEvent.value - (f32)ActiveJoysticks[joystick].axisComp[n].minRead) * deviceScale / readScale) + min);
1416 if (ActiveJoysticks[joystick].persistentData.JoystickEvent.Axis[n] != (s16)hidEvent.value)
1418 ActiveJoysticks[joystick].persistentData.JoystickEvent.Axis[n] = (s16)hidEvent.value;
1422 for (u32 n = 0; n < ActiveJoysticks[joystick].buttonComp.size(); n++) {
1423 IOReturn result = kIOReturnSuccess;
1424 IOHIDEventStruct hidEvent;
1426 result = (*(ActiveJoysticks[joystick].interface))->getElementValue(ActiveJoysticks[joystick].interface, ActiveJoysticks[joystick].buttonComp[n].cookie, &hidEvent);
1427 if (kIOReturnSuccess == result) {
1428 if (hidEvent.value && !((ActiveJoysticks[joystick].persistentData.JoystickEvent.ButtonStates & (1 << n)) ? true : false))
1430 else if (!hidEvent.value && ((ActiveJoysticks[joystick].persistentData.JoystickEvent.ButtonStates & (1 << n)) ? true : false))
1434 ActiveJoysticks[joystick].persistentData.JoystickEvent.ButtonStates |= (1 << n);
1436 ActiveJoysticks[joystick].persistentData.JoystickEvent.ButtonStates &= ~(1 << n);
1439 // still ToDo..will be done soon :)
1441 for (u32 n = 0; n < ActiveJoysticks[joystick].hatComp.size(); n++)
1443 IOReturn result = kIOReturnSuccess;
1444 IOHIDEventStruct hidEvent;
1446 result = (*(ActiveJoysticks[joystick].interface))->getElementValue(ActiveJoysticks[joystick].interface, ActiveJoysticks[joystick].hatComp[n].cookie, &hidEvent);
1447 if (kIOReturnSuccess == result)
1449 if (ActiveJoysticks[joystick].persistentData.JoystickEvent.POV != hidEvent.value)
1451 ActiveJoysticks[joystick].persistentData.JoystickEvent.POV = hidEvent.value;
1458 postEventFromUser(ActiveJoysticks[joystick].persistentData);
1460 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
1465 #endif // _IRR_COMPILE_WITH_OSX_DEVICE_