diff --git a/src/common/PJoystickHandler.cxx b/src/common/PJoystickHandler.cxx index 1a35cef63..173a7482d 100644 --- a/src/common/PJoystickHandler.cxx +++ b/src/common/PJoystickHandler.cxx @@ -378,8 +378,6 @@ void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type even // put all controller events into their own mode's mappings for (const auto& item : DefaultLeftJoystickMapping) setDefaultAction(stick, item, event, EventMode::kJoystickMode, updateDefaults); - for (const auto& item : DefaultLeftPaddlesMapping) - setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults); for (const auto& item : DefaultLeftKeyboardMapping) setDefaultAction(stick, item, event, EventMode::kKeyboardMode, updateDefaults); for (const auto& item : DefaultLeftDrivingMapping) @@ -390,13 +388,79 @@ void PhysicalJoystickHandler::setStickDefaultMapping(int stick, Event::Type even // put all controller events into their own mode's mappings for (const auto& item : DefaultRightJoystickMapping) setDefaultAction(stick, item, event, EventMode::kJoystickMode, updateDefaults); - for (const auto& item : DefaultRightPaddlesMapping) - setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults); for (const auto& item : DefaultRightKeyboardMapping) setDefaultAction(stick, item, event, EventMode::kKeyboardMode, updateDefaults); for (const auto& item : DefaultRightDrivingMapping) setDefaultAction(stick, item, event, EventMode::kDrivingMode, updateDefaults); } + +#if defined(RETRON77) + const bool retron77 = true; +#else + const bool retron77 = false; +#endif + + // Regular joysticks can only be used by one player at a time, + // so we need to separate the paddles onto different + // devices. The R77 controllers support two players each when + // used as paddles, so are different. Similarly, stelladaptors + // and 2600-daptors support two players natively. + const int paddlesPerJoystick = (j->type == PhysicalJoystick::Type::REGULAR && !retron77) ? 1 : 2; + + if( paddlesPerJoystick == 2 ) + { + if( useLeftMappings ) + { + for (const auto& item : DefaultLeftPaddlesMapping) + setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults); + } + else + { + for (const auto& item : DefaultRightPaddlesMapping) + setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults); + } + } + else + { + // One paddle per joystick means we need different defaults, + // such that each player gets the same mapping. + + // This mapping is: + // - stick 0: left paddle A + // - stick 1: left paddle B + // - stick 2: right paddle A + // - stick 3: right paddle B + const bool useLeftPaddleMappings = (stick % 4) < 2; + const bool useAPaddleMappings = (stick % 2) == 0; + + if( useLeftPaddleMappings ) + { + if( useAPaddleMappings ) + { + for (const auto& item : DefaultLeftAPaddlesMapping) + setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults); + } + else + { + for (const auto& item : DefaultLeftBPaddlesMapping) + setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults); + } + } + else + { + if( useAPaddleMappings ) + { + for (const auto& item : DefaultRightAPaddlesMapping) + setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults); + } + else + { + for (const auto& item : DefaultRightBPaddlesMapping) + setDefaultAction(stick, item, event, EventMode::kPaddlesMode, updateDefaults); + } + } + } + for(const auto& item : DefaultCommonMapping) setDefaultAction(stick, item, event, EventMode::kCommonMode, updateDefaults); // update running emulation mapping too @@ -1231,6 +1295,40 @@ PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultRight {Event::RightPaddleBFire, 1}, }; +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultLeftAPaddlesMapping = { + {Event::LeftPaddleAAnalog, JOY_CTRL_NONE, JoyAxis::X, JoyDir::ANALOG}, + // Current code does NOT allow digital and anlog events on the same axis at the same time + //{Event::LeftPaddleADecrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS}, + //{Event::LeftPaddleAIncrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG}, + {Event::LeftPaddleAFire, 0}, +}; + +PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultLeftBPaddlesMapping = { + {Event::LeftPaddleBAnalog, JOY_CTRL_NONE, JoyAxis::X, JoyDir::ANALOG}, + // Current code does NOT allow digital and anlog events on the same axis at the same + //{Event::LeftPaddleBDecrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS}, + //{Event::LeftPaddleBIncrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG}, + {Event::LeftPaddleBFire, 0}, +}; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultRightAPaddlesMapping = { + {Event::RightPaddleAAnalog, JOY_CTRL_NONE, JoyAxis::X, JoyDir::ANALOG}, + // Current code does NOT allow digital and anlog events on the same axis at the same + //{Event::RightPaddleADecrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS}, + //{Event::RightPaddleAIncrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG}, + {Event::RightPaddleAFire, 0}, +}; + +PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultRightBPaddlesMapping = { + {Event::RightPaddleBAnalog, JOY_CTRL_NONE, JoyAxis::X, JoyDir::ANALOG}, + // Current code does NOT allow digital and anlog events on the same axis at the same + //{Event::RightPaddleBDecrease,JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS}, + //{Event::RightPaddleBIncrease,JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG}, + {Event::RightPaddleBFire, 0}, +}; + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultLeftKeyboardMapping = { {Event::LeftKeyboard1, 0}, diff --git a/src/common/PJoystickHandler.hxx b/src/common/PJoystickHandler.hxx index 0b2f067a1..7a609b08c 100644 --- a/src/common/PJoystickHandler.hxx +++ b/src/common/PJoystickHandler.hxx @@ -201,6 +201,10 @@ class PhysicalJoystickHandler static EventMappingArray DefaultRightJoystickMapping; static EventMappingArray DefaultLeftPaddlesMapping; static EventMappingArray DefaultRightPaddlesMapping; + static EventMappingArray DefaultLeftAPaddlesMapping; + static EventMappingArray DefaultLeftBPaddlesMapping; + static EventMappingArray DefaultRightAPaddlesMapping; + static EventMappingArray DefaultRightBPaddlesMapping; static EventMappingArray DefaultLeftKeyboardMapping; static EventMappingArray DefaultRightKeyboardMapping; static EventMappingArray DefaultLeftDrivingMapping; diff --git a/src/emucore/Paddles.cxx b/src/emucore/Paddles.cxx index 3c9dfdcec..d17428fb3 100644 --- a/src/emucore/Paddles.cxx +++ b/src/emucore/Paddles.cxx @@ -155,12 +155,16 @@ void Paddles::swapEvents(Event::Type& event1, Event::Type& event2) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Paddles::update() { - setPin(DigitalPin::Three, true); + updateA(); + updateB(); +} + +void Paddles::updateA() +{ setPin(DigitalPin::Four, true); // Digital events (from keyboard or joystick hats & buttons) bool firePressedA = myEvent.get(myLeftAFireEvent) != 0; - bool firePressedB = myEvent.get(myLeftBFireEvent) != 0; // Paddle movement is a very difficult thing to accurately emulate, // since it originally came from an analog device that had very @@ -173,17 +177,12 @@ void Paddles::update() // And to top it all off, we don't want one devices input to conflict // with the others ... - if(!updateAnalogAxes()) + if(!updateAnalogAxesA()) { - updateMouse(firePressedA, firePressedB); - updateDigitalAxes(); + updateMouseA(firePressedA); + updateDigitalAxesA(); // Only change state if the charge has actually changed - if(myCharge[1] != myLastCharge[1]) - { - setPin(AnalogPin::Five, AnalogReadout::connectToVcc(MAX_RESISTANCE * (myCharge[1] / double(TRIGMAX)))); - myLastCharge[1] = myCharge[1]; - } if(myCharge[0] != myLastCharge[0]) { setPin(AnalogPin::Nine, AnalogReadout::connectToVcc(MAX_RESISTANCE * (myCharge[0] / double(TRIGMAX)))); @@ -192,7 +191,6 @@ void Paddles::update() } setPin(DigitalPin::Four, !getAutoFireState(firePressedA)); - setPin(DigitalPin::Three, !getAutoFireStateP1(firePressedB)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -251,7 +249,7 @@ AnalogReadout::Connection Paddles::getReadOut(int lastAxis, int& newAxis, int ce } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool Paddles::updateAnalogAxes() +bool Paddles::updateAnalogAxesA() { // Analog axis events from Stelladaptor-like devices, // (which includes analog USB controllers) @@ -264,7 +262,6 @@ bool Paddles::updateAnalogAxes() int sa_xaxis = myEvent.get(myAAxisValue); - int sa_yaxis = myEvent.get(myBAxisValue); bool sa_changed = false; if(abs(myLastAxisX - sa_xaxis) > 10) @@ -273,71 +270,52 @@ bool Paddles::updateAnalogAxes() sa_changed = true; } - if(abs(myLastAxisY - sa_yaxis) > 10) - { - setPin(AnalogPin::Five, getReadOut(myLastAxisY, sa_yaxis, YCENTER)); - sa_changed = true; - } myLastAxisX = sa_xaxis; - myLastAxisY = sa_yaxis; - return sa_changed; } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Paddles::updateMouse(bool& firePressedA, bool& firePressedB) +void Paddles::updateMouseA(bool& firePressedA) { // Mouse motion events give relative movement // That is, they're only relevant if they're non-zero - if(myMPaddleID > -1) + if(myMPaddleID == 0) { // We're in auto mode, where a single axis is used for one paddle only myCharge[myMPaddleID] = BSPF::clamp(myCharge[myMPaddleID] - (myEvent.get(myAxisMouseMotion) * MOUSE_SENSITIVITY), TRIGMIN, TRIGRANGE); - if(myMPaddleID == 0) - firePressedA = firePressedA - || myEvent.get(Event::MouseButtonLeftValue) - || myEvent.get(Event::MouseButtonRightValue); - else - firePressedB = firePressedB - || myEvent.get(Event::MouseButtonLeftValue) - || myEvent.get(Event::MouseButtonRightValue); + firePressedA = firePressedA + || myEvent.get(Event::MouseButtonLeftValue) + || myEvent.get(Event::MouseButtonRightValue); } else { // Test for 'untied' mouse axis mode, where each axis is potentially // mapped to a separate paddle - if(myMPaddleIDX > -1) + if(myMPaddleIDX == 0) { myCharge[myMPaddleIDX] = BSPF::clamp(myCharge[myMPaddleIDX] - (myEvent.get(Event::MouseAxisXMove) * MOUSE_SENSITIVITY), TRIGMIN, TRIGRANGE); - if(myMPaddleIDX == 0) - firePressedA = firePressedA - || myEvent.get(Event::MouseButtonLeftValue); - else - firePressedB = firePressedB - || myEvent.get(Event::MouseButtonLeftValue); + firePressedA = firePressedA + || myEvent.get(Event::MouseButtonLeftValue); } - if(myMPaddleIDY > -1) + if(myMPaddleIDY == 0) { myCharge[myMPaddleIDY] = BSPF::clamp(myCharge[myMPaddleIDY] - (myEvent.get(Event::MouseAxisYMove) * MOUSE_SENSITIVITY), TRIGMIN, TRIGRANGE); - if(myMPaddleIDY == 0) - firePressedA = firePressedA - || myEvent.get(Event::MouseButtonRightValue); - else - firePressedB = firePressedB - || myEvent.get(Event::MouseButtonRightValue); + firePressedA = firePressedA + || myEvent.get(Event::MouseButtonRightValue); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Paddles::updateDigitalAxes() +void Paddles::updateDigitalAxesA() { // Finally, consider digital input, where movement happens // until a digital event is released @@ -347,15 +325,8 @@ void Paddles::updateDigitalAxes() if(myPaddleRepeatA > DIGITAL_SENSITIVITY) myPaddleRepeatA = DIGITAL_DISTANCE; } - if(myKeyRepeatB) - { - myPaddleRepeatB++; - if(myPaddleRepeatB > DIGITAL_SENSITIVITY) - myPaddleRepeatB = DIGITAL_DISTANCE; - } myKeyRepeatA = false; - myKeyRepeatB = false; if(myEvent.get(myLeftADecEvent)) { @@ -369,6 +340,100 @@ void Paddles::updateDigitalAxes() if((myCharge[myAxisDigitalZero] + myPaddleRepeatA) < TRIGRANGE) myCharge[myAxisDigitalZero] += myPaddleRepeatA; } +} + +void Paddles::updateB() +{ + setPin(DigitalPin::Three, true); + + // Digital events (from keyboard or joystick hats & buttons) + bool firePressedB = myEvent.get(myLeftBFireEvent) != 0; + + if(!updateAnalogAxesB()) + { + updateMouseB(firePressedB); + updateDigitalAxesB(); + + // Only change state if the charge has actually changed + if(myCharge[1] != myLastCharge[1]) + { + setPin(AnalogPin::Five, AnalogReadout::connectToVcc(MAX_RESISTANCE * (myCharge[1] / double(TRIGMAX)))); + myLastCharge[1] = myCharge[1]; + } + } + + setPin(DigitalPin::Three, !getAutoFireStateP1(firePressedB)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool Paddles::updateAnalogAxesB() +{ + int sa_yaxis = myEvent.get(myBAxisValue); + bool sa_changed = false; + + if(abs(myLastAxisY - sa_yaxis) > 10) + { + setPin(AnalogPin::Five, getReadOut(myLastAxisY, sa_yaxis, YCENTER)); + sa_changed = true; + } + + myLastAxisY = sa_yaxis; + return sa_changed; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Paddles::updateMouseB(bool& firePressedB) +{ + // Mouse motion events give relative movement + // That is, they're only relevant if they're non-zero + if(myMPaddleID == 1) + { + // We're in auto mode, where a single axis is used for one paddle only + myCharge[myMPaddleID] = BSPF::clamp(myCharge[myMPaddleID] - + (myEvent.get(myAxisMouseMotion) * MOUSE_SENSITIVITY), + TRIGMIN, TRIGRANGE); + + firePressedB = firePressedB + || myEvent.get(Event::MouseButtonLeftValue) + || myEvent.get(Event::MouseButtonRightValue); + } + else + { + // Test for 'untied' mouse axis mode, where each axis is potentially + // mapped to a separate paddle + if(myMPaddleIDX == 1) + { + myCharge[myMPaddleIDX] = BSPF::clamp(myCharge[myMPaddleIDX] - + (myEvent.get(Event::MouseAxisXMove) * MOUSE_SENSITIVITY), + TRIGMIN, TRIGRANGE); + firePressedB = firePressedB + || myEvent.get(Event::MouseButtonLeftValue); + } + if(myMPaddleIDY == 1) + { + myCharge[myMPaddleIDY] = BSPF::clamp(myCharge[myMPaddleIDY] - + (myEvent.get(Event::MouseAxisYMove) * MOUSE_SENSITIVITY), + TRIGMIN, TRIGRANGE); + firePressedB = firePressedB + || myEvent.get(Event::MouseButtonRightValue); + } + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Paddles::updateDigitalAxesB() +{ + // Finally, consider digital input, where movement happens + // until a digital event is released + if(myKeyRepeatB) + { + myPaddleRepeatB++; + if(myPaddleRepeatB > DIGITAL_SENSITIVITY) + myPaddleRepeatB = DIGITAL_DISTANCE; + } + + myKeyRepeatB = false; + if(myEvent.get(myLeftBDecEvent)) { myKeyRepeatB = true; diff --git a/src/emucore/Paddles.hxx b/src/emucore/Paddles.hxx index fad15d707..e689cc4de 100644 --- a/src/emucore/Paddles.hxx +++ b/src/emucore/Paddles.hxx @@ -206,20 +206,26 @@ class Paddles : public Controller AnalogReadout::Connection getReadOut(int lastAxis, int& newAxis, int center); + void updateA(); + void updateB(); + /** Update the axes pin state according to the events currently set. */ - bool updateAnalogAxes(); + bool updateAnalogAxesA(); + bool updateAnalogAxesB(); /** Update the entire state according to mouse events currently set. */ - void updateMouse(bool& firePressedA, bool& firePressedB); + void updateMouseA(bool& firePressedA); + void updateMouseB(bool& firePressedB); /** Update the axes pin state according to the keyboard events currently set. */ - void updateDigitalAxes(); + void updateDigitalAxesA(); + void updateDigitalAxesB(); private: // Following constructors and assignment operators not supported