diff --git a/Source/Engine/Platform/Base/WindowBase.h b/Source/Engine/Platform/Base/WindowBase.h index 799a3866e..357663b44 100644 --- a/Source/Engine/Platform/Base/WindowBase.h +++ b/Source/Engine/Platform/Base/WindowBase.h @@ -678,6 +678,14 @@ public: return _trackingMouseOffset; } + /// + /// Gets the value indicating whenever mouse input is tracked by this window. + /// + API_PROPERTY() bool IsMouseTracking() const + { + return _isTrackingMouse; + } + /// /// Ends the mouse tracking. /// diff --git a/Source/Engine/Platform/Mac/MacWindow.cpp b/Source/Engine/Platform/Mac/MacWindow.cpp index e30529e12..53e769048 100644 --- a/Source/Engine/Platform/Mac/MacWindow.cpp +++ b/Source/Engine/Platform/Mac/MacWindow.cpp @@ -4,10 +4,166 @@ #include "../Window.h" #include "MacUtils.h" +#include "Engine/Core/Log.h" +#include "Engine/Input/Input.h" +#include "Engine/Input/Mouse.h" +#include "Engine/Input/Keyboard.h" #include "Engine/Graphics/RenderTask.h" #include #include +KeyboardKeys GetKey(NSEvent* event) +{ + switch ([event keyCode]) + { + case 0x00: return KeyboardKeys::A; + case 0x01: return KeyboardKeys::S; + case 0x02: return KeyboardKeys::D; + case 0x03: return KeyboardKeys::F; + case 0x04: return KeyboardKeys::H; + case 0x05: return KeyboardKeys::G; + case 0x06: return KeyboardKeys::Z; + case 0x07: return KeyboardKeys::X; + case 0x08: return KeyboardKeys::C; + case 0x09: return KeyboardKeys::V; + case 0x0A: return KeyboardKeys::W; + case 0x0B: return KeyboardKeys::B; + case 0x0C: return KeyboardKeys::Q; + case 0x0D: return KeyboardKeys::W; + case 0x0E: return KeyboardKeys::E; + case 0x0F: return KeyboardKeys::R; + + case 0x10: return KeyboardKeys::Y; + case 0x11: return KeyboardKeys::T; + case 0x12: return KeyboardKeys::Alpha1; + case 0x13: return KeyboardKeys::Alpha2; + case 0x14: return KeyboardKeys::Alpha3; + case 0x15: return KeyboardKeys::Alpha4; + case 0x16: return KeyboardKeys::Alpha6; + case 0x17: return KeyboardKeys::Alpha5; + case 0x18: return KeyboardKeys::Plus; + case 0x19: return KeyboardKeys::Alpha9; + case 0x1A: return KeyboardKeys::Alpha7; + case 0x1B: return KeyboardKeys::Minus; + case 0x1C: return KeyboardKeys::Alpha8; + case 0x1D: return KeyboardKeys::Alpha0; + case 0x1E: return KeyboardKeys::RightBracket; + case 0x1F: return KeyboardKeys::O; + + case 0x20: return KeyboardKeys::U; + case 0x21: return KeyboardKeys::LeftBracket; + case 0x22: return KeyboardKeys::I; + case 0x23: return KeyboardKeys::P; + case 0x24: return KeyboardKeys::Return; + case 0x25: return KeyboardKeys::L; + case 0x26: return KeyboardKeys::J; + case 0x27: return KeyboardKeys::Quote; + case 0x28: return KeyboardKeys::K; + case 0x29: return KeyboardKeys::Colon; + case 0x2A: return KeyboardKeys::Backslash; + case 0x2B: return KeyboardKeys::Comma; + case 0x2C: return KeyboardKeys::Slash; + case 0x2D: return KeyboardKeys::N; + case 0x2E: return KeyboardKeys::M; + case 0x2F: return KeyboardKeys::Period; + + case 0x30: return KeyboardKeys::Tab; + case 0x31: return KeyboardKeys::Spacebar; + case 0x32: return KeyboardKeys::BackQuote; + case 0x33: return KeyboardKeys::Delete; + //case 0x34: + case 0x35: return KeyboardKeys::Escape; + //case 0x36: + //case 0x37: Command + case 0x38: return KeyboardKeys::Shift; + case 0x39: return KeyboardKeys::Capital; + case 0x3A: return KeyboardKeys::Alt; + case 0x3B: return KeyboardKeys::Control; + case 0x3C: return KeyboardKeys::Shift; + case 0x3D: return KeyboardKeys::Alt; + case 0x3E: return KeyboardKeys::Control; + //case 0x3F: Function + + case 0x40: return KeyboardKeys::F17; + case 0x41: return KeyboardKeys::NumpadDecimal; + //case 0x42: + case 0x43: return KeyboardKeys::NumpadMultiply; + //case 0x44: + case 0x45: return KeyboardKeys::NumpadAdd; + //case 0x46: + //case 0x47: KeypadClear + case 0x48: return KeyboardKeys::VolumeUp; + case 0x49: return KeyboardKeys::VolumeDown; + case 0x4A: return KeyboardKeys::VolumeMute; + case 0x4B: return KeyboardKeys::NumpadDivide; + case 0x4C: return KeyboardKeys::Return; + //case 0x4D: + case 0x4E: return KeyboardKeys::NumpadSubtract; + case 0x4F: return KeyboardKeys::F18; + + case 0x50: return KeyboardKeys::F19; + //case 0x51: NumpadEquals + case 0x52: return KeyboardKeys::Numpad0; + case 0x53: return KeyboardKeys::Numpad1; + case 0x54: return KeyboardKeys::Numpad2; + case 0x55: return KeyboardKeys::Numpad3; + case 0x56: return KeyboardKeys::Numpad4; + case 0x57: return KeyboardKeys::Numpad5; + case 0x58: return KeyboardKeys::Numpad6; + case 0x59: return KeyboardKeys::Numpad7; + case 0x5A: return KeyboardKeys::F20; + case 0x5B: return KeyboardKeys::Numpad8; + case 0x5C: return KeyboardKeys::Numpad9; + //case 0x5D: Yen + //case 0x5E: Underscore + //case 0x5F: KeypadComma + + case 0x60: return KeyboardKeys::F5; + case 0x61: return KeyboardKeys::F6; + case 0x62: return KeyboardKeys::F7; + case 0x63: return KeyboardKeys::F3; + case 0x64: return KeyboardKeys::F8; + case 0x65: return KeyboardKeys::F9; + //case 0x66: Eisu + case 0x67: return KeyboardKeys::F11; + case 0x68: return KeyboardKeys::Kana; + case 0x69: return KeyboardKeys::F13; + case 0x6A: return KeyboardKeys::F16; + case 0x6B: return KeyboardKeys::F14; + //case 0x6C: + case 0x6D: return KeyboardKeys::F10; + //case 0x6E: + case 0x6F: return KeyboardKeys::F12; + + //case 0x70: + case 0x71: return KeyboardKeys::F15; + case 0x72: return KeyboardKeys::Help; + case 0x73: return KeyboardKeys::Home; + case 0x74: return KeyboardKeys::PageUp; + case 0x75: return KeyboardKeys::Delete; + case 0x76: return KeyboardKeys::F4; + case 0x77: return KeyboardKeys::End; + case 0x78: return KeyboardKeys::F2; + case 0x79: return KeyboardKeys::PageDown; + case 0x7A: return KeyboardKeys::F1; + case 0x7B: return KeyboardKeys::ArrowLeft; + case 0x7C: return KeyboardKeys::ArrowRight; + case 0x7D: return KeyboardKeys::ArrowDown; + case 0x7E: return KeyboardKeys::ArrowUp; + //case 0x7F: + + default: + return KeyboardKeys::None; + } +} + +Vector2 GetMousePosition(MacWindow* window, NSEvent* event) +{ + NSRect frame = [(NSWindow*)window->GetNativePtr() frame]; + NSPoint point = [event locationInWindow]; + return Vector2(point.x, frame.size.height - point.y); +} + @interface MacWindowImpl : NSWindow { MacWindow* Window; @@ -34,8 +190,12 @@ @interface MacViewImpl : NSView { + MacWindow* Window; + NSTrackingArea* TrackingArea; + bool IsMouseOver; } +- (void)setWindow:(MacWindow*)window; - (CALayer*)makeBackingLayer; - (BOOL)wantsUpdateLayer; @@ -43,6 +203,23 @@ @implementation MacViewImpl +- (void)dealloc +{ + if (TrackingArea != nil) + { + [self removeTrackingArea:TrackingArea]; + [TrackingArea release]; + } + [super dealloc]; +} + +- (void)setWindow:(MacWindow*)window +{ + Window = window; + TrackingArea = nil; + IsMouseOver = false; +} + - (CALayer*)makeBackingLayer { return [[CAMetalLayer class] layer]; @@ -53,6 +230,179 @@ return YES; } +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +- (void)updateTrackingAreas +{ + [super updateTrackingAreas]; + + if (TrackingArea != nil) + { + [self removeTrackingArea:TrackingArea]; + [TrackingArea release]; + } + + NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways; + TrackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil]; + [self addTrackingArea:TrackingArea]; +} + +- (void)keyDown:(NSEvent*)event +{ + KeyboardKeys key = GetKey(event); + if (key != KeyboardKeys::None) + Input::Keyboard->OnKeyDown(key); + + // Send a text input event + NSString* text = [event characters]; + int32 length = [text length]; + if (length > 0) + { + unichar buffer[16]; + if (length >= 16) + length = 15; + [text getCharacters:buffer range:NSMakeRange(0, length)]; + Input::Keyboard->OnCharInput((Char)buffer[0]); + } +} + +- (void)keyUp:(NSEvent*)event +{ + KeyboardKeys key = GetKey(event); + if (key != KeyboardKeys::None) + Input::Keyboard->OnKeyUp(key); +} + +- (void)scrollWheel:(NSEvent*)event +{ + Vector2 mousePos = GetMousePosition(Window, event); + double deltaX = [event scrollingDeltaX]; + double deltaY = [event scrollingDeltaY]; + if ([event hasPreciseScrollingDeltas]) + { + deltaX *= 0.03; + deltaY *= 0.03; + } + // TODO: add support for scroll delta as Vector2 in the engine + Input::Mouse->OnMouseWheel(Window->ClientToScreen(mousePos), deltaY, Window); +} + +- (void)mouseMoved:(NSEvent*)event +{ + Vector2 mousePos = GetMousePosition(Window, event); + if (!Window->IsMouseTracking() && !IsMouseOver) + return; + Input::Mouse->OnMouseMove(Window->ClientToScreen(mousePos), Window); +} + +- (void)mouseEntered:(NSEvent*)event +{ + IsMouseOver = true; +} + +- (void)mouseExited:(NSEvent*)event +{ + IsMouseOver = false; + Input::Mouse->OnMouseLeave(Window); +} + +- (void)mouseDown:(NSEvent*)event +{ + Vector2 mousePos = GetMousePosition(Window, event); + MouseButton mouseButton = MouseButton::Left; + if ([event clickCount] == 2) + Input::Mouse->OnMouseDoubleClick(Window->ClientToScreen(mousePos), mouseButton, Window); + else + Input::Mouse->OnMouseDown(Window->ClientToScreen(mousePos), mouseButton, Window); +} + +- (void)mouseDragged:(NSEvent*)event +{ + [self mouseMoved:event]; +} + +- (void)mouseUp:(NSEvent*)event +{ + Vector2 mousePos = GetMousePosition(Window, event); + MouseButton mouseButton = MouseButton::Left; + Input::Mouse->OnMouseUp(Window->ClientToScreen(mousePos), mouseButton, Window); +} + +- (void)rightMouseDown:(NSEvent*)event +{ + Vector2 mousePos = GetMousePosition(Window, event); + MouseButton mouseButton = MouseButton::Right; + if ([event clickCount] == 2) + Input::Mouse->OnMouseDoubleClick(Window->ClientToScreen(mousePos), mouseButton, Window); + else + Input::Mouse->OnMouseDown(Window->ClientToScreen(mousePos), mouseButton, Window); +} + +- (void)rightMouseDragged:(NSEvent*)event +{ + [self mouseMoved:event]; +} + +- (void)rightMouseUp:(NSEvent*)event +{ + Vector2 mousePos = GetMousePosition(Window, event); + MouseButton mouseButton = MouseButton::Right; + Input::Mouse->OnMouseUp(Window->ClientToScreen(mousePos), mouseButton, Window); +} + +- (void)otherMouseDown:(NSEvent*)event +{ + Vector2 mousePos = GetMousePosition(Window, event); + MouseButton mouseButton; + switch ([event buttonNumber]) + { + case 2: + mouseButton = MouseButton::Middle; + break; + case 3: + mouseButton = MouseButton::Extended1; + break; + case 4: + mouseButton = MouseButton::Extended2; + break; + default: + return; + } + if ([event clickCount] == 2) + Input::Mouse->OnMouseDoubleClick(Window->ClientToScreen(mousePos), mouseButton, Window); + else + Input::Mouse->OnMouseDown(Window->ClientToScreen(mousePos), mouseButton, Window); +} + +- (void)otherMouseDragged:(NSEvent*)event +{ + [self mouseMoved:event]; +} + +- (void)otherMouseUp:(NSEvent*)event +{ + Vector2 mousePos = GetMousePosition(Window, event); + MouseButton mouseButton; + switch ([event buttonNumber]) + { + case 2: + mouseButton = MouseButton::Middle; + break; + case 3: + mouseButton = MouseButton::Extended1; + break; + case 4: + mouseButton = MouseButton::Extended2; + break; + default: + return; + } + Input::Mouse->OnMouseUp(Window->ClientToScreen(mousePos), mouseButton, Window); +} + @end MacWindow::MacWindow(const CreateWindowSettings& settings) @@ -86,6 +436,7 @@ MacWindow::MacWindow(const CreateWindowSettings& settings) defer:NO]; MacViewImpl* view = [[MacViewImpl alloc] init]; view.wantsLayer = YES; + [view setWindow:this]; window.title = (__bridge NSString*)MacUtils::ToString(settings.Title); [window setWindow:this]; [window setReleasedWhenClosed:NO];