From 678bd93c52df60468d1a09cb4f3e99c8a16ef63b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 14 Jun 2018 22:37:44 -0400 Subject: [PATCH 1/4] Connects SDL joystick input to joystick machines. --- OSBindings/SDL/main.cpp | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/OSBindings/SDL/main.cpp b/OSBindings/SDL/main.cpp index 8fa5f9abb..8f23a0002 100644 --- a/OSBindings/SDL/main.cpp +++ b/OSBindings/SDL/main.cpp @@ -390,9 +390,9 @@ int main(int argc, char *argv[]) { int window_width, window_height; SDL_GetWindowSize(window, &window_width, &window_height); - // Establish user-friendly options by default. - Configurable::Device *configurable_device = machine->configurable_device(); + Configurable::Device *const configurable_device = machine->configurable_device(); if(configurable_device) { + // Establish user-friendly options by default. configurable_device->set_selections(configurable_device->get_user_friendly_selections()); // Consider transcoding any list selections that map to Boolean options. @@ -410,9 +410,21 @@ int main(int argc, char *argv[]) { } } } + + // Apply the user's actual selections to override the defaults. configurable_device->set_selections(arguments.selections); } + // If this is a joystick machine, check for and open attached joysticks. + std::vector> joysticks; + JoystickMachine::Machine *const joystick_machine = machine->joystick_machine(); + if(joystick_machine) { + SDL_InitSubSystem(SDL_INIT_JOYSTICK); + for(int c = 0; c < SDL_NumJoysticks(); ++c) { + joysticks.emplace_back(SDL_JoystickOpen(c), &SDL_JoystickClose); + } + } + // Run the main event loop until the OS tells us to quit. bool should_quit = false; Uint32 fullscreen_mode = 0; @@ -510,6 +522,27 @@ int main(int argc, char *argv[]) { } } + // Push new joystick state, if any. + JoystickMachine::Machine *const joystick_machine = machine->joystick_machine(); + if(joystick_machine) { + std::vector> &machine_joysticks = joystick_machine->get_joysticks(); + for(size_t c = 0; c < joysticks.size(); ++c) { + size_t target = c % machine_joysticks.size(); + + const float x_axis = static_cast(SDL_JoystickGetAxis(joysticks[c].get(), 0) + 32768) / 65536.0f; + const float y_axis = static_cast(SDL_JoystickGetAxis(joysticks[c].get(), 1) + 32768) / 65536.0f; + machine_joysticks[target]->set_input(Inputs::Joystick::Input(Inputs::Joystick::Input::Type::Horizontal), x_axis); + machine_joysticks[target]->set_input(Inputs::Joystick::Input(Inputs::Joystick::Input::Type::Vertical), y_axis); + + const int number_of_buttons = SDL_JoystickNumButtons(joysticks[c].get()); + for(int button = 0; button < number_of_buttons; ++button) { + machine_joysticks[target]->set_input( + Inputs::Joystick::Input(Inputs::Joystick::Input::Type::Fire, button), + SDL_JoystickGetButton(joysticks[c].get(), button) ? true : false); + } + } + } + // Display a new frame and wait for vsync. updater.update(); machine->crt_machine()->get_crt()->draw_frame(static_cast(window_width), static_cast(window_height), false); @@ -517,6 +550,7 @@ int main(int argc, char *argv[]) { } // Clean up. + joysticks.clear(); SDL_DestroyWindow( window ); SDL_Quit(); From 83a654540a75c0575d39d10c3059d531922bee32 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 16 Jun 2018 22:22:14 -0400 Subject: [PATCH 2/4] Fixes threshold for positive movement. --- Inputs/Joystick.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Inputs/Joystick.hpp b/Inputs/Joystick.hpp index bb25f5e67..b07d1e027 100644 --- a/Inputs/Joystick.hpp +++ b/Inputs/Joystick.hpp @@ -188,11 +188,11 @@ class ConcreteJoystick: public Joystick { default: did_set_input(input, value > 0.5f); break; case Type::Horizontal: did_set_input(Input(Type::Left, input.info.control.index), value <= 0.25f); - did_set_input(Input(Type::Right, input.info.control.index), value >= 0.25f); + did_set_input(Input(Type::Right, input.info.control.index), value >= 0.75f); break; case Type::Vertical: did_set_input(Input(Type::Up, input.info.control.index), value <= 0.25f); - did_set_input(Input(Type::Down, input.info.control.index), value >= 0.25f); + did_set_input(Input(Type::Down, input.info.control.index), value >= 0.75f); break; } } From 6a3702a5c7c4f00f493665fc0b152f5651cd183b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 16 Jun 2018 22:22:40 -0400 Subject: [PATCH 3/4] Reduces space for floating point accuracy errors. --- Machines/AppleII/AppleII.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Machines/AppleII/AppleII.cpp b/Machines/AppleII/AppleII.cpp index 21305ad4a..533349964 100644 --- a/Machines/AppleII/AppleII.cpp +++ b/Machines/AppleII/AppleII.cpp @@ -584,7 +584,7 @@ class ConcreteMachine: } // Update analogue charge level. - analogue_charge_ = std::min(analogue_charge_ + 1.0f / 2820.0f, 1.0f); + analogue_charge_ = std::min(analogue_charge_ + 1.0f / 2820.0f, 1.1f); return Cycles(1); } From d437e06e15d2a722edcdd4c14f25d98ceb1f3ad9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 16 Jun 2018 22:25:46 -0400 Subject: [PATCH 4/4] Adds support for digital hat input as an alternative to analogue sticks. --- OSBindings/SDL/main.cpp | 76 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/OSBindings/SDL/main.cpp b/OSBindings/SDL/main.cpp index 8f23a0002..6101956cc 100644 --- a/OSBindings/SDL/main.cpp +++ b/OSBindings/SDL/main.cpp @@ -416,12 +416,49 @@ int main(int argc, char *argv[]) { } // If this is a joystick machine, check for and open attached joysticks. - std::vector> joysticks; + /*! + Provides a wrapper for SDL_Joystick pointers that can keep track + of historic hat values. + */ + class SDLJoystick { + public: + SDLJoystick(SDL_Joystick *joystick) : joystick_(joystick) { + hat_values_.resize(SDL_JoystickNumHats(joystick)); + } + + ~SDLJoystick() { + SDL_JoystickClose(joystick_); + } + + /// @returns The underlying SDL_Joystick. + SDL_Joystick *get() { + return joystick_; + } + + /// @returns A reference to the storage for the previous state of hat @c c. + Uint8 &last_hat_value(int c) { + return hat_values_[c]; + } + + /// @returns The logic OR of all stored hat states. + Uint8 hat_values() { + Uint8 value = 0; + for(const auto hat_value: hat_values_) { + value |= hat_value; + } + return value; + } + + private: + SDL_Joystick *joystick_; + std::vector hat_values_; + }; + std::vector joysticks; JoystickMachine::Machine *const joystick_machine = machine->joystick_machine(); if(joystick_machine) { SDL_InitSubSystem(SDL_INIT_JOYSTICK); for(int c = 0; c < SDL_NumJoysticks(); ++c) { - joysticks.emplace_back(SDL_JoystickOpen(c), &SDL_JoystickClose); + joysticks.emplace_back(SDL_JoystickOpen(c)); } } @@ -529,11 +566,38 @@ int main(int argc, char *argv[]) { for(size_t c = 0; c < joysticks.size(); ++c) { size_t target = c % machine_joysticks.size(); - const float x_axis = static_cast(SDL_JoystickGetAxis(joysticks[c].get(), 0) + 32768) / 65536.0f; - const float y_axis = static_cast(SDL_JoystickGetAxis(joysticks[c].get(), 1) + 32768) / 65536.0f; - machine_joysticks[target]->set_input(Inputs::Joystick::Input(Inputs::Joystick::Input::Type::Horizontal), x_axis); - machine_joysticks[target]->set_input(Inputs::Joystick::Input(Inputs::Joystick::Input::Type::Vertical), y_axis); + // Post the first two analogue axes presented by the controller as horizontal and vertical inputs, + // unless the user seems to be using a hat. + // SDL will return a value in the range [-32768, 32767], so map from that to [0, 1.0] + if(!joysticks[c].hat_values()) { + const float x_axis = static_cast(SDL_JoystickGetAxis(joysticks[c].get(), 0) + 32768) / 65535.0f; + const float y_axis = static_cast(SDL_JoystickGetAxis(joysticks[c].get(), 1) + 32768) / 65535.0f; + machine_joysticks[target]->set_input(Inputs::Joystick::Input(Inputs::Joystick::Input::Type::Horizontal), x_axis); + machine_joysticks[target]->set_input(Inputs::Joystick::Input(Inputs::Joystick::Input::Type::Vertical), y_axis); + } + // Forward hats as directions; hats always override analogue inputs. + const int number_of_hats = SDL_JoystickNumHats(joysticks[c].get()); + for(int hat = 0; hat < number_of_hats; ++hat) { + const Uint8 hat_value = SDL_JoystickGetHat(joysticks[c].get(), hat); + const Uint8 changes = hat_value ^ joysticks[c].last_hat_value(hat); + joysticks[c].last_hat_value(hat) = hat_value; + + if(changes & SDL_HAT_UP) { + machine_joysticks[target]->set_input(Inputs::Joystick::Input(Inputs::Joystick::Input::Type::Up), !!(hat_value & SDL_HAT_UP)); + } + if(changes & SDL_HAT_DOWN) { + machine_joysticks[target]->set_input(Inputs::Joystick::Input(Inputs::Joystick::Input::Type::Down), !!(hat_value & SDL_HAT_DOWN)); + } + if(changes & SDL_HAT_LEFT) { + machine_joysticks[target]->set_input(Inputs::Joystick::Input(Inputs::Joystick::Input::Type::Left), !!(hat_value & SDL_HAT_LEFT)); + } + if(changes & SDL_HAT_RIGHT) { + machine_joysticks[target]->set_input(Inputs::Joystick::Input(Inputs::Joystick::Input::Type::Right), !!(hat_value & SDL_HAT_RIGHT)); + } + } + + // Forward all fire buttons, retaining their original indices. const int number_of_buttons = SDL_JoystickNumButtons(joysticks[c].get()); for(int button = 0; button < number_of_buttons; ++button) { machine_joysticks[target]->set_input(