Joypad multiplayer support (Cocoa)

This commit is contained in:
Lior Halphon 2018-12-15 18:55:41 +02:00
parent 7b02b3cb89
commit 21eb96a2f5
5 changed files with 155 additions and 73 deletions

View File

@ -19,6 +19,7 @@
NSEventModifierFlags previousModifiers; NSEventModifierFlags previousModifiers;
NSPopUpButton *_dmgPopupButton, *_sgbPopupButton, *_cgbPopupButton; NSPopUpButton *_dmgPopupButton, *_sgbPopupButton, *_cgbPopupButton;
NSPopUpButton *_preferredJoypadButton;
} }
+ (NSArray *)filterList + (NSArray *)filterList
@ -264,6 +265,7 @@
all_mappings[joystick_name] = mapping; all_mappings[joystick_name] = mapping;
[[NSUserDefaults standardUserDefaults] setObject:all_mappings forKey:@"GBJoypadMappings"]; [[NSUserDefaults standardUserDefaults] setObject:all_mappings forKey:@"GBJoypadMappings"];
[self refreshJoypadMenu:nil];
[self advanceConfigurationStateMachine]; [self advanceConfigurationStateMachine];
} }
@ -434,4 +436,51 @@
[self.controlsTableView reloadData]; [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 @end

View File

@ -169,7 +169,7 @@
bool handled = false; bool handled = false;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 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 (unsigned player = 0; player < player_count; player++) {
for (GBButton button = 0; button < GBButtonCount; button++) { for (GBButton button = 0; button < GBButtonCount; button++) {
NSNumber *key = [defaults valueForKey:button_to_preference_name(button, player)]; NSNumber *key = [defaults valueForKey:button_to_preference_name(button, player)];
@ -210,7 +210,7 @@
bool handled = false; bool handled = false;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 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 (unsigned player = 0; player < player_count; player++) {
for (GBButton button = 0; button < GBButtonCount; button++) { for (GBButton button = 0; button < GBButtonCount; button++) {
NSNumber *key = [defaults valueForKey:button_to_preference_name(button, player)]; NSNumber *key = [defaults valueForKey:button_to_preference_name(button, player)];
@ -245,7 +245,17 @@
- (void) joystick:(NSString *)joystick_name button: (unsigned)button changedState: (bool) state - (void) joystick:(NSString *)joystick_name button: (unsigned)button changedState: (bool) state
{ {
unsigned player_count = GB_get_player_count(_gb);
UpdateSystemActivity(UsrActivity); UpdateSystemActivity(UsrActivity);
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]; NSDictionary *mapping = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBJoypadMappings"][joystick_name];
for (GBButton i = 0; i < GBButtonCount; i++) { for (GBButton i = 0; i < GBButtonCount; i++) {
@ -268,16 +278,28 @@
break; break;
default: default:
GB_set_key_state(_gb, (GB_key_t)i, state); GB_set_key_state_for_player(_gb, (GB_key_t)i, player, state);
break; break;
} }
} }
} }
} }
}
- (void) joystick:(NSString *)joystick_name axis: (unsigned)axis movedTo: (signed) value - (void) joystick:(NSString *)joystick_name axis: (unsigned)axis movedTo: (signed) value
{ {
unsigned player_count = GB_get_player_count(_gb);
UpdateSystemActivity(UsrActivity); UpdateSystemActivity(UsrActivity);
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]; NSDictionary *mapping = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBJoypadMappings"][joystick_name];
NSNumber *x_axis = [mapping objectForKey:@"XAxis"]; NSNumber *x_axis = [mapping objectForKey:@"XAxis"];
NSNumber *y_axis = [mapping objectForKey:@"YAxis"]; NSNumber *y_axis = [mapping objectForKey:@"YAxis"];
@ -285,35 +307,36 @@
if (axis == [x_axis integerValue]) { if (axis == [x_axis integerValue]) {
if (value > JOYSTICK_HIGH) { if (value > JOYSTICK_HIGH) {
axisActive[0] = true; axisActive[0] = true;
GB_set_key_state(_gb, GB_KEY_RIGHT, true); GB_set_key_state_for_player(_gb, GB_KEY_RIGHT, player, true);
GB_set_key_state(_gb, GB_KEY_LEFT, false); GB_set_key_state_for_player(_gb, GB_KEY_LEFT, player, false);
} }
else if (value < -JOYSTICK_HIGH) { else if (value < -JOYSTICK_HIGH) {
axisActive[0] = true; axisActive[0] = true;
GB_set_key_state(_gb, GB_KEY_RIGHT, false); GB_set_key_state_for_player(_gb, GB_KEY_RIGHT, player, false);
GB_set_key_state(_gb, GB_KEY_LEFT, true); GB_set_key_state_for_player(_gb, GB_KEY_LEFT, player, true);
} }
else if (axisActive[0] && value < JOYSTICK_LOW && value > -JOYSTICK_LOW) { else if (axisActive[0] && value < JOYSTICK_LOW && value > -JOYSTICK_LOW) {
axisActive[0] = false; axisActive[0] = false;
GB_set_key_state(_gb, GB_KEY_RIGHT, false); GB_set_key_state_for_player(_gb, GB_KEY_RIGHT, player, false);
GB_set_key_state(_gb, GB_KEY_LEFT, false); GB_set_key_state_for_player(_gb, GB_KEY_LEFT, player, false);
} }
} }
else if (axis == [y_axis integerValue]) { else if (axis == [y_axis integerValue]) {
if (value > JOYSTICK_HIGH) { if (value > JOYSTICK_HIGH) {
axisActive[1] = true; axisActive[1] = true;
GB_set_key_state(_gb, GB_KEY_DOWN, true); GB_set_key_state_for_player(_gb, GB_KEY_DOWN, player, true);
GB_set_key_state(_gb, GB_KEY_UP, false); GB_set_key_state_for_player(_gb, GB_KEY_UP, player, false);
} }
else if (value < -JOYSTICK_HIGH) { else if (value < -JOYSTICK_HIGH) {
axisActive[1] = true; axisActive[1] = true;
GB_set_key_state(_gb, GB_KEY_DOWN, false); GB_set_key_state_for_player(_gb, GB_KEY_DOWN, player, false);
GB_set_key_state(_gb, GB_KEY_UP, true); GB_set_key_state_for_player(_gb, GB_KEY_UP, player, true);
} }
else if (axisActive[1] && value < JOYSTICK_LOW && value > -JOYSTICK_LOW) { else if (axisActive[1] && value < JOYSTICK_LOW && value > -JOYSTICK_LOW) {
axisActive[1] = false; axisActive[1] = false;
GB_set_key_state(_gb, GB_KEY_DOWN, false); GB_set_key_state_for_player(_gb, GB_KEY_DOWN, player, false);
GB_set_key_state(_gb, GB_KEY_UP, false); GB_set_key_state_for_player(_gb, GB_KEY_UP, player, false);
}
} }
} }
} }

