MacMouse.cpp 10.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "mac/MacMouse.h"
#include "mac/MacInputManager.h"
#include "mac/MacHelpers.h"
#include "OISException.h"
#include "OISEvents.h"

#include <Carbon/Carbon.h>

#include <list>

#include <iostream>

using namespace OIS;

//Events we subscribe to and remove from queue
const EventTypeSpec mouseEvents[] = {
	{ kEventClassMouse, kEventMouseDown },
	{ kEventClassMouse, kEventMouseUp },
	{ kEventClassMouse, kEventMouseMoved },
	{ kEventClassMouse, kEventMouseDragged },
Ben Hymers's avatar
Ben Hymers committed
21
	{ kEventClassMouse, kEventMouseWheelMoved }
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
};

const EventTypeSpec WinFocusAcquired [] = {{kEventClassApplication, kEventAppDeactivated}};

//-------------------------------------------------------------------//
MacMouse::MacMouse( InputManager* creator, bool buffered )
	: Mouse(creator->inputSystemName(), buffered, 0, creator), mNeedsToRegainFocus( false )
{
    mouseEventRef = NULL;
	mWindowFocusHandler = NULL;

    // Get a "Univeral procedure pointer" for our callback
    mouseUPP = NewEventHandlerUPP(MouseWrapper);
	mWindowFocusListener = NewEventHandlerUPP(WindowFocusChanged);

	static_cast<MacInputManager*>(mCreator)->_setMouseUsed(true);
}

MacMouse::~MacMouse()
{
    if(mouseEventRef != NULL)
		RemoveEventHandler(mouseEventRef);

	if(mWindowFocusHandler != NULL)
		RemoveEventHandler(mWindowFocusHandler);
Ben Hymers's avatar
Ben Hymers committed
47

48
49
	DisposeEventHandlerUPP(mouseUPP);
	DisposeEventHandlerUPP(mWindowFocusListener);
Ben Hymers's avatar
Ben Hymers committed
50

51
52
53
54
55
56
57
58
59
60
61
62
	// Restore Mouse
	CGAssociateMouseAndMouseCursorPosition(TRUE);
	CGDisplayShowCursor(kCGDirectMainDisplay);

	static_cast<MacInputManager*>(mCreator)->_setMouseUsed(false);
}

void MacMouse::_initialize()
{
	mState.clear();
	mTempState.clear();
	mMouseWarped = false;
Ben Hymers's avatar
Ben Hymers committed
63

64
65
66
67
68
	// Hide OS Mouse
 	CGDisplayHideCursor(kCGDirectMainDisplay);

	MacInputManager* im = static_cast<MacInputManager*>(mCreator);
	WindowRef win = im->_getWindow();
Ben Hymers's avatar
Ben Hymers committed
69

70
71
72
73
	if(win)
	{
		Rect clipRect = {0.0f, 0.0f, 0.0f, 0.0f};
		GetWindowBounds(win, kWindowContentRgn, &clipRect);
Ben Hymers's avatar
Ben Hymers committed
74

75
76
77
78
		CGPoint warpPoint;
		warpPoint.x = ((clipRect.right - clipRect.left) / 2) + clipRect.left;
		warpPoint.y = ((clipRect.bottom - clipRect.top) / 2) + clipRect.top;
		CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, warpPoint); //Place at display origin
Ben Hymers's avatar
Ben Hymers committed
79

80
81
82
83
84
		mMouseWarped = true;
	}

	//Now that mouse is warped, start listening for events
	EventTargetRef event = ((MacInputManager*)mCreator)->_getEventTarget();
Ben Hymers's avatar
Ben Hymers committed
85

86
87
	if(mouseEventRef != NULL)
		RemoveEventHandler(mouseEventRef);
Ben Hymers's avatar
Ben Hymers committed
88

89
90
91
92
93
94
95
96
97
	if(mWindowFocusHandler != NULL)
		RemoveEventHandler(mWindowFocusHandler);

	mouseEventRef = mWindowFocusHandler = NULL;

	if(InstallEventHandler(event, mouseUPP, GetEventTypeCount(mouseEvents), mouseEvents, this, &mouseEventRef) != noErr)
		OIS_EXCEPT( E_General, "MacMouse::_initialize >> Error loading Mouse event handler" );

	if(InstallEventHandler(event, mWindowFocusListener, GetEventTypeCount(WinFocusAcquired), WinFocusAcquired, this, &mWindowFocusHandler) != noErr)
Ben Hymers's avatar
Ben Hymers committed
98
		OIS_EXCEPT( E_General, "MacMouse::_initialize >> Error loading Mouse event handler" );
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131

	//Lock OS Mouse movement
	mNeedsToRegainFocus = false;
	CGAssociateMouseAndMouseCursorPosition(FALSE);
}

OSStatus MacMouse::WindowFocusChanged(EventHandlerCallRef nextHandler, EventRef event, void* macMouse)
{
	//std::cout << "Window Focus Changed\n";

	MacMouse* _this = static_cast<MacMouse*>(macMouse);
    if (_this)
	{
		_this->mNeedsToRegainFocus = true;
		CGAssociateMouseAndMouseCursorPosition(TRUE);

        // propagate the event down the chain
        return CallNextEventHandler(nextHandler, event);
    }
    else
        OIS_EXCEPT(E_General, "MouseWrapper >> Being called by something other than our event handler!");
}

void MacMouse::setBuffered( bool buffered )
{
	mBuffered = buffered;
}

void MacMouse::capture()
{
	mState.X.rel = 0;
	mState.Y.rel = 0;
	mState.Z.rel = 0;
Ben Hymers's avatar
Ben Hymers committed
132

133
134
135
136
137
138
139
140
	if(mTempState.X.rel || mTempState.Y.rel || mTempState.Z.rel)
	{
		//printf("%i %i %i\n\n", mTempState.X.rel, mTempState.Y.rel, mTempState.Z.rel);

		//Set new relative motion values
		mState.X.rel = mTempState.X.rel;
		mState.Y.rel = mTempState.Y.rel;
		mState.Z.rel = mTempState.Z.rel;
Ben Hymers's avatar
Ben Hymers committed
141

142
143
144
		//Update absolute position
		mState.X.abs += mTempState.X.rel;
		mState.Y.abs += mTempState.Y.rel;
Ben Hymers's avatar
Ben Hymers committed
145

146
147
148
149
150
151
152
153
154
		if(mState.X.abs > mState.width)
			mState.X.abs = mState.width;
		else if(mState.X.abs < 0)
			mState.X.abs = 0;

		if(mState.Y.abs > mState.height)
			mState.Y.abs = mState.height;
		else if(mState.Y.abs < 0)
			mState.Y.abs = 0;
Ben Hymers's avatar
Ben Hymers committed
155

156
		mState.Z.abs += mTempState.Z.rel;
Ben Hymers's avatar
Ben Hymers committed
157

158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
		//Fire off event
		if(mListener && mBuffered)
			mListener->mouseMoved(MouseEvent(this, mState));
	}

	mTempState.clear();
}

