Fix evdev controller detection, add joystick squircling

This commit is contained in:
Zion Nimchuk 2017-08-16 09:57:38 -07:00 committed by Ivan
parent e9f057c91b
commit 66a43c35db
2 changed files with 83 additions and 10 deletions

View file

@ -11,6 +11,7 @@
#include <errno.h> #include <errno.h>
#include <cstring> #include <cstring>
#include <cstdio> #include <cstdio>
#include <cmath>
evdev_joystick_config g_evdev_joystick_config; evdev_joystick_config g_evdev_joystick_config;
@ -20,8 +21,6 @@ namespace
const u32 THREAD_SLEEP_INACTIVE_USEC = 1000000; const u32 THREAD_SLEEP_INACTIVE_USEC = 1000000;
const u32 READ_TIMEOUT = 10; const u32 READ_TIMEOUT = 10;
const u32 THREAD_TIMEOUT_USEC = 1000000; const u32 THREAD_TIMEOUT_USEC = 1000000;
const std::string EVENT_JOYSTICK = "event-joystick";
} }
evdev_joystick_handler::evdev_joystick_handler() {} evdev_joystick_handler::evdev_joystick_handler() {}
@ -41,17 +40,29 @@ void evdev_joystick_handler::Init(const u32 max_connect)
revaxis.emplace_back(g_evdev_joystick_config.rxreverse); revaxis.emplace_back(g_evdev_joystick_config.rxreverse);
revaxis.emplace_back(g_evdev_joystick_config.ryreverse); revaxis.emplace_back(g_evdev_joystick_config.ryreverse);
fs::dir devdir{"/dev/input/by-path"}; fs::dir devdir{"/dev/input/"};
fs::dir_entry et; fs::dir_entry et;
while (devdir.read(et)) while (devdir.read(et))
{ {
// Does the entry name end with event-joystick? // Check if the entry starts with event (a 5-letter word)
if (et.name.size() > EVENT_JOYSTICK.size() && if (et.name.size() > 5 && et.name.compare(0, 5,"event") == 0)
et.name.compare(et.name.size() - EVENT_JOYSTICK.size(),
EVENT_JOYSTICK.size(), EVENT_JOYSTICK) == 0)
{ {
joy_paths.emplace_back(fmt::format("/dev/input/by-path/%s", et.name)); int fd = open(("/dev/input/" + et.name).c_str(), O_RDONLY|O_NONBLOCK);
struct libevdev *dev = NULL;
int rc = 1;
rc = libevdev_new_from_fd(fd, &dev);
if (rc < 0)
{
// If it's just a bad file descriptor, don't bother logging, but otherwise, log it.
if (rc == -9)
LOG_WARNING(GENERAL, "Failed to connect to device at %s, the error was: %s", "/dev/input/" + et.name, strerror(-rc));
continue;
}
if (libevdev_get_id_bustype(dev) == JOYSTICK_BUSTYPE)
{
joy_paths.emplace_back(fmt::format("/dev/input/%s", et.name));
}
} }
} }
@ -61,6 +72,7 @@ void evdev_joystick_handler::Init(const u32 max_connect)
{ {
joy_devs.push_back(nullptr); joy_devs.push_back(nullptr);
joy_axis_maps.emplace_back(ABS_RZ - ABS_X, -1); joy_axis_maps.emplace_back(ABS_RZ - ABS_X, -1);
joy_axis.emplace_back(ABS_RZ - ABS_X, -1);
joy_button_maps.emplace_back(KEY_MAX - BTN_JOYSTICK, -1); joy_button_maps.emplace_back(KEY_MAX - BTN_JOYSTICK, -1);
joy_hat_ids.emplace_back(-1); joy_hat_ids.emplace_back(-1);
m_pads.emplace_back( m_pads.emplace_back(
@ -111,6 +123,36 @@ void evdev_joystick_handler::update_devs()
m_info.now_connect = connected; m_info.now_connect = connected;
} }
inline u16 Clamp0To255(f32 input)
{
if (input > 255.f)
return 255;
else if (input < 0.f)
return 0;
else return static_cast<u16>(input);
}
std::tuple<u16, u16> evdev_joystick_handler::ConvertToSquirclePoint(u16 inX, u16 inY)
{
// convert inX and Y to a (-1, 1) vector;
const f32 x = (inX - 127) / 127.f;
const f32 y = ((inY - 127) / 127.f);
// compute angle and len of given point to be used for squircle radius
const f32 angle = std::atan2(y, x);
const f32 r = std::sqrt(std::pow(x, 2.f) + std::pow(y, 2.f));
// now find len/point on the given squircle from our current angle and radius in polar coords
// https://thatsmaths.com/2016/07/14/squircles/
const f32 newLen = (1 + std::pow(std::sin(2 * angle), 2.f) / (g_evdev_joystick_config.squirclefactor / 1000.f)) * r;
// we now have len and angle, convert to cartisian
const int newX = Clamp0To255(((newLen * std::cos(angle)) + 1) * 127);
const int newY = Clamp0To255(((newLen * std::sin(angle)) + 1) * 127);
return std::tuple<u16, u16>(newX, newY);
}
bool evdev_joystick_handler::try_open_dev(u32 index) bool evdev_joystick_handler::try_open_dev(u32 index)
{ {
libevdev*& dev = joy_devs[index]; libevdev*& dev = joy_devs[index];
@ -396,6 +438,31 @@ void evdev_joystick_handler::thread_func()
break; break;
} }
if (g_evdev_joystick_config.squirclejoysticks)
{
joy_axis[i][axis] = evt.value;
if (evt.code == ABS_X || evt.code == ABS_Y)
{
int Xaxis = joy_axis_maps[i][ABS_X];
int Yaxis = joy_axis_maps[i][ABS_Y];
pad.m_sticks[Xaxis].m_value = scale_axis(ABS_X, joy_axis[i][Xaxis]);
pad.m_sticks[Yaxis].m_value = scale_axis(ABS_Y, joy_axis[i][Yaxis]);
std::tie(pad.m_sticks[Xaxis].m_value, pad.m_sticks[Yaxis].m_value) =
ConvertToSquirclePoint(pad.m_sticks[Xaxis].m_value, pad.m_sticks[Yaxis].m_value);
}
else
{
int Xaxis = joy_axis_maps[i][ABS_RX];
int Yaxis = joy_axis_maps[i][ABS_RY];
pad.m_sticks[Xaxis].m_value = scale_axis(ABS_RX, joy_axis[i][Xaxis]);
pad.m_sticks[Yaxis].m_value = scale_axis(ABS_RY, joy_axis[i][Yaxis]);
std::tie(pad.m_sticks[Xaxis].m_value, pad.m_sticks[Yaxis].m_value) =
ConvertToSquirclePoint(pad.m_sticks[Xaxis].m_value, pad.m_sticks[Yaxis].m_value);
}
}
else
pad.m_sticks[axis].m_value = scale_axis(evt.code, evt.value); pad.m_sticks[axis].m_value = scale_axis(evt.code, evt.value);
} }
break; break;