View File

@ -373,7 +373,7 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews> <subviews>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Qa7-Z7-yfO"> <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Qa7-Z7-yfO">
<rect key="frame" x="20" y="9" width="168" height="32"/> <rect key="frame" x="20" y="9" width="188" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Configure a Joypad" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="GdK-tQ-Wim"> <buttonCell key="cell" type="push" title="Configure a Joypad" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="GdK-tQ-Wim">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
@ -383,17 +383,6 @@
<action selector="configureJoypad:" target="QvC-M9-y7g" id="IfY-Kc-PKU"/> <action selector="configureJoypad:" target="QvC-M9-y7g" id="IfY-Kc-PKU"/>
</connections> </connections>
</button> </button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="d2I-jU-sLb">
<rect key="frame" x="200" y="9" width="72" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Skip" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="sug-xy-tbw">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="skipButton:" target="QvC-M9-y7g" id="aw8-sw-yJw"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Utu-t4-cLx"> <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Utu-t4-cLx">
<rect key="frame" x="10" y="339" width="122" height="17"/> <rect key="frame" x="10" y="339" width="122" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
@ -471,7 +460,7 @@
</textFieldCell> </textFieldCell>
</textField> </textField>
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0Az-0R-oNw"> <popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0Az-0R-oNw">
<rect key="frame" x="42" y="60" width="208" height="26"/> <rect key="frame" x="42" y="61" width="208" height="26"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="None" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="hy8-cr-RrE" id="uEC-vN-8Jq"> <popUpButtonCell key="cell" type="push" title="None" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="hy8-cr-RrE" id="uEC-vN-8Jq">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
@ -482,6 +471,9 @@
</items> </items>
</menu> </menu>
</popUpButtonCell> </popUpButtonCell>
<connections>
<action selector="changeDefaultJoypad:" target="QvC-M9-y7g" id="TP2-Ug-Jpy"/>
</connections>
</popUpButton> </popUpButton>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="VEc-Ed-Z6f"> <box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="VEc-Ed-Z6f">
<rect key="frame" x="12" y="48" width="268" height="5"/> <rect key="frame" x="12" y="48" width="268" height="5"/>
@ -512,9 +504,20 @@
</menu> </menu>
</popUpButtonCell> </popUpButtonCell>
<connections> <connections>
<action selector="reloadButtonsData:" target="QvC-M9-y7g" id="HCM-gW-m5j"/> <action selector="refreshJoypadMenu:" target="QvC-M9-y7g" id="5hY-tg-9VE"/>
</connections> </connections>
</popUpButton> </popUpButton>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="d2I-jU-sLb">
<rect key="frame" x="212" y="9" width="60" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Skip" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="sug-xy-tbw">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="skipButton:" target="QvC-M9-y7g" id="aw8-sw-yJw"/>
</connections>
</button>
</subviews> </subviews>
<point key="canvasLocation" x="-159" y="1116"/> <point key="canvasLocation" x="-159" y="1116"/>
</customView> </customView>

View File

@ -789,3 +789,8 @@ size_t GB_get_screen_height(GB_gameboy_t *gb)
{ {
return GB_is_sgb(gb)? 224 : 144; 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;
}

View File

@ -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_width(GB_gameboy_t *gb);
size_t GB_get_screen_height(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 */ #endif /* GB_h */