Improved controller assignment in the Cocoa port, affects #532

This commit is contained in:
Lior Halphon
2023-11-26 17:32:33 +02:00
parent 5823bf9d70
commit 1c8a14ff1c
2 changed files with 109 additions and 15 deletions

View File

@@ -117,6 +117,8 @@ static const uint8_t workboy_vk_to_key[] = {
JOYController *lastController; JOYController *lastController;
bool _turbo; bool _turbo;
bool _mouseControlEnabled; bool _mouseControlEnabled;
NSMutableDictionary<NSNumber *, JOYController *> *_controllerMapping;
unsigned _lastPlayerCount;
} }
+ (instancetype)alloc + (instancetype)alloc
@@ -143,6 +145,9 @@ static const uint8_t workboy_vk_to_key[] = {
[self observeStandardDefaultsKey:@"GBAspectRatioUnkept" withBlock:^(id newValue) { [self observeStandardDefaultsKey:@"GBAspectRatioUnkept" withBlock:^(id newValue) {
[weakSelf setFrame:weakSelf.superview.frame]; [weakSelf setFrame:weakSelf.superview.frame];
}]; }];
[self observeStandardDefaultsKey:@"JoyKitDefaultControllers" withBlock:^(id newValue) {
[weakSelf reassignControllers];
}];
tracking_area = [ [NSTrackingArea alloc] initWithRect:(NSRect){} tracking_area = [ [NSTrackingArea alloc] initWithRect:(NSRect){}
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect | NSTrackingMouseMoved options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect | NSTrackingMouseMoved
owner:self owner:self
@@ -154,6 +159,84 @@ static const uint8_t workboy_vk_to_key[] = {
self.internalView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; self.internalView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[JOYController registerListener:self]; [JOYController registerListener:self];
_mouseControlEnabled = true; _mouseControlEnabled = true;
[self reassignControllers];
}
- (void)controllerConnected:(JOYController *)controller
{
[self reassignControllers];
}
- (void)controllerDisconnected:(JOYController *)controller
{
[self reassignControllers];
}
- (unsigned)playerCount
{
if (self.document.partner) {
return 2;
}
if (!_gb) {
return 1;
}
return GB_get_player_count(_gb);
}
- (void)reassignControllers
{
unsigned playerCount = self.playerCount;
/* Don't assign controlelrs if there's only one player, allow all controllers. */
if (playerCount == 1) {
_controllerMapping = [NSMutableDictionary dictionary];
return;
}
if (!_controllerMapping) {
_controllerMapping = [NSMutableDictionary dictionary];
}
for (NSNumber *player in [_controllerMapping copy]) {
if (player.unsignedIntValue >= playerCount || !_controllerMapping[player].connected) {
[_controllerMapping removeObjectForKey:player];
}
}
_lastPlayerCount = playerCount;
for (unsigned i = 0; i < playerCount; i++) {
NSString *preferredJoypad = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"JoyKitDefaultControllers"]
objectForKey:n2s(i)];
for (JOYController *controller in [JOYController allControllers]) {
if (!controller.connected) continue;
if ([controller.uniqueID isEqual:preferredJoypad]) {
_controllerMapping[@(i)] = controller;
break;
}
}
}
}
- (void)tryAssigningController:(JOYController *)controller
{
unsigned playerCount = self.playerCount;
if (playerCount == 1) return;
if (_controllerMapping.count == playerCount) return;
if ([_controllerMapping.allValues containsObject:controller]) return;
for (unsigned i = 0; i < playerCount; i++) {
if (!_controllerMapping[@(i)]) {
_controllerMapping[@(i)] = controller;
return;
}
}
}
- (NSDictionary<NSNumber *, JOYController *> *)controllerMapping
{
if (_lastPlayerCount != self.playerCount) {
[self reassignControllers];
}
return _controllerMapping;
} }
- (void)screenSizeChanged - (void)screenSizeChanged
@@ -486,6 +569,19 @@ static const uint8_t workboy_vk_to_key[] = {
} }
} }
} }
NSDictionary<NSNumber *, JOYController *> *controllerMapping = [self controllerMapping];
GB_gameboy_t *effectiveGB = _gb;
if (self.document.partner) {
if (controllerMapping[@1] == controller) {
effectiveGB = self.document.partner.gb;
}
if (controllerMapping[@0] != controller) {
return;
}
}
if (axes.usage == JOYAxes3DUsageOrientation) { if (axes.usage == JOYAxes3DUsageOrientation) {
for (JOYAxes3D *axes in controller.axes3D) { for (JOYAxes3D *axes in controller.axes3D) {
@@ -495,11 +591,11 @@ static const uint8_t workboy_vk_to_key[] = {
} }
} }
JOYPoint3D point = axes.normalizedValue; JOYPoint3D point = axes.normalizedValue;
GB_set_accelerometer_values(_gb, point.x, point.z); GB_set_accelerometer_values(effectiveGB, point.x, point.z);
} }
else if (axes.usage == JOYAxes3DUsageAcceleration) { else if (axes.usage == JOYAxes3DUsageAcceleration) {
JOYPoint3D point = axes.gUnitsValue; JOYPoint3D point = axes.gUnitsValue;
GB_set_accelerometer_values(_gb, point.x, point.z); GB_set_accelerometer_values(effectiveGB, point.x, point.z);
} }
} }
@@ -510,22 +606,20 @@ static const uint8_t workboy_vk_to_key[] = {
_mouseControlEnabled = false; _mouseControlEnabled = false;
if (button.type == JOYButtonTypeAxes2DEmulated && [self shouldControllerUseJoystickForMotion:controller]) return; if (button.type == JOYButtonTypeAxes2DEmulated && [self shouldControllerUseJoystickForMotion:controller]) return;
unsigned player_count = GB_get_player_count(_gb); [self tryAssigningController:controller];
if (self.document.partner) {
player_count = 2; unsigned playerCount = self.playerCount;
}
IOPMAssertionID assertionID; IOPMAssertionID assertionID;
IOPMAssertionDeclareUserActivity(CFSTR(""), kIOPMUserActiveLocal, &assertionID); IOPMAssertionDeclareUserActivity(CFSTR(""), kIOPMUserActiveLocal, &assertionID);
for (unsigned player = 0; player < player_count; player++) {
NSString *preferred_joypad = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"JoyKitDefaultControllers"] NSDictionary<NSNumber *, JOYController *> *controllerMapping = [self controllerMapping];
objectForKey:n2s(player)]; for (unsigned player = 0; player < playerCount; player++) {
if (player_count != 1 && // Single player, accpet inputs from all joypads JOYController *preferredJoypad = controllerMapping[@(player)];
!(player == 0 && !preferred_joypad) && // Multiplayer, but player 1 has no joypad configured, so it takes inputs from all joypads if (preferredJoypad && preferredJoypad != controller) continue; // The player has a different assigned controller
![preferred_joypad isEqualToString:controller.uniqueID]) { if (!preferredJoypad && playerCount != 1) continue; // The player has no assigned controller in multiplayer mode, prevent controller inputs
continue;
}
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[controller setPlayerLEDs:[controller LEDMaskForPlayer:player]]; [controller setPlayerLEDs:[controller LEDMaskForPlayer:player]];
}); });

View File

@@ -367,7 +367,7 @@ typedef union {
if (!other) goto single; if (!other) goto single;
if (other.usage >= element.usage) goto single; if (other.usage >= element.usage) goto single;
if (other.reportID != element.reportID) goto single; if (other.reportID != element.reportID) goto single;
if (![axisGroups[@(other.usage)] isEqualTo: axisGroups[@(element.usage)]]) goto single; if (![axisGroups[@(other.usage)] isEqual: axisGroups[@(element.usage)]]) goto single;
if (other.parentID != element.parentID) goto single; if (other.parentID != element.parentID) goto single;
JOYAxes2D *axes = nil; JOYAxes2D *axes = nil;