diff --git a/Source/Core/Common/MathUtil.h b/Source/Core/Common/MathUtil.h index 1556f8e39f..c8489a389a 100644 --- a/Source/Core/Common/MathUtil.h +++ b/Source/Core/Common/MathUtil.h @@ -17,6 +17,7 @@ namespace MathUtil { constexpr double TAU = 6.2831853071795865; constexpr double PI = TAU / 2; +constexpr double GRAVITY_ACCELERATION = 9.80665; template constexpr auto Sign(const T& val) -> decltype((T{} < val) - (val < T{})) diff --git a/Source/Core/Core/HW/WiimoteEmu/Dynamics.h b/Source/Core/Core/HW/WiimoteEmu/Dynamics.h index 6d610c394b..ecf55d4ee5 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Dynamics.h +++ b/Source/Core/Core/HW/WiimoteEmu/Dynamics.h @@ -6,6 +6,7 @@ #include +#include "Common/MathUtil.h" #include "Common/Matrix.h" #include "Core/HW/WiimoteCommon/DataReport.h" #include "InputCommon/ControllerEmu/ControlGroup/Buttons.h" @@ -18,7 +19,7 @@ namespace WiimoteEmu { -constexpr double GRAVITY_ACCELERATION = 9.80665; +using MathUtil::GRAVITY_ACCELERATION; struct PositionalState { diff --git a/Source/Core/InputCommon/ControllerInterface/DualShockUDPClient/DualShockUDPClient.cpp b/Source/Core/InputCommon/ControllerInterface/DualShockUDPClient/DualShockUDPClient.cpp index 60086d517c..9ed62e5285 100644 --- a/Source/Core/InputCommon/ControllerInterface/DualShockUDPClient/DualShockUDPClient.cpp +++ b/Source/Core/InputCommon/ControllerInterface/DualShockUDPClient/DualShockUDPClient.cpp @@ -108,7 +108,7 @@ private: int m_touch_y; }; -static constexpr double GRAVITY_ACCELERATION = 9.80665; +using MathUtil::GRAVITY_ACCELERATION; static constexpr char DEFAULT_SERVER_ADDRESS[] = "127.0.0.1"; static constexpr u16 DEFAULT_SERVER_PORT = 26760; static constexpr auto SERVER_REREGISTER_INTERVAL = std::chrono::seconds{1}; diff --git a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp index de14875f56..8aed987a2a 100644 --- a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp +++ b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp @@ -25,6 +25,121 @@ namespace ciface::evdev { +class Input : public Core::Device::Input +{ +public: + Input(u16 code, libevdev* dev) : m_code(code), m_dev(dev) {} + +protected: + const u16 m_code; + libevdev* const m_dev; +}; + +class Button final : public Input +{ +public: + Button(u8 index, u16 code, libevdev* dev) : Input(code, dev), m_index(index) {} + + std::string GetName() const override + { + // Buttons below 0x100 are mostly keyboard keys, and the names make sense + if (m_code < 0x100) + { + const char* name = libevdev_event_code_get_name(EV_KEY, m_code); + if (name) + return std::string(StripSpaces(name)); + } + // But controllers use codes above 0x100, and the standard label often doesn't match. + // We are better off with Button 0 and so on. + return "Button " + std::to_string(m_index); + } + + ControlState GetState() const override + { + int value = 0; + libevdev_fetch_event_value(m_dev, EV_KEY, m_code, &value); + return value; + } + +private: + const u8 m_index; +}; + +class AnalogInput : public Input +{ +public: + using Input::Input; + + ControlState GetState() const override + { + int value = 0; + libevdev_fetch_event_value(m_dev, EV_ABS, m_code, &value); + + return ControlState(value - m_base) / m_range; + } + +protected: + int m_range; + int m_base; +}; + +class Axis final : public AnalogInput +{ +public: + Axis(u8 index, u16 code, bool upper, libevdev* dev) : AnalogInput(code, dev), m_index(index) + { + const int min = libevdev_get_abs_minimum(m_dev, m_code); + const int max = libevdev_get_abs_maximum(m_dev, m_code); + + m_base = (max + min) / 2; + m_range = (upper ? max : min) - m_base; + } + + std::string GetName() const override + { + return "Axis " + std::to_string(m_index) + (m_range < 0 ? '-' : '+'); + } + +private: + const u8 m_index; +}; + +class MotionDataInput final : public AnalogInput +{ +public: + MotionDataInput(u16 code, ControlState resolution_scale, libevdev* dev) : AnalogInput(code, dev) + { + auto* const info = libevdev_get_abs_info(m_dev, m_code); + + // The average of the minimum and maximum value. (neutral value) + m_base = (info->maximum + info->minimum) / 2; + + m_range = info->resolution / resolution_scale; + } + + std::string GetName() const override + { + // Unfortunately there doesn't seem to be a "standard" orientation + // so we can't use "Accel Up"-like names. + constexpr std::array motion_data_names = {{ + "Accel X", + "Accel Y", + "Accel Z", + "Gyro X", + "Gyro Y", + "Gyro Z", + }}; + + // Our name array relies on sane axis codes from 0 to 5. + static_assert(ABS_X == 0, "evdev axis value sanity check"); + static_assert(ABS_RX == 3, "evdev axis value sanity check"); + + return std::string(motion_data_names[m_code]) + (m_range < 0 ? '-' : '+'); + } + + bool IsDetectable() override { return false; } +}; + static std::thread s_hotplug_thread; static Common::Flag s_hotplug_thread_running; static int s_wakeup_eventfd; @@ -213,9 +328,43 @@ evdevDevice::evdevDevice(const std::string& devnode) : m_devfile(devnode) AddInput(new Button(num_buttons++, key, m_dev)); } + int first_axis_code = 0; + + int num_motion_axis = 0; + if (libevdev_has_property(m_dev, INPUT_PROP_ACCELEROMETER)) + { + // If INPUT_PROP_ACCELEROMETER is set then X,Y,Z,RX,RY,RZ contain motion data. + + auto add_motion_inputs = [&num_motion_axis, this](int first_code, double scale) { + for (int i = 0; i != 3; ++i) + { + const int code = first_code + i; + if (libevdev_has_event_code(m_dev, EV_ABS, code)) + { + AddInput(new MotionDataInput(code, scale * -1, m_dev)); + AddInput(new MotionDataInput(code, scale, m_dev)); + + ++num_motion_axis; + } + } + }; + + // evdev resolution is specified in "g"s and deg/s. + // Convert these to m/s/s and rad/s. + constexpr ControlState accel_scale = MathUtil::GRAVITY_ACCELERATION; + constexpr ControlState gyro_scale = MathUtil::TAU / 360; + + add_motion_inputs(ABS_X, accel_scale); + add_motion_inputs(ABS_RX, gyro_scale); + + // evdev says regular axes should not be mixed with motion data, + // but we'll keep looking for regular axes after RZ just in case. + first_axis_code = ABS_RZ + 1; + } + // Absolute axis (thumbsticks) int num_axis = 0; - for (int axis = 0; axis < 0x100; axis++) + for (int axis = first_axis_code; axis != ABS_CNT; ++axis) { if (libevdev_has_event_code(m_dev, EV_ABS, axis)) { @@ -262,7 +411,7 @@ evdevDevice::evdevDevice(const std::string& devnode) : m_devfile(devnode) // TODO: Add leds as output devices // Was there some reasoning behind these numbers? - m_interesting = num_axis >= 2 || num_buttons >= 8; + m_interesting = num_motion_axis != 0 || num_axis >= 2 || num_buttons >= 8; } evdevDevice::~evdevDevice() @@ -306,50 +455,6 @@ bool evdevDevice::IsValid() const return true; } -std::string evdevDevice::Button::GetName() const -{ - // Buttons below 0x100 are mostly keyboard keys, and the names make sense - if (m_code < 0x100) - { - const char* name = libevdev_event_code_get_name(EV_KEY, m_code); - if (name) - return std::string(StripSpaces(name)); - } - // But controllers use codes above 0x100, and the standard label often doesn't match. - // We are better off with Button 0 and so on. - return "Button " + std::to_string(m_index); -} - -ControlState evdevDevice::Button::GetState() const -{ - int value = 0; - libevdev_fetch_event_value(m_dev, EV_KEY, m_code, &value); - return value; -} - -evdevDevice::Axis::Axis(u8 index, u16 code, bool upper, libevdev* dev) - : m_code(code), m_index(index), m_dev(dev) -{ - const int min = libevdev_get_abs_minimum(m_dev, m_code); - const int max = libevdev_get_abs_maximum(m_dev, m_code); - - m_base = (max + min) / 2; - m_range = (upper ? max : min) - m_base; -} - -std::string evdevDevice::Axis::GetName() const -{ - return "Axis " + std::to_string(m_index) + (m_range < 0 ? '-' : '+'); -} - -ControlState evdevDevice::Axis::GetState() const -{ - int value = 0; - libevdev_fetch_event_value(m_dev, EV_ABS, m_code, &value); - - return ControlState(value - m_base) / m_range; -} - evdevDevice::Effect::Effect(int fd) : m_fd(fd) { m_effect.id = -1; diff --git a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h index 9f2996b420..f4b095558b 100644 --- a/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h +++ b/Source/Core/InputCommon/ControllerInterface/evdev/evdev.h @@ -19,34 +19,6 @@ void Shutdown(); class evdevDevice : public Core::Device { private: - class Button : public Core::Device::Input - { - public: - std::string GetName() const override; - Button(u8 index, u16 code, libevdev* dev) : m_index(index), m_code(code), m_dev(dev) {} - ControlState GetState() const override; - - private: - const u8 m_index; - const u16 m_code; - libevdev* m_dev; - }; - - class Axis : public Core::Device::Input - { - public: - std::string GetName() const override; - Axis(u8 index, u16 code, bool upper, libevdev* dev); - ControlState GetState() const override; - - private: - const u16 m_code; - const u8 m_index; - int m_range; - int m_base; - libevdev* m_dev; - }; - class Effect : public Core::Device::Output { public: