Refactored OS X implementation regarding SFOpenGLView

This commit is contained in:
Marco Antognini 2016-01-26 08:24:14 +01:00 committed by Lukas Dürrenberger
parent 7b20093650
commit 2f53489f2a
7 changed files with 677 additions and 489 deletions

View File

@ -133,6 +133,10 @@ elseif(SFML_OS_MACOSX)
${SRCROOT}/OSX/SFKeyboardModifiersHelper.mm ${SRCROOT}/OSX/SFKeyboardModifiersHelper.mm
${SRCROOT}/OSX/SFOpenGLView.h ${SRCROOT}/OSX/SFOpenGLView.h
${SRCROOT}/OSX/SFOpenGLView.mm ${SRCROOT}/OSX/SFOpenGLView.mm
${SRCROOT}/OSX/SFOpenGLView+keyboard.mm
${SRCROOT}/OSX/SFOpenGLView+keyboard_priv.h
${SRCROOT}/OSX/SFOpenGLView+mouse.mm
${SRCROOT}/OSX/SFOpenGLView+mouse_priv.h
${SRCROOT}/OSX/SFSilentResponder.h ${SRCROOT}/OSX/SFSilentResponder.h
${SRCROOT}/OSX/SFSilentResponder.m ${SRCROOT}/OSX/SFSilentResponder.m
${SRCROOT}/OSX/SFWindow.h ${SRCROOT}/OSX/SFWindow.h

View File

