From 66a43c35dbaa63c5ebba2690ad8ff0a982b882e5 Mon Sep 17 00:00:00 2001 From: Zion Nimchuk Date: Wed, 16 Aug 2017 09:57:38 -0700 Subject: [PATCH] Fix evdev controller detection, add joystick squircling --- rpcs3/evdev_joystick_handler.cpp | 87 ++++++++++++++++++++++++++++---- rpcs3/evdev_joystick_handler.h | 6 +++ 2 files changed, 83 insertions(+), 10 deletions(-) diff --git a/rpcs3/evdev_joystick_handler.cpp b/rpcs3/evdev_joystick_handler.cpp index e3f92029bc..097b013988 100644 --- a/rpcs3/evdev_joystick_handler.cpp +++ b/rpcs3/evdev_joystick_handler.cpp @@ -11,6 +11,7 @@ #include #include #include +#include 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(input); +} + +std::tuple 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(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: diff --git a/rpcs3/evdev_joystick_handler.h b/rpcs3/evdev_joystick_handler.h index 30e8a9a120..41026bdda9 100644 --- a/rpcs3/evdev_joystick_handler.h +++ b/rpcs3/evdev_joystick_handler.h @@ -8,6 +8,7 @@ #include #include +#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 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 joy_devs; std::vector> joy_button_maps; std::vector> joy_axis_maps; + // joy_axis is only used for squircling + std::vector> joy_axis; std::vector joy_hat_ids; bool axistrigger; std::map> axis_ranges;