diff options
| author | TellowKrinkle <tellowkrinkle@gmail.com> | 2022-08-12 03:02:47 -0500 |
|---|---|---|
| committer | TellowKrinkle <tellowkrinkle@gmail.com> | 2022-08-18 16:29:43 -0500 |
| commit | 798b241832270bcb7fbc35b07bc297a288e64372 (patch) | |
| tree | c5817ad91c2b5c1bdbd234263e95dbc545023506 /Source/Core/InputCommon/ControllerInterface | |
| parent | b96bc4267ea4f87a332a349187e0038fdcf6253c (diff) | |
InputCommon:QuarzKB&M: Use KVO to watch window position
CGWindowListCreateDescriptionFromArray would block for up to ~1ms, which isn't a great thing to do on the main emulation thread
Diffstat (limited to 'Source/Core/InputCommon/ControllerInterface')
| -rw-r--r-- | Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.h | 11 | ||||
| -rw-r--r-- | Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm | 100 |
2 files changed, 82 insertions, 29 deletions
diff --git a/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.h b/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.h index dfcf216e45..e4bdb6e5fb 100644 --- a/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.h +++ b/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.h @@ -8,6 +8,12 @@ #include "Common/Matrix.h" #include "InputCommon/ControllerInterface/CoreDevice.h" +#ifdef __OBJC__ +@class DolWindowPositionObserver; +#else +class DolWindowPositionObserver; +#endif + namespace ciface::Quartz { std::string KeycodeToName(const CGKeyCode keycode); @@ -59,13 +65,16 @@ public: void UpdateInput() override; explicit KeyboardAndMouse(void* view); + ~KeyboardAndMouse() override; std::string GetName() const override; std::string GetSource() const override; private: + void MainThreadInitialization(void* view); + Common::Vec2 m_cursor; - uint32_t m_windowid; + DolWindowPositionObserver* m_window_pos_observer; }; } // namespace ciface::Quartz diff --git a/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm b/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm index 9cc8d07926..9b82ef591c 100644 --- a/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm +++ b/Source/Core/InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm @@ -4,6 +4,7 @@ #include "InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.h" #include <map> +#include <mutex> #include <Carbon/Carbon.h> #include <Cocoa/Cocoa.h> @@ -12,6 +13,64 @@ #include "InputCommon/ControllerInterface/ControllerInterface.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 +{ + NSWindow* _window; + NSRect _frame; + std::mutex _mtx; +} + +- (NSRect)calcFrame +{ + return [_window frame]; +} + +- (instancetype)initWithView:(NSView*)view +{ + self = [super init]; + if (self) + { + _window = [view window]; + _frame = [self calcFrame]; + [_window addObserver:self forKeyPath:@"frame" options:0 context:nil]; + } + return self; +} + +- (NSRect)frame +{ + std::lock_guard<std::mutex> guard(_mtx); + return _frame; +} + +- (void)observeValueForKeyPath:(NSString*)keyPath + ofObject:(id)object + change:(NSDictionary<NSKeyValueChangeKey, id>*)change + context:(void*)context +{ + if (object == _window) + { + NSRect new_frame = [self calcFrame]; + std::lock_guard<std::mutex> guard(_mtx); + _frame = new_frame; + } +} + +- (void)dealloc +{ + [_window removeObserver:self forKeyPath:@"frame"]; +} + +@end + namespace ciface::Quartz { std::string KeycodeToName(const CGKeyCode keycode) @@ -149,20 +208,12 @@ KeyboardAndMouse::KeyboardAndMouse(void* view) AddCombinedInput("Shift", {"Left Shift", "Right Shift"}); AddCombinedInput("Ctrl", {"Left Control", "Right Control"}); - NSView* cocoa_view = (__bridge NSView*)view; - // PopulateDevices may be called on the Emuthread, so we need to ensure that // these UI APIs are only ever called on the main thread. if ([NSThread isMainThread]) - { - m_windowid = [[cocoa_view window] windowNumber]; - } + MainThreadInitialization(view); else - { - dispatch_sync(dispatch_get_main_queue(), ^{ - m_windowid = [[cocoa_view window] windowNumber]; - }); - } + dispatch_sync(dispatch_get_main_queue(), [this, view] { MainThreadInitialization(view); }); // cursor, with a hax for-loop for (unsigned int i = 0; i < 4; ++i) @@ -173,26 +224,19 @@ KeyboardAndMouse::KeyboardAndMouse(void* view) AddInput(new Button(kCGMouseButtonCenter)); } -void KeyboardAndMouse::UpdateInput() -{ - 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<CFDictionaryRef>(CFArrayGetValueAtIndex(windowDescriptions, 0)); - - if (CFDictionaryContainsKey(windowDescription, kCGWindowBounds)) - { - CFDictionaryRef boundsDictionary = - static_cast<CFDictionaryRef>(CFDictionaryGetValue(windowDescription, kCGWindowBounds)); +// Very important that this is here +// C++ and ObjC++ have different views of the header, and only ObjC++'s will deallocate properly +KeyboardAndMouse::~KeyboardAndMouse() = default; - if (boundsDictionary != nullptr) - CGRectMakeWithDictionaryRepresentation(boundsDictionary, &bounds); - } +void KeyboardAndMouse::MainThreadInitialization(void* view) +{ + NSView* cocoa_view = (__bridge NSView*)view; + m_window_pos_observer = [[DolWindowPositionObserver alloc] initWithView:cocoa_view]; +} - CFRelease(windowDescriptions); - CFRelease(windowArray); +void KeyboardAndMouse::UpdateInput() +{ + NSRect bounds = [m_window_pos_observer frame]; const double window_width = std::max(bounds.size.width, 1.0); const double window_height = std::max(bounds.size.height, 1.0); |
