//////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library // Copyright (C) 2007-2023 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 #include #include #include #include #include #import #import //////////////////////////////////////////////////////////// /// In order to keep track of the keyboard's state and mouse buttons' state /// we use the HID manager. Mouse position is handled differently. /// //////////////////////////////////////////////////////////// namespace sf { namespace priv { //////////////////////////////////////////////////////////// /// \brief Extract the dedicated SFOpenGLView from the SFML window /// /// \param window a SFML window /// \return nil if something went wrong or a SFOpenGLView*. /// //////////////////////////////////////////////////////////// SFOpenGLView* getSFOpenGLViewFromSFMLWindow(const WindowBase& window) { id nsHandle = static_cast(window.getSystemHandle()); // Get our SFOpenGLView from ... SFOpenGLView* view = nil; if ([nsHandle isKindOfClass:[NSWindow class]]) { // If system handle is a window then from its content view. view = [nsHandle contentView]; // Subview doesn't match ? if (![view isKindOfClass:[SFOpenGLView class]]) { if([view isKindOfClass:[NSView class]]) { NSArray* subviews = [view subviews]; for (NSView* subview in subviews) { if ([subview isKindOfClass:[SFOpenGLView class]]) { view = static_cast(subview); break; } } } else { sf::err() << "The content view is not a valid SFOpenGLView" << std::endl; view = nil; } } } else if ([nsHandle isKindOfClass:[NSView class]]) { // If system handle is a view then from a subview of kind SFOpenGLView. NSArray* subviews = [nsHandle subviews]; for (NSView* subview in subviews) { if ([subview isKindOfClass:[SFOpenGLView class]]) { view = static_cast(subview); break; } } // No matching subview ? if (view == nil) sf::err() << "Cannot find a valid SFOpenGLView subview." << std::endl; } else { if (nsHandle != 0) sf::err() << "The system handle is neither a nor " << "object. This shouldn't happen." << std::endl; // Else: this probably means the SFML window was previously closed. } return view; } //////////////////////////////////////////////////////////// bool InputImpl::isKeyPressed(Keyboard::Key key) { AutoreleasePool pool; return HIDInputManager::getInstance().isKeyPressed(key); } //////////////////////////////////////////////////////////// bool InputImpl::isKeyPressed(Keyboard::Scancode code) { return HIDInputManager::getInstance().isKeyPressed(code); } //////////////////////////////////////////////////////////// Keyboard::Key InputImpl::localize(Keyboard::Scancode code) { return HIDInputManager::getInstance().localize(code); } //////////////////////////////////////////////////////////// Keyboard::Scancode InputImpl::delocalize(Keyboard::Key key) { return HIDInputManager::getInstance().delocalize(key); } //////////////////////////////////////////////////////////// String InputImpl::getDescription(Keyboard::Scancode code) { return HIDInputManager::getInstance().getDescription(code); } //////////////////////////////////////////////////////////// void InputImpl::setVirtualKeyboardVisible(bool /*visible*/) { // Not applicable } //////////////////////////////////////////////////////////// bool InputImpl::isMouseButtonPressed(Mouse::Button button) { AutoreleasePool pool; NSUInteger state = [NSEvent pressedMouseButtons]; NSUInteger flag = 1 << button; return (state & flag) != 0; } //////////////////////////////////////////////////////////// Vector2i InputImpl::getMousePosition() { AutoreleasePool pool; // Reverse Y axis to match SFML coord. NSPoint pos = [NSEvent mouseLocation]; pos.y = sf::VideoMode::getDesktopMode().height - pos.y; int scale = static_cast([[NSScreen mainScreen] backingScaleFactor]); return Vector2i(static_cast(pos.x), static_cast(pos.y)) * scale; } //////////////////////////////////////////////////////////// Vector2i InputImpl::getMousePosition(const WindowBase& relativeTo) { AutoreleasePool pool; SFOpenGLView* view = getSFOpenGLViewFromSFMLWindow(relativeTo); // No view ? if (view == nil) return Vector2i(); // Use -cursorPositionFromEvent: with nil. NSPoint pos = [view cursorPositionFromEvent:nil]; int scale = static_cast([view displayScaleFactor]); return Vector2i(static_cast(pos.x), static_cast(pos.y)) * scale; } //////////////////////////////////////////////////////////// void InputImpl::setMousePosition(const Vector2i& position) { AutoreleasePool pool; // Here we don't need to reverse the coordinates. int scale = static_cast([[NSScreen mainScreen] backingScaleFactor]); CGPoint pos = CGPointMake(position.x / scale, position.y / scale); // Place the cursor. CGEventRef event = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, pos, /* we don't care about this: */ kCGMouseButtonLeft); CGEventPost(kCGHIDEventTap, event); CFRelease(event); // This is a workaround to deprecated CGSetLocalEventsSuppressionInterval. } //////////////////////////////////////////////////////////// void InputImpl::setMousePosition(const Vector2i& position, const WindowBase& relativeTo) { AutoreleasePool pool; SFOpenGLView* view = getSFOpenGLViewFromSFMLWindow(relativeTo); // No view ? if (view == nil) return; // Let SFOpenGLView compute the position in global coordinate int scale = static_cast([view displayScaleFactor]); NSPoint p = NSMakePoint(position.x / scale, position.y / scale); p = [view computeGlobalPositionOfRelativePoint:p]; setMousePosition(sf::Vector2i(static_cast(p.x), static_cast(p.y)) * scale); } //////////////////////////////////////////////////////////// bool InputImpl::isTouchDown(unsigned int /*finger*/) { // Not applicable return false; } //////////////////////////////////////////////////////////// Vector2i InputImpl::getTouchPosition(unsigned int /*finger*/) { // Not applicable return Vector2i(); } //////////////////////////////////////////////////////////// Vector2i InputImpl::getTouchPosition(unsigned int /*finger*/, const WindowBase& /*relativeTo*/) { // Not applicable return Vector2i(); } } // namespace priv } // namespace sf