core/hid: Fully emulate motion from button
This commit is contained in:
parent
77fa4d4bf6
commit
136eb9c4c2
7 changed files with 97 additions and 37 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue