core/hid: Fully emulate motion from button

This commit is contained in:
german77 2021-11-01 19:49:14 -06:00 committed by Narr the Reg
parent 77fa4d4bf6
commit 136eb9c4c2
7 changed files with 97 additions and 37 deletions

View file

@ -110,9 +110,14 @@ struct MotionSensor {
}; };
struct MotionStatus { struct MotionStatus {
// Gyroscope vector measurement in radians/s.
MotionSensor gyro{}; MotionSensor gyro{};
// Acceleration vector measurement in G force
MotionSensor accel{}; MotionSensor accel{};
// Time since last measurement in microseconds
u64 delta_timestamp{}; u64 delta_timestamp{};
// Request to update after reading the value
bool force_update{};
}; };
struct TouchStatus { struct TouchStatus {

View file

@ -644,6 +644,7 @@ void EmulatedController::SetMotion(Common::Input::CallbackStatus callback, std::
}); });
emulated.UpdateRotation(raw_status.delta_timestamp); emulated.UpdateRotation(raw_status.delta_timestamp);
emulated.UpdateOrientation(raw_status.delta_timestamp); emulated.UpdateOrientation(raw_status.delta_timestamp);
force_update_motion = raw_status.force_update;
if (is_configuring) { if (is_configuring) {
TriggerOnChange(ControllerTriggerType::Motion, false); TriggerOnChange(ControllerTriggerType::Motion, false);
@ -653,7 +654,7 @@ void EmulatedController::SetMotion(Common::Input::CallbackStatus callback, std::
auto& motion = controller.motion_state[index]; auto& motion = controller.motion_state[index];
motion.accel = emulated.GetAcceleration(); motion.accel = emulated.GetAcceleration();
motion.gyro = emulated.GetGyroscope(); motion.gyro = emulated.GetGyroscope();
motion.rotation = emulated.GetGyroscope(); motion.rotation = emulated.GetRotations();
motion.orientation = emulated.GetOrientation(); motion.orientation = emulated.GetOrientation();
motion.is_at_rest = emulated.IsMoving(motion_sensitivity); motion.is_at_rest = emulated.IsMoving(motion_sensitivity);
@ -962,6 +963,14 @@ NpadGcTriggerState EmulatedController::GetTriggers() const {
} }
MotionState EmulatedController::GetMotions() const { MotionState EmulatedController::GetMotions() const {
if (force_update_motion) {
for (auto& device : motion_devices) {
if (!device) {
continue;
}
device->ForceUpdate();
}
}
return controller.motion_state; return controller.motion_state;
} }

View file

@ -355,6 +355,7 @@ private:
bool is_connected{false}; bool is_connected{false};
bool is_configuring{false}; bool is_configuring{false};
f32 motion_sensitivity{0.01f}; f32 motion_sensitivity{0.01f};
bool force_update_motion{false};
// Temporary values to avoid doing changes while the controller is on configuration mode // Temporary values to avoid doing changes while the controller is on configuration mode
NpadType tmp_npad_type{NpadType::None}; NpadType tmp_npad_type{NpadType::None};

View file

@ -74,45 +74,53 @@ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatu
Common::Input::MotionStatus status{}; Common::Input::MotionStatus status{};
switch (callback.type) { switch (callback.type) {
case Common::Input::InputType::Button: { case Common::Input::InputType::Button: {
Common::Input::AnalogProperties properties{
.deadzone = 0.0f,
.range = 1.0f,
.offset = 0.0f,
};
status.delta_timestamp = 5000;
status.force_update = true;
status.accel.x = {
.value = 0.0f,
.raw_value = 0.0f,
.properties = properties,
};
status.accel.y = {
.value = 0.0f,
.raw_value = 0.0f,
.properties = properties,
};
status.accel.z = {
.value = 0.0f,
.raw_value = -1.0f,
.properties = properties,
};
status.gyro.x = {
.value = 0.0f,
.raw_value = 0.0f,
.properties = properties,
};
status.gyro.y = {
.value = 0.0f,
.raw_value = 0.0f,
.properties = properties,
};
status.gyro.z = {
.value = 0.0f,
.raw_value = 0.0f,
.properties = properties,
};
if (TransformToButton(callback).value) { if (TransformToButton(callback).value) {
std::random_device device; std::random_device device;
std::mt19937 gen(device()); std::mt19937 gen(device());
std::uniform_int_distribution<s16> distribution(-1000, 1000); std::uniform_int_distribution<s16> distribution(-1000, 1000);
Common::Input::AnalogProperties properties{ status.accel.x.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
.deadzone = 0.0, status.accel.y.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
.range = 1.0f, status.accel.z.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
.offset = 0.0, status.gyro.x.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
}; status.gyro.y.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
status.accel.x = { status.gyro.z.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
.value = 0,
.raw_value = static_cast<f32>(distribution(gen)) * 0.001f,
.properties = properties,
};
status.accel.y = {
.value = 0,
.raw_value = static_cast<f32>(distribution(gen)) * 0.001f,
.properties = properties,
};
status.accel.z = {
.value = 0,
.raw_value = static_cast<f32>(distribution(gen)) * 0.001f,
.properties = properties,
};
status.gyro.x = {
.value = 0,
.raw_value = static_cast<f32>(distribution(gen)) * 0.001f,
.properties = properties,
};
status.gyro.y = {
.value = 0,
.raw_value = static_cast<f32>(distribution(gen)) * 0.001f,
.properties = properties,
};
status.gyro.z = {
.value = 0,
.raw_value = static_cast<f32>(distribution(gen)) * 0.001f,
.properties = properties,
};
} }
break; break;
} }

View file

@ -56,15 +56,31 @@ private:
Common::Vec3f integral_error; Common::Vec3f integral_error;
Common::Vec3f derivative_error; Common::Vec3f derivative_error;
// Quaternion containing the device orientation
Common::Quaternion<f32> quat{{0.0f, 0.0f, -1.0f}, 0.0f}; Common::Quaternion<f32> quat{{0.0f, 0.0f, -1.0f}, 0.0f};
// Number of full rotations in each axis
Common::Vec3f rotations; Common::Vec3f rotations;
// Acceleration vector measurement in G force
Common::Vec3f accel; Common::Vec3f accel;
// Gyroscope vector measurement in radians/s.
Common::Vec3f gyro; Common::Vec3f gyro;
// Vector to be substracted from gyro measurements
Common::Vec3f gyro_drift; Common::Vec3f gyro_drift;
// Minimum gyro amplitude to detect if the device is moving
f32 gyro_threshold = 0.0f; f32 gyro_threshold = 0.0f;
// Number of invalid sequential data
u32 reset_counter = 0; u32 reset_counter = 0;
// If the provided data is invalid the device will be autocalibrated
bool reset_enabled = true; bool reset_enabled = true;
// Use accelerometer values to calculate position
bool only_accelerometer = true; bool only_accelerometer = true;
}; };

View file

@ -36,6 +36,8 @@ public:
left->SetCallback(button_left_callback); left->SetCallback(button_left_callback);
right->SetCallback(button_right_callback); right->SetCallback(button_right_callback);
modifier->SetCallback(button_modifier_callback); modifier->SetCallback(button_modifier_callback);
last_x_axis_value = 0.0f;
last_y_axis_value = 0.0f;
} }
bool IsAngleGreater(float old_angle, float new_angle) const { bool IsAngleGreater(float old_angle, float new_angle) const {
@ -199,6 +201,8 @@ public:
.type = Common::Input::InputType::Stick, .type = Common::Input::InputType::Stick,
.stick_status = GetStatus(), .stick_status = GetStatus(),
}; };
last_x_axis_value = status.stick_status.x.raw_value;
last_y_axis_value = status.stick_status.y.raw_value;
TriggerOnChange(status); TriggerOnChange(status);
} }
@ -215,6 +219,12 @@ public:
.type = Common::Input::InputType::Stick, .type = Common::Input::InputType::Stick,
.stick_status = GetStatus(), .stick_status = GetStatus(),
}; };
if (last_x_axis_value == status.stick_status.x.raw_value &&
last_y_axis_value == status.stick_status.y.raw_value) {
return;
}
last_x_axis_value = status.stick_status.x.raw_value;
last_y_axis_value = status.stick_status.y.raw_value;
TriggerOnChange(status); TriggerOnChange(status);
} }
@ -265,6 +275,8 @@ private:
bool left_status; bool left_status;
bool right_status; bool right_status;
bool modifier_status; bool modifier_status;
float last_x_axis_value;
float last_y_axis_value;
const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false};
std::chrono::time_point<std::chrono::steady_clock> last_update; std::chrono::time_point<std::chrono::steady_clock> last_update;
}; };

