Home | History | Annotate | Download | only in mac
      1 /*
      2  The zlib/libpng License
      3 
      4  Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
      5 
      6  This software is provided 'as-is', without any express or implied warranty. In no event will
      7  the authors be held liable for any damages arising from the use of this software.
      8 
      9  Permission is granted to anyone to use this software for any purpose, including commercial
     10  applications, and to alter it and redistribute it freely, subject to the following
     11  restrictions:
     12 
     13  1. The origin of this software must not be misrepresented; you must not claim that
     14  you wrote the original software. If you use this software in a product,
     15  an acknowledgment in the product documentation would be appreciated but is
     16  not required.
     17 
     18  2. Altered source versions must be plainly marked as such, and must not be
     19  misrepresented as being the original software.
     20 
     21  3. This notice may not be removed or altered from any source distribution.
     22  */
     23 
     24 #ifndef __LP64__
     25 
     26 #include "mac/MacMouse.h"
     27 #include "mac/MacInputManager.h"
     28 #include "mac/MacHelpers.h"
     29 #include "OISException.h"
     30 #include "OISEvents.h"
     31 
     32 #include <Carbon/Carbon.h>
     33 
     34 #include <list>
     35 
     36 #include <iostream>
     37 
     38 using namespace OIS;
     39 
     40 //Events we subscribe to and remove from queue
     41 const EventTypeSpec mouseEvents[] = {
     42 	{ kEventClassMouse, kEventMouseDown },
     43 	{ kEventClassMouse, kEventMouseUp },
     44 	{ kEventClassMouse, kEventMouseMoved },
     45 	{ kEventClassMouse, kEventMouseDragged },
     46 	{ kEventClassMouse, kEventMouseWheelMoved }
     47 };
     48 
     49 const EventTypeSpec WinFocusAcquired [] = {{kEventClassApplication, kEventAppDeactivated}};
     50 
     51 //-------------------------------------------------------------------//
     52 MacMouse::MacMouse( InputManager* creator, bool buffered )
     53 	: Mouse(creator->inputSystemName(), buffered, 0, creator), mNeedsToRegainFocus( false )
     54 {
     55     mouseEventRef = NULL;
     56 	mWindowFocusHandler = NULL;
     57 
     58     // Get a "Univeral procedure pointer" for our callback
     59     mouseUPP = NewEventHandlerUPP(MouseWrapper);
     60 	mWindowFocusListener = NewEventHandlerUPP(WindowFocusChanged);
     61 
     62 	static_cast<MacInputManager*>(mCreator)->_setMouseUsed(true);
     63 }
     64 
     65 MacMouse::~MacMouse()
     66 {
     67     if(mouseEventRef != NULL)
     68 		RemoveEventHandler(mouseEventRef);
     69 
     70 	if(mWindowFocusHandler != NULL)
     71 		RemoveEventHandler(mWindowFocusHandler);
     72 
     73 	DisposeEventHandlerUPP(mouseUPP);
     74 	DisposeEventHandlerUPP(mWindowFocusListener);
     75 
     76 	// Restore Mouse
     77 	CGAssociateMouseAndMouseCursorPosition(TRUE);
     78 	CGDisplayShowCursor(kCGDirectMainDisplay);
     79 
     80 	static_cast<MacInputManager*>(mCreator)->_setMouseUsed(false);
     81 }
     82 
     83 void MacMouse::_initialize()
     84 {
     85 	mState.clear();
     86 	mTempState.clear();
     87 	mMouseWarped = false;
     88 
     89 	// Hide OS Mouse
     90  	CGDisplayHideCursor(kCGDirectMainDisplay);
     91 
     92 	MacInputManager* im = static_cast<MacInputManager*>(mCreator);
     93 	WindowRef win = im->_getWindow();
     94 
     95 	if(win)
     96 	{
     97 		Rect clipRect = {0.0f, 0.0f, 0.0f, 0.0f};
     98 		GetWindowBounds(win, kWindowContentRgn, &clipRect);
     99 
    100 		CGPoint warpPoint;
    101 		warpPoint.x = ((clipRect.right - clipRect.left) / 2) + clipRect.left;
    102 		warpPoint.y = ((clipRect.bottom - clipRect.top) / 2) + clipRect.top;
    103 		CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, warpPoint); //Place at display origin
    104 
    105 		mMouseWarped = true;
    106 	}
    107 
    108 	//Now that mouse is warped, start listening for events
    109 	EventTargetRef event = ((MacInputManager*)mCreator)->_getEventTarget();
    110 
    111 	if(mouseEventRef != NULL)
    112 		RemoveEventHandler(mouseEventRef);
    113 
    114 	if(mWindowFocusHandler != NULL)
    115 		RemoveEventHandler(mWindowFocusHandler);
    116 
    117 	mouseEventRef = mWindowFocusHandler = NULL;
    118 
    119 	if(InstallEventHandler(event, mouseUPP, GetEventTypeCount(mouseEvents), mouseEvents, this, &mouseEventRef) != noErr)
    120 		OIS_EXCEPT( E_General, "MacMouse::_initialize >> Error loading Mouse event handler" );
    121 
    122 	if(InstallEventHandler(event, mWindowFocusListener, GetEventTypeCount(WinFocusAcquired), WinFocusAcquired, this, &mWindowFocusHandler) != noErr)
    123 		OIS_EXCEPT( E_General, "MacMouse::_initialize >> Error loading Mouse event handler" );
    124 
    125 	//Lock OS Mouse movement
    126 	mNeedsToRegainFocus = false;
    127 	CGAssociateMouseAndMouseCursorPosition(FALSE);
    128 }
    129 
    130 OSStatus MacMouse::WindowFocusChanged(EventHandlerCallRef nextHandler, EventRef event, void* macMouse)
    131 {
    132 	//std::cout << "Window Focus Changed\n";
    133 
    134 	MacMouse* _this = static_cast<MacMouse*>(macMouse);
    135     if (_this)
    136 	{
    137 		_this->mNeedsToRegainFocus = true;
    138 		CGAssociateMouseAndMouseCursorPosition(TRUE);
    139 
    140         // propagate the event down the chain
    141         return CallNextEventHandler(nextHandler, event);
    142     }
    143     else
    144         OIS_EXCEPT(E_General, "MouseWrapper >> Being called by something other than our event handler!");
    145 }
    146 
    147 void MacMouse::setBuffered( bool buffered )
    148 {
    149 	mBuffered = buffered;
    150 }
    151 
    152 void MacMouse::capture()
    153 {
    154 	mState.X.rel = 0;
    155 	mState.Y.rel = 0;
    156 	mState.Z.rel = 0;
    157 
    158 	if(mTempState.X.rel || mTempState.Y.rel || mTempState.Z.rel)
    159 	{
    160 		//printf("%i %i %i\n\n", mTempState.X.rel, mTempState.Y.rel, mTempState.Z.rel);
    161 
    162 		//Set new relative motion values
    163 		mState.X.rel = mTempState.X.rel;
    164 		mState.Y.rel = mTempState.Y.rel;
    165 		mState.Z.rel = mTempState.Z.rel;
    166 
    167 		//Update absolute position
    168 		mState.X.abs += mTempState.X.rel;
    169 		mState.Y.abs += mTempState.Y.rel;
    170 
    171 		if(mState.X.abs > mState.width)
    172 			mState.X.abs = mState.width;
    173 		else if(mState.X.abs < 0)
    174 			mState.X.abs = 0;
    175 
    176 		if(mState.Y.abs > mState.height)
    177 			mState.Y.abs = mState.height;
    178 		else if(mState.Y.abs < 0)
    179 			mState.Y.abs = 0;
    180 
    181 		mState.Z.abs += mTempState.Z.rel;
    182 
    183 		//Fire off event
    184 		if(mListener && mBuffered)
    185 			mListener->mouseMoved(MouseEvent(this, mState));
    186 	}
    187 
    188 	mTempState.clear();
    189 }
    190 
    191 void MacMouse::_mouseCallback( EventRef theEvent )
    192 {
    193     UInt32 kind = GetEventKind (theEvent);
    194 
    195 	switch(kind)
    196 	{
    197 		case kEventMouseDragged:
    198 		case kEventMouseMoved:
    199 		{
    200 			//HIPoint location = {0.0f, 0.0f};
    201 			HIPoint delta = {0.0f, 0.0f};
    202 			//Rect clipRect = {0.0f, 0.0f, 0.0f, 0.0f};
    203 
    204 			if(mNeedsToRegainFocus)
    205 				break;
    206 
    207 			// Capture the parameters
    208 			// TODO: Look into HIViewNewTrackingArea
    209 			//GetEventParameter(theEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(HIPoint), NULL, &location);
    210 			GetEventParameter(theEvent, kEventParamMouseDelta, typeHIPoint, NULL, sizeof(HIPoint), NULL, &delta);
    211 
    212 			// Mouse X and Y are the position on the screen,
    213 			// startng from top-left at 0,0 caps at full monitor resolution
    214 
    215 			// If we have a window we need to return adjusted coordinates
    216 			// If not, just use raw coordinates - only do this if showing OS mouse
    217 			//MacInputManager* im = static_cast<MacInputManager*>(mCreator);
    218 			//WindowRef win = im->_getWindow();
    219 
    220 			//if(win != NULL)
    221 			//{
    222 			//	GetWindowBounds(win, kWindowContentRgn, &clipRect);
    223 			//}
    224             //else
    225             //{
    226             //    clipRect.right = mState.width;
    227             //    clipRect.bottom = mState.height;
    228             //}
    229 
    230             // clip the mouse, absolute positioning
    231             //if (location.x <= clipRect.left)
    232 			//	mState.X.abs = 0;
    233 			//else if(location.x >= clipRect.right)
    234 			//	mState.X.abs = clipRect.right - clipRect.left;
    235 			//else
    236 			//	mState.X.abs = location.x - clipRect.left;
    237 
    238 			//if (location.y <= clipRect.top)
    239 			//	mState.Y.abs = 0;
    240 			//else if(location.y >= clipRect.bottom)
    241 			//	mState.Y.abs = clipRect.bottom - clipRect.top;
    242 			//else
    243 			//	mState.Y.abs = location.y - clipRect.top;
    244 
    245 			// relative positioning
    246 			if(!mMouseWarped)
    247 			{
    248 				mTempState.X.rel += delta.x;
    249 				mTempState.Y.rel += delta.y;
    250 			}
    251 
    252 			mMouseWarped = false;
    253 
    254 			break;
    255 		}
    256 		case kEventMouseDown:
    257 		{
    258 			EventMouseButton button = 0;
    259 			int mouseButton = 3;
    260 			UInt32 modifiers = 0;
    261 
    262 			if(mNeedsToRegainFocus)
    263 				break;
    264 
    265 			// Capture parameters
    266 			GetEventParameter(theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(EventMouseButton), NULL, &button);
    267 			GetEventParameter(theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
    268 
    269 			if((button == kEventMouseButtonTertiary) || ((button == kEventMouseButtonPrimary) && (modifiers & optionKey)))
    270 			{
    271 				mouseButton = 2;
    272 				mState.buttons |= 1 << mouseButton;
    273 			}
    274             else if((button == kEventMouseButtonSecondary) || ((button == kEventMouseButtonPrimary) && (modifiers & controlKey)))
    275             {
    276                 mouseButton = 1;
    277                 mState.buttons |= 1 << mouseButton;
    278             }
    279             else if(button == kEventMouseButtonPrimary)
    280             {
    281                 mouseButton = 0;
    282                 mState.buttons |= 1 << mouseButton;
    283             }
    284 
    285             if( mListener && mBuffered )
    286                 mListener->mousePressed( MouseEvent( this, mState ), (MouseButtonID)mouseButton );
    287 
    288             break;
    289 		}
    290 		case kEventMouseUp:
    291 		{
    292 			EventMouseButton button = 0;
    293 			int mouseButton = 3;
    294 			UInt32 modifiers = 0;
    295 
    296 			if(mNeedsToRegainFocus)
    297 			{
    298 				mNeedsToRegainFocus = false;
    299 				CGAssociateMouseAndMouseCursorPosition(false);
    300 
    301 				MacInputManager* im = static_cast<MacInputManager*>(mCreator);
    302 				WindowRef win = im->_getWindow();
    303 
    304 				if(win)
    305 				{
    306 					Rect clipRect = {0.0f, 0.0f, 0.0f, 0.0f};
    307 					GetWindowBounds(win, kWindowContentRgn, &clipRect);
    308 
    309 					CGPoint warpPoint;
    310 					warpPoint.x = ((clipRect.right - clipRect.left) / 2) + clipRect.left;
    311 					warpPoint.y = ((clipRect.bottom - clipRect.top) / 2) + clipRect.top;
    312 					CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, warpPoint); //Place at display origin
    313 
    314 					CGDisplayHideCursor(kCGDirectMainDisplay);
    315 
    316 					mMouseWarped = true;
    317 				}
    318 
    319 				//Once we regain focus, we do not really know what state all the buttons are in - for now, set to not pressed. todo, check current status
    320 				//compare against old status, and send off any needed events
    321 				mState.buttons = 0;
    322 
    323 				break;
    324 			}
    325 
    326 			// Capture parameters
    327 			GetEventParameter(theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(EventMouseButton), NULL, &button);
    328 			GetEventParameter(theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
    329 
    330 			if ((button == kEventMouseButtonTertiary) || ((button == kEventMouseButtonPrimary) && (modifiers & optionKey)))
    331 			{
    332 				mouseButton = 2;
    333 				mState.buttons &= ~(1 << mouseButton);
    334 			}
    335             else if ((button == kEventMouseButtonSecondary) || ((button == kEventMouseButtonPrimary) && (modifiers & controlKey)))
    336             {
    337                 mouseButton = 1;
    338                 mState.buttons &= ~(1 << mouseButton);
    339             }
    340             else if (button == kEventMouseButtonPrimary)
    341             {
    342                 mouseButton = 0;
    343                 mState.buttons &= ~(1 << mouseButton);
    344             }
    345 
    346             if( mListener && mBuffered )
    347                 mListener->mouseReleased( MouseEvent( this, mState ), (MouseButtonID)mouseButton );
    348 
    349             break;
    350 		}
    351 		case kEventMouseWheelMoved:
    352 		{
    353 			SInt32 wheelDelta = 0;
    354 			EventMouseWheelAxis	wheelAxis = 0;
    355 
    356 			// Capture parameters
    357 			GetEventParameter(theEvent, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(EventMouseWheelAxis), NULL, &wheelAxis);
    358 			GetEventParameter(theEvent, kEventParamMouseWheelDelta, typeSInt32, NULL, sizeof(SInt32), NULL, &wheelDelta);
    359 
    360 			// If the Y axis of the wheel changed, then update the Z
    361 			// Does OIS care about the X wheel axis?
    362 			if(wheelAxis == kEventMouseWheelAxisY)
    363 				mTempState.Z.rel += (wheelDelta * 60);
    364 
    365             break;
    366 		}
    367 		default:
    368 			break;
    369 	}
    370 }
    371 #endif
    372