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;
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

View File

@ -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 (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;
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;
case GBUnderclock:
underclockKeyDown = state;
break;
default:
GB_set_key_state(_gb, (GB_key_t)i, 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
{
UpdateSystemActivity(UsrActivity);
NSDictionary *mapping = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"GBJoypadMappings"][joystick_name];
NSNumber *x_axis = [mapping objectForKey:@"XAxis"];
NSNumber *y_axis = [mapping objectForKey:@"YAxis"];
unsigned player_count = GB_get_player_count(_gb);
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);
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;
}
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);
}
}
}
}

View File

@ -373,7 +373,7 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<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"/>
<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"/>
@ -383,17 +383,6 @@
<action selector="configureJoypad:" target="QvC-M9-y7g" id="IfY-Kc-PKU"/>
</connections>
</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">
<rect key="frame" x="10" y="339" width="122" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
@ -471,7 +460,7 @@
</textFieldCell>
</textField>
<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"/>
<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"/>
@ -482,6 +471,9 @@
</items>
</menu>
</popUpButtonCell>
<connections>
<action selector="changeDefaultJoypad:" target="QvC-M9-y7g" id="TP2-Ug-Jpy"/>
</connections>
</popUpButton>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="VEc-Ed-Z6f">
<rect key="frame" x="12" y="48" width="268" height="5"/>
@ -512,9 +504,20 @@
</menu>
</popUpButtonCell>
<connections>
<action selector="reloadButtonsData:" target="QvC-M9-y7g" id="HCM-gW-m5j"/>
<action selector="refreshJoypadMenu:" target="QvC-M9-y7g" id="5hY-tg-9VE"/>
</connections>
</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>
<point key="canvasLocation" x="-159" y="1116"/>
</customView>

View File

@ -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;
}

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_height(GB_gameboy_t *gb);
unsigned GB_get_player_count(GB_gameboy_t *gb);
#endif /* GB_h */