View file

@ -8,6 +8,7 @@
#include <vector> #include <vector>
#include <thread> #include <thread>
#define JOYSTICK_BUSTYPE 3
enum { EVDEV_DPAD_HAT_AXIS_X = -1, EVDEV_DPAD_HAT_AXIS_Y = -2 }; enum { EVDEV_DPAD_HAT_AXIS_X = -1, EVDEV_DPAD_HAT_AXIS_Y = -2 };
@ -45,6 +46,8 @@ struct evdev_joystick_config final : cfg::node
cfg::_bool lyreverse{this, "Reverse left stick Y axis", false}; cfg::_bool lyreverse{this, "Reverse left stick Y axis", false};
cfg::_bool axistrigger{this, "Z axis triggers", true}; cfg::_bool axistrigger{this, "Z axis triggers", true};
cfg::_bool squirclejoysticks{this, "Squircle Joysticks", true};
cfg::int32 squirclefactor{this, "Squircle Factor", 5000};
bool load() bool load()
{ {
@ -74,6 +77,7 @@ public:
private: private:
void update_devs(); void update_devs();
std::tuple<u16, u16> ConvertToSquirclePoint(u16 inX, u16 inY);
bool try_open_dev(u32 index); bool try_open_dev(u32 index);
int scale_axis(int axis, int value); int scale_axis(int axis, int value);
void thread_func(); void thread_func();
@ -84,6 +88,8 @@ private:
std::vector<libevdev*> joy_devs; std::vector<libevdev*> joy_devs;
std::vector<std::vector<int>> joy_button_maps; std::vector<std::vector<int>> joy_button_maps;
std::vector<std::vector<int>> joy_axis_maps; std::vector<std::vector<int>> joy_axis_maps;
// joy_axis is only used for squircling
std::vector<std::vector<int>> joy_axis;
std::vector<int> joy_hat_ids; std::vector<int> joy_hat_ids;
bool axistrigger; bool axistrigger;
std::map<int, std::pair<int, int>> axis_ranges; std::map<int, std::pair<int, int>> axis_ranges;