| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- // Copyright 2021 yuzu Emulator Project
- // Licensed under GPLv2 or any later version
- // Refer to the license.txt file included
- #include <random>
- #include "common/input.h"
- #include "core/hid/input_converter.h"
- namespace Core::HID {
- Common::Input::BatteryStatus TransformToBattery(const Common::Input::CallbackStatus& callback) {
- Common::Input::BatteryStatus battery{Common::Input::BatteryStatus::None};
- switch (callback.type) {
- case Common::Input::InputType::Analog:
- case Common::Input::InputType::Trigger: {
- const auto value = TransformToTrigger(callback).analog.value;
- battery = Common::Input::BatteryLevel::Empty;
- if (value > 0.2f) {
- battery = Common::Input::BatteryLevel::Critical;
- }
- if (value > 0.4f) {
- battery = Common::Input::BatteryLevel::Low;
- }
- if (value > 0.6f) {
- battery = Common::Input::BatteryLevel::Medium;
- }
- if (value > 0.8f) {
- battery = Common::Input::BatteryLevel::Full;
- }
- if (value >= 1.0f) {
- battery = Common::Input::BatteryLevel::Charging;
- }
- break;
- }
- case Common::Input::InputType::Button:
- battery = callback.button_status.value ? Common::Input::BatteryLevel::Charging
- : Common::Input::BatteryLevel::Critical;
- break;
- case Common::Input::InputType::Battery:
- battery = callback.battery_status;
- break;
- default:
- LOG_ERROR(Input, "Conversion from type {} to battery not implemented", callback.type);
- break;
- }
- return battery;
- }
- Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatus& callback) {
- Common::Input::ButtonStatus status{};
- switch (callback.type) {
- case Common::Input::InputType::Analog:
- case Common::Input::InputType::Trigger:
- status.value = TransformToTrigger(callback).pressed;
- break;
- case Common::Input::InputType::Button:
- status = callback.button_status;
- break;
- default:
- LOG_ERROR(Input, "Conversion from type {} to button not implemented", callback.type);
- break;
- }
- if (status.inverted) {
- status.value = !status.value;
- }
- return status;
- }
- Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatus& callback) {
- Common::Input::MotionStatus status{};
- switch (callback.type) {
- case Common::Input::InputType::Button: {
- if (TransformToButton(callback).value) {
- std::random_device device;
- std::mt19937 gen(device());
- std::uniform_int_distribution<s16> distribution(-1000, 1000);
- Common::Input::AnalogProperties properties{
- .deadzone = 0.0,
- .range = 1.0f,
- .offset = 0.0,
- };
- status.accel.x = {
- .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;
- }
- case Common::Input::InputType::Motion:
- status = callback.motion_status;
- break;
- default:
- LOG_ERROR(Input, "Conversion from type {} to motion not implemented", callback.type);
- break;
- }
- SanitizeAnalog(status.accel.x, false);
- SanitizeAnalog(status.accel.y, false);
- SanitizeAnalog(status.accel.z, false);
- SanitizeAnalog(status.gyro.x, false);
- SanitizeAnalog(status.gyro.y, false);
- SanitizeAnalog(status.gyro.z, false);
- return status;
- }
- Common::Input::StickStatus TransformToStick(const Common::Input::CallbackStatus& callback) {
- Common::Input::StickStatus status{};
- switch (callback.type) {
- case Common::Input::InputType::Stick:
- status = callback.stick_status;
- break;
- default:
- LOG_ERROR(Input, "Conversion from type {} to stick not implemented", callback.type);
- break;
- }
- SanitizeStick(status.x, status.y, true);
- const auto& properties_x = status.x.properties;
- const auto& properties_y = status.y.properties;
- const float x = status.x.value;
- const float y = status.y.value;
- // Set directional buttons
- status.right = x > properties_x.threshold;
- status.left = x < -properties_x.threshold;
- status.up = y > properties_y.threshold;
- status.down = y < -properties_y.threshold;
- return status;
- }
- Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& callback) {
- Common::Input::TouchStatus status{};
- switch (callback.type) {
- case Common::Input::InputType::Touch:
- status = callback.touch_status;
- break;
- default:
- LOG_ERROR(Input, "Conversion from type {} to touch not implemented", callback.type);
- break;
- }
- SanitizeAnalog(status.x, true);
- SanitizeAnalog(status.y, true);
- float& x = status.x.value;
- float& y = status.y.value;
- // Adjust if value is inverted
- x = status.x.properties.inverted ? 1.0f + x : x;
- y = status.y.properties.inverted ? 1.0f + y : y;
- // clamp value
- x = std::clamp(x, 0.0f, 1.0f);
- y = std::clamp(y, 0.0f, 1.0f);
- if (status.pressed.inverted) {
- status.pressed.value = !status.pressed.value;
- }
- return status;
- }
- Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackStatus& callback) {
- Common::Input::TriggerStatus status{};
- float& raw_value = status.analog.raw_value;
- bool calculate_button_value = true;
- switch (callback.type) {
- case Common::Input::InputType::Analog:
- status.analog.properties = callback.analog_status.properties;
- raw_value = callback.analog_status.raw_value;
- break;
- case Common::Input::InputType::Button:
- status.analog.properties.range = 1.0f;
- status.analog.properties.inverted = callback.button_status.inverted;
- raw_value = callback.button_status.value ? 1.0f : 0.0f;
- break;
- case Common::Input::InputType::Trigger:
- status = callback.trigger_status;
- calculate_button_value = false;
- break;
- default:
- LOG_ERROR(Input, "Conversion from type {} to trigger not implemented", callback.type);
- break;
- }
- SanitizeAnalog(status.analog, true);
- const auto& properties = status.analog.properties;
- float& value = status.analog.value;
- // Set button status
- if (calculate_button_value) {
- status.pressed = value > properties.threshold;
- }
- // Adjust if value is inverted
- value = properties.inverted ? 1.0f + value : value;
- // clamp value
- value = std::clamp(value, 0.0f, 1.0f);
- return status;
- }
- void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) {
- const auto& properties = analog.properties;
- float& raw_value = analog.raw_value;
- float& value = analog.value;
- if (!std::isnormal(raw_value)) {
- raw_value = 0;
- }
- // Apply center offset
- raw_value -= properties.offset;
- // Set initial values to be formated
- value = raw_value;
- // Calculate vector size
- const float r = std::abs(value);
- // Return zero if value is smaller than the deadzone
- if (r <= properties.deadzone || properties.deadzone == 1.0f) {
- analog.value = 0;
- return;
- }
- // Adjust range of value
- const float deadzone_factor =
- 1.0f / r * (r - properties.deadzone) / (1.0f - properties.deadzone);
- value = value * deadzone_factor / properties.range;
- // Invert direction if needed
- if (properties.inverted) {
- value = -value;
- }
- // Clamp value
- if (clamp_value) {
- value = std::clamp(value, -1.0f, 1.0f);
- }
- }
- void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogStatus& analog_y,
- bool clamp_value) {
- const auto& properties_x = analog_x.properties;
- const auto& properties_y = analog_y.properties;
- float& raw_x = analog_x.raw_value;
- float& raw_y = analog_y.raw_value;
- float& x = analog_x.value;
- float& y = analog_y.value;
- if (!std::isnormal(raw_x)) {
- raw_x = 0;
- }
- if (!std::isnormal(raw_y)) {
- raw_y = 0;
- }
- // Apply center offset
- raw_x += properties_x.offset;
- raw_y += properties_y.offset;
- // Apply X scale correction from offset
- if (std::abs(properties_x.offset) < 0.5f) {
- if (raw_x > 0) {
- raw_x /= 1 + properties_x.offset;
- } else {
- raw_x /= 1 - properties_x.offset;
- }
- }
- // Apply Y scale correction from offset
- if (std::abs(properties_y.offset) < 0.5f) {
- if (raw_y > 0) {
- raw_y /= 1 + properties_y.offset;
- } else {
- raw_y /= 1 - properties_y.offset;
- }
- }
- // Invert direction if needed
- raw_x = properties_x.inverted ? -raw_x : raw_x;
- raw_y = properties_y.inverted ? -raw_y : raw_y;
- // Set initial values to be formated
- x = raw_x;
- y = raw_y;
- // Calculate vector size
- float r = x * x + y * y;
- r = std::sqrt(r);
- // TODO(German77): Use deadzone and range of both axis
- // Return zero if values are smaller than the deadzone
- if (r <= properties_x.deadzone || properties_x.deadzone >= 1.0f) {
- x = 0;
- y = 0;
- return;
- }
- // Adjust range of joystick
- const float deadzone_factor =
- 1.0f / r * (r - properties_x.deadzone) / (1.0f - properties_x.deadzone);
- x = x * deadzone_factor / properties_x.range;
- y = y * deadzone_factor / properties_x.range;
- r = r * deadzone_factor / properties_x.range;
- // Normalize joystick
- if (clamp_value && r > 1.0f) {
- x /= r;
- y /= r;
- }
- }
- } // namespace Core::HID
|