View file

@ -16,10 +16,15 @@ public:
: button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) { : button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) {
Common::Input::InputCallback button_up_callback{ Common::Input::InputCallback button_up_callback{
[this](Common::Input::CallbackStatus callback_) { UpdateButtonStatus(callback_); }}; [this](Common::Input::CallbackStatus callback_) { UpdateButtonStatus(callback_); }};
last_button_value = false;
button->SetCallback(button_up_callback); button->SetCallback(button_up_callback);
button->ForceUpdate(); button->ForceUpdate();
} }
void ForceUpdate() override {
button->ForceUpdate();
}
Common::Input::TouchStatus GetStatus(bool pressed) const { Common::Input::TouchStatus GetStatus(bool pressed) const {
const Common::Input::ButtonStatus button_status{ const Common::Input::ButtonStatus button_status{
.value = pressed, .value = pressed,
@ -47,11 +52,15 @@ public:
.type = Common::Input::InputType::Touch, .type = Common::Input::InputType::Touch,
.touch_status = GetStatus(button_callback.button_status.value), .touch_status = GetStatus(button_callback.button_status.value),
}; };
TriggerOnChange(status); if (last_button_value != button_callback.button_status.value) {
last_button_value = button_callback.button_status.value;
TriggerOnChange(status);
}
} }
private: private:
Button button; Button button;
bool last_button_value;
const int touch_id; const int touch_id;
const float x; const float x;
const float y; const float y;