void MacMouse::_mouseCallback( EventRef theEvent )
{
	OSStatus result = eventNotHandledErr;
    UInt32 kind = GetEventKind (theEvent);

	switch(kind)
	{
		case kEventMouseDragged:
		case kEventMouseMoved:
		{
			//HIPoint location = {0.0f, 0.0f};
			HIPoint delta = {0.0f, 0.0f};
			//Rect clipRect = {0.0f, 0.0f, 0.0f, 0.0f};
Ben Hymers's avatar
Ben Hymers committed
179

180
181
182
183
184
185
186
			if(mNeedsToRegainFocus)
				break;

			// Capture the parameters
			// TODO: Look into HIViewNewTrackingArea
			//GetEventParameter(theEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(HIPoint), NULL, &location);
			GetEventParameter(theEvent, kEventParamMouseDelta, typeHIPoint, NULL, sizeof(HIPoint), NULL, &delta);
Ben Hymers's avatar
Ben Hymers committed
187
188

			// Mouse X and Y are the position on the screen,
189
			// startng from top-left at 0,0 caps at full monitor resolution
Ben Hymers's avatar
Ben Hymers committed
190

191
192
193
194
			// If we have a window we need to return adjusted coordinates
			// If not, just use raw coordinates - only do this if showing OS mouse
			//MacInputManager* im = static_cast<MacInputManager*>(mCreator);
			//WindowRef win = im->_getWindow();
Ben Hymers's avatar
Ben Hymers committed
195

196
197
198
199
200
201
202
203
204
			//if(win != NULL)
			//{
			//	GetWindowBounds(win, kWindowContentRgn, &clipRect);
			//}
            //else
            //{
            //    clipRect.right = mState.width;
            //    clipRect.bottom = mState.height;
            //}
Ben Hymers's avatar
Ben Hymers committed
205

206
207
208
209
210
211
212
            // clip the mouse, absolute positioning
            //if (location.x <= clipRect.left)
			//	mState.X.abs = 0;
			//else if(location.x >= clipRect.right)
			//	mState.X.abs = clipRect.right - clipRect.left;
			//else
			//	mState.X.abs = location.x - clipRect.left;
Ben Hymers's avatar
Ben Hymers committed
213

214
215
216
217
218
219
			//if (location.y <= clipRect.top)
			//	mState.Y.abs = 0;
			//else if(location.y >= clipRect.bottom)
			//	mState.Y.abs = clipRect.bottom - clipRect.top;
			//else
			//	mState.Y.abs = location.y - clipRect.top;
Ben Hymers's avatar
Ben Hymers committed
220

221
222
223
224
225
226
			// relative positioning
			if(!mMouseWarped)
			{
				mTempState.X.rel += delta.x;
				mTempState.Y.rel += delta.y;
			}
Ben Hymers's avatar
Ben Hymers committed
227

228
229
230
231
232
233
234
235
236
			mMouseWarped = false;

			break;
		}
		case kEventMouseDown:
		{
			EventMouseButton button = 0;
			int mouseButton = 3;
			UInt32 modifiers = 0;
Ben Hymers's avatar
Ben Hymers committed
237

238
239
240
241
242
243
			if(mNeedsToRegainFocus)
				break;

			// Capture parameters
			GetEventParameter(theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(EventMouseButton), NULL, &button);
			GetEventParameter(theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
Ben Hymers's avatar
Ben Hymers committed
244

245
246
247
248
249
250
			if((button == kEventMouseButtonTertiary) || ((button == kEventMouseButtonPrimary) && (modifiers & optionKey)))
			{
				mouseButton = 2;
				mState.buttons |= 1 << mouseButton;
			}
            else if((button == kEventMouseButtonSecondary) || ((button == kEventMouseButtonPrimary) && (modifiers & controlKey)))
Ben Hymers's avatar
Ben Hymers committed
251
            {
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
                mouseButton = 1;
                mState.buttons |= 1 << mouseButton;
            }
            else if(button == kEventMouseButtonPrimary)
            {
                mouseButton = 0;
                mState.buttons |= 1 << mouseButton;
            }

            if( mListener && mBuffered )
                mListener->mousePressed( MouseEvent( this, mState ), (MouseButtonID)mouseButton );

            break;
		}
		case kEventMouseUp:
		{
			EventMouseButton button = 0;
			int mouseButton = 3;
			UInt32 modifiers = 0;
Ben Hymers's avatar
Ben Hymers committed
271

272
273
274
275
			if(mNeedsToRegainFocus)
			{
				mNeedsToRegainFocus = false;
				CGAssociateMouseAndMouseCursorPosition(false);
Ben Hymers's avatar
Ben Hymers committed
276

277
278
				MacInputManager* im = static_cast<MacInputManager*>(mCreator);
				WindowRef win = im->_getWindow();
Ben Hymers's avatar
Ben Hymers committed
279

280
281
282
283
				if(win)
				{
					Rect clipRect = {0.0f, 0.0f, 0.0f, 0.0f};
					GetWindowBounds(win, kWindowContentRgn, &clipRect);
Ben Hymers's avatar
Ben Hymers committed
284

285
286
287
288
					CGPoint warpPoint;
					warpPoint.x = ((clipRect.right - clipRect.left) / 2) + clipRect.left;
					warpPoint.y = ((clipRect.bottom - clipRect.top) / 2) + clipRect.top;
					CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, warpPoint); //Place at display origin
Ben Hymers's avatar
Ben Hymers committed
289

290
					CGDisplayHideCursor(kCGDirectMainDisplay);
Ben Hymers's avatar
Ben Hymers committed
291

292
293
					mMouseWarped = true;
				}
Ben Hymers's avatar
Ben Hymers committed
294

295
296
297
				//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
				//compare against old status, and send off any needed events
				mState.buttons = 0;
Ben Hymers's avatar
Ben Hymers committed
298

299
300
				break;
			}
Ben Hymers's avatar
Ben Hymers committed
301

302
303
304
			// Capture parameters
			GetEventParameter(theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(EventMouseButton), NULL, &button);
			GetEventParameter(theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
Ben Hymers's avatar
Ben Hymers committed
305

306
307
308
309
310
311
			if ((button == kEventMouseButtonTertiary) || ((button == kEventMouseButtonPrimary) && (modifiers & optionKey)))
			{
				mouseButton = 2;
				mState.buttons &= ~(1 << mouseButton);
			}
            else if ((button == kEventMouseButtonSecondary) || ((button == kEventMouseButtonPrimary) && (modifiers & controlKey)))
Ben Hymers's avatar
Ben Hymers committed
312
            {
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
                mouseButton = 1;
                mState.buttons &= ~(1 << mouseButton);
            }
            else if (button == kEventMouseButtonPrimary)
            {
                mouseButton = 0;
                mState.buttons &= ~(1 << mouseButton);
            }

            if( mListener && mBuffered )
                mListener->mouseReleased( MouseEvent( this, mState ), (MouseButtonID)mouseButton );

            break;
		}
		case kEventMouseWheelMoved:
		{
			SInt32 wheelDelta = 0;
Ben Hymers's avatar
Ben Hymers committed
330
			EventMouseWheelAxis	wheelAxis = 0;
331
332
333
334

			// Capture parameters
			GetEventParameter(theEvent, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(EventMouseWheelAxis), NULL, &wheelAxis);
			GetEventParameter(theEvent, kEventParamMouseWheelDelta, typeSInt32, NULL, sizeof(SInt32), NULL, &wheelDelta);
Ben Hymers's avatar
Ben Hymers committed
335

336
337
338
339
340
341
342
343
344
			// If the Y axis of the wheel changed, then update the Z
			// Does OIS care about the X wheel axis?
			if(wheelAxis == kEventMouseWheelAxisY)
				mTempState.Z.rel += (wheelDelta * 60);

            break;
		}
		default:
			break;
Ben Hymers's avatar
Ben Hymers committed
345
	}
346
}