From a17ace9d89d5b7b83bec15383a36c6e558baf86d Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sat, 20 Apr 2024 19:01:32 -0500 Subject: [PATCH 01/12] Input:Quartz: Move DolWindowPositionObserver to header --- .../ControllerInterface/Quartz/QuartzKeyboardAndMouse.h | 8 +++++++- .../ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm | 8 -------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.h b/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.h index e4bdb6e5fb45..31ab29aa9aa3 100644 --- a/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.h +++ b/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.h @@ -9,7 +9,13 @@ #include "InputCommon/ControllerInterface/CoreDevice.h" #ifdef __OBJC__ -@class DolWindowPositionObserver; +/// Helper class to get window position data from threads other than the main thread +@interface DolWindowPositionObserver : NSObject + +- (instancetype)initWithView:(NSView*)view; +@property(readonly) NSRect frame; + +@end #else class DolWindowPositionObserver; #endif diff --git a/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm b/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm index 1fda63c23a70..5cca8d2d7220 100644 --- a/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm +++ b/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm @@ -14,14 +14,6 @@ #include "InputCommon/ControllerInterface/ControllerInterface.h" #include "InputCommon/QuartzInputMouse.h" -/// Helper class to get window position data from threads other than the main thread -@interface DolWindowPositionObserver : NSObject - -- (instancetype)initWithView:(NSView*)view; -@property(readonly) NSRect frame; - -@end - @implementation DolWindowPositionObserver { NSView* _view; From 36386f567e3c152b95e4357e3e207dcefa2002ef Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sat, 20 Apr 2024 22:43:18 -0500 Subject: [PATCH 02/12] Input:Quartz: Fix macOS compile --- Source/Core/InputCommon/CMakeLists.txt | 5 - .../Quartz/QuartzKeyboardAndMouse.mm | 2 +- Source/Core/InputCommon/GenericMouse.h | 1 + Source/Core/InputCommon/QuartzInputMouse.h | 23 ++-- Source/Core/InputCommon/QuartzInputMouse.mm | 102 ++++++++---------- 5 files changed, 61 insertions(+), 72 deletions(-) diff --git a/Source/Core/InputCommon/CMakeLists.txt b/Source/Core/InputCommon/CMakeLists.txt index c959fc0de5b5..773f37e26109 100644 --- a/Source/Core/InputCommon/CMakeLists.txt +++ b/Source/Core/InputCommon/CMakeLists.txt @@ -122,11 +122,6 @@ elseif(APPLE) target_sources(inputcommon PRIVATE QuartzInputMouse.h QuartzInputMouse.mm - ControllerInterface/OSX/OSX.h - ControllerInterface/OSX/OSX.mm - ControllerInterface/OSX/OSXJoystick.h - ControllerInterface/OSX/OSXJoystick.mm - ControllerInterface/OSX/RunLoopStopper.h ControllerInterface/Quartz/Quartz.h ControllerInterface/Quartz/Quartz.mm ControllerInterface/Quartz/QuartzKeyboardAndMouse.h diff --git a/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm b/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm index 5cca8d2d7220..d3b322284884 100644 --- a/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm +++ b/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm @@ -209,7 +209,7 @@ - (void)dealloc MainThreadInitialization(view); else dispatch_sync(dispatch_get_main_queue(), [this, view] { MainThreadInitialization(view); }); - prime::InitQuartzInputMouse(&m_windowid); + prime::InitQuartzInputMouse(); // cursor, with a hax for-loop for (unsigned int i = 0; i < 4; ++i) diff --git a/Source/Core/InputCommon/GenericMouse.h b/Source/Core/InputCommon/GenericMouse.h index 627dbfff7c83..07dd52c89f47 100644 --- a/Source/Core/InputCommon/GenericMouse.h +++ b/Source/Core/InputCommon/GenericMouse.h @@ -10,6 +10,7 @@ namespace prime class GenericMouse { public: + virtual ~GenericMouse() = default; // Platform dependant implementations are made virtual virtual void UpdateInput() = 0; virtual void LockCursorToGameWindow() = 0; diff --git a/Source/Core/InputCommon/QuartzInputMouse.h b/Source/Core/InputCommon/QuartzInputMouse.h index 449c85cdc7be..b559bc0c8af4 100644 --- a/Source/Core/InputCommon/QuartzInputMouse.h +++ b/Source/Core/InputCommon/QuartzInputMouse.h @@ -1,24 +1,33 @@ #include #include "GenericMouse.h" +#include "ControllerInterface/Quartz/QuartzKeyboardAndMouse.h" + +#ifdef __OBJC__ +@class NSEvent; +#else +class NSEvent +typedef void* id; +#endif namespace prime { -bool InitQuartzInputMouse(uint32_t* windowid); +bool InitQuartzInputMouse(); class QuartzInputMouse: public GenericMouse { public: - explicit QuartzInputMouse(uint32_t* windowid); + explicit QuartzInputMouse(); + ~QuartzInputMouse(); + void InputCallback(NSEvent* event); void UpdateInput() override; void LockCursorToGameWindow() override; private: - CGPoint current_loc, center; - CGEventRef event{}; - uint32_t* m_windowid; - CGRect getBounds(); - CGPoint getWindowCenter(); + NSEvent*(^m_event_callback)(NSEvent*); + id m_monitor = nullptr; + std::atomic thread_dx; + std::atomic thread_dy; }; } diff --git a/Source/Core/InputCommon/QuartzInputMouse.mm b/Source/Core/InputCommon/QuartzInputMouse.mm index 8ac6c6aa0207..a66df54c83fd 100644 --- a/Source/Core/InputCommon/QuartzInputMouse.mm +++ b/Source/Core/InputCommon/QuartzInputMouse.mm @@ -1,94 +1,78 @@ #include "QuartzInputMouse.h" #include "Core/Host.h" +#include /** - * This interface works by centering the cursor within the window - * ever time the `UpdateInput` method is called. It then calculates - * the delta based on how far the mouse has moved from the center of - * the screen before it is re-centered. + * This interface works by registering an event monitor and updating deltas on mouse moves. */ +#if ! __has_feature(objc_arc) +#error "Compile this with -fobjc-arc" +#endif int win_w = 0, win_h = 0; namespace prime { -bool InitQuartzInputMouse(uint32_t* windowid) +bool InitQuartzInputMouse() { - g_mouse_input = new QuartzInputMouse(windowid); + g_mouse_input = new QuartzInputMouse(); return true; } -QuartzInputMouse::QuartzInputMouse(uint32_t* windowid) +QuartzInputMouse::QuartzInputMouse() { - m_windowid = windowid; - center = current_loc = getWindowCenter(); + m_event_callback = ^NSEvent*(NSEvent* event) { + InputCallback(event); + return event; + }; +} + +QuartzInputMouse::~QuartzInputMouse() +{ + if (m_monitor) + [NSEvent removeMonitor:m_monitor]; +} + +void QuartzInputMouse::InputCallback(NSEvent* event) +{ + thread_dx.fetch_add([event deltaX], std::memory_order_relaxed); + thread_dy.fetch_add([event deltaY], std::memory_order_relaxed); } void QuartzInputMouse::UpdateInput() { - event = CGEventCreate(nil); - current_loc = CGEventGetLocation(event); - CFRelease(event); - center = getWindowCenter(); - if (Host_RendererHasFocus() && cursor_locked) - { - this->dx += current_loc.x - center.x; - this->dy += current_loc.y - center.y; - } + this->dx += thread_dx.exchange(0, std::memory_order_relaxed); + this->dy += thread_dy.exchange(0, std::memory_order_relaxed); LockCursorToGameWindow(); } void QuartzInputMouse::LockCursorToGameWindow() { - if (Host_RendererHasFocus() && cursor_locked) + bool wants_locked = Host_RendererHasFocus() && cursor_locked; + bool is_locked = m_monitor; + if (wants_locked == is_locked) + return; + if (wants_locked) { - // Hack to avoid short bit of input suppression after warp - // Credit/explanation: https://stackoverflow.com/a/17559012/7341382 - CGWarpMouseCursorPosition(center); - CGAssociateMouseAndMouseCursorPosition(true); - CGDisplayHideCursor(CGMainDisplayID()); + // Disable cursor movement + CGAssociateMouseAndMouseCursorPosition(false); + [NSCursor hide]; + // Clear any accumulated movement + thread_dx.store(0, std::memory_order_relaxed); + thread_dy.store(0, std::memory_order_relaxed); + m_monitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskMouseMoved + handler:m_event_callback]; } else { - cursor_locked = false; - Host_RendererUpdateCursor(false); CGAssociateMouseAndMouseCursorPosition(true); - CGDisplayShowCursor(CGMainDisplayID()); - } -} - -CGRect QuartzInputMouse::getBounds() -{ - CGRect bounds = CGRectZero; - CGWindowID windowid[1] = {*m_windowid}; - - CFArrayRef windowArray = CFArrayCreate(nullptr, (const void**)windowid, 1, nullptr); - CFArrayRef windowDescriptions = CGWindowListCreateDescriptionFromArray(windowArray); - CFDictionaryRef windowDescription = - static_cast(CFArrayGetValueAtIndex(windowDescriptions, 0)); - - if (CFDictionaryContainsKey(windowDescription, kCGWindowBounds)) - { - CFDictionaryRef boundsDictionary = - static_cast(CFDictionaryGetValue(windowDescription, kCGWindowBounds)); - - if (boundsDictionary != nullptr) - CGRectMakeWithDictionaryRepresentation(boundsDictionary, &bounds); + [NSCursor unhide]; + [NSEvent removeMonitor:m_monitor]; + m_monitor = nullptr; + cursor_locked = false; } - - CFRelease(windowDescriptions); - CFRelease(windowArray); - return bounds; -} - -CGPoint QuartzInputMouse::getWindowCenter() -{ - const auto bounds = getBounds(); - const double x = bounds.origin.x + (bounds.size.width / 2); - const double y = bounds.origin.y + (bounds.size.height / 2); - return CGPointMake(x, y); } } From 9e1a1e9893c92497047693c67fb9ca3d951883f8 Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Thu, 21 Dec 2023 22:43:56 -0600 Subject: [PATCH 03/12] GHActions:mac: Fix MoltenVK build --- .github/workflows/macos_build.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/macos_build.yml b/.github/workflows/macos_build.yml index 41f129325333..a1b8bb15d0ae 100644 --- a/.github/workflows/macos_build.yml +++ b/.github/workflows/macos_build.yml @@ -19,6 +19,11 @@ jobs: with: submodules: recursive + # MoltenVK's build process breaks on Python 3.12 + - uses: actions/setup-python@v4 + with: + python-version: '3.11' + - name: Install Packages env: HOMEBREW_NO_INSTALL_CLEANUP: 1 From 0c7a4269ea965980dd9a7db2658756eced6a16be Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Fri, 22 Dec 2023 20:07:22 -0600 Subject: [PATCH 04/12] GHActions: Update SDL to 2.30.2 --- .github/workflows/scripts/macos/build-dependencies.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/scripts/macos/build-dependencies.sh b/.github/workflows/scripts/macos/build-dependencies.sh index ad48e1640fc0..6c8af6708e0d 100755 --- a/.github/workflows/scripts/macos/build-dependencies.sh +++ b/.github/workflows/scripts/macos/build-dependencies.sh @@ -5,7 +5,7 @@ set -e export MACOSX_DEPLOYMENT_TARGET=10.15 INSTALLDIR="$HOME/deps" NPROCS="$(getconf _NPROCESSORS_ONLN)" -SDL=SDL2-2.26.0 +SDL=SDL2-2.30.2 QT=6.2.4 mkdir deps-build @@ -17,7 +17,7 @@ export CFLAGS="-I$INSTALLDIR/include -Os $CFLAGS" export CXXFLAGS="-I$INSTALLDIR/include -Os $CXXFLAGS" cat > SHASUMS < Date: Fri, 22 Dec 2023 20:16:47 -0600 Subject: [PATCH 05/12] GHActions: Update Qt to 6.2.8 --- .../scripts/macos/build-dependencies.sh | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/scripts/macos/build-dependencies.sh b/.github/workflows/scripts/macos/build-dependencies.sh index 6c8af6708e0d..f3d56d3043a6 100755 --- a/.github/workflows/scripts/macos/build-dependencies.sh +++ b/.github/workflows/scripts/macos/build-dependencies.sh @@ -6,7 +6,8 @@ export MACOSX_DEPLOYMENT_TARGET=10.15 INSTALLDIR="$HOME/deps" NPROCS="$(getconf _NPROCESSORS_ONLN)" SDL=SDL2-2.30.2 -QT=6.2.4 +QT=6.2.8 +QT_SUFFIX=-opensource mkdir deps-build cd deps-build @@ -18,16 +19,16 @@ export CXXFLAGS="-I$INSTALLDIR/include -Os $CXXFLAGS" cat > SHASUMS < Date: Fri, 22 Dec 2023 20:26:12 -0600 Subject: [PATCH 06/12] GHActions: Use /archive/ links for Qt They stay available even if we wait too long to update and official support ends --- .github/workflows/scripts/macos/build-dependencies.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/scripts/macos/build-dependencies.sh b/.github/workflows/scripts/macos/build-dependencies.sh index f3d56d3043a6..7177c0105cd1 100755 --- a/.github/workflows/scripts/macos/build-dependencies.sh +++ b/.github/workflows/scripts/macos/build-dependencies.sh @@ -26,9 +26,9 @@ EOF curl -L \ -O "https://libsdl.org/release/$SDL.tar.gz" \ - -O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere$QT_SUFFIX-src-$QT.tar.xz" \ - -O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttools-everywhere$QT_SUFFIX-src-$QT.tar.xz" \ - -O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere$QT_SUFFIX-src-$QT.tar.xz" \ + -O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtbase-everywhere$QT_SUFFIX-src-$QT.tar.xz" \ + -O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttools-everywhere$QT_SUFFIX-src-$QT.tar.xz" \ + -O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere$QT_SUFFIX-src-$QT.tar.xz" \ shasum -a 256 --check SHASUMS From 392dc9c1e099156c42855e952876f30958a2eace Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sun, 21 Apr 2024 00:06:55 -0500 Subject: [PATCH 07/12] GHActions: Add Qt SVG --- .github/workflows/scripts/macos/build-dependencies.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/scripts/macos/build-dependencies.sh b/.github/workflows/scripts/macos/build-dependencies.sh index 7177c0105cd1..82cb67c08bac 100755 --- a/.github/workflows/scripts/macos/build-dependencies.sh +++ b/.github/workflows/scripts/macos/build-dependencies.sh @@ -20,6 +20,7 @@ export CXXFLAGS="-I$INSTALLDIR/include -Os $CXXFLAGS" cat > SHASUMS < Date: Sun, 21 Apr 2024 00:15:50 -0500 Subject: [PATCH 08/12] GHActions: Update to macOS 14 --- .github/workflows/macos_build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/macos_build.yml b/.github/workflows/macos_build.yml index a1b8bb15d0ae..3dd7a6c09542 100644 --- a/.github/workflows/macos_build.yml +++ b/.github/workflows/macos_build.yml @@ -5,7 +5,7 @@ on: [push, pull_request] jobs: build_macos: name: macOS Build - runs-on: macos-11.0 + runs-on: macos-14 env: CCACHE_BASEDIR: ${{ github.workspace }} CCACHE_DIR: ${{ github.workspace }}/.ccache From ffe8ede371cf18dcdbf2e1313afcee3e206b0611 Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sun, 21 Apr 2024 01:13:03 -0500 Subject: [PATCH 09/12] GHActions: Disable searching for system libs We don't want to pick up random homebrew libs --- .github/workflows/macos_build.yml | 35 +++++++++++++++++-------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/.github/workflows/macos_build.yml b/.github/workflows/macos_build.yml index 3dd7a6c09542..9728ba055237 100644 --- a/.github/workflows/macos_build.yml +++ b/.github/workflows/macos_build.yml @@ -85,31 +85,34 @@ jobs: - name: Generate CMake Files run: | + COMMON_ARGS=( + -DCMAKE_PREFIX_PATH="$HOME/deps;$HOME/moltenvk" + -DCMAKE_BUILD_TYPE=Release + -DUSE_BUNDLED_MOLTENVK=OFF + -DMACOS_CODE_SIGNING=OFF + -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON + -DCMAKE_C_COMPILER_LAUNCHER=ccache + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON + -DUSE_SYSTEM_LIBS=OFF + -DUSE_SYSTEM_BZIP2=ON + -DUSE_SYSTEM_CURL=ON + -DUSE_SYSTEM_ICONV=ON + -DUSE_SYSTEM_LIBLZMA=ON + -DUSE_SYSTEM_SDL2=ON + ) + cmake -DCMAKE_OSX_ARCHITECTURES=x86_64 \ -DCMAKE_SYSTEM_PROCESSOR=x86_64 \ -DCMAKE_SYSTEM_NAME=Darwin \ -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 \ - -DCMAKE_PREFIX_PATH="$HOME/deps;$HOME/moltenvk" \ - -DCMAKE_BUILD_TYPE=Release \ - -DUSE_BUNDLED_MOLTENVK=OFF \ - -DMACOS_CODE_SIGNING=OFF \ - -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \ - -DCMAKE_C_COMPILER_LAUNCHER=ccache \ - -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ - -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON \ + "${COMMON_ARGS[@]}" \ -B build . cmake -DCMAKE_OSX_ARCHITECTURES=arm64 \ -DCMAKE_SYSTEM_PROCESSOR=arm64 \ -DCMAKE_SYSTEM_NAME=Darwin \ -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 \ - -DCMAKE_PREFIX_PATH="$HOME/deps;$HOME/moltenvk" \ - -DCMAKE_BUILD_TYPE=Release \ - -DUSE_BUNDLED_MOLTENVK=OFF \ - -DMACOS_CODE_SIGNING=OFF \ - -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \ - -DCMAKE_C_COMPILER_LAUNCHER=ccache \ - -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ - -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON \ + "${COMMON_ARGS[@]}" \ -B build-arm . - name: Build Dolphin (x86_64) From a9798266afe80d8b312b44d52b507a664ff1015c Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sun, 21 Apr 2024 02:20:17 -0500 Subject: [PATCH 10/12] GHActions: Update actions --- .github/workflows/macos_build.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/macos_build.yml b/.github/workflows/macos_build.yml index 9728ba055237..03f4c9015fa6 100644 --- a/.github/workflows/macos_build.yml +++ b/.github/workflows/macos_build.yml @@ -15,12 +15,12 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: recursive # MoltenVK's build process breaks on Python 3.12 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.11' @@ -36,7 +36,7 @@ jobs: - name: Cache Dependencies id: cache-deps - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/deps key: macOS deps ${{ hashFiles('.github/workflows/scripts/macos/build-dependencies.sh') }} @@ -47,7 +47,7 @@ jobs: - name: Cache MoltenVK id: cache-moltenvk - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/moltenvk key: macOS MoltenVK ${{ hashFiles('Externals/MoltenVK') }} @@ -77,7 +77,7 @@ jobs: run: echo "timestamp=$(date -u "+%Y-%m-%d-%H;%M;%S")" >> $GITHUB_OUTPUT - name: Cache ccache cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: .ccache key: macOS ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }} @@ -159,7 +159,7 @@ jobs: echo "name=$APPNAME" >> "$GITHUB_OUTPUT" - name: Upload Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ steps.create-artifact.outputs.name }} path: "*.tar.gz" From 21dbd6ab6428045e96ac072335d1332633741516 Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sat, 20 Apr 2024 22:57:56 -0500 Subject: [PATCH 11/12] Input: Don't leak mouse inputs --- .../InputCommon/ControllerInterface/ControllerInterface.cpp | 2 +- Source/Core/InputCommon/DInputMouseAbsolute.cpp | 2 +- Source/Core/InputCommon/GenericMouse.cpp | 2 +- Source/Core/InputCommon/GenericMouse.h | 3 ++- Source/Core/InputCommon/QuartzInputMouse.mm | 2 +- Source/Core/InputCommon/XInput2Mouse.cpp | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp index 16196e0f11fc..c6696d4d8a14 100644 --- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp +++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp @@ -160,7 +160,7 @@ void ControllerInterface::RefreshDevices(RefreshReason reason) // device. // An empty mouse class for when no platform specific one exists. - prime::g_mouse_input = new prime::NullMouse(); + prime::g_mouse_input.reset(new prime::NullMouse()); #ifdef CIFACE_USE_WIN32 ciface::Win32::PopulateDevices(m_wsi.render_surface); diff --git a/Source/Core/InputCommon/DInputMouseAbsolute.cpp b/Source/Core/InputCommon/DInputMouseAbsolute.cpp index f1b0d991caec..38c59dee3121 100644 --- a/Source/Core/InputCommon/DInputMouseAbsolute.cpp +++ b/Source/Core/InputCommon/DInputMouseAbsolute.cpp @@ -30,7 +30,7 @@ void InitMouse(IDirectInput8* const idi8) mo_device->SetProperty(DIPROP_AXISMODE, &dipdw.diph); auto mouse_input = new DInputMouse(); mouse_input->Init(mo_device); - g_mouse_input = mouse_input; + g_mouse_input.reset(mouse_input); return; } } diff --git a/Source/Core/InputCommon/GenericMouse.cpp b/Source/Core/InputCommon/GenericMouse.cpp index ad02327871a8..9467eba74ac3 100644 --- a/Source/Core/InputCommon/GenericMouse.cpp +++ b/Source/Core/InputCommon/GenericMouse.cpp @@ -27,6 +27,6 @@ int32_t GenericMouse::GetDeltaVerticalAxis() const return dy; } -GenericMouse* g_mouse_input; +std::unique_ptr g_mouse_input; } // namespace prime diff --git a/Source/Core/InputCommon/GenericMouse.h b/Source/Core/InputCommon/GenericMouse.h index 07dd52c89f47..004d880169bd 100644 --- a/Source/Core/InputCommon/GenericMouse.h +++ b/Source/Core/InputCommon/GenericMouse.h @@ -1,6 +1,7 @@ #pragma once #include +#include extern int win_w, win_h; @@ -32,6 +33,6 @@ class NullMouse : public GenericMouse { void LockCursorToGameWindow() override {} }; -extern GenericMouse* g_mouse_input; +extern std::unique_ptr g_mouse_input; } // namespace prime diff --git a/Source/Core/InputCommon/QuartzInputMouse.mm b/Source/Core/InputCommon/QuartzInputMouse.mm index a66df54c83fd..591df8db08ec 100644 --- a/Source/Core/InputCommon/QuartzInputMouse.mm +++ b/Source/Core/InputCommon/QuartzInputMouse.mm @@ -17,7 +17,7 @@ bool InitQuartzInputMouse() { - g_mouse_input = new QuartzInputMouse(); + g_mouse_input.reset(new QuartzInputMouse()); return true; } diff --git a/Source/Core/InputCommon/XInput2Mouse.cpp b/Source/Core/InputCommon/XInput2Mouse.cpp index e81bc4834d8b..eba7428cb7b4 100644 --- a/Source/Core/InputCommon/XInput2Mouse.cpp +++ b/Source/Core/InputCommon/XInput2Mouse.cpp @@ -33,7 +33,7 @@ bool InitXInput2Mouse(void* const hwnd) current_master = &all_masters[0]; if (current_master->use == XIMasterPointer) { - g_mouse_input = new XInput2Mouse((Window)hwnd, xi_opcode, current_master->deviceid); + g_mouse_input.reset(XInput2Mouse((Window)hwnd, xi_opcode, current_master->deviceid)); } XCloseDisplay(dpy); From bfc16765cffd6a68b650f8d90c59cf0bd5ceee3f Mon Sep 17 00:00:00 2001 From: TellowKrinkle Date: Sat, 20 Apr 2024 23:55:26 -0500 Subject: [PATCH 12/12] Input:Quartz: Release cursor during modal popups --- .../Quartz/QuartzKeyboardAndMouse.h | 3 ++ .../Quartz/QuartzKeyboardAndMouse.mm | 42 +++++++++++++++- Source/Core/InputCommon/QuartzInputMouse.h | 9 ++-- Source/Core/InputCommon/QuartzInputMouse.mm | 50 ++++++++++++++----- 4 files changed, 87 insertions(+), 17 deletions(-) diff --git a/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.h b/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.h index 31ab29aa9aa3..b919bb24ff5c 100644 --- a/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.h +++ b/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.h @@ -13,7 +13,10 @@ @interface DolWindowPositionObserver : NSObject - (instancetype)initWithView:(NSView*)view; +- (void)addKeyWindowChangeCallback:(void(*)(void*, bool))callback ctx:(void*)ctx; +- (void)removeKeyWindowChangeCallback:(void*)ctx; @property(readonly) NSRect frame; +@property(readonly, getter=isKeyWindow) bool keyWindow; @end #else diff --git a/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm b/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm index d3b322284884..b5574075c174 100644 --- a/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm +++ b/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm @@ -19,7 +19,9 @@ @implementation DolWindowPositionObserver NSView* _view; NSWindow* _window; NSRect _frame; + std::atomic _is_key; std::mutex _mtx; + std::vector> _key_callbacks; } - (NSRect)calcFrame @@ -35,7 +37,12 @@ - (instancetype)initWithView:(NSView*)view _view = view; _window = [view window]; _frame = [self calcFrame]; + _is_key.store([_window isKeyWindow], std::memory_order_relaxed); [_window addObserver:self forKeyPath:@"frame" options:0 context:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(keyWindowDidChange:) + name:NSWindowDidBecomeKeyNotification + object:nil]; } return self; } @@ -46,6 +53,38 @@ - (NSRect)frame return _frame; } +- (bool)isKeyWindow +{ + return _is_key.load(std::memory_order_relaxed); +} + +- (void)addKeyWindowChangeCallback:(void(*)(void*, bool))callback ctx:(void*)ctx; +{ + std::lock_guard guard(_mtx); + _key_callbacks.push_back(std::make_pair(callback, ctx)); +} + +- (void)removeKeyWindowChangeCallback:(void*)ctx +{ + std::lock_guard guard(_mtx); + _key_callbacks.erase(std::remove_if(_key_callbacks.begin(), _key_callbacks.end(), + [ctx](auto& entry){ return entry.second == ctx; }), + _key_callbacks.end()); +} + +- (void)keyWindowDidChange:(id)window +{ + bool key = [_window isKeyWindow]; + bool changed = key != _is_key.load(std::memory_order_relaxed); + _is_key.store(key, std::memory_order_relaxed); + if (changed) + { + std::lock_guard guard(_mtx); + for (const auto& callback : _key_callbacks) + callback.first(callback.second, key); + } +} + - (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change @@ -62,6 +101,7 @@ - (void)observeValueForKeyPath:(NSString*)keyPath - (void)dealloc { [_window removeObserver:self forKeyPath:@"frame"]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; } @end @@ -209,7 +249,7 @@ - (void)dealloc MainThreadInitialization(view); else dispatch_sync(dispatch_get_main_queue(), [this, view] { MainThreadInitialization(view); }); - prime::InitQuartzInputMouse(); + prime::InitQuartzInputMouse(m_window_pos_observer); // cursor, with a hax for-loop for (unsigned int i = 0; i < 4; ++i) diff --git a/Source/Core/InputCommon/QuartzInputMouse.h b/Source/Core/InputCommon/QuartzInputMouse.h index b559bc0c8af4..b2d0b31291e8 100644 --- a/Source/Core/InputCommon/QuartzInputMouse.h +++ b/Source/Core/InputCommon/QuartzInputMouse.h @@ -12,22 +12,25 @@ typedef void* id; namespace prime { -bool InitQuartzInputMouse(); +bool InitQuartzInputMouse(DolWindowPositionObserver* window); class QuartzInputMouse: public GenericMouse { public: - explicit QuartzInputMouse(); + explicit QuartzInputMouse(DolWindowPositionObserver* window); ~QuartzInputMouse(); void InputCallback(NSEvent* event); void UpdateInput() override; void LockCursorToGameWindow() override; + void UnlockCursor(); private: NSEvent*(^m_event_callback)(NSEvent*); - id m_monitor = nullptr; + std::atomic m_monitor{nullptr}; + DolWindowPositionObserver* m_window; std::atomic thread_dx; std::atomic thread_dy; + std::mutex m_mtx; }; } diff --git a/Source/Core/InputCommon/QuartzInputMouse.mm b/Source/Core/InputCommon/QuartzInputMouse.mm index 591df8db08ec..204b8a118dff 100644 --- a/Source/Core/InputCommon/QuartzInputMouse.mm +++ b/Source/Core/InputCommon/QuartzInputMouse.mm @@ -15,24 +15,34 @@ namespace prime { -bool InitQuartzInputMouse() +bool InitQuartzInputMouse(DolWindowPositionObserver* window) { - g_mouse_input.reset(new QuartzInputMouse()); + g_mouse_input.reset(new QuartzInputMouse(window)); return true; } -QuartzInputMouse::QuartzInputMouse() +QuartzInputMouse::QuartzInputMouse(DolWindowPositionObserver* window) { + m_window = window; m_event_callback = ^NSEvent*(NSEvent* event) { InputCallback(event); return event; }; + void (*key_callback)(void*, bool) = [](void* ctx, bool key){ + if (key) + return; + QuartzInputMouse* me = static_cast(ctx); + std::lock_guard lock(me->m_mtx); + me->UnlockCursor(); + }; + [m_window addKeyWindowChangeCallback:key_callback ctx:this]; } QuartzInputMouse::~QuartzInputMouse() { - if (m_monitor) - [NSEvent removeMonitor:m_monitor]; + [m_window removeKeyWindowChangeCallback:this]; + if (void* monitor = m_monitor.load(std::memory_order_relaxed)) + [NSEvent removeMonitor:(__bridge id)monitor]; } void QuartzInputMouse::InputCallback(NSEvent* event) @@ -50,8 +60,13 @@ bool InitQuartzInputMouse() void QuartzInputMouse::LockCursorToGameWindow() { - bool wants_locked = Host_RendererHasFocus() && cursor_locked; - bool is_locked = m_monitor; + bool wants_locked = Host_RendererHasFocus() && cursor_locked && [m_window isKeyWindow]; + bool is_locked = m_monitor.load(std::memory_order_relaxed); + if (wants_locked == is_locked) + return; + std::lock_guard lock(m_mtx); + wants_locked = Host_RendererHasFocus() && cursor_locked && [m_window isKeyWindow]; + is_locked = m_monitor.load(std::memory_order_relaxed); if (wants_locked == is_locked) return; if (wants_locked) @@ -62,17 +77,26 @@ bool InitQuartzInputMouse() // Clear any accumulated movement thread_dx.store(0, std::memory_order_relaxed); thread_dy.store(0, std::memory_order_relaxed); - m_monitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskMouseMoved - handler:m_event_callback]; + id monitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskMouseMoved + handler:m_event_callback]; + m_monitor.store((__bridge void*)monitor, std::memory_order_relaxed); } else { - CGAssociateMouseAndMouseCursorPosition(true); - [NSCursor unhide]; - [NSEvent removeMonitor:m_monitor]; - m_monitor = nullptr; + UnlockCursor(); cursor_locked = false; } } +void QuartzInputMouse::UnlockCursor() +{ + void* monitor = m_monitor.load(std::memory_order_relaxed); + if (!monitor) + return; + CGAssociateMouseAndMouseCursorPosition(true); + [NSCursor unhide]; + [NSEvent removeMonitor:(__bridge id)monitor]; + m_monitor.store(nullptr, std::memory_order_relaxed); +} + }