From 21eb96a2f5deb5e8f23e282e3dd12b0a303db906 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Sat, 15 Dec 2018 18:55:41 +0200 Subject: [PATCH] Joypad multiplayer support (Cocoa) --- Cocoa/GBPreferencesWindow.m | 49 +++++++++++++ Cocoa/GBView.m | 141 +++++++++++++++++++++--------------- Cocoa/Preferences.xib | 31 ++++---- Core/gb.c | 5 ++ Core/gb.h | 2 + 5 files changed, 155 insertions(+), 73 deletions(-) diff --git a/Cocoa/GBPreferencesWindow.m b/Cocoa/GBPreferencesWindow.m index ac63080..982aa45 100644 --- a/Cocoa/GBPreferencesWindow.m +++ b/Cocoa/GBPreferencesWindow.m @@ -19,6 +19,7 @@ NSEventModifierFlags previousModifiers; NSPopUpButton *_dmgPopupButton, *_sgbPopupButton, *_cgbPopupButton; + NSPopUpButton *_preferredJoypadButton; } + (NSArray *)filterList @@ -264,6 +265,7 @@ all_mappings[joystick_name] = mapping; [[NSUserDefaults standardUserDefaults] setObject:all_mappings forKey:@"GBJoypadMappings"]; + [self refreshJoypadMenu:nil]; [self advanceConfigurationStateMachine]; } @@ -434,4 +436,51 @@ [self.controlsTableView reloadData]; } +- (void)setPreferredJoypadButton:(NSPopUpButton *)preferredJoypadButton +{ + _preferredJoypadButton = preferredJoypadButton; + [self refreshJoypadMenu:nil]; +} + +- (NSPopUpButton *)preferredJoypadButton +{ + return _preferredJoypadButton; +} + +- (IBAction)refreshJoypadMenu:(id)sender +{ + NSArray *joypads = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBJoypadMappings"] allKeys]; + for (NSString *joypad in joypads) { + if ([self.preferredJoypadButton indexOfItemWithTitle:joypad] == -1) { + [self.preferredJoypadButton addItemWithTitle:joypad]; + } + } + + NSString *player_string = [NSString stringWithFormat: @"%ld", (long)self.playerListButton.selectedTag]; + NSString *selected_joypad = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBDefaultJoypads"][player_string]; + if (selected_joypad && [self.preferredJoypadButton indexOfItemWithTitle:selected_joypad] != -1) { + [self.preferredJoypadButton selectItemWithTitle:selected_joypad]; + } + else { + [self.preferredJoypadButton selectItemWithTitle:@"None"]; + } + [self.controlsTableView reloadData]; +} + +- (IBAction)changeDefaultJoypad:(id)sender +{ + NSMutableDictionary *default_joypads = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBDefaultJoypads"] mutableCopy]; + if (!default_joypads) { + default_joypads = [[NSMutableDictionary alloc] init]; + } + + NSString *player_string = [NSString stringWithFormat: @"%ld", self.playerListButton.selectedTag]; + if ([[sender titleOfSelectedItem] isEqualToString:@"None"]) { + [default_joypads removeObjectForKey:player_string]; + } + else { + default_joypads[player_string] = [sender titleOfSelectedItem]; + } + [[NSUserDefaults standardUserDefaults] setObject:default_joypads forKey:@"GBDefaultJoypads"]; +} @end diff --git a/Cocoa/GBView.m b/Cocoa/GBView.m index b954839..7e425c5 100644 --- a/Cocoa/GBView.m +++ b/Cocoa/GBView.m @@ -169,7 +169,7 @@ bool handled = false; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - unsigned player_count = GB_is_sgb(_gb)? 4: 1; + unsigned player_count = GB_get_player_count(_gb); for (unsigned player = 0; player < player_count; player++) { for (GBButton button = 0; button < GBButtonCount; button++) { NSNumber *key = [defaults valueForKey:button_to_preference_name(button, player)]; @@ -210,7 +210,7 @@ bool handled = false; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - unsigned player_count = GB_is_sgb(_gb)? 4: 1; + unsigned player_count = GB_get_player_count(_gb); for (unsigned player = 0; player < player_count; player++) { for (GBButton button = 0; button < GBButtonCount; button++) { NSNumber *key = [defaults valueForKey:button_to_preference_name(button, player)]; @@ -245,31 +245,42 @@ - (void) joystick:(NSString *)joystick_name button: (unsigned)button changedState: (bool) state { + unsigned player_count = GB_get_player_count(_gb); + UpdateSystemActivity(UsrActivity); - NSDictionary *mapping = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBJoypadMappings"][joystick_name]; - - for (GBButton i = 0; i < GBButtonCount; i++) { - NSNumber *mapped_button = [mapping objectForKey:GBButtonNames[i]]; - if (mapped_button && [mapped_button integerValue] == button) { - switch (i) { - case GBTurbo: - GB_set_turbo_mode(_gb, state, state && self.isRewinding); - break; + for (unsigned player = 0; player < player_count; player++) { + NSString *preferred_joypad = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBDefaultJoypads"] + objectForKey:[NSString stringWithFormat:@"%u", player]]; + if (player_count != 1 && // Single player, accpet inputs from all joypads + !(player == 0 && !preferred_joypad) && // Multiplayer, but player 1 has no joypad configured, so it takes inputs from all joypads + ![preferred_joypad isEqualToString:joystick_name]) { + continue; + } + NSDictionary *mapping = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBJoypadMappings"][joystick_name]; + + for (GBButton i = 0; i < GBButtonCount; i++) { + NSNumber *mapped_button = [mapping objectForKey:GBButtonNames[i]]; + if (mapped_button && [mapped_button integerValue] == button) { + switch (i) { + case GBTurbo: + GB_set_turbo_mode(_gb, state, state && self.isRewinding); + break; + + case GBRewind: + self.isRewinding = state; + if (state) { + GB_set_turbo_mode(_gb, false, false); + } + break; - case GBRewind: - self.isRewinding = state; - if (state) { - GB_set_turbo_mode(_gb, false, false); - } - break; - - case GBUnderclock: - underclockKeyDown = state; - break; - - default: - GB_set_key_state(_gb, (GB_key_t)i, state); - break; + case GBUnderclock: + underclockKeyDown = state; + break; + + default: + GB_set_key_state_for_player(_gb, (GB_key_t)i, player, state); + break; + } } } } @@ -277,43 +288,55 @@ - (void) joystick:(NSString *)joystick_name axis: (unsigned)axis movedTo: (signed) value { + unsigned player_count = GB_get_player_count(_gb); + UpdateSystemActivity(UsrActivity); - NSDictionary *mapping = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBJoypadMappings"][joystick_name]; - NSNumber *x_axis = [mapping objectForKey:@"XAxis"]; - NSNumber *y_axis = [mapping objectForKey:@"YAxis"]; - - if (axis == [x_axis integerValue]) { - if (value > JOYSTICK_HIGH) { - axisActive[0] = true; - GB_set_key_state(_gb, GB_KEY_RIGHT, true); - GB_set_key_state(_gb, GB_KEY_LEFT, false); + for (unsigned player = 0; player < player_count; player++) { + NSString *preferred_joypad = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBDefaultJoypads"] + objectForKey:[NSString stringWithFormat:@"%u", player]]; + if (player_count != 1 && // Single player, accpet inputs from all joypads + !(player == 0 && !preferred_joypad) && // Multiplayer, but player 1 has no joypad configured, so it takes inputs from all joypads + ![preferred_joypad isEqualToString:joystick_name]) { + continue; } - else if (value < -JOYSTICK_HIGH) { - axisActive[0] = true; - GB_set_key_state(_gb, GB_KEY_RIGHT, false); - GB_set_key_state(_gb, GB_KEY_LEFT, true); + + NSDictionary *mapping = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBJoypadMappings"][joystick_name]; + NSNumber *x_axis = [mapping objectForKey:@"XAxis"]; + NSNumber *y_axis = [mapping objectForKey:@"YAxis"]; + + if (axis == [x_axis integerValue]) { + if (value > JOYSTICK_HIGH) { + axisActive[0] = true; + GB_set_key_state_for_player(_gb, GB_KEY_RIGHT, player, true); + GB_set_key_state_for_player(_gb, GB_KEY_LEFT, player, false); + } + else if (value < -JOYSTICK_HIGH) { + axisActive[0] = true; + GB_set_key_state_for_player(_gb, GB_KEY_RIGHT, player, false); + GB_set_key_state_for_player(_gb, GB_KEY_LEFT, player, true); + } + else if (axisActive[0] && value < JOYSTICK_LOW && value > -JOYSTICK_LOW) { + axisActive[0] = false; + GB_set_key_state_for_player(_gb, GB_KEY_RIGHT, player, false); + GB_set_key_state_for_player(_gb, GB_KEY_LEFT, player, false); + } } - else if (axisActive[0] && value < JOYSTICK_LOW && value > -JOYSTICK_LOW) { - axisActive[0] = false; - GB_set_key_state(_gb, GB_KEY_RIGHT, false); - GB_set_key_state(_gb, GB_KEY_LEFT, false); - } - } - else if (axis == [y_axis integerValue]) { - if (value > JOYSTICK_HIGH) { - axisActive[1] = true; - GB_set_key_state(_gb, GB_KEY_DOWN, true); - GB_set_key_state(_gb, GB_KEY_UP, false); - } - else if (value < -JOYSTICK_HIGH) { - axisActive[1] = true; - GB_set_key_state(_gb, GB_KEY_DOWN, false); - GB_set_key_state(_gb, GB_KEY_UP, true); - } - else if (axisActive[1] && value < JOYSTICK_LOW && value > -JOYSTICK_LOW) { - axisActive[1] = false; - GB_set_key_state(_gb, GB_KEY_DOWN, false); - GB_set_key_state(_gb, GB_KEY_UP, false); + else if (axis == [y_axis integerValue]) { + if (value > JOYSTICK_HIGH) { + axisActive[1] = true; + GB_set_key_state_for_player(_gb, GB_KEY_DOWN, player, true); + GB_set_key_state_for_player(_gb, GB_KEY_UP, player, false); + } + else if (value < -JOYSTICK_HIGH) { + axisActive[1] = true; + GB_set_key_state_for_player(_gb, GB_KEY_DOWN, player, false); + GB_set_key_state_for_player(_gb, GB_KEY_UP, player, true); + } + else if (axisActive[1] && value < JOYSTICK_LOW && value > -JOYSTICK_LOW) { + axisActive[1] = false; + GB_set_key_state_for_player(_gb, GB_KEY_DOWN, player, false); + GB_set_key_state_for_player(_gb, GB_KEY_UP, player, false); + } } } } diff --git a/Cocoa/Preferences.xib b/Cocoa/Preferences.xib index fe6241e..e754199 100644 --- a/Cocoa/Preferences.xib +++ b/Cocoa/Preferences.xib @@ -373,7 +373,7 @@ - @@ -471,7 +460,7 @@ - + @@ -482,6 +471,9 @@ + + + @@ -512,9 +504,20 @@ - + + diff --git a/Core/gb.c b/Core/gb.c index 93ecb08..d9963c1 100644 --- a/Core/gb.c +++ b/Core/gb.c @@ -789,3 +789,8 @@ size_t GB_get_screen_height(GB_gameboy_t *gb) { return GB_is_sgb(gb)? 224 : 144; } + +unsigned GB_get_player_count(GB_gameboy_t *gb) +{ + return GB_is_sgb(gb)? gb->sgb->player_count : 1; +} diff --git a/Core/gb.h b/Core/gb.h index 2808677..39f4162 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -675,4 +675,6 @@ void GB_set_clock_multiplier(GB_gameboy_t *gb, double multiplier); size_t GB_get_screen_width(GB_gameboy_t *gb); size_t GB_get_screen_height(GB_gameboy_t *gb); +unsigned GB_get_player_count(GB_gameboy_t *gb); + #endif /* GB_h */