InputCommon: Detect when evdev exposes acceleration/gyroscope data.
This commit is contained in:
parent
d8c62b5965
commit
1180c231a6
|
@ -17,6 +17,7 @@ namespace MathUtil
|
|||
{
|
||||
constexpr double TAU = 6.2831853071795865;
|
||||
constexpr double PI = TAU / 2;
|
||||
constexpr double GRAVITY_ACCELERATION = 9.80665;
|
||||
|
||||
template <typename T>
|
||||
constexpr auto Sign(const T& val) -> decltype((T{} < val) - (val < T{}))
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <array>
|
||||
|
||||
#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
|
||||
{
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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<const char*, 6> 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;
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue