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 #include "mac/CocoaMouse.h" 24 #include "mac/CocoaInputManager.h" 25 #include "mac/CocoaHelpers.h" 26 #include "OISException.h" 27 #include "OISEvents.h" 28 29 using namespace OIS; 30 31 //-------------------------------------------------------------------// 32 CocoaMouse::CocoaMouse( InputManager* creator, bool buffered ) 33 : Mouse(creator->inputSystemName(), buffered, 0, creator) 34 { 35 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 36 37 CocoaInputManager *man = static_cast<CocoaInputManager*>(mCreator); 38 mResponder = [[CocoaMouseView alloc] initWithFrame:[[man->_getWindow() contentView] frame]]; 39 if(!mResponder) 40 OIS_EXCEPT( E_General, "CocoaMouseView::CocoaMouseView >> Error creating event responder" ); 41 42 [[man->_getWindow() contentView] addSubview:mResponder]; 43 [mResponder setOISMouseObj:this]; 44 45 static_cast<CocoaInputManager*>(mCreator)->_setMouseUsed(true); 46 47 [pool drain]; 48 } 49 50 CocoaMouse::~CocoaMouse() 51 { 52 // Restore Mouse 53 // CGAssociateMouseAndMouseCursorPosition(true); 54 CGDisplayShowCursor(kCGDirectMainDisplay); 55 56 if (mResponder) 57 { 58 [mResponder release]; 59 mResponder = nil; 60 } 61 62 static_cast<CocoaInputManager*>(mCreator)->_setMouseUsed(false); 63 } 64 65 void CocoaMouse::_initialize() 66 { 67 mState.clear(); 68 CGAssociateMouseAndMouseCursorPosition(false); 69 } 70 71 void CocoaMouse::setBuffered( bool buffered ) 72 { 73 mBuffered = buffered; 74 } 75 76 void CocoaMouse::capture() 77 { 78 [mResponder capture]; 79 } 80 81 @implementation CocoaMouseView 82 83 - (id)initWithFrame:(NSRect)frame 84 { 85 self = [super initWithFrame:frame]; 86 if (self) { 87 mTempState.clear(); 88 mMouseWarped = false; 89 mNeedsToRegainFocus = false; 90 91 // Hide OS Mouse 92 CGDisplayHideCursor(kCGDirectMainDisplay); 93 94 NSRect clipRect = NSMakeRect(0.0f, 0.0f, 0.0f, 0.0f); 95 clipRect = [[[self window] contentView] frame]; 96 97 CGPoint warpPoint; 98 warpPoint.x = (((frame.origin.x + frame.size.width) - frame.origin.x) / 2) + frame.origin.x; 99 warpPoint.y = (((frame.origin.y + frame.size.height) - frame.origin.y) / 2) - frame.origin.y; 100 // warpPoint = CGPointMake(clipRect.size.height, clipRect.size.width); 101 CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, warpPoint); 102 103 // Use NSTrackingArea to track mouse move events 104 NSTrackingAreaOptions trackingOptions = 105 NSTrackingMouseMoved | NSTrackingEnabledDuringMouseDrag | 106 NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp; 107 108 NSDictionary *trackerData = [NSDictionary dictionaryWithObjectsAndKeys: 109 [NSNumber numberWithInt:0], @"OISMouseTrackingKey", nil]; 110 NSTrackingArea *trackingArea = [[NSTrackingArea alloc] 111 initWithRect:[self frame]// in our case track the entire view 112 options:trackingOptions 113 owner:self 114 userInfo:trackerData]; 115 [self addTrackingArea:trackingArea]; 116 [[self window] setAcceptsMouseMovedEvents:YES]; 117 [trackingArea release]; 118 } 119 return self; 120 } 121 122 - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent 123 { 124 return YES; 125 } 126 127 - (void)setOISMouseObj:(CocoaMouse *)obj 128 { 129 oisMouseObj = obj; 130 } 131 132 - (void)capture 133 { 134 MouseState *state = oisMouseObj->getMouseStatePtr(); 135 state->X.rel = 0; 136 state->Y.rel = 0; 137 state->Z.rel = 0; 138 139 if(mTempState.X.rel || mTempState.Y.rel || mTempState.Z.rel) 140 { 141 // NSLog(@"%i %i %i", mTempState.X.rel, mTempState.Y.rel, mTempState.Z.rel); 142 143 // Set new relative motion values 144 state->X.rel = mTempState.X.rel; 145 state->Y.rel = mTempState.Y.rel; 146 state->Z.rel = mTempState.Z.rel; 147 148 // Update absolute position 149 state->X.abs += mTempState.X.rel; 150 state->Y.abs += mTempState.Y.rel; 151 152 if(state->X.abs > state->width) 153 state->X.abs = state->width; 154 else if(state->X.abs < 0) 155 state->X.abs = 0; 156 157 if(state->Y.abs > state->height) 158 state->Y.abs = state->height; 159 else if(state->Y.abs < 0) 160 state->Y.abs = 0; 161 162 state->Z.abs += mTempState.Z.rel; 163 164 //Fire off event 165 if ( oisMouseObj->buffered() && oisMouseObj->getEventCallback() ) 166 oisMouseObj->getEventCallback()->mouseMoved(MouseEvent(oisMouseObj, *state)); 167 } 168 169 mTempState.clear(); 170 } 171 172 #pragma mark Left Mouse Event overrides 173 - (void)mouseDown:(NSEvent *)theEvent 174 { 175 int mouseButton = MB_Left; 176 NSEventType type = [theEvent type]; 177 MouseState *state = oisMouseObj->getMouseStatePtr(); 178 179 if(mNeedsToRegainFocus) 180 return; 181 182 if((type == NSLeftMouseDown) && ([theEvent modifierFlags] & NSAlternateKeyMask)) 183 { 184 mouseButton = MB_Middle; 185 } 186 else if((type == NSLeftMouseDown) && ([theEvent modifierFlags] & NSControlKeyMask)) 187 { 188 mouseButton = MB_Right; 189 } 190 else if(type == NSLeftMouseDown) 191 { 192 mouseButton = MB_Left; 193 } 194 state->buttons |= 1 << mouseButton; 195 if ( oisMouseObj->buffered() && oisMouseObj->getEventCallback() ) 196 oisMouseObj->getEventCallback()->mousePressed( MouseEvent( oisMouseObj, *state ), (MouseButtonID)mouseButton ); 197 } 198 199 - (void)mouseUp:(NSEvent *)theEvent { 200 int mouseButton = MB_Left; 201 NSEventType type = [theEvent type]; 202 MouseState *state = oisMouseObj->getMouseStatePtr(); 203 204 if((type == NSLeftMouseUp) && ([theEvent modifierFlags] & NSAlternateKeyMask)) 205 { 206 mouseButton = MB_Middle; 207 } 208 else if((type == NSLeftMouseUp) && ([theEvent modifierFlags] & NSControlKeyMask)) 209 { 210 mouseButton = MB_Right; 211 } 212 else if(type == NSLeftMouseUp) 213 { 214 mouseButton = MB_Left; 215 } 216 state->buttons &= ~(1 << mouseButton); 217 218 if ( oisMouseObj->buffered() && oisMouseObj->getEventCallback() ) 219 oisMouseObj->getEventCallback()->mouseReleased( MouseEvent( oisMouseObj, *state ), (MouseButtonID)mouseButton ); 220 } 221 222 223 - (void)mouseDragged:(NSEvent *)theEvent 224 { 225 CGPoint delta = CGPointMake([theEvent deltaX], [theEvent deltaY]); 226 if(mNeedsToRegainFocus) 227 return; 228 229 // Relative positioning 230 if(!mMouseWarped) 231 { 232 mTempState.X.rel += delta.x; 233 mTempState.Y.rel += delta.y; 234 } 235 236 mMouseWarped = false; 237 } 238 239 #pragma mark Right Mouse Event overrides 240 - (void)rightMouseDown:(NSEvent *)theEvent 241 { 242 int mouseButton = MB_Right; 243 NSEventType type = [theEvent type]; 244 MouseState *state = oisMouseObj->getMouseStatePtr(); 245 246 if(mNeedsToRegainFocus) 247 return; 248 249 if(type == NSRightMouseDown) 250 { 251 state->buttons |= 1 << mouseButton; 252 } 253 254 if ( oisMouseObj->buffered() && oisMouseObj->getEventCallback() ) 255 oisMouseObj->getEventCallback()->mousePressed( MouseEvent( oisMouseObj, *state ), (MouseButtonID)mouseButton ); 256 } 257 258 - (void)rightMouseUp:(NSEvent *)theEvent { 259 int mouseButton = MB_Right; 260 NSEventType type = [theEvent type]; 261 MouseState *state = oisMouseObj->getMouseStatePtr(); 262 263 if(type == NSRightMouseUp) 264 { 265 state->buttons &= ~(1 << mouseButton); 266 } 267 268 if ( oisMouseObj->buffered() && oisMouseObj->getEventCallback() ) 269 oisMouseObj->getEventCallback()->mouseReleased( MouseEvent( oisMouseObj, *state ), (MouseButtonID)mouseButton ); 270 } 271 272 - (void)rightMouseDragged:(NSEvent *)theEvent 273 { 274 CGPoint delta = CGPointMake([theEvent deltaX], [theEvent deltaY]); 275 if(mNeedsToRegainFocus) 276 return; 277 278 // Relative positioning 279 if(!mMouseWarped) 280 { 281 mTempState.X.rel += delta.x; 282 mTempState.Y.rel += delta.y; 283 } 284 285 mMouseWarped = false; 286 } 287 288 #pragma mark Other Mouse Event overrides 289 - (void)otherMouseDown:(NSEvent *)theEvent 290 { 291 int mouseButton = MB_Middle; 292 NSEventType type = [theEvent type]; 293 MouseState *state = oisMouseObj->getMouseStatePtr(); 294 295 if(mNeedsToRegainFocus) 296 return; 297 298 if(type == NSOtherMouseDown) 299 { 300 state->buttons |= 1 << mouseButton; 301 } 302 303 if ( oisMouseObj->buffered() && oisMouseObj->getEventCallback() ) 304 oisMouseObj->getEventCallback()->mousePressed( MouseEvent( oisMouseObj, *state ), (MouseButtonID)mouseButton ); 305 } 306 307 - (void)otherMouseUp:(NSEvent *)theEvent { 308 int mouseButton = MB_Middle; 309 NSEventType type = [theEvent type]; 310 MouseState *state = oisMouseObj->getMouseStatePtr(); 311 312 if(type == NSOtherMouseUp) 313 { 314 state->buttons &= ~(1 << mouseButton); 315 } 316 317 if ( oisMouseObj->buffered() && oisMouseObj->getEventCallback() ) 318 oisMouseObj->getEventCallback()->mouseReleased( MouseEvent( oisMouseObj, *state ), (MouseButtonID)mouseButton ); 319 } 320 321 - (void)otherMouseDragged:(NSEvent *)theEvent 322 { 323 CGPoint delta = CGPointMake([theEvent deltaX], [theEvent deltaY]); 324 if(mNeedsToRegainFocus) 325 return; 326 327 // Relative positioning 328 if(!mMouseWarped) 329 { 330 mTempState.X.rel += delta.x; 331 mTempState.Y.rel += delta.y; 332 } 333 334 mMouseWarped = false; 335 } 336 337 - (void)scrollWheel:(NSEvent *)theEvent 338 { 339 if([theEvent deltaY] != 0.0) 340 mTempState.Z.rel += ([theEvent deltaY] * 60); 341 } 342 343 - (void)mouseMoved:(NSEvent *)theEvent 344 { 345 CGPoint delta = CGPointMake([theEvent deltaX], [theEvent deltaY]); 346 if(mNeedsToRegainFocus) 347 return; 348 349 // Relative positioning 350 if(!mMouseWarped) 351 { 352 mTempState.X.rel += delta.x; 353 mTempState.Y.rel += delta.y; 354 } 355 356 mMouseWarped = false; 357 } 358 359 - (void)mouseEntered:(NSEvent *)theEvent 360 { 361 CGDisplayHideCursor(kCGDirectMainDisplay); 362 CGAssociateMouseAndMouseCursorPosition(false); 363 if(!mMouseWarped) 364 { 365 NSPoint pos = [[self window] mouseLocationOutsideOfEventStream]; 366 NSRect frame = [[[self window] contentView] frame]; 367 368 // Clear the previous mouse state 369 MouseState *state = oisMouseObj->getMouseStatePtr(); 370 state->clear(); 371 372 // Cocoa's coordinate system has the origin in the bottom left so we need to transform the height 373 mTempState.X.rel = pos.x; 374 mTempState.Y.rel = frame.size.height - pos.y; 375 } 376 } 377 378 - (void)mouseExited:(NSEvent *)theEvent 379 { 380 CGDisplayShowCursor(kCGDirectMainDisplay); 381 CGAssociateMouseAndMouseCursorPosition(true); 382 } 383 384 @end 385