VMDisplayMetalViewController+Gamepad.m 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. //
  2. // Copyright © 2020 osy. All rights reserved.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. #import "VMCursor.h"
  17. #import "VMScroll.h"
  18. #import "VMDisplayMetalViewController+Private.h"
  19. #import "VMDisplayMetalViewController+Gamepad.h"
  20. #import "VMDisplayMetalViewController+Touch.h"
  21. #import "CSDisplay.h"
  22. #import "UTMLogging.h"
  23. #import "UTM-Swift.h"
  24. const CGFloat kThumbstickSpeedMultiplier = 1000; // in points per second
  25. @implementation VMDisplayMetalViewController(Gamepad)
  26. - (void)initGamepad {
  27. // notifications for controller (dis)connect
  28. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerWasConnected:) name:GCControllerDidConnectNotification object:nil];
  29. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controllerWasDisconnected:) name:GCControllerDidDisconnectNotification object:nil];
  30. for (GCController *controller in [GCController controllers]) {
  31. [self setupController:controller];
  32. }
  33. }
  34. #pragma mark - Gamepad connection
  35. - (void)controllerWasConnected:(NSNotification *)notification {
  36. // a controller was connected
  37. GCController *controller = (GCController *)notification.object;
  38. UTMLog(@"Controller connected: %@", controller.vendorName);
  39. [self setupController:controller];
  40. }
  41. - (void)controllerWasDisconnected:(NSNotification *)notification {
  42. // a controller was disconnected
  43. GCController *controller = (GCController *)notification.object;
  44. UTMLog(@"Controller disconnected: %@", controller.vendorName);
  45. }
  46. - (void)setupController:(GCController *)controller {
  47. GCExtendedGamepad *gamepad = controller.extendedGamepad;
  48. __weak typeof(self) _self = self;
  49. self.controller = controller;
  50. UTMLog(@"active controller switched to: %@", controller.vendorName);
  51. gamepad.leftTrigger.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
  52. [_self gamepadButton:@"GCButtonTriggerLeft" pressed:pressed];
  53. };
  54. gamepad.rightTrigger.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
  55. [_self gamepadButton:@"GCButtonTriggerRight" pressed:pressed];
  56. };
  57. gamepad.leftShoulder.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
  58. [_self gamepadButton:@"GCButtonShoulderLeft" pressed:pressed];
  59. };
  60. gamepad.rightShoulder.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
  61. [_self gamepadButton:@"GCButtonShoulderRight" pressed:pressed];
  62. };
  63. gamepad.buttonA.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
  64. [_self gamepadButton:@"GCButtonA" pressed:pressed];
  65. };
  66. gamepad.buttonB.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
  67. [_self gamepadButton:@"GCButtonB" pressed:pressed];
  68. };
  69. gamepad.buttonX.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
  70. [_self gamepadButton:@"GCButtonX" pressed:pressed];
  71. };
  72. gamepad.buttonY.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
  73. [_self gamepadButton:@"GCButtonY" pressed:pressed];
  74. };
  75. gamepad.dpad.up.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
  76. [_self gamepadButton:@"GCButtonDpadUp" pressed:pressed];
  77. };
  78. gamepad.dpad.left.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
  79. [_self gamepadButton:@"GCButtonDpadLeft" pressed:pressed];
  80. };
  81. gamepad.dpad.down.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
  82. [_self gamepadButton:@"GCButtonDpadDown" pressed:pressed];
  83. };
  84. gamepad.dpad.right.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
  85. [_self gamepadButton:@"GCButtonDpadRight" pressed:pressed];
  86. };
  87. gamepad.leftThumbstick.valueChangedHandler = ^(GCControllerDirectionPad * _Nonnull dpad, float xValue, float yValue) {
  88. VMDisplayMetalViewController *s = _self;
  89. CGPoint velocity = CGPointMake(xValue * kThumbstickSpeedMultiplier, -yValue * kThumbstickSpeedMultiplier);
  90. [s.scroll startMovement:CGPointZero];
  91. [s.scroll updateMovement:CGPointMake(xValue, yValue)];
  92. [s.scroll endMovementWithVelocity:velocity resistance:0];
  93. };
  94. gamepad.rightThumbstick.valueChangedHandler = ^(GCControllerDirectionPad * _Nonnull dpad, float xValue, float yValue) {
  95. NSInteger speed = [_self integerForSetting:@"GCThumbstickRightSpeed"];
  96. VMDisplayMetalViewController *s = _self;
  97. CGPoint center = s.cursor.center;
  98. CGPoint start = CGPointMake(xValue * speed, -yValue * speed);
  99. CGPoint velocity = CGPointMake(xValue * kThumbstickSpeedMultiplier, -yValue * kThumbstickSpeedMultiplier);
  100. [s.cursor startMovement:center];
  101. [s.cursor updateMovement:CGPointMake(center.x + start.x, center.y + start.y)];
  102. [s.cursor endMovementWithVelocity:velocity resistance:0];
  103. };
  104. if (@available(iOS 13.0, *)) {
  105. gamepad.buttonMenu.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) {
  106. [_self gamepadButton:@"GCButtonMenu" pressed:pressed];
  107. };
  108. }
  109. }
  110. - (void)gamepadButton:(NSString *)identifier pressed:(BOOL)isPressed {
  111. NSInteger value = [self integerForSetting:identifier];
  112. UTMLog(@"GC button %@ (%ld) pressed:%d", identifier, value, isPressed);
  113. switch (value) {
  114. case 0:
  115. break;
  116. case -1:
  117. [self.vmInput sendMouseButton:kCSInputButtonLeft mask:self.mouseButtonDown pressed:isPressed];
  118. self.mouseLeftDown = isPressed;
  119. break;
  120. case -3:
  121. [self.vmInput sendMouseButton:kCSInputButtonRight mask:self.mouseButtonDown pressed:isPressed];
  122. self.mouseRightDown = isPressed;
  123. break;
  124. case -2:
  125. [self.vmInput sendMouseButton:kCSInputButtonMiddle mask:self.mouseButtonDown pressed:isPressed];
  126. self.mouseMiddleDown = isPressed;
  127. break;
  128. default:
  129. [self sendExtendedKey:isPressed ? kCSInputKeyPress : kCSInputKeyRelease code:(int)value];
  130. break;
  131. }
  132. }
  133. @end