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 //-------------------------------------------------------------------//
MacMouse(InputManager * creator,bool buffered)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
~MacMouse()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
_initialize()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
WindowFocusChanged(EventHandlerCallRef nextHandler,EventRef event,void * macMouse)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
setBuffered(bool buffered)147 void MacMouse::setBuffered( bool buffered )
148 {
149 mBuffered = buffered;
150 }
151
capture()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
_mouseCallback(EventRef theEvent)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