From cb16d20f2d4ed1ebf150b6ba4d64fe469c1263f1 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 21 Mar 2021 20:27:00 +0100 Subject: [PATCH] ControllerEmu: Add new "input override" system --- Source/Core/Core/HW/GCPadEmu.cpp | 13 +-- Source/Core/Core/HW/WiimoteEmu/Dynamics.cpp | 6 +- Source/Core/Core/HW/WiimoteEmu/Dynamics.h | 4 +- .../Core/HW/WiimoteEmu/Extension/Classic.cpp | 19 ++-- .../WiimoteEmu/Extension/DrawsomeTablet.cpp | 4 +- .../Core/HW/WiimoteEmu/Extension/Drums.cpp | 7 +- .../Core/HW/WiimoteEmu/Extension/Guitar.cpp | 15 +-- .../Core/HW/WiimoteEmu/Extension/Nunchuk.cpp | 37 +++++--- .../Core/HW/WiimoteEmu/Extension/TaTaCon.cpp | 4 +- .../HW/WiimoteEmu/Extension/Turntable.cpp | 13 +-- Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp | 95 ++++++++++++++++--- Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h | 14 ++- .../ControlGroup/AnalogStick.cpp | 29 ++++++ .../ControllerEmu/ControlGroup/AnalogStick.h | 2 + .../ControllerEmu/ControlGroup/Buttons.h | 17 ++++ .../ControllerEmu/ControlGroup/ControlGroup.h | 7 ++ .../ControllerEmu/ControlGroup/Cursor.cpp | 25 +++-- .../ControllerEmu/ControlGroup/Cursor.h | 3 + .../ControlGroup/MixedTriggers.cpp | 48 ++++++++++ .../ControlGroup/MixedTriggers.h | 2 + .../ControllerEmu/ControlGroup/Slider.cpp | 17 ++++ .../ControllerEmu/ControlGroup/Slider.h | 3 + .../ControllerEmu/ControlGroup/Triggers.cpp | 22 +++++ .../ControllerEmu/ControlGroup/Triggers.h | 1 + .../ControllerEmu/ControllerEmu.cpp | 12 +++ .../InputCommon/ControllerEmu/ControllerEmu.h | 6 ++ .../InputCommon/ControllerEmu/StickGate.h | 4 + 27 files changed, 355 insertions(+), 74 deletions(-) diff --git a/Source/Core/Core/HW/GCPadEmu.cpp b/Source/Core/Core/HW/GCPadEmu.cpp index e387d4765a..94f1605edb 100644 --- a/Source/Core/Core/HW/GCPadEmu.cpp +++ b/Source/Core/Core/HW/GCPadEmu.cpp @@ -138,14 +138,15 @@ GCPadStatus GCPad::GetInput() const const auto lock = GetStateLock(); GCPadStatus pad = {}; - if (!(m_always_connected_setting.GetValue() || IsDefaultDeviceConnected())) + if (!(m_always_connected_setting.GetValue() || IsDefaultDeviceConnected() || + m_input_override_function)) { pad.isConnected = false; return pad; } // buttons - m_buttons->GetState(&pad.button, button_bitmasks); + m_buttons->GetState(&pad.button, button_bitmasks, m_input_override_function); // set analog A/B analog to full or w/e, prolly not needed if (pad.button & PAD_BUTTON_A) @@ -154,20 +155,20 @@ GCPadStatus GCPad::GetInput() const pad.analogB = 0xFF; // dpad - m_dpad->GetState(&pad.button, dpad_bitmasks); + m_dpad->GetState(&pad.button, dpad_bitmasks, m_input_override_function); // sticks - const auto main_stick_state = m_main_stick->GetState(); + const auto main_stick_state = m_main_stick->GetState(m_input_override_function); pad.stickX = MapFloat(main_stick_state.x, GCPadStatus::MAIN_STICK_CENTER_X, 1); pad.stickY = MapFloat(main_stick_state.y, GCPadStatus::MAIN_STICK_CENTER_Y, 1); - const auto c_stick_state = m_c_stick->GetState(); + const auto c_stick_state = m_c_stick->GetState(m_input_override_function); pad.substickX = MapFloat(c_stick_state.x, GCPadStatus::C_STICK_CENTER_X, 1); pad.substickY = MapFloat(c_stick_state.y, GCPadStatus::C_STICK_CENTER_Y, 1); // triggers std::array triggers; - m_triggers->GetState(&pad.button, trigger_bitmasks, triggers.data()); + m_triggers->GetState(&pad.button, trigger_bitmasks, triggers.data(), m_input_override_function); pad.triggerLeft = MapFloat(triggers[0], 0); pad.triggerRight = MapFloat(triggers[1], 0); diff --git a/Source/Core/Core/HW/WiimoteEmu/Dynamics.cpp b/Source/Core/Core/HW/WiimoteEmu/Dynamics.cpp index 4b4109a119..dd21cd721a 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Dynamics.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Dynamics.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "Common/MathUtil.h" #include "Core/Config/SYSCONFSettings.h" @@ -221,9 +222,10 @@ WiimoteCommon::AccelData ConvertAccelData(const Common::Vec3& accel, u16 zero_g, u16(std::clamp(std::lround(scaled_accel.z + zero_g), 0l, MAX_VALUE))}); } -void EmulatePoint(MotionState* state, ControllerEmu::Cursor* ir_group, float time_elapsed) +void EmulatePoint(MotionState* state, ControllerEmu::Cursor* ir_group, + const ControllerEmu::InputOverrideFunction& override_func, float time_elapsed) { - const auto cursor = ir_group->GetState(true); + const auto cursor = ir_group->GetState(true, override_func); if (!cursor.IsVisible()) { diff --git a/Source/Core/Core/HW/WiimoteEmu/Dynamics.h b/Source/Core/Core/HW/WiimoteEmu/Dynamics.h index 2933fbb7c3..08b3cbda9a 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Dynamics.h +++ b/Source/Core/Core/HW/WiimoteEmu/Dynamics.h @@ -15,6 +15,7 @@ #include "InputCommon/ControllerEmu/ControlGroup/IMUCursor.h" #include "InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.h" #include "InputCommon/ControllerEmu/ControlGroup/Tilt.h" +#include "InputCommon/ControllerEmu/ControllerEmu.h" namespace WiimoteEmu { @@ -81,7 +82,8 @@ void ApproachAngleWithAccel(RotationalState* state, const Common::Vec3& target, void EmulateShake(PositionalState* state, ControllerEmu::Shake* shake_group, float time_elapsed); void EmulateTilt(RotationalState* state, ControllerEmu::Tilt* tilt_group, float time_elapsed); void EmulateSwing(MotionState* state, ControllerEmu::Force* swing_group, float time_elapsed); -void EmulatePoint(MotionState* state, ControllerEmu::Cursor* ir_group, float time_elapsed); +void EmulatePoint(MotionState* state, ControllerEmu::Cursor* ir_group, + const ControllerEmu::InputOverrideFunction& override_func, float time_elapsed); void EmulateIMUCursor(IMUCursorState* state, ControllerEmu::IMUCursor* imu_ir_group, ControllerEmu::IMUAccelerometer* imu_accelerometer_group, ControllerEmu::IMUGyroscope* imu_gyroscope_group, float time_elapsed); diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.cpp b/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.cpp index 3cdc02e0b3..24ab805a86 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.cpp @@ -113,7 +113,8 @@ void Classic::BuildDesiredExtensionState(DesiredExtensionState* target_state) // left stick { - const ControllerEmu::AnalogStick::StateData left_stick_state = m_left_stick->GetState(); + const ControllerEmu::AnalogStick::StateData left_stick_state = + m_left_stick->GetState(m_input_override_function); const u8 x = static_cast(LEFT_STICK_CENTER + (left_stick_state.x * LEFT_STICK_RADIUS)); const u8 y = static_cast(LEFT_STICK_CENTER + (left_stick_state.y * LEFT_STICK_RADIUS)); @@ -123,7 +124,8 @@ void Classic::BuildDesiredExtensionState(DesiredExtensionState* target_state) // right stick { - const ControllerEmu::AnalogStick::StateData right_stick_data = m_right_stick->GetState(); + const ControllerEmu::AnalogStick::StateData right_stick_data = + m_right_stick->GetState(m_input_override_function); const u8 x = static_cast(RIGHT_STICK_CENTER + (right_stick_data.x * RIGHT_STICK_RADIUS)); const u8 y = static_cast(RIGHT_STICK_CENTER + (right_stick_data.y * RIGHT_STICK_RADIUS)); @@ -135,19 +137,20 @@ void Classic::BuildDesiredExtensionState(DesiredExtensionState* target_state) // triggers { - ControlState trigs[2] = {0, 0}; - m_triggers->GetState(&buttons, classic_trigger_bitmasks.data(), trigs); + ControlState triggers[2] = {0, 0}; + m_triggers->GetState(&buttons, classic_trigger_bitmasks.data(), triggers, + m_input_override_function); - const u8 lt = static_cast(trigs[0] * TRIGGER_RANGE); - const u8 rt = static_cast(trigs[1] * TRIGGER_RANGE); + const u8 lt = static_cast(triggers[0] * TRIGGER_RANGE); + const u8 rt = static_cast(triggers[1] * TRIGGER_RANGE); classic_data.SetLeftTrigger(lt); classic_data.SetRightTrigger(rt); } // buttons and dpad - m_buttons->GetState(&buttons, classic_button_bitmasks.data()); - m_dpad->GetState(&buttons, classic_dpad_bitmasks.data()); + m_buttons->GetState(&buttons, classic_button_bitmasks.data(), m_input_override_function); + m_dpad->GetState(&buttons, classic_dpad_bitmasks.data(), m_input_override_function); classic_data.SetButtons(buttons); diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/DrawsomeTablet.cpp b/Source/Core/Core/HW/WiimoteEmu/Extension/DrawsomeTablet.cpp index 9a0d16790e..e093c9ac67 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/DrawsomeTablet.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/DrawsomeTablet.cpp @@ -47,7 +47,7 @@ void DrawsomeTablet::BuildDesiredExtensionState(DesiredExtensionState* target_st constexpr double CENTER_X = (MAX_X + MIN_X) / 2.0; constexpr double CENTER_Y = (MAX_Y + MIN_Y) / 2.0; - const auto stylus_state = m_stylus->GetState(); + const auto stylus_state = m_stylus->GetState(m_input_override_function); const auto stylus_x = u16(std::lround(CENTER_X + stylus_state.x * (MAX_X - CENTER_X))); const auto stylus_y = u16(std::lround(CENTER_Y + stylus_state.y * (MAX_Y - CENTER_Y))); @@ -74,7 +74,7 @@ void DrawsomeTablet::BuildDesiredExtensionState(DesiredExtensionState* target_st // Pressure (0 - 0x7ff): constexpr u16 MAX_PRESSURE = 0x7ff; - const auto touch_state = m_touch->GetState(); + const auto touch_state = m_touch->GetState(m_input_override_function); const auto pressure = u16(std::lround(touch_state.data[0] * MAX_PRESSURE)); tablet_data.pressure1 = u8(pressure); diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Drums.cpp b/Source/Core/Core/HW/WiimoteEmu/Extension/Drums.cpp index 0a37f278d2..01ca315843 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/Drums.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Drums.cpp @@ -84,17 +84,18 @@ void Drums::BuildDesiredExtensionState(DesiredExtensionState* target_state) DesiredState& state = target_state->data.emplace(); { - const ControllerEmu::AnalogStick::StateData stick_state = m_stick->GetState(); + const ControllerEmu::AnalogStick::StateData stick_state = + m_stick->GetState(m_input_override_function); state.stick_x = MapFloat(stick_state.x, STICK_CENTER, STICK_MIN, STICK_MAX); state.stick_y = MapFloat(stick_state.y, STICK_CENTER, STICK_MIN, STICK_MAX); } state.buttons = 0; - m_buttons->GetState(&state.buttons, drum_button_bitmasks.data()); + m_buttons->GetState(&state.buttons, drum_button_bitmasks.data(), m_input_override_function); state.drum_pads = 0; - m_pads->GetState(&state.drum_pads, drum_pad_bitmasks.data()); + m_pads->GetState(&state.drum_pads, drum_pad_bitmasks.data(), m_input_override_function); state.softness = u8(7 - std::lround(m_hit_strength_setting.GetValue() * 7 / 100)); } diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Guitar.cpp b/Source/Core/Core/HW/WiimoteEmu/Extension/Guitar.cpp index cd86a04a32..2776eaef87 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/Guitar.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Guitar.cpp @@ -101,7 +101,8 @@ void Guitar::BuildDesiredExtensionState(DesiredExtensionState* target_state) // stick { - const ControllerEmu::AnalogStick::StateData stick_state = m_stick->GetState(); + const ControllerEmu::AnalogStick::StateData stick_state = + m_stick->GetState(m_input_override_function); guitar_data.sx = static_cast((stick_state.x * STICK_RADIUS) + STICK_CENTER); guitar_data.sy = static_cast((stick_state.y * STICK_RADIUS) + STICK_CENTER); @@ -111,7 +112,8 @@ void Guitar::BuildDesiredExtensionState(DesiredExtensionState* target_state) if (m_slider_bar->controls[0]->control_ref->BoundCount() && m_slider_bar->controls[1]->control_ref->BoundCount()) { - const ControllerEmu::Slider::StateData slider_data = m_slider_bar->GetState(); + const ControllerEmu::Slider::StateData slider_data = + m_slider_bar->GetState(m_input_override_function); guitar_data.sb = s_slider_bar_control_codes.lower_bound(slider_data.value)->second; } @@ -122,17 +124,18 @@ void Guitar::BuildDesiredExtensionState(DesiredExtensionState* target_state) } // whammy bar - const ControllerEmu::Triggers::StateData whammy_state = m_whammy->GetState(); + const ControllerEmu::Triggers::StateData whammy_state = + m_whammy->GetState(m_input_override_function); guitar_data.whammy = static_cast(whammy_state.data[0] * 0x1F); // buttons - m_buttons->GetState(&guitar_data.bt, guitar_button_bitmasks.data()); + m_buttons->GetState(&guitar_data.bt, guitar_button_bitmasks.data(), m_input_override_function); // frets - m_frets->GetState(&guitar_data.bt, guitar_fret_bitmasks.data()); + m_frets->GetState(&guitar_data.bt, guitar_fret_bitmasks.data(), m_input_override_function); // strum - m_strum->GetState(&guitar_data.bt, guitar_strum_bitmasks.data()); + m_strum->GetState(&guitar_data.bt, guitar_strum_bitmasks.data(), m_input_override_function); // flip button bits guitar_data.bt ^= 0xFFFF; diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.cpp b/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.cpp index 73f73aadd0..18452641ac 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.cpp @@ -67,29 +67,34 @@ void Nunchuk::BuildDesiredExtensionState(DesiredExtensionState* target_state) DataFormat nc_data = {}; // stick - const ControllerEmu::AnalogStick::StateData stick_state = m_stick->GetState(); + bool override_occurred = false; + const ControllerEmu::AnalogStick::StateData stick_state = + m_stick->GetState(m_input_override_function, &override_occurred); nc_data.jx = u8(STICK_CENTER + stick_state.x * STICK_RADIUS); nc_data.jy = u8(STICK_CENTER + stick_state.y * STICK_RADIUS); - // Some terribly coded games check whether to move with a check like - // - // if (x != 0 && y != 0) - // do_movement(x, y); - // - // With keyboard controls, these games break if you simply hit - // of the axes. Adjust this if you're hitting one of the axes so that - // we slightly tweak the other axis. - if (nc_data.jx != STICK_CENTER || nc_data.jy != STICK_CENTER) + if (!override_occurred) { - if (nc_data.jx == STICK_CENTER) - ++nc_data.jx; - if (nc_data.jy == STICK_CENTER) - ++nc_data.jy; + // Some terribly coded games check whether to move with a check like + // + // if (x != 0 && y != 0) + // do_movement(x, y); + // + // With keyboard controls, these games break if you simply hit one + // of the axes. Adjust this if you're hitting one of the axes so that + // we slightly tweak the other axis. + if (nc_data.jx != STICK_CENTER || nc_data.jy != STICK_CENTER) + { + if (nc_data.jx == STICK_CENTER) + ++nc_data.jx; + if (nc_data.jy == STICK_CENTER) + ++nc_data.jy; + } } // buttons u8 buttons = 0; - m_buttons->GetState(&buttons, nunchuk_button_bitmasks.data()); + m_buttons->GetState(&buttons, nunchuk_button_bitmasks.data(), m_input_override_function); nc_data.SetButtons(buttons); // Acceleration data: @@ -108,6 +113,8 @@ void Nunchuk::BuildDesiredExtensionState(DesiredExtensionState* target_state) // shake accel += m_shake_state.acceleration; + accel = Wiimote::OverrideVec3(m_imu_accelerometer, accel, m_input_override_function); + // Calibration values are 8-bit but we want 10-bit precision, so << 2. const auto acc = ConvertAccelData(accel, ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2); nc_data.SetAccel(acc.value); diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/TaTaCon.cpp b/Source/Core/Core/HW/WiimoteEmu/Extension/TaTaCon.cpp index 04c13dc961..f81825a0ff 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/TaTaCon.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/TaTaCon.cpp @@ -54,8 +54,8 @@ void TaTaCon::BuildDesiredExtensionState(DesiredExtensionState* target_state) { DataFormat tatacon_data = {}; - m_center->GetState(&tatacon_data.state, center_bitmasks.data()); - m_rim->GetState(&tatacon_data.state, rim_bitmasks.data()); + m_center->GetState(&tatacon_data.state, center_bitmasks.data(), m_input_override_function); + m_rim->GetState(&tatacon_data.state, rim_bitmasks.data(), m_input_override_function); // Flip button bits. tatacon_data.state ^= 0xff; diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Turntable.cpp b/Source/Core/Core/HW/WiimoteEmu/Extension/Turntable.cpp index aaa928686f..7c8c36f127 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/Turntable.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Turntable.cpp @@ -86,7 +86,8 @@ void Turntable::BuildDesiredExtensionState(DesiredExtensionState* target_state) // stick { - const ControllerEmu::AnalogStick::StateData stick_state = m_stick->GetState(); + const ControllerEmu::AnalogStick::StateData stick_state = + m_stick->GetState(m_input_override_function); tt_data.sx = static_cast((stick_state.x * STICK_RADIUS) + STICK_CENTER); tt_data.sy = static_cast((stick_state.y * STICK_RADIUS) + STICK_CENTER); @@ -94,7 +95,7 @@ void Turntable::BuildDesiredExtensionState(DesiredExtensionState* target_state) // left table { - const ControllerEmu::Slider::StateData lt = m_left_table->GetState(); + const ControllerEmu::Slider::StateData lt = m_left_table->GetState(m_input_override_function); const s8 tt = static_cast(lt.value * TABLE_RANGE); tt_data.ltable1 = tt; @@ -103,7 +104,7 @@ void Turntable::BuildDesiredExtensionState(DesiredExtensionState* target_state) // right table { - const ControllerEmu::Slider::StateData rt = m_right_table->GetState(); + const ControllerEmu::Slider::StateData rt = m_right_table->GetState(m_input_override_function); const s8 tt = static_cast(rt.value * TABLE_RANGE); tt_data.rtable1 = tt; @@ -114,7 +115,7 @@ void Turntable::BuildDesiredExtensionState(DesiredExtensionState* target_state) // effect dial { - const auto dial_state = m_effect_dial->GetState(); + const auto dial_state = m_effect_dial->GetState(m_input_override_function); const u8 dial = static_cast(dial_state.value * EFFECT_DIAL_RANGE) + EFFECT_DIAL_CENTER; tt_data.dial1 = dial; @@ -123,13 +124,13 @@ void Turntable::BuildDesiredExtensionState(DesiredExtensionState* target_state) // crossfade slider { - const ControllerEmu::Slider::StateData cfs = m_crossfade->GetState(); + const ControllerEmu::Slider::StateData cfs = m_crossfade->GetState(m_input_override_function); tt_data.slider = static_cast((cfs.value * CROSSFADE_RANGE) + CROSSFADE_CENTER); } // buttons - m_buttons->GetState(&tt_data.bt, turntable_button_bitmasks.data()); + m_buttons->GetState(&tt_data.bt, turntable_button_bitmasks.data(), m_input_override_function); // flip button bits :/ tt_data.bt ^= (BUTTON_L_GREEN | BUTTON_L_RED | BUTTON_L_BLUE | BUTTON_R_GREEN | BUTTON_R_RED | diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index 4aa11b3e70..b89dbfcdec 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -458,9 +459,10 @@ void Wiimote::BuildDesiredWiimoteState(DesiredWiimoteState* target_state) // Fetch pressed buttons from user input. target_state->buttons.hex = 0; - m_buttons->GetState(&target_state->buttons.hex, button_bitmasks); + m_buttons->GetState(&target_state->buttons.hex, button_bitmasks, m_input_override_function); m_dpad->GetState(&target_state->buttons.hex, - IsSideways() ? dpad_sideways_bitmasks : dpad_bitmasks); + IsSideways() ? dpad_sideways_bitmasks : dpad_bitmasks, + m_input_override_function); // Calculate accelerometer state. // Calibration values are 8-bit but we want 10-bit precision, so << 2. @@ -628,9 +630,6 @@ void Wiimote::SendDataReport(const DesiredWiimoteState& target_state) std::fill_n(ext_data, ext_size, u8(0xff)); } } - - Movie::CallWiiInputManip(rpt_builder, m_bt_device_index, m_active_extension, - GetExtensionEncryptionKey()); } Movie::CheckWiimoteStatus(m_bt_device_index, rpt_builder, m_active_extension, @@ -651,8 +650,9 @@ ButtonData Wiimote::GetCurrentlyPressedButtons() const auto lock = GetStateLock(); ButtonData buttons{}; - m_buttons->GetState(&buttons.hex, button_bitmasks); - m_dpad->GetState(&buttons.hex, IsSideways() ? dpad_sideways_bitmasks : dpad_bitmasks); + m_buttons->GetState(&buttons.hex, button_bitmasks, m_input_override_function); + m_dpad->GetState(&buttons.hex, IsSideways() ? dpad_sideways_bitmasks : dpad_bitmasks, + m_input_override_function); return buttons; } @@ -789,7 +789,7 @@ void Wiimote::StepDynamics() { EmulateSwing(&m_swing_state, m_swing, 1.f / ::Wiimote::UPDATE_FREQ); EmulateTilt(&m_tilt_state, m_tilt, 1.f / ::Wiimote::UPDATE_FREQ); - EmulatePoint(&m_point_state, m_ir, 1.f / ::Wiimote::UPDATE_FREQ); + EmulatePoint(&m_point_state, m_ir, m_input_override_function, 1.f / ::Wiimote::UPDATE_FREQ); EmulateShake(&m_shake_state, m_shake, 1.f / ::Wiimote::UPDATE_FREQ); EmulateIMUCursor(&m_imu_cursor_state, m_imu_ir, m_imu_accelerometer, m_imu_gyroscope, 1.f / ::Wiimote::UPDATE_FREQ); @@ -831,20 +831,87 @@ Common::Quaternion Wiimote::GetOrientation() const Common::Quaternion::RotateX(float(MathUtil::TAU / 4 * IsUpright())); } +std::optional Wiimote::OverrideVec3(const ControllerEmu::ControlGroup* control_group, + std::optional optional_vec) const +{ + bool has_value = optional_vec.has_value(); + Common::Vec3 vec = has_value ? *optional_vec : Common::Vec3{}; + + if (m_input_override_function) + { + if (const std::optional x_override = m_input_override_function( + control_group->name, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE, vec.x)) + { + has_value = true; + vec.x = *x_override; + } + + if (const std::optional y_override = m_input_override_function( + control_group->name, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE, vec.y)) + { + has_value = true; + vec.y = *y_override; + } + + if (const std::optional z_override = m_input_override_function( + control_group->name, ControllerEmu::ReshapableInput::Z_INPUT_OVERRIDE, vec.z)) + { + has_value = true; + vec.z = *z_override; + } + } + + return has_value ? std::make_optional(vec) : std::nullopt; +} + +Common::Vec3 Wiimote::OverrideVec3(const ControllerEmu::ControlGroup* control_group, + Common::Vec3 vec) const +{ + return OverrideVec3(control_group, vec, m_input_override_function); +} + +Common::Vec3 +Wiimote::OverrideVec3(const ControllerEmu::ControlGroup* control_group, Common::Vec3 vec, + const ControllerEmu::InputOverrideFunction& input_override_function) +{ + if (input_override_function) + { + if (const std::optional x_override = input_override_function( + control_group->name, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE, vec.x)) + { + vec.x = *x_override; + } + + if (const std::optional y_override = input_override_function( + control_group->name, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE, vec.y)) + { + vec.y = *y_override; + } + + if (const std::optional z_override = input_override_function( + control_group->name, ControllerEmu::ReshapableInput::Z_INPUT_OVERRIDE, vec.z)) + { + vec.z = *z_override; + } + } + + return vec; +} + Common::Vec3 Wiimote::GetTotalAcceleration() const { - if (const auto accel = m_imu_accelerometer->GetState()) - return GetAcceleration(*accel); + const Common::Vec3 default_accel = Common::Vec3(0, 0, float(GRAVITY_ACCELERATION)); + const Common::Vec3 accel = m_imu_accelerometer->GetState().value_or(default_accel); - return GetAcceleration(); + return OverrideVec3(m_imu_accelerometer, GetAcceleration(accel)); } Common::Vec3 Wiimote::GetTotalAngularVelocity() const { - if (const auto ang_vel = m_imu_gyroscope->GetState()) - return GetAngularVelocity(*ang_vel); + const Common::Vec3 default_ang_vel = {}; + const Common::Vec3 ang_vel = m_imu_gyroscope->GetState().value_or(default_ang_vel); - return GetAngularVelocity(); + return OverrideVec3(m_imu_gyroscope, GetAngularVelocity(ang_vel)); } Common::Matrix44 Wiimote::GetTotalTransformation() const diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h index c360f33ab7..ce9b35ae2d 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h @@ -5,6 +5,7 @@ #include #include +#include #include #include "Core/HW/WiimoteCommon/WiimoteReport.h" @@ -146,6 +147,10 @@ public: // Active extension number is exposed for TAS. ExtensionNumber GetActiveExtensionNumber() const; + static Common::Vec3 + OverrideVec3(const ControllerEmu::ControlGroup* control_group, Common::Vec3 vec, + const ControllerEmu::InputOverrideFunction& input_override_function); + private: // Used only for error generation: static constexpr u8 EEPROM_I2C_ADDR = 0x50; @@ -161,11 +166,10 @@ private: void BuildDesiredWiimoteState(DesiredWiimoteState* target_state); // Returns simulated accelerometer data in m/s^2. - Common::Vec3 GetAcceleration( - Common::Vec3 extra_acceleration = Common::Vec3(0, 0, float(GRAVITY_ACCELERATION))) const; + Common::Vec3 GetAcceleration(Common::Vec3 extra_acceleration) const; // Returns simulated gyroscope data in radians/s. - Common::Vec3 GetAngularVelocity(Common::Vec3 extra_angular_velocity = {}) const; + Common::Vec3 GetAngularVelocity(Common::Vec3 extra_angular_velocity) const; // Returns the transformation of the world around the wiimote. // Used for simulating camera data and for rotating acceleration data. @@ -176,6 +180,10 @@ private: // Returns the world rotation from the effects of sideways/upright settings. Common::Quaternion GetOrientation() const; + std::optional OverrideVec3(const ControllerEmu::ControlGroup* control_group, + std::optional optional_vec) const; + Common::Vec3 OverrideVec3(const ControllerEmu::ControlGroup* control_group, + Common::Vec3 vec) const; Common::Vec3 GetTotalAcceleration() const; Common::Vec3 GetTotalAngularVelocity() const; Common::Matrix44 GetTotalTransformation() const; diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp index 539e02b449..0f30b50f63 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp @@ -4,6 +4,7 @@ #include "InputCommon/ControllerEmu/ControlGroup/AnalogStick.h" #include +#include #include "Common/Common.h" #include "Common/MathUtil.h" @@ -48,6 +49,34 @@ AnalogStick::StateData AnalogStick::GetState() const return GetReshapableState(true); } +AnalogStick::StateData AnalogStick::GetState(const InputOverrideFunction& override_func) const +{ + bool override_occurred = false; + return GetState(override_func, &override_occurred); +} + +AnalogStick::StateData AnalogStick::GetState(const InputOverrideFunction& override_func, + bool* override_occurred) const +{ + StateData state = GetState(); + if (!override_func) + return state; + + if (const std::optional x_override = override_func(name, X_INPUT_OVERRIDE, state.x)) + { + state.x = *x_override; + *override_occurred = true; + } + + if (const std::optional y_override = override_func(name, Y_INPUT_OVERRIDE, state.y)) + { + state.y = *y_override; + *override_occurred = true; + } + + return state; +} + ControlState AnalogStick::GetGateRadiusAtAngle(double ang) const { return m_stick_gate->GetRadiusAtAngle(ang); diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h index 47e3ad5743..377e63251d 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h @@ -21,6 +21,8 @@ public: ControlState GetGateRadiusAtAngle(double ang) const override; StateData GetState() const; + StateData GetState(const InputOverrideFunction& override_func) const; + StateData GetState(const InputOverrideFunction& override_func, bool* override_occurred) const; private: Control* GetModifierInput() const override; diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.h index 2d02adabf1..652f64ae5f 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.h +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include "InputCommon/ControlReference/ControlReference.h" @@ -24,5 +25,21 @@ public: for (auto& control : controls) *buttons |= *(bitmasks++) * control->GetState(); } + + template + void GetState(C* const buttons, const C* bitmasks, + const InputOverrideFunction& override_func) const + { + if (!override_func) + return GetState(buttons, bitmasks); + + for (auto& control : controls) + { + ControlState state = control->GetState(); + if (std::optional state_override = override_func(name, control->name, state)) + state = *state_override; + *buttons |= *(bitmasks++) * (std::lround(state) > 0); + } + } }; } // namespace ControllerEmu diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h index c08c072aba..fb10bab074 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h @@ -5,14 +5,18 @@ #include #include +#include #include +#include #include +#include #include #include #include "Common/CommonTypes.h" #include "Common/IniFile.h" #include "InputCommon/ControllerEmu/Control/Control.h" +#include "InputCommon/ControllerInterface/CoreDevice.h" namespace ControllerEmu { @@ -27,6 +31,9 @@ class NumericSetting; template class SettingValue; +using InputOverrideFunction = std::function( + const std::string_view group_name, const std::string_view control_name, ControlState state)>; + enum class GroupType { Other, diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp index 043ef37356..7359a4e66d 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp @@ -82,15 +82,28 @@ ControlState Cursor::GetGateRadiusAtAngle(double ang) const Cursor::StateData Cursor::GetState(const bool adjusted) { - if (!adjusted) - { - const auto raw_input = GetReshapableState(false); + const ReshapeData input = GetReshapableState(adjusted); + const StateData state = adjusted ? UpdateState(input) : StateData{input.x, input.y}; + return state; +} - return {raw_input.x, raw_input.y}; - } +Cursor::StateData Cursor::GetState(const bool adjusted, + const ControllerEmu::InputOverrideFunction& override_func) +{ + StateData state = GetState(adjusted); + if (!override_func) + return state; - const auto input = GetReshapableState(true); + if (const std::optional x_override = override_func(name, X_INPUT_OVERRIDE, state.x)) + state.x = *x_override; + if (const std::optional y_override = override_func(name, Y_INPUT_OVERRIDE, state.y)) + state.y = *y_override; + return state; +} + +Cursor::StateData Cursor::UpdateState(Cursor::ReshapeData input) +{ // TODO: Using system time is ugly. // Kill this after state is moved into wiimote rather than this class. const auto now = Clock::now(); diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.h index 5e64ce86dc..3710a40d92 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.h +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.h @@ -29,6 +29,7 @@ public: // Modifies the state StateData GetState(bool adjusted); + StateData GetState(bool adjusted, const ControllerEmu::InputOverrideFunction& override_func); // Yaw movement in radians. ControlState GetTotalYaw() const; @@ -40,6 +41,8 @@ public: ControlState GetVerticalOffset() const; private: + Cursor::StateData UpdateState(Cursor::ReshapeData input); + // This is used to reduce the cursor speed for relative input // to something that makes sense with the default range. static constexpr double STEP_PER_SEC = 0.01 * 200; diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp index 8c2f4cbac5..8783087650 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp @@ -4,6 +4,7 @@ #include "InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h" #include +#include #include #include #include @@ -63,6 +64,53 @@ void MixedTriggers::GetState(u16* const digital, const u16* bitmasks, ControlSta } } +void MixedTriggers::GetState(u16* digital, const u16* bitmasks, ControlState* analog, + const InputOverrideFunction& override_func, bool adjusted) const +{ + if (!override_func) + return GetState(digital, bitmasks, analog, adjusted); + + const ControlState threshold = GetThreshold(); + ControlState deadzone = GetDeadzone(); + + // Return raw values. (used in UI) + if (!adjusted) + { + deadzone = 0.0; + } + + const int trigger_count = int(controls.size() / 2); + for (int i = 0; i != trigger_count; ++i) + { + bool button_bool = false; + const ControlState button_value = ApplyDeadzone(controls[i]->GetState(), deadzone); + ControlState analog_value = ApplyDeadzone(controls[trigger_count + i]->GetState(), deadzone); + + // Apply threshold: + if (button_value > threshold) + { + analog_value = 1.0; + button_bool = true; + } + + if (const std::optional button_override = + override_func(name, controls[i]->name, static_cast(button_bool))) + { + button_bool = std::lround(*button_override) > 0; + } + + if (const std::optional analog_override = + override_func(name, controls[trigger_count + i]->name, analog_value)) + { + analog_value = *analog_override; + } + + if (button_bool) + *digital |= bitmasks[i]; + analog[i] = std::min(analog_value, 1.0); + } +} + ControlState MixedTriggers::GetDeadzone() const { return m_deadzone_setting.GetValue() / 100; diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h index fcd98b279e..2e1014d047 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h @@ -17,6 +17,8 @@ public: void GetState(u16* digital, const u16* bitmasks, ControlState* analog, bool adjusted = true) const; + void GetState(u16* digital, const u16* bitmasks, ControlState* analog, + const InputOverrideFunction& override_func, bool adjusted = true) const; ControlState GetDeadzone() const; ControlState GetThreshold() const; diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.cpp index f0516a567f..708831a4c3 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.cpp @@ -35,4 +35,21 @@ Slider::StateData Slider::GetState() const return {std::clamp(ApplyDeadzone(state, deadzone), -1.0, 1.0)}; } + +Slider::StateData Slider::GetState(const InputOverrideFunction& override_func) const +{ + if (!override_func) + return GetState(); + + const ControlState deadzone = m_deadzone_setting.GetValue() / 100; + ControlState state = controls[1]->GetState() - controls[0]->GetState(); + + state = ApplyDeadzone(state, deadzone); + + if (std::optional state_override = override_func(name, X_INPUT_OVERRIDE, state)) + state = *state_override; + + return {std::clamp(state, -1.0, 1.0)}; +} + } // namespace ControllerEmu diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.h index 9d1bf697a5..0e635da235 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.h +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.h @@ -23,6 +23,9 @@ public: explicit Slider(const std::string& name_); StateData GetState() const; + StateData GetState(const InputOverrideFunction& override_func) const; + + static constexpr const char* X_INPUT_OVERRIDE = "X"; private: SettingValue m_deadzone_setting; diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.cpp index 17e64d2a8b..321c9272d0 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "Common/Common.h" @@ -31,4 +32,25 @@ Triggers::StateData Triggers::GetState() const return result; } + +Triggers::StateData Triggers::GetState(const InputOverrideFunction& override_func) const +{ + if (!override_func) + return GetState(); + + const size_t trigger_count = controls.size(); + const ControlState deadzone = m_deadzone_setting.GetValue() / 100; + + StateData result(trigger_count); + for (size_t i = 0; i < trigger_count; ++i) + { + ControlState state = ApplyDeadzone(controls[i]->GetState(), deadzone); + if (std::optional state_override = override_func(name, controls[i]->name, state)) + state = *state_override; + result.data[i] = std::min(state, 1.0); + } + + return result; +} + } // namespace ControllerEmu diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.h index 2ea02bedb5..c73dee9cfa 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.h +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.h @@ -26,6 +26,7 @@ public: explicit Triggers(const std::string& name); StateData GetState() const; + StateData GetState(const InputOverrideFunction& override_func) const; private: SettingValue m_deadzone_setting; diff --git a/Source/Core/InputCommon/ControllerEmu/ControllerEmu.cpp b/Source/Core/InputCommon/ControllerEmu/ControllerEmu.cpp index 0a3de3e391..dc9830de3f 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControllerEmu.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControllerEmu.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "Common/IniFile.h" @@ -176,4 +177,15 @@ void EmulatedController::LoadDefaults(const ControllerInterface& ciface) SetDefaultDevice(default_device_string); } } + +void EmulatedController::SetInputOverrideFunction(InputOverrideFunction override_func) +{ + m_input_override_function = std::move(override_func); +} + +void EmulatedController::ClearInputOverrideFunction() +{ + m_input_override_function = {}; +} + } // namespace ControllerEmu diff --git a/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h b/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h index 2db991eb82..b0e514d20a 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h +++ b/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h @@ -15,6 +15,7 @@ #include "Common/IniFile.h" #include "Common/MathUtil.h" #include "InputCommon/ControlReference/ExpressionParser.h" +#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h" #include "InputCommon/ControllerInterface/CoreDevice.h" class ControllerInterface; @@ -184,6 +185,9 @@ public: void SetDefaultDevice(const std::string& device); void SetDefaultDevice(ciface::Core::DeviceQualifier devq); + void SetInputOverrideFunction(InputOverrideFunction override_func); + void ClearInputOverrideFunction(); + void UpdateReferences(const ControllerInterface& devi); void UpdateSingleControlReference(const ControllerInterface& devi, ControlReference* ref); @@ -228,6 +232,8 @@ protected: // so theirs won't be used (and thus shouldn't even exist). ciface::ExpressionParser::ControlEnvironment::VariableContainer m_expression_vars; + InputOverrideFunction m_input_override_function; + void UpdateReferences(ciface::ExpressionParser::ControlEnvironment& env); private: diff --git a/Source/Core/InputCommon/ControllerEmu/StickGate.h b/Source/Core/InputCommon/ControllerEmu/StickGate.h index 528aa4a5c8..831762fda3 100644 --- a/Source/Core/InputCommon/ControllerEmu/StickGate.h +++ b/Source/Core/InputCommon/ControllerEmu/StickGate.h @@ -106,6 +106,10 @@ public: const ReshapeData& GetCenter() const; void SetCenter(ReshapeData center); + static constexpr const char* X_INPUT_OVERRIDE = "X"; + static constexpr const char* Y_INPUT_OVERRIDE = "Y"; + static constexpr const char* Z_INPUT_OVERRIDE = "Z"; + protected: ReshapeData Reshape(ControlState x, ControlState y, ControlState modifier = 0.0, ControlState clamp = 1.0) const;