diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiJoystickMachine.cpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiJoystickMachine.cpp index 526b43749..70255b13e 100644 --- a/Analyser/Dynamic/MultiMachine/Implementation/MultiJoystickMachine.cpp +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiJoystickMachine.cpp @@ -81,6 +81,6 @@ MultiJoystickMachine::MultiJoystickMachine(const std::vector> &MultiJoystickMachine::get_joysticks() { +const std::vector> &MultiJoystickMachine::get_joysticks() { return joysticks_; } diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiJoystickMachine.hpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiJoystickMachine.hpp index f755d3061..6425a9a0a 100644 --- a/Analyser/Dynamic/MultiMachine/Implementation/MultiJoystickMachine.hpp +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiJoystickMachine.hpp @@ -28,7 +28,7 @@ class MultiJoystickMachine: public JoystickMachine::Machine { MultiJoystickMachine(const std::vector> &machines); // Below is the standard JoystickMachine::Machine interface; see there for documentation. - std::vector> &get_joysticks() override; + const std::vector> &get_joysticks() override; private: std::vector> joysticks_; diff --git a/Components/6850/6850.cpp b/Components/6850/6850.cpp index c61c4bb4d..9b08ca8eb 100644 --- a/Components/6850/6850.cpp +++ b/Components/6850/6850.cpp @@ -25,7 +25,6 @@ uint8_t ACIA::read(int address) { received_data_ |= NoValueMask; return uint8_t(received_data_); } else { - clear_interrupt_cause(StatusNeedsRead); return ((received_data_ & NoValueMask) ? 0x00 : 0x01) | ((next_transmission_ == NoValueMask) ? 0x02 : 0x00) | @@ -176,7 +175,7 @@ void ACIA::set_interrupt_delegate(InterruptDelegate *delegate) { void ACIA::add_interrupt_cause(int cause) { const bool is_changing_state = !interrupt_causes_; - interrupt_causes_ |= cause | StatusNeedsRead; + interrupt_causes_ |= cause; if(interrupt_delegate_ && is_changing_state) interrupt_delegate_->acia6850_did_change_interrupt_status(this); } diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index 6ebd9d5b6..bf869cf12 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -604,7 +604,7 @@ class KeyboardState: public GI::AY38910::PortHandler { memset(rows_, 0xff, sizeof(rows_)); } - std::vector> &get_joysticks() { + const std::vector> &get_joysticks() { return joysticks_; } @@ -1093,7 +1093,7 @@ template class ConcreteMachine: } // MARK: - Joysticks - std::vector> &get_joysticks() override { + const std::vector> &get_joysticks() override { return key_state_.get_joysticks(); } diff --git a/Machines/Apple/AppleII/AppleII.cpp b/Machines/Apple/AppleII/AppleII.cpp index 3757092e1..f561059ca 100644 --- a/Machines/Apple/AppleII/AppleII.cpp +++ b/Machines/Apple/AppleII/AppleII.cpp @@ -893,7 +893,7 @@ template class ConcreteMachine: } // MARK: JoystickMachine - std::vector> &get_joysticks() override { + const std::vector> &get_joysticks() override { return joysticks_; } }; diff --git a/Machines/Atari/2600/Atari2600.cpp b/Machines/Atari/2600/Atari2600.cpp index 3b2afe210..f1bce4903 100644 --- a/Machines/Atari/2600/Atari2600.cpp +++ b/Machines/Atari/2600/Atari2600.cpp @@ -124,7 +124,7 @@ class ConcreteMachine: joysticks_.emplace_back(new Joystick(bus_.get(), 4, 1)); } - std::vector> &get_joysticks() override { + const std::vector> &get_joysticks() override { return joysticks_; } diff --git a/Machines/Atari/ST/AtariST.cpp b/Machines/Atari/ST/AtariST.cpp index e100043f8..413b94acb 100644 --- a/Machines/Atari/ST/AtariST.cpp +++ b/Machines/Atari/ST/AtariST.cpp @@ -9,6 +9,7 @@ #include "AtariST.hpp" #include "../../CRTMachine.hpp" +#include "../../JoystickMachine.hpp" #include "../../KeyboardMachine.hpp" #include "../../MouseMachine.hpp" #include "../../MediaTarget.hpp" @@ -49,6 +50,7 @@ class ConcreteMachine: public Motorola::MFP68901::MFP68901::InterruptDelegate, public DMAController::Delegate, public MouseMachine::Machine, + public JoystickMachine::Machine, public KeyboardMachine::MappedMachine, public Activity::Source, public MediaTarget::Machine, @@ -527,6 +529,11 @@ class ConcreteMachine: return &keyboard_mapper_; } + // MARK: - JoystickMachine + const std::vector> &get_joysticks() final { + return ikbd_.get_joysticks(); + } + // MARK: - AYPortHandler void set_port_output(bool port_b, uint8_t value) final { if(port_b) { diff --git a/Machines/Atari/ST/IntelligentKeyboard.cpp b/Machines/Atari/ST/IntelligentKeyboard.cpp index c644508b5..17975563e 100644 --- a/Machines/Atari/ST/IntelligentKeyboard.cpp +++ b/Machines/Atari/ST/IntelligentKeyboard.cpp @@ -14,6 +14,10 @@ IntelligentKeyboard::IntelligentKeyboard(Serial::Line &input, Serial::Line &outp input.set_read_delegate(this, Storage::Time(2, 15625)); output_line_.set_writer_clock_rate(15625); + // Add two joysticks into the mix. + joysticks_.emplace_back(new Joystick); + joysticks_.emplace_back(new Joystick); + mouse_button_state_ = 0; mouse_movement_[0] = 0; mouse_movement_[1] = 0; @@ -40,7 +44,7 @@ ClockingHint::Preference IntelligentKeyboard::preferred_clocking() { } void IntelligentKeyboard::run_for(HalfCycles duration) { - // Take this opportunity to check for mouse and keyboard events, + // Take this opportunity to check for joystick, mouse and keyboard events, // which will have been received asynchronously. if(mouse_mode_ == MouseMode::Relative) { const int captured_movement[2] = { mouse_movement_[0].load(), mouse_movement_[1].load() }; @@ -55,7 +59,7 @@ void IntelligentKeyboard::run_for(HalfCycles duration) { post_relative_mouse_event(captured_movement[0], captured_movement[1]); } } else { - + // TODO: absolute-mode mouse updates. } // Forward key changes; implicit assumption here: mutexs are cheap while there's @@ -68,6 +72,17 @@ void IntelligentKeyboard::run_for(HalfCycles duration) { key_queue_.clear(); } + // Check for joystick changes. + for(size_t c = 0; c < 2; ++c) { + const auto joystick = static_cast(joysticks_[c].get()); + if(joystick->has_event()) { + output_bytes({ + uint8_t(0xfe | c), + joystick->get_state() + }); + } + } + output_line_.advance_writer(duration); } @@ -152,10 +167,30 @@ void IntelligentKeyboard::dispatch_command(uint8_t command) { case 0x12: disable_mouse(); break; case 0x13: pause(); break; - case 0x14: set_joystick_event_mode(); break; - case 0x15: set_joystick_interrogation_mode(); break; - case 0x16: interrogate_joysticks(); break; - case 0x1a: disable_joysticks(); break; + /* Joystick commands. */ + case 0x14: set_joystick_event_mode(); break; + case 0x15: set_joystick_interrogation_mode(); break; + case 0x16: interrogate_joysticks(); break; + case 0x17: + if(command_sequence_.size() != 2) return; + set_joystick_monitoring_mode(command_sequence_[1]); + break; + case 0x18: set_joystick_fire_button_monitoring_mode(); break; + case 0x19: { + if(command_sequence_.size() != 7) return; + + VelocityThreshold horizontal, vertical; + horizontal.threshold = command_sequence_[1]; + horizontal.prior_rate = command_sequence_[3]; + horizontal.post_rate = command_sequence_[5]; + + vertical.threshold = command_sequence_[2]; + vertical.prior_rate = command_sequence_[4]; + vertical.post_rate = command_sequence_[6]; + + set_joystick_keycode_mode(horizontal, vertical); + } break; + case 0x1a: disable_joysticks(); break; } // There was no premature exit, so a complete command sequence must have been satisfied. @@ -346,9 +381,21 @@ void IntelligentKeyboard::set_joystick_interrogation_mode() { } void IntelligentKeyboard::interrogate_joysticks() { + const auto joystick1 = static_cast(joysticks_[0].get()); + const auto joystick2 = static_cast(joysticks_[1].get()); + output_bytes({ 0xfd, - 0x00, - 0x00 + joystick1->get_state(), + joystick2->get_state() }); } + +void IntelligentKeyboard::set_joystick_monitoring_mode(uint8_t rate) { +} + +void IntelligentKeyboard::set_joystick_fire_button_monitoring_mode() { +} + +void IntelligentKeyboard::set_joystick_keycode_mode(VelocityThreshold horizontal, VelocityThreshold vertical) { +} diff --git a/Machines/Atari/ST/IntelligentKeyboard.hpp b/Machines/Atari/ST/IntelligentKeyboard.hpp index f81cfcc08..488bc5aef 100644 --- a/Machines/Atari/ST/IntelligentKeyboard.hpp +++ b/Machines/Atari/ST/IntelligentKeyboard.hpp @@ -13,10 +13,13 @@ #include "../../../Components/Serial/Line.hpp" #include "../../KeyboardMachine.hpp" +#include "../../../Inputs/Joystick.hpp" #include "../../../Inputs/Mouse.hpp" #include #include +#include +#include namespace Atari { namespace ST { @@ -61,6 +64,10 @@ class IntelligentKeyboard: uint16_t mapped_key_for_key(Inputs::Keyboard::Key key) final; }; + const std::vector> &get_joysticks() { + return joysticks_; + } + private: // MARK: - Key queue. std::mutex key_queue_mutex_; @@ -123,11 +130,59 @@ class IntelligentKeyboard: void disable_joysticks(); void set_joystick_event_mode(); void set_joystick_interrogation_mode(); + void set_joystick_monitoring_mode(uint8_t rate); + void set_joystick_fire_button_monitoring_mode(); + struct VelocityThreshold { + uint8_t threshold; + uint8_t prior_rate; + uint8_t post_rate; + }; + void set_joystick_keycode_mode(VelocityThreshold horizontal, VelocityThreshold vertical); void interrogate_joysticks(); enum class JoystickMode { Disabled, Event, Interrogation } joystick_mode_ = JoystickMode::Event; + + class Joystick: public Inputs::ConcreteJoystick { + public: + Joystick() : + ConcreteJoystick({ + Input(Input::Up), + Input(Input::Down), + Input(Input::Left), + Input(Input::Right), + Input(Input::Fire, 0), + }) {} + + void did_set_input(const Input &input, bool is_active) override { + uint8_t mask = 0; + switch(input.type) { + default: return; + case Input::Up: mask = 0x01; break; + case Input::Down: mask = 0x02; break; + case Input::Left: mask = 0x04; break; + case Input::Right: mask = 0x08; break; + case Input::Fire: mask = 0x80; break; + } + + if(is_active) state_ |= mask; else state_ &= ~mask; + } + + uint8_t get_state() { + returned_state_ = state_; + return state_; + } + + bool has_event() { + return returned_state_ != state_; + } + + private: + uint8_t state_ = 0x00; + uint8_t returned_state_ = 0x00; + }; + std::vector> joysticks_; }; } diff --git a/Machines/ColecoVision/ColecoVision.cpp b/Machines/ColecoVision/ColecoVision.cpp index 371cca534..c3386d633 100644 --- a/Machines/ColecoVision/ColecoVision.cpp +++ b/Machines/ColecoVision/ColecoVision.cpp @@ -177,7 +177,7 @@ class ConcreteMachine: audio_queue_.flush(); } - std::vector> &get_joysticks() override { + const std::vector> &get_joysticks() override { return joysticks_; } diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index 4c65dc304..cb7682c80 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -494,7 +494,7 @@ class ConcreteMachine: keyboard_via_port_handler_->clear_all_keys(); } - std::vector> &get_joysticks() override { + const std::vector> &get_joysticks() override { return joysticks_; } diff --git a/Machines/JoystickMachine.hpp b/Machines/JoystickMachine.hpp index 15c74e2eb..ae884cc25 100644 --- a/Machines/JoystickMachine.hpp +++ b/Machines/JoystickMachine.hpp @@ -16,7 +16,7 @@ namespace JoystickMachine { class Machine { public: - virtual std::vector> &get_joysticks() = 0; + virtual const std::vector> &get_joysticks() = 0; }; } diff --git a/Machines/MSX/MSX.cpp b/Machines/MSX/MSX.cpp index 0c00ab83d..bed05c068 100644 --- a/Machines/MSX/MSX.cpp +++ b/Machines/MSX/MSX.cpp @@ -89,7 +89,7 @@ class AYPortHandler: public GI::AY38910::PortHandler { return 0xff; } - std::vector> &get_joysticks() { + const std::vector> &get_joysticks() { return joysticks_; } @@ -686,7 +686,7 @@ class ConcreteMachine: } // MARK: - Joysticks - std::vector> &get_joysticks() override { + const std::vector> &get_joysticks() override { return ay_port_handler_.get_joysticks(); } diff --git a/Machines/MasterSystem/MasterSystem.cpp b/Machines/MasterSystem/MasterSystem.cpp index a005b4e3d..b32453eda 100644 --- a/Machines/MasterSystem/MasterSystem.cpp +++ b/Machines/MasterSystem/MasterSystem.cpp @@ -340,7 +340,7 @@ class ConcreteMachine: audio_queue_.perform(); } - std::vector> &get_joysticks() override { + const std::vector> &get_joysticks() override { return joysticks_; } diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index a8160f139..5723930f6 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -268,7 +268,7 @@ struct ActivityObserver: public Activity::Observer { // Until then, apply a default mapping. size_t c = 0; - std::vector> &machine_joysticks = _joystickMachine->get_joysticks(); + auto &machine_joysticks = _joystickMachine->get_joysticks(); for(CSJoystick *joystick in _joystickManager.joysticks) { size_t target = c % machine_joysticks.size(); ++c; @@ -373,7 +373,7 @@ struct ActivityObserver: public Activity::Observer { @synchronized(self) { _joystickManager = joystickManager; if(_joystickMachine) { - std::vector> &machine_joysticks = _joystickMachine->get_joysticks(); + auto &machine_joysticks = _joystickMachine->get_joysticks(); for(const auto &joystick: machine_joysticks) { joystick->reset_all_inputs(); } @@ -467,7 +467,7 @@ struct ActivityObserver: public Activity::Observer { auto joystick_machine = _machine->joystick_machine(); if(self.inputMode == CSMachineKeyboardInputModeJoystick && joystick_machine) { @synchronized(self) { - std::vector> &joysticks = joystick_machine->get_joysticks(); + auto &joysticks = joystick_machine->get_joysticks(); if(!joysticks.empty()) { // Convert to a C++ bool so that the following calls are resolved correctly even if overloaded. bool is_pressed = !!isPressed; diff --git a/OSBindings/SDL/main.cpp b/OSBindings/SDL/main.cpp index cde2106fa..337c5c26b 100644 --- a/OSBindings/SDL/main.cpp +++ b/OSBindings/SDL/main.cpp @@ -741,7 +741,7 @@ int main(int argc, char *argv[]) { JoystickMachine::Machine *const joystick_machine = machine->joystick_machine(); if(joystick_machine) { - std::vector> &joysticks = joystick_machine->get_joysticks(); + auto &joysticks = joystick_machine->get_joysticks(); if(!joysticks.empty()) { switch(event.key.keysym.scancode) { case SDL_SCANCODE_LEFT: joysticks[0]->set_input(Inputs::Joystick::Input::Left, is_pressed); break; @@ -791,7 +791,7 @@ 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(); + auto &machine_joysticks = joystick_machine->get_joysticks(); for(size_t c = 0; c < joysticks.size(); ++c) { size_t target = c % machine_joysticks.size();