ControllerEmu: Add new "input override" system
This commit is contained in:
parent
cb6d476538
commit
cb16d20f2d
|
@ -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<u8>(main_stick_state.x, GCPadStatus::MAIN_STICK_CENTER_X, 1);
|
||||
pad.stickY = MapFloat<u8>(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<u8>(c_stick_state.x, GCPadStatus::C_STICK_CENTER_X, 1);
|
||||
pad.substickY = MapFloat<u8>(c_stick_state.y, GCPadStatus::C_STICK_CENTER_Y, 1);
|
||||
|
||||
// triggers
|
||||
std::array<ControlState, 2> 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<u8>(triggers[0], 0);
|
||||
pad.triggerRight = MapFloat<u8>(triggers[1], 0);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
|
||||
#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())
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<u8>(LEFT_STICK_CENTER + (left_stick_state.x * LEFT_STICK_RADIUS));
|
||||
const u8 y = static_cast<u8>(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<u8>(RIGHT_STICK_CENTER + (right_stick_data.x * RIGHT_STICK_RADIUS));
|
||||
const u8 y = static_cast<u8>(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<u8>(trigs[0] * TRIGGER_RANGE);
|
||||
const u8 rt = static_cast<u8>(trigs[1] * TRIGGER_RANGE);
|
||||
const u8 lt = static_cast<u8>(triggers[0] * TRIGGER_RANGE);
|
||||
const u8 rt = static_cast<u8>(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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -84,17 +84,18 @@ void Drums::BuildDesiredExtensionState(DesiredExtensionState* target_state)
|
|||
DesiredState& state = target_state->data.emplace<DesiredState>();
|
||||
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -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<u8>((stick_state.x * STICK_RADIUS) + STICK_CENTER);
|
||||
guitar_data.sy = static_cast<u8>((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<u8>(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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<u8>((stick_state.x * STICK_RADIUS) + STICK_CENTER);
|
||||
tt_data.sy = static_cast<u8>((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<s8>(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<s8>(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<u8>(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<u8>((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 |
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
@ -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<Common::Vec3> Wiimote::OverrideVec3(const ControllerEmu::ControlGroup* control_group,
|
||||
std::optional<Common::Vec3> 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<ControlState> 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<ControlState> 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<ControlState> 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<ControlState> x_override = input_override_function(
|
||||
control_group->name, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE, vec.x))
|
||||
{
|
||||
vec.x = *x_override;
|
||||
}
|
||||
|
||||
if (const std::optional<ControlState> y_override = input_override_function(
|
||||
control_group->name, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE, vec.y))
|
||||
{
|
||||
vec.y = *y_override;
|
||||
}
|
||||
|
||||
if (const std::optional<ControlState> 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
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <array>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#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<Common::Vec3> OverrideVec3(const ControllerEmu::ControlGroup* control_group,
|
||||
std::optional<Common::Vec3> 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;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "InputCommon/ControllerEmu/ControlGroup/AnalogStick.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
|
||||
#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<ControlState> x_override = override_func(name, X_INPUT_OVERRIDE, state.x))
|
||||
{
|
||||
state.x = *x_override;
|
||||
*override_occurred = true;
|
||||
}
|
||||
|
||||
if (const std::optional<ControlState> 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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
#include "InputCommon/ControlReference/ControlReference.h"
|
||||
|
@ -24,5 +25,21 @@ public:
|
|||
for (auto& control : controls)
|
||||
*buttons |= *(bitmasks++) * control->GetState<bool>();
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
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<ControlState> state_override = override_func(name, control->name, state))
|
||||
state = *state_override;
|
||||
*buttons |= *(bitmasks++) * (std::lround(state) > 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace ControllerEmu
|
||||
|
|
|
@ -5,14 +5,18 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#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 <typename T>
|
||||
class SettingValue;
|
||||
|
||||
using InputOverrideFunction = std::function<std::optional<ControlState>(
|
||||
const std::string_view group_name, const std::string_view control_name, ControlState state)>;
|
||||
|
||||
enum class GroupType
|
||||
{
|
||||
Other,
|
||||
|
|
|
@ -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<ControlState> x_override = override_func(name, X_INPUT_OVERRIDE, state.x))
|
||||
state.x = *x_override;
|
||||
if (const std::optional<ControlState> 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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
@ -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<ControlState> button_override =
|
||||
override_func(name, controls[i]->name, static_cast<ControlState>(button_bool)))
|
||||
{
|
||||
button_bool = std::lround(*button_override) > 0;
|
||||
}
|
||||
|
||||
if (const std::optional<ControlState> 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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<ControlState> state_override = override_func(name, X_INPUT_OVERRIDE, state))
|
||||
state = *state_override;
|
||||
|
||||
return {std::clamp(state, -1.0, 1.0)};
|
||||
}
|
||||
|
||||
} // namespace ControllerEmu
|
||||
|
|
|
@ -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<double> m_deadzone_setting;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#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<ControlState> state_override = override_func(name, controls[i]->name, state))
|
||||
state = *state_override;
|
||||
result.data[i] = std::min(state, 1.0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace ControllerEmu
|
||||
|
|
|
@ -26,6 +26,7 @@ public:
|
|||
explicit Triggers(const std::string& name);
|
||||
|
||||
StateData GetState() const;
|
||||
StateData GetState(const InputOverrideFunction& override_func) const;
|
||||
|
||||
private:
|
||||
SettingValue<double> m_deadzone_setting;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue