160 lines
6.9 KiB
Objective-C
160 lines
6.9 KiB
Objective-C
//
|
|
// Copyright © 2020 osy. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
#import "UIViewController+Extensions.h"
|
|
#import "VMCursor.h"
|
|
#import "VMScroll.h"
|
|
#import "VMDisplayMetalViewController+Gamepad.h"
|
|
#import "VMDisplayMetalViewController+Touch.h"
|
|
#import "CSDisplay.h"
|
|
#import "UTMQemuConfiguration.h"
|
|
#import "UTMQemuConfiguration+Constants.h"
|
|
#import "UTMLogging.h"
|
|
|
|
const CGFloat kThumbstickSpeedMultiplier = 1000; // in points per second
|
|
|
|
@implementation VMDisplayMetalViewController(Gamepad)
|
|
|
|
- (void)initGamepad {
|
|
// notifications for controller (dis)connect
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerWasConnected:) name:GCControllerDidConnectNotification object:nil];
|
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerWasDisconnected:) name:GCControllerDidDisconnectNotification object:nil];
|
|
for (GCController *controller in [GCController controllers]) {
|
|
[self setupController:controller];
|
|
}
|
|
}
|
|
|
|
#pragma mark - Gamepad connection
|
|
|
|
- (void)controllerWasConnected:(NSNotification *)notification {
|
|
// a controller was connected
|
|
GCController *controller = (GCController *)notification.object;
|
|
UTMLog(@"Controller connected: %@", controller.vendorName);
|
|
[self setupController:controller];
|
|
}
|
|
|
|
- (void)controllerWasDisconnected:(NSNotification *)notification {
|
|
// a controller was disconnected
|
|
GCController *controller = (GCController *)notification.object;
|
|
UTMLog(@"Controller disconnected: %@", controller.vendorName);
|
|
}
|
|
|
|
- (void)setupController:(GCController *)controller {
|
|
GCExtendedGamepad *gamepad = controller.extendedGamepad;
|
|
__weak typeof(self) _self = self;
|
|
_controller = controller;
|
|
UTMLog(@"active controller switched to: %@", controller.vendorName);
|
|
|
|
gamepad.leftTrigger.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[_self gamepadButton:@"GCButtonTriggerLeft" pressed:pressed];
|
|
};
|
|
|
|
gamepad.rightTrigger.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[_self gamepadButton:@"GCButtonTriggerRight" pressed:pressed];
|
|
};
|
|
|
|
gamepad.leftShoulder.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[_self gamepadButton:@"GCButtonShoulderLeft" pressed:pressed];
|
|
};
|
|
|
|
gamepad.rightShoulder.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[_self gamepadButton:@"GCButtonShoulderRight" pressed:pressed];
|
|
};
|
|
|
|
gamepad.buttonA.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[_self gamepadButton:@"GCButtonA" pressed:pressed];
|
|
};
|
|
|
|
gamepad.buttonB.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[_self gamepadButton:@"GCButtonB" pressed:pressed];
|
|
};
|
|
|
|
gamepad.buttonX.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[_self gamepadButton:@"GCButtonX" pressed:pressed];
|
|
};
|
|
|
|
gamepad.buttonY.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[_self gamepadButton:@"GCButtonY" pressed:pressed];
|
|
};
|
|
|
|
gamepad.dpad.up.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[_self gamepadButton:@"GCButtonDpadUp" pressed:pressed];
|
|
};
|
|
|
|
gamepad.dpad.left.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[_self gamepadButton:@"GCButtonDpadLeft" pressed:pressed];
|
|
};
|
|
|
|
gamepad.dpad.down.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[_self gamepadButton:@"GCButtonDpadDown" pressed:pressed];
|
|
};
|
|
|
|
gamepad.dpad.right.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[_self gamepadButton:@"GCButtonDpadRight" pressed:pressed];
|
|
};
|
|
|
|
gamepad.leftThumbstick.valueChangedHandler = ^(GCControllerDirectionPad * _Nonnull dpad, float xValue, float yValue) {
|
|
VMDisplayMetalViewController *s = _self;
|
|
CGPoint velocity = CGPointMake(xValue * kThumbstickSpeedMultiplier, -yValue * kThumbstickSpeedMultiplier);
|
|
[s->_scroll startMovement:CGPointZero];
|
|
[s->_scroll updateMovement:CGPointMake(xValue, yValue)];
|
|
[s->_scroll endMovementWithVelocity:velocity resistance:0];
|
|
};
|
|
|
|
gamepad.rightThumbstick.valueChangedHandler = ^(GCControllerDirectionPad * _Nonnull dpad, float xValue, float yValue) {
|
|
NSInteger speed = [_self integerForSetting:@"GCThumbstickRightSpeed"];
|
|
VMDisplayMetalViewController *s = _self;
|
|
CGPoint center = s->_cursor.center;
|
|
CGPoint start = CGPointMake(xValue * speed, -yValue * speed);
|
|
CGPoint velocity = CGPointMake(xValue * kThumbstickSpeedMultiplier, -yValue * kThumbstickSpeedMultiplier);
|
|
[s->_cursor startMovement:center];
|
|
[s->_cursor updateMovement:CGPointMake(center.x + start.x, center.y + start.y)];
|
|
[s->_cursor endMovementWithVelocity:velocity resistance:0];
|
|
};
|
|
|
|
if (@available(iOS 13.0, *)) {
|
|
gamepad.buttonMenu.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
|
|
[_self gamepadButton:@"GCButtonMenu" pressed:pressed];
|
|
};
|
|
}
|
|
}
|
|
|
|
- (void)gamepadButton:(NSString *)identifier pressed:(BOOL)isPressed {
|
|
NSInteger value = [self integerForSetting:identifier];
|
|
UTMLog(@"GC button %@ (%ld) pressed:%d", identifier, value, isPressed);
|
|
switch (value) {
|
|
case 0:
|
|
break;
|
|
case -1:
|
|
[self.vmInput sendMouseButton:kCSInputButtonLeft pressed:isPressed];
|
|
_mouseLeftDown = isPressed;
|
|
break;
|
|
case -3:
|
|
[self.vmInput sendMouseButton:kCSInputButtonRight pressed:isPressed];
|
|
_mouseRightDown = isPressed;
|
|
break;
|
|
case -2:
|
|
[self.vmInput sendMouseButton:kCSInputButtonMiddle pressed:isPressed];
|
|
_mouseMiddleDown = isPressed;
|
|
break;
|
|
default:
|
|
[self sendExtendedKey:isPressed ? kCSInputKeyPress : kCSInputKeyRelease code:(int)value];
|
|
break;
|
|
}
|
|
}
|
|
|
|
@end
|