Skip to content

Commit

Permalink
Merge pull request #2377 from js-john/master
Browse files Browse the repository at this point in the history
iOS: use GCMouse API on iOS 14 and above
  • Loading branch information
osy authored Apr 26, 2021
2 parents a2aadf0 + 05a72f5 commit 40c647c
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 3 deletions.
3 changes: 2 additions & 1 deletion Platform/iOS/Display/VMDisplayMetalViewController+Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

#import "UIKit/UIKit.h"
#import "VMDisplayMetalViewController.h"

@import GameController;
NS_ASSUME_NONNULL_BEGIN

NS_AVAILABLE_IOS(13.4)
Expand All @@ -25,6 +25,7 @@ NS_AVAILABLE_IOS(13.4)
@property (nonatomic, readonly) BOOL hasTouchpadPointer;

-(void)initPointerInteraction;
-(void)initGCMouse;

@end

Expand Down
75 changes: 74 additions & 1 deletion Platform/iOS/Display/VMDisplayMetalViewController+Pointer.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,79 @@
#import "VMDisplayMetalViewController+Pointer.h"
#import "VMCursor.h"
#import "CSDisplayMetal.h"
#import "VMScroll.h"
#import "UTMVirtualMachine.h"
#import "UTMVirtualMachine+SPICE.h"
#import "UTMLogging.h"

@interface VMDisplayMetalViewController ()

- (BOOL)switchMouseType:(VMMouseType)type; // defined in VMDisplayMetalViewController+Touch.m

@end

NS_AVAILABLE_IOS(13.4)
@implementation VMDisplayMetalViewController (Pointer)

#pragma mark - GCMouse

- (void)initGCMouse {
if (@available(iOS 14.0, *)) { //if ios 14.0 above, use CGMouse instead
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(mouseDidBecomeCurrent:) name:GCMouseDidBecomeCurrentNotification object:nil];
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(mouseDidStopBeingCurrent:) name:GCMouseDidStopBeingCurrentNotification object:nil];
}
}

- (BOOL)prefersPointerLocked {
return _mouseCaptured;
}

- (void)mouseDidBecomeCurrent:(NSNotification *)notification API_AVAILABLE(ios(14)) {
GCMouse *mouse = notification.object;
UTMLog(@"mouseDidBecomeCurrent: %p", mouse);
if (!mouse) {
UTMLog(@"invalid mouse object!");
return;
}
mouse.mouseInput.mouseMovedHandler = ^(GCMouseInput * _Nonnull mouse, float deltaX, float deltaY) {
[self.vmInput sendMouseMotion:self.mouseButtonDown point:CGPointMake(deltaX, -deltaY)];
};
mouse.mouseInput.leftButton.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
self->_mouseLeftDown = pressed;
[self.vmInput sendMouseButton:kCSInputButtonLeft pressed:pressed point:CGPointZero];
};
mouse.mouseInput.rightButton.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
self->_mouseRightDown = pressed;
[self.vmInput sendMouseButton:kCSInputButtonRight pressed:pressed point:CGPointZero];

};
mouse.mouseInput.middleButton.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
self->_mouseMiddleDown = pressed;
[self.vmInput sendMouseButton:kCSInputButtonMiddle pressed:pressed point:CGPointZero];
};
// no handler to the gcmouse scroll event, gestureScroll works fine.
[self switchMouseType:VMMouseTypeRelative];
_mouseCaptured = YES;
dispatch_async(dispatch_get_main_queue(), ^{
[self setNeedsUpdateOfPrefersPointerLocked];
});
}

- (void)mouseDidStopBeingCurrent:(NSNotification *)notification API_AVAILABLE(ios(14)) {
GCMouse *mouse = notification.object;
UTMLog(@"mouseDidStopBeingCurrent: %p", mouse);
mouse.mouseInput.mouseMovedHandler = nil;
mouse.mouseInput.leftButton.pressedChangedHandler = nil;
mouse.mouseInput.rightButton.pressedChangedHandler = nil;
mouse.mouseInput.middleButton.pressedChangedHandler = nil;
_mouseCaptured = NO;
dispatch_async(dispatch_get_main_queue(), ^{
[self setNeedsUpdateOfPrefersPointerLocked];
});
}

#pragma mark - UIPointerInteractionDelegate

// Add pointer interaction to VM view
-(void)initPointerInteraction {
[self.mtkView addInteraction:[[UIPointerInteraction alloc] initWithDelegate:self]];
Expand All @@ -42,7 +111,6 @@ - (BOOL)hasTouchpadPointer {
return !self.vmConfiguration.inputLegacy && !self.vmInput.serverModeCursor && self.indirectMouseType != VMMouseTypeRelative;
}

#pragma mark - UIPointerInteractionDelegate
- (UIPointerStyle *)pointerInteraction:(UIPointerInteraction *)interaction styleForRegion:(UIPointerRegion *)region {
// Hide cursor while hovering in VM view
if (interaction.view == self.mtkView && self.hasTouchpadPointer) {
Expand Down Expand Up @@ -74,6 +142,11 @@ - (bool)isPointOnVMDisplay:(CGPoint)pos {


- (UIPointerRegion *)pointerInteraction:(UIPointerInteraction *)interaction regionForRequest:(UIPointerRegionRequest *)request defaultRegion:(UIPointerRegion *)defaultRegion {
if (@available(iOS 14.0, *)) {
if (self.prefersPointerLocked) {
return nil;
}
}
// Requesting region for the VM display?
if (interaction.view == self.mtkView && self.hasTouchpadPointer) {
// Then we need to find out if the pointer is in the actual display area or outside
Expand Down
7 changes: 6 additions & 1 deletion Platform/iOS/Display/VMDisplayMetalViewController+Touch.m
Original file line number Diff line number Diff line change
Expand Up @@ -583,8 +583,13 @@ - (BOOL)switchMouseType:(VMMouseType)type {
#pragma mark - Touch event handling

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
if (!self.vmConfiguration.inputLegacy) {
if (!_mouseCaptured && !self.vmConfiguration.inputLegacy) {
for (UITouch *touch in [event touchesForView:self.mtkView]) {
if (@available(iOS 14, *)) {
if (self.prefersPointerLocked && (touch.type == UITouchTypeIndirect || touch.type == UITouchTypeIndirectPointer)) {
continue; // skip indirect touches if we are capturing mouse input
}
}
VMMouseType type = [self touchTypeToMouseType:touch.type];
if ([self switchMouseType:type]) {
[self dragCursor:UIGestureRecognizerStateEnded primary:YES secondary:YES middle:YES]; // reset drag
Expand Down
1 change: 1 addition & 0 deletions Platform/iOS/Display/VMDisplayMetalViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ NS_ASSUME_NONNULL_BEGIN
BOOL _pencilForceRightClickOnce;
VMCursor *_cursor;
VMScroll *_scroll;
BOOL _mouseCaptured;

// Gestures
UISwipeGestureRecognizer *_swipeUp;
Expand Down
1 change: 1 addition & 0 deletions Platform/iOS/Display/VMDisplayMetalViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ - (void)viewDidLoad {

[self initTouch];
[self initGamepad];
[self initGCMouse];
// Pointing device support on iPadOS 13.4 GM or later
if (@available(iOS 13.4, *)) {
// Betas of iPadOS 13.4 did not include this API, that's why I check if the class exists
Expand Down

0 comments on commit 40c647c

Please sign in to comment.