1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2025-01-31 20:41:45 +01:00

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 <cstring>
#include <cstdio>
#include <cmath>
evdev_joystick_config g_evdev_joystick_config;
@ -20,8 +21,6 @@ namespace
const u32 THREAD_SLEEP_INACTIVE_USEC = 1000000;
const u32 READ_TIMEOUT = 10;
const u32 THREAD_TIMEOUT_USEC = 1000000;
const std::string EVENT_JOYSTICK = "event-joystick";
}
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.ryreverse);
fs::dir devdir{"/dev/input/by-path"};
fs::dir devdir{"/dev/input/"};
fs::dir_entry et;
while (devdir.read(et))
{
// Does the entry name end with event-joystick?
if (et.name.size() > EVENT_JOYSTICK.size() &&
et.name.compare(et.name.size() - EVENT_JOYSTICK.size(),
EVENT_JOYSTICK.size(), EVENT_JOYSTICK) == 0)
// Check if the entry starts with event (a 5-letter word)
if (et.name.size() > 5 && et.name.compare(0, 5,"event") == 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_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_hat_ids.emplace_back(-1);
m_pads.emplace_back(
@ -111,6 +123,36 @@ void evdev_joystick_handler::update_devs()
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)
{
libevdev*& dev = joy_devs[index];
@ -395,8 +437,33 @@ void evdev_joystick_handler::thread_func()
LOG_ERROR(GENERAL, "Joystick #%d sent axis event for invalid axis %d", i, axis);
break;
}
pad.m_sticks[axis].m_value = scale_axis(evt.code, evt.value);
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);
}
break;
default:

View File

@ -8,6 +8,7 @@
#include <vector>
#include <thread>
#define JOYSTICK_BUSTYPE 3
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 axistrigger{this, "Z axis triggers", true};
cfg::_bool squirclejoysticks{this, "Squircle Joysticks", true};
cfg::int32 squirclefactor{this, "Squircle Factor", 5000};
bool load()
{
@ -74,6 +77,7 @@ public:
private:
void update_devs();
std::tuple<u16, u16> ConvertToSquirclePoint(u16 inX, u16 inY);
bool try_open_dev(u32 index);
int scale_axis(int axis, int value);
void thread_func();
@ -84,6 +88,8 @@ private:
std::vector<libevdev*> joy_devs;
std::vector<std::vector<int>> joy_button_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;
bool axistrigger;
std::map<int, std::pair<int, int>> axis_ranges;