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