summaryrefslogtreecommitdiff
path: root/src/SFML/Window/OSX/SFOpenGLView+mouse.mm
diff options
context:
space:
mode:
authorJames Cowgill <jcowgill@debian.org>2016-08-09 15:20:03 +0000
committerJames Cowgill <jcowgill@debian.org>2016-08-09 15:20:03 +0000
commitdf93e238e30e97850d76ad5585b8ab9ad9c03e67 (patch)
tree2ae5f3305e1ee1882f563d2803f94aa6446dc367 /src/SFML/Window/OSX/SFOpenGLView+mouse.mm
parent301fd78b3ac87cf1fbce9d2c955db89094a304a5 (diff)
Imported Upstream version 2.4.0+dfsg
Diffstat (limited to 'src/SFML/Window/OSX/SFOpenGLView+mouse.mm')
-rw-r--r--src/SFML/Window/OSX/SFOpenGLView+mouse.mm402
1 files changed, 402 insertions, 0 deletions
diff --git a/src/SFML/Window/OSX/SFOpenGLView+mouse.mm b/src/SFML/Window/OSX/SFOpenGLView+mouse.mm
new file mode 100644
index 0000000..6349081
--- /dev/null
+++ b/src/SFML/Window/OSX/SFOpenGLView+mouse.mm
@@ -0,0 +1,402 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2016 Marco Antognini (antognini.marco@gmail.com),
+// Laurent Gomila (laurent@sfml-dev.org)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/OSX/WindowImplCocoa.hpp>
+#include <cmath>
+
+#import <SFML/Window/OSX/SFOpenGLView.h>
+#import <SFML/Window/OSX/SFOpenGLView+mouse_priv.h>
+
+
+////////////////////////////////////////////////////////////
+/// In this file, we implement mouse handling for SFOpenGLView
+///
+////////////////////////////////////////////////////////////
+
+@implementation SFOpenGLView (mouse)
+
+////////////////////////////////////////////////////////
+-(BOOL)isMouseInside
+{
+ NSPoint relativeToWindow = [[self window] mouseLocationOutsideOfEventStream];
+ NSPoint relativeToView = [self convertPoint:relativeToWindow fromView:nil];
+
+ return NSPointInRect(relativeToView, [self bounds]);
+}
+
+
+////////////////////////////////////////////////////////
+-(void)updateMouseState
+{
+ // Update in/out state
+ BOOL mouseWasIn = m_mouseIsIn;
+ m_mouseIsIn = [self isMouseInside];
+
+ // Send event if needed.
+ if (m_requester != 0)
+ {
+ if (mouseWasIn && !m_mouseIsIn)
+ m_requester->mouseMovedOut();
+ else if (!mouseWasIn && m_mouseIsIn)
+ m_requester->mouseMovedIn();
+ }
+}
+
+
+////////////////////////////////////////////////////////
+-(void)setCursorGrabbed:(BOOL)grabbed
+{
+ m_cursorGrabbed = grabbed;
+
+ [self updateCursorGrabbed];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)mouseDown:(NSEvent*)theEvent
+{
+ [self handleMouseDown:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] mouseDown:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)rightMouseDown:(NSEvent*)theEvent
+{
+ [self handleMouseDown:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] rightMouseDown:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)otherMouseDown:(NSEvent*)theEvent
+{
+ [self handleMouseDown:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] otherMouseDown:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)handleMouseDown:(NSEvent*)theEvent
+{
+ sf::Mouse::Button button = [SFOpenGLView mouseButtonFromEvent:theEvent];
+
+ if (m_requester != 0)
+ {
+ NSPoint loc = [self cursorPositionFromEvent:theEvent];
+
+ if (button != sf::Mouse::ButtonCount)
+ m_requester->mouseDownAt(button, loc.x, loc.y);
+ }
+}
+
+
+////////////////////////////////////////////////////////
+-(void)mouseUp:(NSEvent*)theEvent
+{
+ [self handleMouseUp:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] mouseUp:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)rightMouseUp:(NSEvent*)theEvent
+{
+ [self handleMouseUp:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] rightMouseUp:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)otherMouseUp:(NSEvent*)theEvent
+{
+ [self handleMouseUp:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] otherMouseUp:theEvent];
+}
+
+
+////////////////////////////////////////////////////////////
+-(void)handleMouseUp:(NSEvent*)theEvent
+{
+ sf::Mouse::Button button = [SFOpenGLView mouseButtonFromEvent:theEvent];
+
+ if (m_requester != 0)
+ {
+ NSPoint loc = [self cursorPositionFromEvent:theEvent];
+
+ if (button != sf::Mouse::ButtonCount)
+ m_requester->mouseUpAt(button, loc.x, loc.y);
+ }
+}
+
+
+////////////////////////////////////////////////////////
+-(void)mouseMoved:(NSEvent*)theEvent
+{
+ [self handleMouseMove:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] mouseMoved:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)rightMouseDragged:(NSEvent*)theEvent
+{
+ [self handleMouseMove:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] rightMouseDragged:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)mouseDragged:(NSEvent*)theEvent
+{
+ [self handleMouseMove:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] mouseDragged:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)otherMouseDragged:(NSEvent*)theEvent
+{
+ [self handleMouseMove:theEvent];
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] otherMouseUp:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)handleMouseMove:(NSEvent*)theEvent
+{
+ NSPoint loc = [self cursorPositionFromEvent:theEvent];
+
+ // If the cursor is grabbed, cursorPositionFromEvent: will
+ // return its correct position but not move actually it
+ // so we do it now.
+ if ([self isCursorCurrentlyGrabbed])
+ [self moveCursorTo:loc];
+
+ // Make sure the point is inside the view.
+ // (mouseEntered: and mouseExited: are not immediately called
+ // when the mouse is dragged. That would be too easy!)
+ [self updateMouseState];
+ if ((m_requester != 0) && m_mouseIsIn)
+ m_requester->mouseMovedAt(loc.x, loc.y);
+}
+
+
+////////////////////////////////////////////////////////
+-(BOOL)isCursorCurrentlyGrabbed
+{
+ return [[self window] isKeyWindow] && (m_cursorGrabbed || m_fullscreen);
+}
+
+
+////////////////////////////////////////////////////////
+-(void)updateCursorGrabbed
+{
+ // Disable/enable normal movements of the cursor
+ // and project the cursor if needed.
+ if ([self isCursorCurrentlyGrabbed])
+ {
+ CGAssociateMouseAndMouseCursorPosition(NO);
+
+ // Similarly to handleMouseMove: but without event.
+ NSPoint loc = [self cursorPositionFromEvent:nil];
+ [self moveCursorTo:loc];
+ }
+ else
+ {
+ CGAssociateMouseAndMouseCursorPosition(YES);
+ }
+}
+
+
+////////////////////////////////////////////////////////
+-(void)moveCursorTo:(NSPoint)loc
+{
+ // Convert the point from SFML coord system to screen coord system.
+ NSPoint screenLocation = [self computeGlobalPositionOfRelativePoint:loc];
+
+ // This won't produce a move event, which is perfect if the cursor was grabbed
+ // as we move it manually based on delta values of the cursor.
+ CGDisplayMoveCursorToPoint([self displayId], NSPointToCGPoint(screenLocation));
+}
+
+
+////////////////////////////////////////////////////////
+-(CGDirectDisplayID)displayId
+{
+ NSScreen* screen = [[self window] screen];
+ NSNumber* displayId = [[screen deviceDescription] objectForKey:@"NSScreenNumber"];
+ return [displayId intValue];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)scrollWheel:(NSEvent*)theEvent
+{
+ if (m_requester != 0)
+ {
+ NSPoint loc = [self cursorPositionFromEvent:theEvent];
+ m_requester->mouseWheelScrolledAt([theEvent deltaX], [theEvent deltaY], loc.x, loc.y);
+ }
+
+ // Transmit to non-SFML responder
+ [[self nextResponder] scrollWheel:theEvent];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)mouseEntered:(NSEvent*)theEvent
+{
+ (void)theEvent;
+ [self updateMouseState];
+}
+
+
+////////////////////////////////////////////////////////
+-(void)mouseExited:(NSEvent*)theEvent
+{
+ (void)theEvent;
+ [self updateMouseState];
+}
+
+
+////////////////////////////////////////////////////////
+-(NSPoint)cursorPositionFromEvent:(NSEvent*)eventOrNil
+{
+ NSPoint rawPos;
+
+ // If no event given then get current mouse pos.
+ if (eventOrNil == nil)
+ rawPos = [[self window] mouseLocationOutsideOfEventStream];
+ else
+ rawPos = [eventOrNil locationInWindow];
+
+ if ([self isCursorCurrentlyGrabbed])
+ {
+ if (eventOrNil != nil)
+ {
+ // Special case when the mouse is grabbed:
+ // we need to take into account the delta since the cursor
+ // is dissociated from its position.
+
+ // Ignore any non-move related event
+ if (([eventOrNil type] == NSMouseMoved) ||
+ ([eventOrNil type] == NSLeftMouseDragged) ||
+ ([eventOrNil type] == NSRightMouseDragged) ||
+ ([eventOrNil type] == NSOtherMouseDragged))
+ {
+ // Without this factor, the cursor flies around waaay too fast!
+ // But I don't know if it because of retina display or because
+ // some event are sent twice (and that in itself is another mystery).
+ CGFloat factor = 2;
+
+ // Also, this factor is not the same when keeping track of how much
+ // we move the cursor (buffers) when projecting the cursor into the
+ // view when grabbing the cursor for the first time.
+ CGFloat factorBuffer = m_fullscreen ? 1 : 2;
+
+ CGFloat deltaX = [eventOrNil deltaX];
+ CGFloat deltaY = [eventOrNil deltaY];
+
+ // If the buffer for X is empty, move the cursor;
+ // otherwise decrement this buffer a bit.
+ if (m_deltaXBuffer <= 0)
+ rawPos.x += deltaX / factor;
+ else
+ m_deltaXBuffer -= std::abs(deltaX / factorBuffer);
+
+ // Rinse and repeat for Y.
+ if (m_deltaYBuffer <= 0)
+ rawPos.y -= deltaY / factor;
+ else
+ m_deltaYBuffer -= std::abs(deltaY / factorBuffer);
+ }
+ }
+
+ // We also make sure the new point is inside the view
+ NSSize size = [self frame].size;
+ NSPoint origin = [self frame].origin;
+ NSPoint oldPos = rawPos;
+ rawPos.x = std::min(std::max(origin.x, rawPos.x), origin.x + size.width - 1);
+ rawPos.y = std::min(std::max(origin.y + 1, rawPos.y), origin.y + size.height);
+ // Note: the `-1` and `+1` on the two lines above prevent the user to click
+ // on the left or below the window, repectively, and therefore prevent the
+ // application to lose focus by accident. The sign of this offset is determinded
+ // by the direction of the x and y axis.
+
+ // Increase X and Y buffer with the distance of the projection
+ m_deltaXBuffer += std::abs(rawPos.x - oldPos.x);
+ m_deltaYBuffer += std::abs(rawPos.y - oldPos.y);
+ }
+
+ NSPoint loc = [self convertPoint:rawPos fromView:nil];
+
+ // Don't forget to change to SFML coord system.
+ float h = [self frame].size.height;
+ loc.y = h - loc.y;
+
+ return loc;
+}
+
+
+////////////////////////////////////////////////////////
++(sf::Mouse::Button)mouseButtonFromEvent:(NSEvent*)event
+{
+ switch ([event buttonNumber])
+ {
+ case 0: return sf::Mouse::Left;
+ case 1: return sf::Mouse::Right;
+ case 2: return sf::Mouse::Middle;
+ case 3: return sf::Mouse::XButton1;
+ case 4: return sf::Mouse::XButton2;
+ default: return sf::Mouse::ButtonCount; // Never happens! (hopefully)
+ }
+}
+
+
+@end