@ -0,0 +1,220 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2015 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 <SFML/Window/OSX/HIDInputManager.hpp> // For localizedKeys and nonLocalizedKeys
#import <SFML/Window/OSX/SFKeyboardModifiersHelper.h>
#import <SFML/Window/OSX/SFOpenGLView.h>
#import <SFML/Window/OSX/SFOpenGLView+keyboard_priv.h>
////////////////////////////////////////////////////////////
/// In this file, we implement keyboard handling for SFOpenGLView
///
////////////////////////////////////////////////////////////
@implementation SFOpenGLView (keyboard)
////////////////////////////////////////////////////////
-(BOOL)acceptsFirstResponder
{
// Accepts key event.
return YES;
}
////////////////////////////////////////////////////////
-(BOOL)canBecomeKeyView
{
// Accepts key event.
return YES;
}
////////////////////////////////////////////////////////
-(void)enableKeyRepeat
{
m_useKeyRepeat = YES;
}
////////////////////////////////////////////////////////
-(void)disableKeyRepeat
{
m_useKeyRepeat = NO;
}
////////////////////////////////////////////////////////
-(void)keyDown:(NSEvent*)theEvent
{
// Transmit to non-SFML responder
[[self nextResponder] keyDown:theEvent];
if (m_requester == 0)
return;
// Handle key down event
if (m_useKeyRepeat || ![theEvent isARepeat])
{
sf::Event::KeyEvent key = [SFOpenGLView convertNSKeyEventToSFMLEvent:theEvent];
if (key.code != sf::Keyboard::Unknown) // The key is recognized.
m_requester->keyDown(key);
}
// Handle text entered event:
// Ignore event if we don't want repeated keystrokes
if (m_useKeyRepeat || ![theEvent isARepeat])
{
// Ignore escape key and other non text keycode (See NSEvent.h)
// because they produce a sound alert.
if ([SFOpenGLView isValidTextUnicode:theEvent])
{
// Send the event to the hidden text view for processing
[m_hiddenTextView interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
}
// Carefully handle backspace and delete..
// Note: the event is intentionally sent to the hidden view
// even if we do something more specific below. This way
// key combination are correctly interpreted.
unsigned short keycode = [theEvent keyCode];
// Backspace
if (keycode == 0x33)
{
// Send the correct Unicode value (i.e. 8) instead of 127 (which is 'delete')
m_requester->textEntered(8);
}
// Delete
else if ((keycode == 0x75) || (keycode == NSDeleteFunctionKey))
{
// Instead of the value 63272 we send 127.
m_requester->textEntered(127);
}
// Otherwise, let's see what our hidden field has computed
else
{
NSString* string = [m_hiddenTextView string];
// Send each character to SFML event requester
for (NSUInteger index = 0; index < [string length]; ++index)
m_requester->textEntered([string characterAtIndex:index]);
// Empty our hidden cache
[m_hiddenTextView setString:@""];
}
}
}
////////////////////////////////////////////////////////
-(void)sfKeyUp:(NSEvent*)theEvent
{
// For some mystic reasons, key released events don't work the same way
// as key pressed events... We somewhat hijack the event chain of response
// in -[SFApplication sendEvent:] and resume this chain with the next
// responder.
// This is workaround to make sure key released events are fired in
// fullscreen window too.
// Transmit to non-SFML responder
[[self nextResponder] keyUp:theEvent];
if (m_requester == 0)
return;
sf::Event::KeyEvent key = [SFOpenGLView convertNSKeyEventToSFMLEvent:theEvent];
if (key.code != sf::Keyboard::Unknown) // The key is recognized.
m_requester->keyUp(key);
}
////////////////////////////////////////////////////////
-(void)flagsChanged:(NSEvent*)theEvent
{
// Transmit to non-SFML responder
[[self nextResponder] flagsChanged:theEvent];
if (m_requester == 0)
return;
NSUInteger modifiers = [theEvent modifierFlags];
handleModifiersChanged(modifiers, *m_requester);
}
////////////////////////////////////////////////////////
+(sf::Event::KeyEvent)convertNSKeyEventToSFMLEvent:(NSEvent*)event
{
// Key code
sf::Keyboard::Key key = sf::Keyboard::Unknown;
// First we look if the key down is from a list of characters
// that depend on keyboard localization.
NSString* string = [event charactersIgnoringModifiers];
if ([string length] > 0)
key = sf::priv::HIDInputManager::localizedKeys([string characterAtIndex:0]);
// If the key is not a localized one, we try to find a corresponding code
// through virtual key code.
if (key == sf::Keyboard::Unknown)
key = sf::priv::HIDInputManager::nonLocalizedKeys([event keyCode]);
return keyEventWithModifiers([event modifierFlags], key);
}
////////////////////////////////////////////////////////
+(BOOL)isValidTextUnicode:(NSEvent*)event
{
if ([event keyCode] == 0x35) // Escape
{
return false;
}
else if ([[event characters] length] > 0)
{
unichar code = [[event characters] characterAtIndex:0];
return ((code < 0xF700) || (code > 0xF8FF));
}
else
{
return true;
}
}
@end

View File

@ -0,0 +1,68 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2015 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/Mouse.hpp>
#import <AppKit/AppKit.h>
////////////////////////////////////////////////////////////
/// Here are defined a few private messages for keyboard
/// handling in SFOpenGLView.
///
////////////////////////////////////////////////////////////
@interface SFOpenGLView (keyboard_priv)
////////////////////////////////////////////////////////////
/// \brief Convert a key down/up NSEvent into an SFML key event
///
/// The conversion is based on localizedKeys and nonLocalizedKeys functions.
///
/// \param event a key event
///
/// \return sf::Keyboard::Unknown as Code if the key is unknown
///
////////////////////////////////////////////////////////////
+(sf::Event::KeyEvent)convertNSKeyEventToSFMLEvent:(NSEvent*)event;
////////////////////////////////////////////////////////////
/// \brief Check if the event represent some Unicode text
///
/// The event is assumed to be a key down event.
/// False is returned if the event is either escape or a non text Unicode.
///
/// \param event a key down event
///
/// \return true if event represents a Unicode character, false otherwise
///
////////////////////////////////////////////////////////////
+(BOOL)isValidTextUnicode:(NSEvent*)event;
@end

View File

@ -0,0 +1,285 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2015 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>
#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
{
BOOL mouseWasIn = m_mouseIsIn;
m_mouseIsIn = [self isMouseInside];
if (m_requester == 0)
return;
// Send event if needed.
if (mouseWasIn && !m_mouseIsIn)
m_requester->mouseMovedOut();
else if (!mouseWasIn && m_mouseIsIn)
m_requester->mouseMovedIn();
}
////////////////////////////////////////////////////////
-(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
{
if (m_requester != 0)
{
NSPoint loc = [self cursorPositionFromEvent:theEvent];
// 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_mouseIsIn)
m_requester->mouseMovedAt(loc.x, loc.y);
}
}
////////////////////////////////////////////////////////
-(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 loc;
// If no event given then get current mouse pos.
if (eventOrNil == nil)
{
NSPoint rawPos = [[self window] mouseLocationOutsideOfEventStream];
loc = [self convertPoint:rawPos fromView:nil];
}
else
{
loc = [self convertPoint:[eventOrNil locationInWindow] 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

View File

@ -0,0 +1,79 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2015 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/Mouse.hpp>
#import <AppKit/AppKit.h>
////////////////////////////////////////////////////////////
/// Here are defined a few private messages for mouse
/// handling in SFOpenGLView.
///
////////////////////////////////////////////////////////////
@interface SFOpenGLView (mouse_priv)
////////////////////////////////////////////////////////////
/// \brief Update the mouse state (in or out)
///
/// Fire an event if its state has changed.
///
////////////////////////////////////////////////////////////
-(void)updateMouseState;
////////////////////////////////////////////////////////////
/// \brief handle mouse down event
///
////////////////////////////////////////////////////////////
-(void)handleMouseDown:(NSEvent*)theEvent;
////////////////////////////////////////////////////////////
/// \brief handle mouse up event
///
////////////////////////////////////////////////////////////
-(void)handleMouseUp:(NSEvent*)theEvent;
////////////////////////////////////////////////////////////
/// \brief handle mouse move event
///
////////////////////////////////////////////////////////////
-(void)handleMouseMove:(NSEvent*)theEvent;
////////////////////////////////////////////////////////////
/// \brief Convert the NSEvent mouse button type to SFML type
///
/// \param event a mouse button event
///
/// \return Left, Right, ..., or ButtonCount if the button is unknown
///
////////////////////////////////////////////////////////////
+(sf::Mouse::Button)mouseButtonFromEvent:(NSEvent*)event;
@end

View File

@ -47,6 +47,11 @@ namespace sf {
/// Modifiers keys (cmd, ctrl, alt, shift) are handled by this class /// Modifiers keys (cmd, ctrl, alt, shift) are handled by this class
/// but the actual logic is done in SFKeyboardModifiersHelper.(h|mm). /// but the actual logic is done in SFKeyboardModifiersHelper.(h|mm).
/// ///
/// The interface is subdivided into several categories in order
/// to have multiple implementation files to divide this monolithic
/// implementation. However, all attributes are defined in the main
/// interface declaration right below.
///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@interface SFOpenGLView : NSOpenGLView @interface SFOpenGLView : NSOpenGLView
{ {
@ -105,6 +110,18 @@ namespace sf {
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
-(NSPoint)computeGlobalPositionOfRelativePoint:(NSPoint)point; -(NSPoint)computeGlobalPositionOfRelativePoint:(NSPoint)point;
////////////////////////////////////////////////////////////
/// \brief Get the display scale factor
///
/// \return e.g. 1.0 for classic display, 2.0 for retina display
///
////////////////////////////////////////////////////////////
-(CGFloat)displayScaleFactor;
@end
@interface SFOpenGLView (keyboard)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Enable key repeat /// \brief Enable key repeat
/// ///
@ -117,13 +134,9 @@ namespace sf {
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
-(void)disableKeyRepeat; -(void)disableKeyRepeat;
//////////////////////////////////////////////////////////// @end
/// \brief Get the display scale factor
/// @interface SFOpenGLView (mouse)
/// \return e.g. 1.0 for classic display, 2.0 for retina display
///
////////////////////////////////////////////////////////////
-(CGFloat)displayScaleFactor;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Compute the position of the cursor /// \brief Compute the position of the cursor

View File

@ -27,28 +27,13 @@
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Window/OSX/WindowImplCocoa.hpp> #include <SFML/Window/OSX/WindowImplCocoa.hpp>
#include <SFML/Window/OSX/HIDInputManager.hpp> // For localizedKeys and nonLocalizedKeys
#include <SFML/System/Err.hpp> #include <SFML/System/Err.hpp>
#import <SFML/Window/OSX/SFKeyboardModifiersHelper.h>
#import <SFML/Window/OSX/SFOpenGLView.h> #import <SFML/Window/OSX/SFOpenGLView.h>
#import <SFML/Window/OSX/SFOpenGLView+mouse_priv.h>
#import <SFML/Window/OSX/SFSilentResponder.h> #import <SFML/Window/OSX/SFSilentResponder.h>
////////////////////////////////////////////////////////////
/// \brief Check if the event represent some Unicode text
///
/// The event is assumed to be a key down event.
/// False is returned if the event is either escape or a non text Unicode.
///
/// \param event a key down event
///
/// \return true if event represents a Unicode character, false otherwise
///
////////////////////////////////////////////////////////////
BOOL isValidTextUnicode(NSEvent* event);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// SFOpenGLView class: Privates Methods Declaration /// SFOpenGLView class: Privates Methods Declaration
/// ///
@ -67,14 +52,6 @@ BOOL isValidTextUnicode(NSEvent* event);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
-(void)viewDidEndLiveResize; -(void)viewDidEndLiveResize;
////////////////////////////////////////////////////////////
/// \brief Update the mouse state (in or out)
///
/// Fire an event if its state has changed.
///
////////////////////////////////////////////////////////////
-(void)updateMouseState;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Callback for focus event /// \brief Callback for focus event
/// ///
@ -99,28 +76,6 @@ BOOL isValidTextUnicode(NSEvent* event);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
-(void)exitFullscreen; -(void)exitFullscreen;
////////////////////////////////////////////////////////////
/// \brief Convert the NSEvent mouse button type to SFML type
///
/// \param event a mouse button event
///
/// \return Left, Right, ..., or ButtonCount if the button is unknown
///
////////////////////////////////////////////////////////////
-(sf::Mouse::Button)mouseButtonFromEvent:(NSEvent*)event;
////////////////////////////////////////////////////////////
/// \brief Convert a key down/up NSEvent into an SFML key event
///
/// The conversion is based on localizedKeys and nonLocalizedKeys functions.
///
/// \param event a key event
///
/// \return sf::Keyboard::Unknown as Code if the key is unknown
///
////////////////////////////////////////////////////////////
+(sf::Event::KeyEvent)convertNSKeyEventToSFMLEvent:(NSEvent*)event;
@end @end
@implementation SFOpenGLView @implementation SFOpenGLView
@ -251,20 +206,6 @@ BOOL isValidTextUnicode(NSEvent* event);
} }
////////////////////////////////////////////////////////
-(void)enableKeyRepeat
{
m_useKeyRepeat = YES;
}
////////////////////////////////////////////////////////
-(void)disableKeyRepeat
{
m_useKeyRepeat = NO;
}
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
-(CGFloat)displayScaleFactor -(CGFloat)displayScaleFactor
{ {
@ -317,34 +258,6 @@ BOOL isValidTextUnicode(NSEvent* event);
m_requester->windowResized(newSize.width, newSize.height); m_requester->windowResized(newSize.width, newSize.height);
} }
////////////////////////////////////////////////////////
-(BOOL)isMouseInside
{
NSPoint relativeToWindow = [[self window] mouseLocationOutsideOfEventStream];
NSPoint relativeToView = [self convertPoint:relativeToWindow fromView:nil];
return NSPointInRect(relativeToView, [self bounds]);
}
////////////////////////////////////////////////////////
-(void)updateMouseState
{
BOOL mouseWasIn = m_mouseIsIn;
m_mouseIsIn = [self isMouseInside];
if (m_requester == 0)
return;
// Send event if needed.
if (mouseWasIn && !m_mouseIsIn)
m_requester->mouseMovedOut();
else if (!mouseWasIn && m_mouseIsIn)
m_requester->mouseMovedIn();
}
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
-(void)windowDidBecomeKey:(NSNotification*)notification -(void)windowDidBecomeKey:(NSNotification*)notification
{ {
@ -426,398 +339,4 @@ BOOL isValidTextUnicode(NSEvent* event);
} }
////////////////////////////////////////////////////////
-(BOOL)acceptsFirstResponder
{
// Accepts key event.
return YES;
}
////////////////////////////////////////////////////////
-(BOOL)canBecomeKeyView
{
// Accepts key event.
return YES;
}
#pragma mark
#pragma mark Mouse-event methods
////////////////////////////////////////////////////////
-(void)mouseDown:(NSEvent*)theEvent
{
// Forward to...
[self otherMouseDown:theEvent];
// Transmit to non-SFML responder
[[self nextResponder] mouseDown:theEvent];
}
////////////////////////////////////////////////////////
-(void)mouseUp:(NSEvent*)theEvent
{
// Forward to...
[self otherMouseUp:theEvent];
// Transmit to non-SFML responder
[[self nextResponder] mouseUp:theEvent];
}
////////////////////////////////////////////////////////
-(void)mouseMoved:(NSEvent*)theEvent
{
// Forward to...
[self otherMouseDragged:theEvent];
// Transmit to non-SFML responder
[[self nextResponder] mouseMoved:theEvent];
}
////////////////////////////////////////////////////////
-(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];
}
////////////////////////////////////////////////////////
-(void)rightMouseDown:(NSEvent*)theEvent
{
// Forward to...
[self otherMouseDown:theEvent];
// Transmit to non-SFML responder
[[self nextResponder] rightMouseDown:theEvent];
}
////////////////////////////////////////////////////////
-(void)rightMouseUp:(NSEvent*)theEvent
{
// Forward to...
[self otherMouseUp:theEvent];
// Transmit to non-SFML responder
[[self nextResponder] rightMouseUp:theEvent];
}
////////////////////////////////////////////////////////
-(void)otherMouseDown:(NSEvent*)theEvent
{
sf::Mouse::Button button = [self mouseButtonFromEvent:theEvent];
if (m_requester != 0)
{
NSPoint loc = [self cursorPositionFromEvent:theEvent];
if (button != sf::Mouse::ButtonCount)
m_requester->mouseDownAt(button, loc.x, loc.y);
}
// If the event is not forwarded by mouseDown or rightMouseDown...
if ((button != sf::Mouse::Left) && (button != sf::Mouse::Right))
{
// ... transmit to non-SFML responder
[[self nextResponder] otherMouseDown:theEvent];
}
}
////////////////////////////////////////////////////////
-(void)otherMouseUp:(NSEvent*)theEvent
{
sf::Mouse::Button button = [self mouseButtonFromEvent:theEvent];
if (m_requester != 0)
{
NSPoint loc = [self cursorPositionFromEvent:theEvent];
if (button != sf::Mouse::ButtonCount)
m_requester->mouseUpAt(button, loc.x, loc.y);
}
// If the event is not forwarded by mouseUp or rightMouseUp...
if ((button != sf::Mouse::Left) && (button != sf::Mouse::Right))
{
// ... transmit to non-SFML responder
[[self nextResponder] otherMouseUp:theEvent];
}
}
////////////////////////////////////////////////////////
-(void)rightMouseDragged:(NSEvent*)theEvent
{
// Forward to...
[self otherMouseDragged:theEvent];
// Transmit to non-SFML responder
[[self nextResponder] rightMouseDragged:theEvent];
}
////////////////////////////////////////////////////////
-(void)mouseDragged:(NSEvent*)theEvent
{
// Forward to...
[self otherMouseDragged:theEvent];
// Transmit to non-SFML responder
[[self nextResponder] mouseDragged:theEvent];
}
////////////////////////////////////////////////////////
-(void)otherMouseDragged:(NSEvent*)theEvent
{
if (m_requester != 0)
{
NSPoint loc = [self cursorPositionFromEvent:theEvent];
// 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_mouseIsIn)
m_requester->mouseMovedAt(loc.x, loc.y);
}
// If the event is not forwarded by mouseDragged or rightMouseDragged...
sf::Mouse::Button button = [self mouseButtonFromEvent:theEvent];
if ((button != sf::Mouse::Left) && (button != sf::Mouse::Right))
{
// ... transmit to non-SFML responder
[[self nextResponder] otherMouseUp:theEvent];
}
}
////////////////////////////////////////////////////////
-(NSPoint)cursorPositionFromEvent:(NSEvent*)eventOrNil
{
NSPoint loc;
// If no event given then get current mouse pos.
if (eventOrNil == nil)
{
NSPoint rawPos = [[self window] mouseLocationOutsideOfEventStream];
loc = [self convertPoint:rawPos fromView:nil];
}
else
{
loc = [self convertPoint:[eventOrNil locationInWindow] 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)
}
}
#pragma mark
#pragma mark Key-event methods
////////////////////////////////////////////////////////
-(void)keyDown:(NSEvent*)theEvent
{
// Transmit to non-SFML responder
[[self nextResponder] keyDown:theEvent];
if (m_requester == 0)
return;
// Handle key down event
if (m_useKeyRepeat || ![theEvent isARepeat])
{
sf::Event::KeyEvent key = [SFOpenGLView convertNSKeyEventToSFMLEvent:theEvent];
if (key.code != sf::Keyboard::Unknown) // The key is recognized.
m_requester->keyDown(key);
}
// Handle text entered event:
// Ignore event if we don't want repeated keystrokes
if (m_useKeyRepeat || ![theEvent isARepeat])
{
// Ignore escape key and other non text keycode (See NSEvent.h)
// because they produce a sound alert.
if (isValidTextUnicode(theEvent))
{
// Send the event to the hidden text view for processing
[m_hiddenTextView interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
}
// Carefully handle backspace and delete..
// Note: the event is intentionally sent to the hidden view
// even if we do something more specific below. This way
// key combination are correctly interpreted.
unsigned short keycode = [theEvent keyCode];
// Backspace
if (keycode == 0x33)
{
// Send the correct Unicode value (i.e. 8) instead of 127 (which is 'delete')
m_requester->textEntered(8);
}
// Delete
else if ((keycode == 0x75) || (keycode == NSDeleteFunctionKey))
{
// Instead of the value 63272 we send 127.
m_requester->textEntered(127);
}
// Otherwise, let's see what our hidden field has computed
else
{
NSString* string = [m_hiddenTextView string];
// Send each character to SFML event requester
for (NSUInteger index = 0; index < [string length]; ++index)
m_requester->textEntered([string characterAtIndex:index]);
// Empty our hidden cache
[m_hiddenTextView setString:@""];
}
}
}
////////////////////////////////////////////////////////
-(void)sfKeyUp:(NSEvent*)theEvent
{
// For some mystic reasons, key released events don't work the same way
// as key pressed events... We somewhat hijack the event chain of response
// in -[SFApplication sendEvent:] and resume this chain with the next
// responder.
// This is workaround to make sure key released events are fired in
// fullscreen window too.
// Transmit to non-SFML responder
[[self nextResponder] keyUp:theEvent];
if (m_requester == 0)
return;
sf::Event::KeyEvent key = [SFOpenGLView convertNSKeyEventToSFMLEvent:theEvent];
if (key.code != sf::Keyboard::Unknown) // The key is recognized.
m_requester->keyUp(key);
}
////////////////////////////////////////////////////////
-(void)flagsChanged:(NSEvent*)theEvent
{
// Transmit to non-SFML responder
[[self nextResponder] flagsChanged:theEvent];
if (m_requester == 0)
return;
NSUInteger modifiers = [theEvent modifierFlags];
handleModifiersChanged(modifiers, *m_requester);
}
////////////////////////////////////////////////////////
+(sf::Event::KeyEvent)convertNSKeyEventToSFMLEvent:(NSEvent*)event
{
// Key code
sf::Keyboard::Key key = sf::Keyboard::Unknown;
// First we look if the key down is from a list of characters
// that depend on keyboard localization.
NSString* string = [event charactersIgnoringModifiers];
if ([string length] > 0)
key = sf::priv::HIDInputManager::localizedKeys([string characterAtIndex:0]);
// If the key is not a localized one, we try to find a corresponding code
// through virtual key code.
if (key == sf::Keyboard::Unknown)
key = sf::priv::HIDInputManager::nonLocalizedKeys([event keyCode]);
//#ifdef SFML_DEBUG // Don't bother the final customers with annoying messages.
// if (key.code == sf::Keyboard::Unknown) { // The key is unknown.
// sf::err() << "This is an unknown key. Virtual key code is 0x"
// << std::hex
// << [event keyCode]
// << "."
// << std::endl;
// }
//#endif
return keyEventWithModifiers([event modifierFlags], key);
}
@end @end
#pragma mark - C-like functions
BOOL isValidTextUnicode(NSEvent* event)
{
if ([event keyCode] == 0x35) // Escape
{
return false;
}
else if ([[event characters] length] > 0)
{
unichar code = [[event characters] characterAtIndex:0];
return ((code < 0xF700) || (code > 0xF8FF));
}
else
{
return true;
}
}