From bfafa95f65e42c315f67a53bce4ade02ae0def9d Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Thu, 25 Aug 2022 00:54:22 +1000 Subject: [PATCH] EvdevInputSource: Migrate to new abstractions --- src/frontend-common/CMakeLists.txt | 4 +- src/frontend-common/common_host.cpp | 2 +- .../evdev_controller_interface.cpp | 447 --------------- .../evdev_controller_interface.h | 103 ---- src/frontend-common/evdev_input_source.cpp | 534 ++++++++++++++++++ src/frontend-common/evdev_input_source.h | 88 +++ src/frontend-common/input_manager.cpp | 6 + src/frontend-common/input_manager.h | 3 + src/frontend-common/input_source.h | 3 + 9 files changed, 637 insertions(+), 553 deletions(-) delete mode 100644 src/frontend-common/evdev_controller_interface.cpp delete mode 100644 src/frontend-common/evdev_controller_interface.h create mode 100644 src/frontend-common/evdev_input_source.cpp create mode 100644 src/frontend-common/evdev_input_source.h diff --git a/src/frontend-common/CMakeLists.txt b/src/frontend-common/CMakeLists.txt index 9a090e70f..7476cfc34 100644 --- a/src/frontend-common/CMakeLists.txt +++ b/src/frontend-common/CMakeLists.txt @@ -107,8 +107,8 @@ if(USE_EVDEV) target_include_directories(frontend-common PRIVATE ${LIBEVDEV_INCLUDE_DIRS}) target_link_libraries(frontend-common PRIVATE ${LIBEVDEV_LIBRARIES}) target_sources(frontend-common PRIVATE - evdev_controller_interface.cpp - evdev_controller_interface.h + evdev_input_source.cpp + evdev_input_source.h ) endif() diff --git a/src/frontend-common/common_host.cpp b/src/frontend-common/common_host.cpp index 2b5eed923..f99b747fa 100644 --- a/src/frontend-common/common_host.cpp +++ b/src/frontend-common/common_host.cpp @@ -92,7 +92,6 @@ void CommonHost::Initialize() { // This will call back to Host::LoadSettings() -> ReloadSources(). System::LoadSettings(false); - UpdateLogSettings(); #ifdef WITH_CHEEVOS #ifdef WITH_RAINTEGRATION @@ -347,6 +346,7 @@ void CommonHost::SetDefaultHotkeyBindings(SettingsInterface& si) void CommonHost::LoadSettings(SettingsInterface& si, std::unique_lock& lock) { + UpdateLogSettings(); InputManager::ReloadSources(si, lock); InputManager::ReloadBindings(si, *Host::GetSettingsInterfaceForBindings()); diff --git a/src/frontend-common/evdev_controller_interface.cpp b/src/frontend-common/evdev_controller_interface.cpp deleted file mode 100644 index 2a730fe45..000000000 --- a/src/frontend-common/evdev_controller_interface.cpp +++ /dev/null @@ -1,447 +0,0 @@ -#include "evdev_controller_interface.h" -#include "common/assert.h" -#include "common/file_system.h" -#include "common/log.h" -#include "core/controller.h" -#include "core/system.h" -#include -#include -#include -#include -#include - -#ifdef __linux__ -#include -#endif - -#if 0 - -Log_SetChannel(EvdevControllerInterface); - -EvdevControllerInterface::EvdevControllerInterface() = default; - -EvdevControllerInterface::~EvdevControllerInterface() = default; - -ControllerInterface::Backend EvdevControllerInterface::GetBackend() const -{ - return ControllerInterface::Backend::Evdev; -} - -bool EvdevControllerInterface::Initialize(CommonHostInterface* host_interface) -{ - for (int index = 0; index < 1000; index++) - { - TinyString path; - path.Format("/dev/input/event%d", index); - - int fd = open(path, O_RDONLY | O_NONBLOCK); - if (fd < 0) - break; - - struct libevdev* obj; - if (libevdev_new_from_fd(fd, &obj) != 0) - { - Log_ErrorPrintf("libevdev_new_from_fd(%s) failed", path.GetCharArray()); - close(fd); - continue; - } - - ControllerData data(fd, obj); - data.controller_id = static_cast(m_controllers.size()); - if (InitializeController(index, &data)) - m_controllers.push_back(std::move(data)); - } - - if (!ControllerInterface::Initialize(host_interface)) - return false; - - return true; -} - -void EvdevControllerInterface::Shutdown() -{ - ControllerInterface::Shutdown(); -} - -EvdevControllerInterface::ControllerData::ControllerData(int fd_, struct libevdev* obj_) : obj(obj_), fd(fd_) {} - -EvdevControllerInterface::ControllerData::ControllerData(ControllerData&& move) - : obj(move.obj), fd(move.fd), controller_id(move.controller_id), num_motors(move.num_motors), deadzone(move.deadzone), - axes(std::move(move.axes)), buttons(std::move(move.buttons)) -{ - move.obj = nullptr; - move.fd = -1; -} - -EvdevControllerInterface::ControllerData::~ControllerData() -{ - if (obj) - libevdev_free(obj); - if (fd >= 0) - close(fd); -} - -EvdevControllerInterface::ControllerData& -EvdevControllerInterface::ControllerData::operator=(EvdevControllerInterface::ControllerData&& move) -{ - if (obj) - libevdev_free(obj); - obj = move.obj; - move.obj = nullptr; - if (fd >= 0) - close(fd); - fd = move.fd; - move.fd = -1; - controller_id = move.controller_id; - num_motors = move.num_motors; - deadzone = move.deadzone; - axes = std::move(move.axes); - buttons = std::move(move.buttons); - return *this; -} - -EvdevControllerInterface::ControllerData* EvdevControllerInterface::GetControllerById(int id) -{ - for (ControllerData& cd : m_controllers) - { - if (cd.controller_id == id) - return &cd; - } - - return nullptr; -} - -bool EvdevControllerInterface::InitializeController(int index, ControllerData* cd) -{ - const char* name = libevdev_get_name(cd->obj); - Log_DevPrintf("Input %d device name: \"%s\"", index, name); - Log_DevPrintf("Input %d device ID: bus %#x vendor %#x product %#x", index, libevdev_get_id_bustype(cd->obj), - libevdev_get_id_vendor(cd->obj), libevdev_get_id_product(cd->obj)); - - for (u32 key = 0; key < KEY_CNT; key++) - { - if (!libevdev_has_event_code(cd->obj, EV_KEY, key)) - continue; - - const char* button_name = libevdev_event_code_get_name(EV_KEY, key); - Log_DevPrintf("Key %d: %s -> Button %zu", key, button_name ? button_name : "null", cd->buttons.size()); - - ControllerData::Button button; - button.id = key; - cd->buttons.push_back(std::move(button)); - } - - for (u32 axis = 0; axis <= ABS_TOOL_WIDTH; axis++) - { - if (!libevdev_has_event_code(cd->obj, EV_ABS, axis)) - continue; - - const s32 min = libevdev_get_abs_minimum(cd->obj, axis); - const s32 max = libevdev_get_abs_maximum(cd->obj, axis); - const char* axis_name = libevdev_event_code_get_name(EV_ABS, axis); - Log_DevPrintf("Axis %u: %s -> Axis %zu [%d-%d]", axis, axis_name ? axis_name : "null", cd->axes.size(), min, max); - - ControllerData::Axis ad; - ad.id = axis; - ad.min = min; - ad.range = max - min; - cd->axes.push_back(std::move(ad)); - } - - // Heuristic borrowed from Dolphin's evdev controller interface - ignore bogus devices - // which do have less than 2 axes and less than 8 buttons. - if (cd->axes.size() < 2 && cd->buttons.size() < 8) - { - Log_VerbosePrintf("Ignoring device %s with %zu axes and %zu buttons due to heuristic", name, cd->axes.size(), - cd->buttons.size()); - return false; - } - - Log_InfoPrintf("Controller %d -> %s with %zu axes and %zu buttons", cd->controller_id, name, cd->axes.size(), - cd->buttons.size()); - return true; -} - -void EvdevControllerInterface::HandleControllerEvents(ControllerData* cd) -{ - struct input_event ev; - while (libevdev_next_event(cd->obj, LIBEVDEV_READ_FLAG_NORMAL, &ev) == 0) - { - switch (ev.type) - { - case EV_KEY: - { - // auto-repeat - if (ev.value == 2) - continue; - - const bool pressed = (ev.value == 1); - Log_DevPrintf("Key %d %s", ev.code, pressed ? "pressed" : "unpressed"); - - for (u32 i = 0; i < static_cast(cd->buttons.size()); i++) - { - if (cd->buttons[i].id == ev.code) - { - HandleButtonEvent(cd, i, ev.code, pressed); - break; - } - } - } - break; - - case EV_ABS: - { - // axis - Log_DebugPrintf("Axis %u %d", ev.code, ev.value); - - for (u32 i = 0; i < static_cast(cd->axes.size()); i++) - { - if (cd->axes[i].id == ev.code) - { - HandleAxisEvent(cd, i, ev.value); - break; - } - } - } - break; - - default: - break; - } - } -} - -void EvdevControllerInterface::PollEvents() -{ - if (m_controllers.empty()) - return; - - struct pollfd* fds = static_cast(alloca(sizeof(struct pollfd) * m_controllers.size())); - for (size_t i = 0; i < m_controllers.size(); i++) - { - fds[i].events = POLLIN; - fds[i].fd = m_controllers[i].fd; - fds[i].revents = 0; - } - - if (poll(fds, static_cast(m_controllers.size()), 0) <= 0) - return; - - for (size_t i = 0; i < m_controllers.size(); i++) - { - if (fds[i].revents & POLLIN) - HandleControllerEvents(&m_controllers[i]); - } -} - -void EvdevControllerInterface::ClearBindings() -{ - for (ControllerData& cd : m_controllers) - { - for (ControllerData::Button& btn : cd.buttons) - { - btn.callback = {}; - btn.axis_callback = {}; - } - for (ControllerData::Axis& axis : cd.axes) - { - axis.callback = {}; - axis.button_callback = {}; - } - } -} - -bool EvdevControllerInterface::BindControllerAxis(int controller_index, int axis_number, AxisSide axis_side, - AxisCallback callback) -{ - ControllerData* cd = GetControllerById(controller_index); - if (!cd || static_cast(axis_number) >= cd->axes.size()) - return false; - - cd->axes[axis_number].callback[axis_side] = std::move(callback); - return true; -} - -bool EvdevControllerInterface::BindControllerButton(int controller_index, int button_number, ButtonCallback callback) -{ - ControllerData* cd = GetControllerById(controller_index); - if (!cd || static_cast(button_number) >= cd->buttons.size()) - return false; - - cd->buttons[button_number].callback = std::move(callback); - return true; -} - -bool EvdevControllerInterface::BindControllerAxisToButton(int controller_index, int axis_number, bool direction, - ButtonCallback callback) -{ - ControllerData* cd = GetControllerById(controller_index); - if (!cd || static_cast(axis_number) >= cd->axes.size()) - return false; - - cd->axes[axis_number].button_callback[BoolToUInt8(direction)] = std::move(callback); - return true; -} - -bool EvdevControllerInterface::BindControllerHatToButton(int controller_index, int hat_number, - std::string_view hat_position, ButtonCallback callback) -{ - // Hats don't exist in XInput - return false; -} - -bool EvdevControllerInterface::BindControllerButtonToAxis(int controller_index, int button_number, - AxisCallback callback) -{ - ControllerData* cd = GetControllerById(controller_index); - if (!cd || static_cast(button_number) >= cd->buttons.size()) - return false; - - cd->buttons[button_number].axis_callback = std::move(callback); - return true; -} - -bool EvdevControllerInterface::HandleAxisEvent(ControllerData* cd, u32 axis, s32 value) -{ - const ControllerData::Axis& ad = cd->axes[axis]; - float f_value = (static_cast(value - ad.min) / static_cast(ad.range)); - if (ad.min < 0) - f_value = (f_value * 2.0f) - 1.0f; - - Log_DevPrintf("controller %u axis %u %d %f range %d", cd->controller_id, axis, value, f_value, ad.range); - - if (DoEventHook(Hook::Type::Axis, cd->controller_id, axis, f_value)) - return true; - - const AxisCallback& cb = ad.callback[AxisSide::Full]; - if (cb) - { - cb(f_value); - return true; - } - else - { - const AxisCallback& positive_cb = ad.callback[AxisSide::Positive]; - const AxisCallback& negative_cb = ad.callback[AxisSide::Negative]; - if (positive_cb || negative_cb) - { - if (positive_cb) - positive_cb((f_value < 0.0f) ? 0.0f : f_value); - if (negative_cb) - negative_cb((f_value >= 0.0f) ? 0.0f : -f_value); - - return true; - } - } - - // set the other direction to false so large movements don't leave the opposite on - const bool outside_deadzone = (std::abs(f_value) >= cd->deadzone); - const bool positive = (f_value >= 0.0f); - const ButtonCallback& other_button_cb = ad.button_callback[BoolToUInt8(!positive)]; - const ButtonCallback& button_cb = ad.button_callback[BoolToUInt8(positive)]; - if (button_cb) - { - button_cb(outside_deadzone); - if (other_button_cb) - other_button_cb(false); - return true; - } - else if (other_button_cb) - { - other_button_cb(false); - return true; - } - else - { - return false; - } -} - -static FrontendCommon::ControllerNavigationButton MapEventButtonToNavigationButton(int button_id) -{ - switch (button_id) - { - case BTN_A: - return FrontendCommon::ControllerNavigationButton::Activate; - case BTN_B: - return FrontendCommon::ControllerNavigationButton::Cancel; - case BTN_TL: - return FrontendCommon::ControllerNavigationButton::LeftShoulder; - case BTN_TR: - return FrontendCommon::ControllerNavigationButton::RightShoulder; - case BTN_DPAD_LEFT: - return FrontendCommon::ControllerNavigationButton::DPadLeft; - case BTN_DPAD_RIGHT: - return FrontendCommon::ControllerNavigationButton::DPadRight; - case BTN_DPAD_UP: - return FrontendCommon::ControllerNavigationButton::DPadUp; - case BTN_DPAD_DOWN: - return FrontendCommon::ControllerNavigationButton::DPadDown; - default: - return FrontendCommon::ControllerNavigationButton::Count; - } -} - -bool EvdevControllerInterface::HandleButtonEvent(ControllerData* cd, u32 button, int button_id, bool pressed) -{ - Log_DevPrintf("controller %d button %u %s", cd->controller_id, button, pressed ? "pressed" : "released"); - - if (DoEventHook(Hook::Type::Button, cd->controller_id, button, pressed ? 1.0f : 0.0f)) - return true; - - const FrontendCommon::ControllerNavigationButton nav_button = MapEventButtonToNavigationButton(button_id); - if (nav_button < FrontendCommon::ControllerNavigationButton::Count) - m_host_interface->SetControllerNavigationButtonState(nav_button, pressed); - - if (m_host_interface->IsControllerNavigationActive()) - { - // UI consumed the event - return true; - } - - const ButtonCallback& cb = cd->buttons[button].callback; - if (cb) - { - cb(pressed); - return true; - } - - // Assume a half-axis, i.e. in 0..1 range - const AxisCallback& axis_cb = cd->buttons[button].axis_callback; - if (axis_cb) - { - axis_cb(pressed ? 1.0f : 0.0f); - } - return true; -} - -u32 EvdevControllerInterface::GetControllerRumbleMotorCount(int controller_index) -{ - ControllerData* cd = GetControllerById(controller_index); - return cd ? cd->num_motors : 0; -} - -void EvdevControllerInterface::SetControllerRumbleStrength(int controller_index, const float* strengths, u32 num_motors) -{ - ControllerData* cd = GetControllerById(controller_index); - if (!cd) - return; - - /* XINPUT_VIBRATION vib; - vib.wLeftMotorSpeed = static_cast(strengths[0] * 65535.0f); - vib.wRightMotorSpeed = static_cast(strengths[1] * 65535.0f); - m_xinput_set_state(static_cast(controller_index), &vib);*/ -} - -bool EvdevControllerInterface::SetControllerDeadzone(int controller_index, float size /* = 0.25f */) -{ - ControllerData* cd = GetControllerById(controller_index); - if (!cd) - return false; - - cd->deadzone = std::clamp(std::abs(size), 0.01f, 0.99f); - Log_InfoPrintf("Controller %d deadzone size set to %f", controller_index, cd->deadzone); - return true; -} - -#endif diff --git a/src/frontend-common/evdev_controller_interface.h b/src/frontend-common/evdev_controller_interface.h deleted file mode 100644 index 56d52108b..000000000 --- a/src/frontend-common/evdev_controller_interface.h +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once -#include "input_source.h" -#include "core/types.h" -#include -#include -#include -#include -#include - -#if 0 - -class EvdevControllerInterface final : public ControllerInterface -{ -public: - EvdevControllerInterface(); - ~EvdevControllerInterface() override; - - Backend GetBackend() const override; - bool Initialize(CommonHostInterface* host_interface) override; - void Shutdown() override; - - // Removes all bindings. Call before setting new bindings. - void ClearBindings() override; - - // Binding to events. If a binding for this axis/button already exists, returns false. - bool BindControllerAxis(int controller_index, int axis_number, AxisSide axis_side, AxisCallback callback) override; - bool BindControllerButton(int controller_index, int button_number, ButtonCallback callback) override; - bool BindControllerAxisToButton(int controller_index, int axis_number, bool direction, - ButtonCallback callback) override; - bool BindControllerHatToButton(int controller_index, int hat_number, std::string_view hat_position, - ButtonCallback callback) override; - bool BindControllerButtonToAxis(int controller_index, int button_number, AxisCallback callback) override; - - // Changing rumble strength. - u32 GetControllerRumbleMotorCount(int controller_index) override; - void SetControllerRumbleStrength(int controller_index, const float* strengths, u32 num_motors) override; - - // Set deadzone that will be applied on axis-to-button mappings - bool SetControllerDeadzone(int controller_index, float size = 0.25f) override; - - void PollEvents() override; - -private: - enum class Axis : u32 - { - LeftX, - LeftY, - RightX, - RightY, - LeftTrigger, - RightTrigger - }; - - struct ControllerData - { - ControllerData(int fd_, struct libevdev* obj_); - ControllerData(const ControllerData&) = delete; - ControllerData(ControllerData&& move); - ~ControllerData(); - - ControllerData& operator=(const ControllerData&) = delete; - ControllerData& operator=(ControllerData&& move); - - struct libevdev* obj = nullptr; - int fd = -1; - int controller_id = 0; - u32 num_motors = 0; - - float deadzone = 0.25f; - - struct Axis - { - u32 id; - s32 min; - s32 range; - std::array callback; - std::array button_callback; - }; - - struct Button - { - u32 id; - ButtonCallback callback; - AxisCallback axis_callback; - }; - - std::vector axes; - std::vector