diff --git a/Cocoa/GBApp.m b/Cocoa/GBApp.m index 0e3c0f0..2b9fada 100644 --- a/Cocoa/GBApp.m +++ b/Cocoa/GBApp.m @@ -43,7 +43,7 @@ static uint32_t color_to_int(NSColor *color) [NSApplication sharedApplication].applicationIconImage = [NSImage imageNamed:@"AppIcon"]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - for (unsigned i = 0; i < GBButtonCount; i++) { + for (unsigned i = 0; i < GBKeyboardButtonCount; i++) { if ([[defaults objectForKey:button_to_preference_name(i, 0)] isKindOfClass:[NSString class]]) { [defaults removeObjectForKey:button_to_preference_name(i, 0)]; } diff --git a/Cocoa/GBButtons.h b/Cocoa/GBButtons.h index 54a2f09..0939947 100644 --- a/Cocoa/GBButtons.h +++ b/Cocoa/GBButtons.h @@ -7,20 +7,24 @@ typedef enum { GBB, GBSelect, GBStart, + GBRapidA, + GBRapidB, GBTurbo, GBRewind, GBUnderclock, GBHotkey1, GBHotkey2, - GBJoypadButtonCount, - GBButtonCount = GBUnderclock + 1, - GBGameBoyButtonCount = GBStart + 1, + GBTotalButtonCount, + GBKeyboardButtonCount = GBUnderclock + 1, + GBPerPlayerButtonCount = GBRapidB + 1, } GBButton; #define GBJoyKitHotkey1 JOYButtonUsageGeneric0 + 0x100 #define GBJoyKitHotkey2 JOYButtonUsageGeneric0 + 0x101 +#define GBJoyKitRapidA JOYButtonUsageGeneric0 + 0x102 +#define GBJoyKitRapidB JOYButtonUsageGeneric0 + 0x103 -extern NSString const *GBButtonNames[GBJoypadButtonCount]; +extern NSString const *GBButtonNames[GBTotalButtonCount]; static inline NSString *n2s(uint64_t number) { diff --git a/Cocoa/GBButtons.m b/Cocoa/GBButtons.m index ef86738..b430a90 100644 --- a/Cocoa/GBButtons.m +++ b/Cocoa/GBButtons.m @@ -1,4 +1,4 @@ #import #import "GBButtons.h" -NSString const *GBButtonNames[] = {@"Right", @"Left", @"Up", @"Down", @"A", @"B", @"Select", @"Start", @"Turbo", @"Rewind", @"Slow-Motion", @"Hotkey 1", @"Hotkey 2"}; +NSString const *GBButtonNames[] = {@"Right", @"Left", @"Up", @"Down", @"A", @"B", @"Select", @"Start", @"Rapid A", @"Rapid B", @"Turbo", @"Rewind", @"Slow-Motion", @"Hotkey 1", @"Hotkey 2"}; diff --git a/Cocoa/GBPreferencesWindow.m b/Cocoa/GBPreferencesWindow.m index 7826d01..ee2be91 100644 --- a/Cocoa/GBPreferencesWindow.m +++ b/Cocoa/GBPreferencesWindow.m @@ -40,16 +40,16 @@ static inline NSString *keyEquivalentString(NSMenuItem *item) - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { if (self.playerListButton.selectedTag == 0) { - return GBButtonCount; + return GBKeyboardButtonCount; } - return GBGameBoyButtonCount; + return GBPerPlayerButtonCount; } - (unsigned) usesForKey:(unsigned) key { unsigned ret = 0; for (unsigned player = 4; player--;) { - for (unsigned button = player == 0? GBButtonCount:GBGameBoyButtonCount; button--;) { + for (unsigned button = player == 0? GBKeyboardButtonCount:GBPerPlayerButtonCount; button--;) { NSNumber *other = [[NSUserDefaults standardUserDefaults] valueForKey:button_to_preference_name(button, player)]; if (other && [other unsignedIntValue] == key) { ret++; @@ -205,7 +205,7 @@ static inline NSString *keyEquivalentString(NSMenuItem *item) if (joystick_configuration_state == GBUnderclock) { [self.configureJoypadButton setTitle:@"Press Button for Slo-Mo"]; // Full name is too long :< } - else if (joystick_configuration_state < GBJoypadButtonCount) { + else if (joystick_configuration_state < GBTotalButtonCount) { [self.configureJoypadButton setTitle:[NSString stringWithFormat:@"Press Button for %@", GBButtonNames[joystick_configuration_state]]]; } else { @@ -227,7 +227,7 @@ static inline NSString *keyEquivalentString(NSMenuItem *item) if (!button.isPressed) return; if (joystick_configuration_state == -1) return; - if (joystick_configuration_state == GBJoypadButtonCount) return; + if (joystick_configuration_state == GBTotalButtonCount) return; if (!joystick_being_configured) { joystick_being_configured = controller.uniqueID; } @@ -266,6 +266,8 @@ static inline NSString *keyEquivalentString(NSMenuItem *item) [GBB] = JOYButtonUsageB, [GBSelect] = JOYButtonUsageSelect, [GBStart] = JOYButtonUsageStart, + [GBRapidA] = GBJoyKitRapidA, + [GBRapidB] = GBJoyKitRapidB, [GBTurbo] = JOYButtonUsageL1, [GBRewind] = JOYButtonUsageL2, [GBUnderclock] = JOYButtonUsageR1, diff --git a/Cocoa/GBView.m b/Cocoa/GBView.m index 14b66e1..ee0d783 100644 --- a/Cocoa/GBView.m +++ b/Cocoa/GBView.m @@ -119,6 +119,9 @@ static const uint8_t workboy_vk_to_key[] = { bool _mouseControlEnabled; NSMutableDictionary *_controllerMapping; unsigned _lastPlayerCount; + + bool _rapidA[4], _rapidB[4]; + uint8_t _rapidACount[4], _rapidBCount[4]; } + (instancetype)alloc @@ -343,6 +346,17 @@ static const uint8_t workboy_vk_to_key[] = { (analogClockMultiplierValid && analogClockMultiplier < 1)) { [self.osdView displayText:@"Slow motion…"]; } + + for (unsigned i = GB_get_player_count(_gb); i--;) { + if (_rapidA[i]) { + _rapidACount[i]++; + GB_set_key_state_for_player(_gb, GB_KEY_A, i, !(_rapidACount[i] & 2)); + } + if (_rapidB[i]) { + _rapidBCount[i]++; + GB_set_key_state_for_player(_gb, GB_KEY_B, i, !(_rapidBCount[i] & 2)); + } + } [super flip]; } @@ -370,7 +384,7 @@ static const uint8_t workboy_vk_to_key[] = { player_count = 2; } for (unsigned player = 0; player < player_count; player++) { - for (GBButton button = 0; button < GBButtonCount; button++) { + for (GBButton button = 0; button < GBKeyboardButtonCount; button++) { NSNumber *key = [defaults valueForKey:button_to_preference_name(button, player)]; if (!key) continue; @@ -401,6 +415,18 @@ static const uint8_t workboy_vk_to_key[] = { analogClockMultiplierValid = false; break; + case GBRapidA: + _rapidA[player] = true; + _rapidACount[player] = 0; + GB_set_key_state_for_player(_gb, GB_KEY_A, player, true); + break; + + case GBRapidB: + _rapidB[player] = true; + _rapidBCount[player] = 0; + GB_set_key_state_for_player(_gb, GB_KEY_B, player, true); + break; + default: if (self.document.partner) { if (player == 0) { @@ -444,7 +470,7 @@ static const uint8_t workboy_vk_to_key[] = { player_count = 2; } for (unsigned player = 0; player < player_count; player++) { - for (GBButton button = 0; button < GBButtonCount; button++) { + for (GBButton button = 0; button < GBKeyboardButtonCount; button++) { NSNumber *key = [defaults valueForKey:button_to_preference_name(button, player)]; if (!key) continue; @@ -470,6 +496,16 @@ static const uint8_t workboy_vk_to_key[] = { underclockKeyDown = false; analogClockMultiplierValid = false; break; + + case GBRapidA: + _rapidA[player] = false; + GB_set_key_state_for_player(_gb, GB_KEY_A, player, false); + break; + + case GBRapidB: + _rapidB[player] = false; + GB_set_key_state_for_player(_gb, GB_KEY_B, player, false); + break; default: if (self.document.partner) { @@ -651,7 +687,7 @@ static const uint8_t workboy_vk_to_key[] = { } } - switch (usage) { + switch ((unsigned)usage) { case JOYButtonUsageNone: break; case JOYButtonUsageA: GB_set_key_state_for_player(effectiveGB, GB_KEY_A, effectivePlayer, button.isPressed); break; @@ -696,7 +732,16 @@ static const uint8_t workboy_vk_to_key[] = { case JOYButtonUsageDPadUp: GB_set_key_state_for_player(effectiveGB, GB_KEY_UP, effectivePlayer, button.isPressed); break; case JOYButtonUsageDPadDown: GB_set_key_state_for_player(effectiveGB, GB_KEY_DOWN, effectivePlayer, button.isPressed); break; - default: + case GBJoyKitRapidA: + _rapidA[effectivePlayer] = button.isPressed; + _rapidACount[effectivePlayer] = 0; + GB_set_key_state_for_player(_gb, GB_KEY_A, effectivePlayer, button.isPressed); + break; + + case GBJoyKitRapidB: + _rapidB[effectivePlayer] = button.isPressed; + _rapidBCount[effectivePlayer] = 0; + GB_set_key_state_for_player(_gb, GB_KEY_B, effectivePlayer, button.isPressed); break; } } diff --git a/Cocoa/PopoverView.xib b/Cocoa/PopoverView.xib index 7ccdf49..dbaa2f5 100644 --- a/Cocoa/PopoverView.xib +++ b/Cocoa/PopoverView.xib @@ -1,8 +1,8 @@ - + - + @@ -13,7 +13,7 @@ - + diff --git a/Cocoa/Preferences.xib b/Cocoa/Preferences.xib index 0d1153e..7c38b54 100644 --- a/Cocoa/Preferences.xib +++ b/Cocoa/Preferences.xib @@ -986,15 +986,15 @@ - + - - - + + + - - + + @@ -1044,7 +1044,7 @@ - + @@ -1053,7 +1053,7 @@ - + diff --git a/SDL/configuration.h b/SDL/configuration.h index 7b5275d..a3739a4 100644 --- a/SDL/configuration.h +++ b/SDL/configuration.h @@ -11,6 +11,27 @@ enum scaling_mode { GB_SDL_SCALING_MAX, }; +enum { + GB_CONF_KEYS_RIGHT = GB_KEY_RIGHT, + GB_CONF_KEYS_LEFT = GB_KEY_LEFT, + GB_CONF_KEYS_UP = GB_KEY_UP, + GB_CONF_KEYS_DOWN = GB_KEY_DOWN, + GB_CONF_KEYS_A = GB_KEY_A, + GB_CONF_KEYS_B = GB_KEY_B, + GB_CONF_KEYS_SELECT = GB_KEY_SELECT, + GB_CONF_KEYS_START = GB_KEY_START, + GB_CONF_KEYS_TURBO, + GB_CONF_KEYS_COUNT, +}; + +enum { + GB_CONF_KEYS2_REWIND, + GB_CONF_KEYS2_UNDERCLOCK, + GB_CONF_KEYS2_RAPID_A, + GB_CONF_KEYS2_RAPID_B, + GB_CONF_KEYS2_COUNT = 32, +}; + typedef enum { JOYPAD_BUTTON_RIGHT, JOYPAD_BUTTON_LEFT, @@ -26,6 +47,8 @@ typedef enum { JOYPAD_BUTTON_SLOW_MOTION, JOYPAD_BUTTON_HOTKEY_1, JOYPAD_BUTTON_HOTKEY_2, + JOYPAD_BUTTON_RAPID_A, + JOYPAD_BUTTON_RAPID_B, JOYPAD_BUTTONS_MAX } joypad_button_t; @@ -65,7 +88,7 @@ typedef enum { } hotkey_action_t; typedef struct { - SDL_Scancode keys[9]; + SDL_Scancode keys[GB_CONF_KEYS_COUNT]; GB_color_correction_mode_t color_correction_mode; enum scaling_mode scaling_mode; uint8_t blending_mode; @@ -89,7 +112,7 @@ typedef struct { /* v0.11 */ uint32_t rewind_length; - SDL_Scancode keys_2[32]; /* Rewind and underclock, + padding for the future */ + SDL_Scancode keys_2[GB_CONF_KEYS2_COUNT]; /* Rewind and underclock, + padding for the future */ uint8_t joypad_configuration[32]; /* 14 Keys + padding for the future*/; uint8_t joypad_axises[JOYPAD_AXISES_MAX]; diff --git a/SDL/gui.c b/SDL/gui.c index ffdb63d..712b083 100644 --- a/SDL/gui.c +++ b/SDL/gui.c @@ -1764,16 +1764,17 @@ static const struct menu_item keyboard_menu[] = { {"Turbo:", modify_key, key_name,}, {"Rewind:", modify_key, key_name,}, {"Slow-Motion:", modify_key, key_name,}, + {"Rapid A:", modify_key, key_name,}, + {"Rapid B:", modify_key, key_name,}, {"Back", enter_controls_menu}, {NULL,} }; static const char *key_name(unsigned index) { - if (index > 8) { - return SDL_GetScancodeName(configuration.keys_2[index - 9]); - } - return SDL_GetScancodeName(configuration.keys[index]); + SDL_Scancode code = index >= GB_CONF_KEYS_COUNT? configuration.keys_2[index - GB_CONF_KEYS_COUNT] : configuration.keys[index]; + if (!code) return "Not Set"; + return SDL_GetScancodeName(code); } static void enter_keyboard_menu(unsigned index) @@ -2532,7 +2533,7 @@ void run_gui(bool is_running) } else if (gui_state == WAITING_FOR_KEY) { if (current_selection > 8) { - configuration.keys_2[current_selection - 9] = event.key.keysym.scancode; + configuration.keys_2[current_selection - GB_CONF_KEYS_COUNT] = event.key.keysym.scancode; } else { configuration.keys[current_selection] = event.key.keysym.scancode; @@ -2773,6 +2774,8 @@ void run_gui(bool is_running) "Slow-Motion", "Hotkey 1", "Hotkey 2", + "Rapid A", + "Rapid B", "", }) [joypad_configuration_progress], gui_palette_native[3], gui_palette_native[0], STYLE_CENTER); diff --git a/SDL/main.c b/SDL/main.c index b38d6c5..af318b3 100644 --- a/SDL/main.c +++ b/SDL/main.c @@ -26,6 +26,8 @@ static bool paused = false; static uint32_t pixel_buffer_1[256 * 224], pixel_buffer_2[256 * 224]; static uint32_t *active_pixel_buffer = pixel_buffer_1, *previous_pixel_buffer = pixel_buffer_2; static bool underclock_down = false, rewind_down = false, do_rewind = false, rewind_paused = false, turbo_down = false; +static bool rapid_a = false, rapid_b = false; +static uint8_t rapid_a_count = 0, rapid_b_count = 0; static double clock_mutliplier = 1.0; char *filename = NULL; @@ -322,8 +324,18 @@ static void handle_events(GB_gameboy_t *gb) break; } } + else if (button == JOYPAD_BUTTON_RAPID_A) { + rapid_a = event.type == SDL_JOYBUTTONDOWN; + rapid_a_count = 0; + GB_set_key_state(gb, GB_KEY_A, event.type == SDL_JOYBUTTONDOWN); + } + else if (button == JOYPAD_BUTTON_RAPID_B) { + rapid_b = event.type == SDL_JOYBUTTONDOWN; + rapid_b_count = 0; + GB_set_key_state(gb, GB_KEY_B, event.type == SDL_JOYBUTTONDOWN); + } } - break; + break; case SDL_JOYAXISMOTION: { static bool axis_active[2] = {false, false}; @@ -475,21 +487,31 @@ static void handle_events(GB_gameboy_t *gb) break; } case SDL_KEYUP: // Fallthrough - if (event.key.keysym.scancode == configuration.keys[8]) { + if (event.key.keysym.scancode == configuration.keys[GB_CONF_KEYS_TURBO]) { turbo_down = event.type == SDL_KEYDOWN; GB_audio_clear_queue(); GB_set_turbo_mode(gb, turbo_down, turbo_down && rewind_down); } - else if (event.key.keysym.scancode == configuration.keys_2[0]) { + else if (event.key.keysym.scancode == configuration.keys_2[GB_CONF_KEYS2_REWIND]) { rewind_down = event.type == SDL_KEYDOWN; if (event.type == SDL_KEYUP) { rewind_paused = false; } GB_set_turbo_mode(gb, turbo_down, turbo_down && rewind_down); } - else if (event.key.keysym.scancode == configuration.keys_2[1]) { + else if (event.key.keysym.scancode == configuration.keys_2[GB_CONF_KEYS2_UNDERCLOCK]) { underclock_down = event.type == SDL_KEYDOWN; } + else if (event.key.keysym.scancode == configuration.keys_2[GB_CONF_KEYS2_RAPID_A]) { + rapid_a = event.type == SDL_KEYDOWN; + rapid_a_count = 0; + GB_set_key_state(gb, GB_KEY_A, event.type == SDL_KEYDOWN); + } + else if (event.key.keysym.scancode == configuration.keys_2[GB_CONF_KEYS2_RAPID_B]) { + rapid_b = event.type == SDL_KEYDOWN; + rapid_b_count = 0; + GB_set_key_state(gb, GB_KEY_B, event.type == SDL_KEYDOWN); + } else { for (unsigned i = 0; i < GB_KEY_MAX; i++) { if (event.key.keysym.scancode == configuration.keys[i]) { @@ -520,6 +542,15 @@ static void vblank(GB_gameboy_t *gb, GB_vblank_type_t type) GB_set_clock_multiplier(gb, clock_mutliplier); } + if (rapid_a) { + rapid_a_count++; + GB_set_key_state(gb, GB_KEY_A, !(rapid_a_count & 2)); + } + if (rapid_b) { + rapid_b_count++; + GB_set_key_state(gb, GB_KEY_B, !(rapid_b_count & 2)); + } + if (turbo_down) { show_osd_text("Fast forward..."); } diff --git a/iOS/GBSettingsViewController.h b/iOS/GBSettingsViewController.h index 5583cd6..679c931 100644 --- a/iOS/GBSettingsViewController.h +++ b/iOS/GBSettingsViewController.h @@ -17,9 +17,9 @@ typedef enum { GBUnderclock, // GBHotkey1, // Todo // GBHotkey2, // Todo - GBJoypadButtonCount, - GBButtonCount = GBUnderclock + 1, - GBGameBoyButtonCount = GBStart + 1, + GBTotalButtonCount, + GBKeyboardButtonCount = GBUnderclock + 1, + GBPerPlayerButtonCount = GBStart + 1, GBUnusedButton = 0xFF, } GBButton;