SFML/src/SFML/Window/OSX/SFOpenGLView.mm
2011-09-24 13:34:58 +02:00

1064 lines
32 KiB
Plaintext

////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2011 Marco Antognini (antognini.marco@gmail.com),
// Laurent Gomila (laurent.gom@gmail.com),
//
// 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
#include <SFML/System/Err.hpp>
#import <SFML/Window/OSX/SFOpenGLView.h>
////////////////////////////////////////////////////////////
/// Here are define the mask value for the 'modifiers' keys (cmd, ctrl, alt, shift)
///
/// As I don't have the right control keycode I cannot implement left-right
/// recognition for this key.
#warning Missing keycode for right control key.
/// #define NSRightControlKeyMask 0x...
/// #define NSLeftControlKeyMask 0x40101
///
////////////////////////////////////////////////////////////
#define NSRightShiftKeyMask 0x020004
#define NSLeftShiftKeyMask 0x020002
#define NSRightCommandKeyMask 0x100010
#define NSLeftCommandKeyMask 0x100008
#define NSRightAlternateKeyMask 0x080040
#define NSLeftAlternateKeyMask 0x080020
////////////////////////////////////////////////////////////
/// Erase (replace with 0) the given bits mask from the given data bits.
///
////////////////////////////////////////////////////////////
NSUInteger EraseMaskFromData(NSUInteger data, NSUInteger mask);
////////////////////////////////////////////////////////////
/// Erase (replace with 0) everything execept the given bits mask from the given data bits.
///
////////////////////////////////////////////////////////////
NSUInteger KeepOnlyMaskFromData(NSUInteger data, NSUInteger mask);
////////////////////////////////////////////////////////////
/// SFOpenGLView class : Privates Methods Declaration
///
////////////////////////////////////////////////////////////
@interface SFOpenGLView ()
////////////////////////////////////////////////////////////
/// Handle view resized event.
///
////////////////////////////////////////////////////////////
-(void)frameDidChange:(NSNotification *)notification;
////////////////////////////////////////////////////////////
/// Establish if the mouse is inside or outside the OpenGL view.
///
////////////////////////////////////////////////////////////
-(BOOL)isMouseInside;
////////////////////////////////////////////////////////////
/// Init the 'modifiers' key state.
///
////////////////////////////////////////////////////////////
-(void)initModifiersState;
////////////////////////////////////////////////////////////
/// Converte the NSEvent mouse button type to SFML type.
///
/// Returns ButtonCount if the button is unknown
///
////////////////////////////////////////////////////////////
-(sf::Mouse::Button)mouseButtonFromEvent:(NSEvent *)event;
////////////////////////////////////////////////////////////
/// Convert a key down/up NSEvent into an SFML key event.
/// Based on LocalizedKeys and NonLocalizedKeys function.
///
/// Return sf::Keyboard::KeyCount as Code if the key is unknown.
///
////////////////////////////////////////////////////////////
+(sf::Event::KeyEvent)convertNSKeyEventToSFMLEvent:(NSEvent *)anEvent;
@end
@implementation SFOpenGLView
#pragma mark
#pragma mark SFOpenGLView's methods
////////////////////////////////////////////////////////
-(id)initWithFrame:(NSRect)frameRect
{
if ((self = [super initWithFrame:frameRect])) {
[self setRequesterTo:0];
[self enableKeyRepeat];
myRealSize = NSZeroSize;
[self initModifiersState];
// Register for mouse-move event
myMouseIsIn = [self isMouseInside];
myTrackingTag = [self addTrackingRect:[self frame]
owner:self
userData:nil
assumeInside:myMouseIsIn];
// Register for resize event
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:@selector(frameDidChange:)
name:NSViewFrameDidChangeNotification
object:self];
}
return self;
}
////////////////////////////////////////////////////////
-(void)setRequesterTo:(sf::priv::WindowImplCocoa *)requester
{
myRequester = requester;
}
////////////////////////////////////////////////////////
-(void)setRealSize:(NSSize)newSize
{
myRealSize = newSize;
}
////////////////////////////////////////////////////////
-(void)setCursorPositionToX:(unsigned int)x Y:(unsigned int)y
{
// Flip for SFML window coordinate system
y = NSHeight([[self window] frame]) - y;
// Adjust for view reference instead of window
y -= NSHeight([[self window] frame]) - NSHeight([self frame]);
// Convert to screen coordinates
NSPoint screenCoord = [[self window] convertBaseToScreen:NSMakePoint(x, y)];
// Flip screen coodinates
float const screenHeight = NSHeight([[[self window] screen] frame]);
screenCoord.y = screenHeight - screenCoord.y;
// Recompute the mouse pos if required.
if (!NSEqualSizes(myRealSize, NSZeroSize)) {
screenCoord.x = screenCoord.x / myRealSize.width * [self frame].size.width;
screenCoord.y = screenCoord.y / myRealSize.height * [self frame].size.height;
}
// Place the cursor.
CGEventRef event = CGEventCreateMouseEvent(NULL,
kCGEventMouseMoved,
CGPointMake(screenCoord.x,
screenCoord.y),
/*we don't care about this : */0);
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
// This is a workaround to deprecated CGSetLocalEventsSuppressionInterval function
}
////////////////////////////////////////////////////////
-(void)enableKeyRepeat
{
myUseKeyRepeat = YES;
}
////////////////////////////////////////////////////////
-(void)disableKeyRepeat
{
myUseKeyRepeat = NO;
}
////////////////////////////////////////////////////////
-(void)frameDidChange:(NSNotification *)notification
{
// Update mouse internal state.
BOOL mouseWasIn = myMouseIsIn;
myMouseIsIn = [self isMouseInside];
// Send event if needed.
if (mouseWasIn && !myMouseIsIn) {
[self mouseExited:nil];
} else if (!mouseWasIn && myMouseIsIn) {
[self mouseEntered:nil];
}
// Adapt tracking area for mouse mouse event.
[self removeTrackingRect:myTrackingTag];
myTrackingTag = [self addTrackingRect:[self frame]
owner:self
userData:nil
assumeInside:myMouseIsIn];
// Update the OGL view to fit the new size.
[self update];
// Send an event
if (myRequester == 0) return;
// The new size
NSSize newSize = [self frame].size;
myRequester->WindowResized(newSize.width, newSize.height);
}
////////////////////////////////////////////////////////
-(BOOL)isMouseInside
{
NSPoint relativeToWindow = [[self window] mouseLocationOutsideOfEventStream];
NSPoint relativeToView = [self convertPoint:relativeToWindow fromView:nil];
if (NSPointInRect(relativeToView, [self frame])) {
return YES;
}
return NO;
}
#pragma mark
#pragma mark Subclassing methods
////////////////////////////////////////////////////////
-(void)dealloc
{
// Unregister
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self removeTrackingRect:myTrackingTag];
[super dealloc];
}
////////////////////////////////////////////////////////
-(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 (myRequester != 0) {
NSPoint loc = [self cursorPositionFromEvent:theEvent];
myRequester->MouseWheelScrolledAt([theEvent deltaY], loc.x, loc.y);
}
// Transmit to non-SFML responder
[[self nextResponder] scrollWheel:theEvent];
}
////////////////////////////////////////////////////////
-(void)mouseEntered:(NSEvent *)theEvent
{
myMouseIsIn = YES;
if (myRequester == 0) return;
myRequester->MouseMovedIn();
}
////////////////////////////////////////////////////////
-(void)mouseExited:(NSEvent *)theEvent
{
myMouseIsIn = NO;
if (myRequester == 0) return;
myRequester->MouseMovedOut();
}
////////////////////////////////////////////////////////
-(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 (myRequester != 0) {
NSPoint loc = [self cursorPositionFromEvent:theEvent];
if (button != sf::Mouse::ButtonCount) {
myRequester->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 (myRequester != 0) {
NSPoint loc = [self cursorPositionFromEvent:theEvent];
if (button != sf::Mouse::ButtonCount) {
myRequester->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 (myRequester != 0) {
// If the event is not useful.
if (!myMouseIsIn) return;
NSPoint loc = [self cursorPositionFromEvent:theEvent];
myRequester->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;
// Recompute the mouse pos if required.
if (!NSEqualSizes(myRealSize, NSZeroSize)) {
loc.x = loc.x * myRealSize.width / [self frame].size.width;
loc.y = loc.y * myRealSize.height / [self frame].size.height;
}
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 (myRequester == 0) return;
// Handle key down event
if (myUseKeyRepeat || ![theEvent isARepeat]) {
sf::Event::KeyEvent key = [SFOpenGLView convertNSKeyEventToSFMLEvent:theEvent];
if (key.Code != sf::Keyboard::KeyCount) { // The key is recognized.
myRequester->KeyDown(key);
}
}
// Handle text entred event
// We create a new event without command/ctrl modifiers
// to prevent the OS from sending an alert
NSUInteger modifiers = [theEvent modifierFlags];
if (modifiers & NSCommandKeyMask) modifiers = modifiers & ~NSCommandKeyMask;
if (modifiers & NSControlKeyMask) modifiers = modifiers & ~NSControlKeyMask;
NSEvent* ev = [NSEvent keyEventWithType:NSKeyDown
location:[theEvent locationInWindow]
modifierFlags:modifiers
timestamp:[theEvent timestamp]
windowNumber:[theEvent windowNumber]
context:[theEvent context]
characters:[theEvent characters]
charactersIgnoringModifiers:[theEvent charactersIgnoringModifiers]
isARepeat:[theEvent isARepeat]
keyCode:[theEvent keyCode]];
if ((myUseKeyRepeat || ![ev isARepeat]) && [[ev characters] length] > 0) {
// Ignore escape key and non text keycode. (See NSEvent.h)
// They produce a sound alert.
unichar code = [[ev characters] characterAtIndex:0];
if ([ev keyCode] != 0x35 && (code < 0xF700 || code > 0xF8FF)) {
// Let's see if its a valid text.
NSText* text = [[self window] fieldEditor:YES forObject:self];
[text interpretKeyEvents:[NSArray arrayWithObject:ev]];
NSString* string = [text string];
if ([string length] > 0) {
// It's a valid TextEntered event.
myRequester->TextEntered([string characterAtIndex:0]);
[text setString:@""];
}
}
}
}
////////////////////////////////////////////////////////
-(void)keyUp:(NSEvent *)theEvent
{
// Transmit to non-SFML responder
[[self nextResponder] keyUp:theEvent];
if (myRequester == 0) return;
sf::Event::KeyEvent key = [SFOpenGLView convertNSKeyEventToSFMLEvent:theEvent];
if (key.Code != sf::Keyboard::KeyCount) { // The key is recognized.
myRequester->KeyUp(key);
}
}
////////////////////////////////////////////////////////
-(void)flagsChanged:(NSEvent *)theEvent
{
// Transmit to non-SFML responder
[[self nextResponder] flagsChanged:theEvent];
if (myRequester == 0) return;
NSUInteger modifiers = [theEvent modifierFlags];
// Setup a potential event key.
sf::Event::KeyEvent key;
key.Code = sf::Keyboard::KeyCount;
key.Alt = modifiers & NSAlternateKeyMask;
key.Control = modifiers & NSControlKeyMask;
key.Shift = modifiers & NSShiftKeyMask;
key.System = modifiers & NSCommandKeyMask;
// State
BOOL rightShiftIsDown = NO;
BOOL leftShiftIsDown = NO;
BOOL rightCommandIsDown = NO;
BOOL leftCommandIsDown = NO;
BOOL rightAlternateIsDown = NO;
BOOL leftAlternateIsDown = NO;
BOOL controlIsDown = NO;
// Shift keys.
if (modifiers & NSShiftKeyMask) { // At least one shift key is down.
// Clean up modifiers to keep only 'shift' bits.
NSUInteger shift = KeepOnlyMaskFromData(modifiers, NSRightShiftKeyMask | NSLeftShiftKeyMask);
// Only right shift is down ?
if (shift == NSRightShiftKeyMask) {
rightShiftIsDown = YES;
if (myLeftShiftWasDown) {
// left shift released
leftShiftIsDown = NO;
key.Code = sf::Keyboard::LShift;
myRequester->KeyUp(key);
}
if (!myRightShiftWasDown) {
// right shift pressed
key.Code = sf::Keyboard::RShift;
myRequester->KeyDown(key);
}
}
// Only left shift is down ?
if (shift == NSLeftShiftKeyMask) {
leftShiftIsDown = YES;
if (myRightShiftWasDown) {
// right shift released
rightShiftIsDown = NO;
key.Code = sf::Keyboard::RShift;
myRequester->KeyUp(key);
}
if (!myLeftShiftWasDown) {
// left shift pressed
key.Code = sf::Keyboard::LShift;
myRequester->KeyDown(key);
}
}
// Or are they both down ?
if (shift == (NSRightShiftKeyMask | NSLeftShiftKeyMask)) {
rightShiftIsDown = YES;
leftShiftIsDown = YES;
if (!myRightShiftWasDown) {
// right shift pressed
key.Code = sf::Keyboard::RShift;
myRequester->KeyDown(key);
}
if (!myLeftShiftWasDown) {
// left shift pressed
key.Code = sf::Keyboard::LShift;
myRequester->KeyDown(key);
}
}
} else { // No shift key down.
rightShiftIsDown = NO;
leftShiftIsDown = NO;
if (myRightShiftWasDown) {
// right shift released
key.Code = sf::Keyboard::RShift;
myRequester->KeyUp(key);
}
if (myLeftShiftWasDown) {
// left shift released
key.Code = sf::Keyboard::LShift;
myRequester->KeyUp(key);
}
}
// Command keys.
if (modifiers & NSCommandKeyMask) { // At least one command key is down.
// Clean up modifiers to keep only 'Command' bits.
NSUInteger command = KeepOnlyMaskFromData(modifiers, NSRightCommandKeyMask | NSLeftCommandKeyMask);
// Only right Command is down ?
if (command == NSRightCommandKeyMask) {
rightCommandIsDown = YES;
if (myLeftCommandWasDown) {
// left command released
leftCommandIsDown = NO;
key.Code = sf::Keyboard::LSystem;
myRequester->KeyUp(key);
}
if (!myRightCommandWasDown) {
// right command pressed
key.Code = sf::Keyboard::RSystem;
myRequester->KeyDown(key);
}
}
// Only left Command is down ?
if (command == NSLeftCommandKeyMask) {
leftCommandIsDown = YES;
if (myRightCommandWasDown) {
// right command released
rightCommandIsDown = NO;
key.Code = sf::Keyboard::RSystem;
myRequester->KeyUp(key);
}
if (!myLeftCommandWasDown) {
// left command pressed
key.Code = sf::Keyboard::LSystem;
myRequester->KeyDown(key);
}
}
// Or are they both down ?
if (command == (NSRightCommandKeyMask | NSLeftCommandKeyMask)) {
rightCommandIsDown = YES;
leftCommandIsDown = YES;
if (!myRightCommandWasDown) {
// right command pressed
key.Code = sf::Keyboard::RSystem;
myRequester->KeyDown(key);
}
if (!myLeftCommandWasDown) {
// left command pressed
key.Code = sf::Keyboard::LSystem;
myRequester->KeyDown(key);
}
}
} else { // No Command key down.
rightCommandIsDown = NO;
leftCommandIsDown = NO;
if (myRightCommandWasDown) {
// right command released
key.Code = sf::Keyboard::RSystem;
myRequester->KeyUp(key);
}
if (myLeftCommandWasDown) {
// left command released
key.Code = sf::Keyboard::LSystem;
myRequester->KeyUp(key);
}
}
// Alternate keys.
if (modifiers & NSAlternateKeyMask) { // At least one alternate key is down.
// Clean up modifiers to keep only 'Alternate' bits.
NSUInteger alternate = KeepOnlyMaskFromData(modifiers, NSRightAlternateKeyMask | NSLeftAlternateKeyMask);
// Only right Alternate is down ?
if (alternate == NSRightAlternateKeyMask) {
rightAlternateIsDown = YES;
if (myLeftAlternateWasDown) {
// left alt released
leftAlternateIsDown = NO;
key.Code = sf::Keyboard::LAlt;
myRequester->KeyUp(key);
}
if (!myRightAlternateWasDown) {
// right alt pressed
key.Code = sf::Keyboard::RAlt;
myRequester->KeyDown(key);
}
}
// Only left Alternate is down ?
if (alternate == NSLeftAlternateKeyMask) {
leftAlternateIsDown = YES;
if (myRightAlternateWasDown) {
// right alt released
rightAlternateIsDown = NO;
key.Code = sf::Keyboard::RAlt;
myRequester->KeyUp(key);
}
if (!myLeftAlternateWasDown) {
// left alt pressed
key.Code = sf::Keyboard::LAlt;
myRequester->KeyDown(key);
}
}
// Or are they both down ?
if (alternate == (NSRightAlternateKeyMask | NSLeftAlternateKeyMask)) {
rightAlternateIsDown = YES;
leftAlternateIsDown = YES;
if (!myRightAlternateWasDown) {
// right alt pressed
key.Code = sf::Keyboard::RAlt;
myRequester->KeyDown(key);
}
if (!myLeftAlternateWasDown) {
// left alt pressed
key.Code = sf::Keyboard::LAlt;
myRequester->KeyDown(key);
}
}
} else { // No Alternate key down.
rightAlternateIsDown = NO;
leftAlternateIsDown = NO;
if (myRightAlternateWasDown) {
// right alt released
key.Code = sf::Keyboard::RAlt;
myRequester->KeyUp(key);
}
if (myLeftAlternateWasDown) {
// left alt released
key.Code = sf::Keyboard::LAlt;
myRequester->KeyUp(key);
}
}
// Control keys.
if (modifiers & NSControlKeyMask) {
// Currently only the left control key will be used in SFML (see note above).
controlIsDown = YES;
if (!myControlWasDown) {
// ctrl pressed
key.Code = sf::Keyboard::LControl;
myRequester->KeyDown(key);
}
} else { // No control key down.
controlIsDown = NO;
if (myControlWasDown) {
// ctrl released
key.Code = sf::Keyboard::LControl;
myRequester->KeyUp(key);
}
}
// Update the state
myRightShiftWasDown = rightShiftIsDown;
myLeftShiftWasDown = leftShiftIsDown;
myRightCommandWasDown = rightCommandIsDown;
myLeftCommandWasDown = leftCommandIsDown;
myRightAlternateWasDown = rightAlternateIsDown;
myLeftAlternateWasDown = leftAlternateIsDown;
myControlWasDown = controlIsDown;
}
////////////////////////////////////////////////////////
-(void)initModifiersState
{
// Set default value to NO.
myRightShiftWasDown = NO;
myLeftShiftWasDown = NO;
myRightCommandWasDown = NO;
myLeftCommandWasDown = NO;
myRightAlternateWasDown = NO;
myLeftAlternateWasDown = NO;
myControlWasDown = NO;
NSUInteger modifiers = [[NSApp currentEvent] modifierFlags];
modifiers = EraseMaskFromData(modifiers, 0x100); // We erase something useless that might be present.
// Shift keys.
if (modifiers & NSShiftKeyMask) { // At least one shift key is down.
// Clean up modifiers to keep only 'shift' bits.
NSUInteger shift = KeepOnlyMaskFromData(modifiers, NSRightShiftKeyMask | NSLeftShiftKeyMask);
// Only right shift is down ?
if (shift == NSRightShiftKeyMask) {
myRightShiftWasDown = YES;
}
// Only left shift is down ?
if (shift == NSLeftShiftKeyMask) {
myLeftShiftWasDown = YES;
}
// Or are they both down ?
if (shift == (NSRightShiftKeyMask | NSLeftShiftKeyMask)) {
myRightShiftWasDown = YES;
myLeftShiftWasDown = YES;
}
}
// Command keys.
if (modifiers & NSCommandKeyMask) { // At least one command key is down.
// Clean up modifiers to keep only 'Command' bits.
NSUInteger command = KeepOnlyMaskFromData(modifiers, NSRightCommandKeyMask | NSLeftCommandKeyMask);
// Only right Command is down ?
if (command == NSRightCommandKeyMask) {
myRightCommandWasDown = YES;
}
// Only left Command is down ?
if (command == NSLeftCommandKeyMask) {
myLeftCommandWasDown = YES;
}
// Or are they both down ?
if (command == (NSRightCommandKeyMask | NSLeftCommandKeyMask)) {
myRightCommandWasDown = YES;
myLeftCommandWasDown = YES;
}
}
// Alternate keys.
if (modifiers & NSAlternateKeyMask) { // At least one alternate key is down.
// Clean up modifiers to keep only 'Alternate' bits.
NSUInteger alternate = KeepOnlyMaskFromData(modifiers, NSRightAlternateKeyMask | NSLeftAlternateKeyMask);
// Only right Alternate is down ?
if (alternate == NSRightAlternateKeyMask) {
myRightAlternateWasDown = YES;
}
// Only left Alternate is down ?
if (alternate == NSLeftAlternateKeyMask) {
myLeftAlternateWasDown = YES;
}
// Or are they both down ?
if (alternate == (NSRightAlternateKeyMask | NSLeftAlternateKeyMask)) {
myRightAlternateWasDown = YES;
myLeftAlternateWasDown = YES;
}
}
// Control keys.
if (modifiers & NSControlKeyMask) {
// Currently only the left control key will be used in SFML (see note above).
myControlWasDown = YES;
}
}
////////////////////////////////////////////////////////
+(sf::Event::KeyEvent)convertNSKeyEventToSFMLEvent:(NSEvent *)anEvent
{
sf::Event::KeyEvent key;
// Modifiers.
NSUInteger modifierFlags = [anEvent modifierFlags];
key.Alt = modifierFlags & NSAlternateKeyMask;
key.Control = modifierFlags & NSControlKeyMask;
key.Shift = modifierFlags & NSShiftKeyMask;
key.System = modifierFlags & NSCommandKeyMask;
// Key code.
key.Code = sf::Keyboard::KeyCount;
// First we look if the key down is from a list of caracter
// that depend on keyboard localization.
NSString* string = [anEvent charactersIgnoringModifiers];
if ([string length] > 0) {
key.Code = sf::priv::HIDInputManager::LocalizedKeys([string characterAtIndex:0]);
}
// The key is not a localized one, so we try to find a corresponding code
// through virtual key code.
if (key.Code == sf::Keyboard::KeyCount) {
key.Code = sf::priv::HIDInputManager::NonLocalizedKeys([anEvent keyCode]);
}
//#ifdef SFML_DEBUG // Don't bother the final customers with annoying messages.
// if (key.Code == sf::Keyboard::KeyCount) { // The key is unknown.
// sf::Err() << "This is an unknow key. Virtual key code is 0x"
// << std::hex
// << [anEvent keyCode]
// << "."
// << std::endl;
// }
//#endif
return key;
}
@end
#pragma mark - C-like functions
////////////////////////////////////////////////////////
NSUInteger EraseMaskFromData(NSUInteger data, NSUInteger mask)
{
return (data | mask) ^ mask;
}
////////////////////////////////////////////////////////
NSUInteger KeepOnlyMaskFromData(NSUInteger data, NSUInteger mask)
{
NSUInteger negative = NSUIntegerMax ^ mask;
return EraseMaskFromData(data, negative);
}