mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-04-05 22:47:03 +00:00
evdev: add motion device
This commit is contained in:
parent
a3007e11ca
commit
829af30568
35 changed files with 1588 additions and 316 deletions
|
|
@ -34,6 +34,7 @@ evdev_joystick_handler::evdev_joystick_handler()
|
|||
// set capabilities
|
||||
b_has_config = true;
|
||||
b_has_rumble = true;
|
||||
b_has_motion = true;
|
||||
b_has_deadzones = true;
|
||||
|
||||
m_trigger_threshold = trigger_max / 2;
|
||||
|
|
@ -44,7 +45,7 @@ evdev_joystick_handler::evdev_joystick_handler()
|
|||
|
||||
evdev_joystick_handler::~evdev_joystick_handler()
|
||||
{
|
||||
Close();
|
||||
close_devices();
|
||||
}
|
||||
|
||||
void evdev_joystick_handler::init_config(cfg_pad* cfg)
|
||||
|
|
@ -78,6 +79,11 @@ void evdev_joystick_handler::init_config(cfg_pad* cfg)
|
|||
cfg->l2.def = axis_list.at(ABS_Z);
|
||||
cfg->l3.def = button_list.at(BTN_THUMBL);
|
||||
|
||||
cfg->motion_sensor_x.axis.def = motion_axis_list.at(ABS_X);
|
||||
cfg->motion_sensor_y.axis.def = motion_axis_list.at(ABS_Y);
|
||||
cfg->motion_sensor_z.axis.def = motion_axis_list.at(ABS_Z);
|
||||
cfg->motion_sensor_g.axis.def = motion_axis_list.at(ABS_RX);
|
||||
|
||||
cfg->pressure_intensity_button.def = button_list.at(NO_BUTTON);
|
||||
|
||||
// Set default misc variables
|
||||
|
|
@ -92,6 +98,11 @@ void evdev_joystick_handler::init_config(cfg_pad* cfg)
|
|||
cfg->from_default();
|
||||
}
|
||||
|
||||
std::unordered_map<u32, std::string> evdev_joystick_handler::get_motion_axis_list() const
|
||||
{
|
||||
return motion_axis_list;
|
||||
}
|
||||
|
||||
bool evdev_joystick_handler::Init()
|
||||
{
|
||||
if (m_is_init)
|
||||
|
|
@ -124,11 +135,14 @@ std::string evdev_joystick_handler::get_device_name(const libevdev* dev)
|
|||
std::string name = libevdev_get_name(dev);
|
||||
const auto unique = libevdev_get_uniq(dev);
|
||||
|
||||
if (name == "" && unique != nullptr)
|
||||
name = unique;
|
||||
if (name.empty())
|
||||
{
|
||||
if (unique)
|
||||
name = unique;
|
||||
|
||||
if (name == "")
|
||||
name = "Unknown Device";
|
||||
if (name.empty())
|
||||
name = "Unknown Device";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
|
@ -180,31 +194,34 @@ bool evdev_joystick_handler::update_device(const std::shared_ptr<PadDevice>& dev
|
|||
return true;
|
||||
}
|
||||
|
||||
void evdev_joystick_handler::update_devs()
|
||||
void evdev_joystick_handler::close_devices()
|
||||
{
|
||||
for (auto& binding : bindings)
|
||||
const auto free_device = [](EvdevDevice* evdev_device)
|
||||
{
|
||||
update_device(binding.first);
|
||||
}
|
||||
}
|
||||
|
||||
void evdev_joystick_handler::Close()
|
||||
{
|
||||
for (auto& binding : bindings)
|
||||
{
|
||||
EvdevDevice* evdev_device = static_cast<EvdevDevice*>(binding.first.get());
|
||||
if (evdev_device)
|
||||
if (evdev_device && evdev_device->device)
|
||||
{
|
||||
auto& dev = evdev_device->device;
|
||||
if (dev != nullptr)
|
||||
{
|
||||
const int fd = libevdev_get_fd(dev);
|
||||
if (evdev_device->effect_id != -1)
|
||||
ioctl(fd, EVIOCRMFF, evdev_device->effect_id);
|
||||
libevdev_free(dev);
|
||||
close(fd);
|
||||
}
|
||||
const int fd = libevdev_get_fd(evdev_device->device);
|
||||
if (evdev_device->effect_id != -1)
|
||||
ioctl(fd, EVIOCRMFF, evdev_device->effect_id);
|
||||
libevdev_free(evdev_device->device);
|
||||
close(fd);
|
||||
}
|
||||
};
|
||||
|
||||
for (auto& binding : m_bindings)
|
||||
{
|
||||
free_device(static_cast<EvdevDevice*>(binding.device.get()));
|
||||
free_device(static_cast<EvdevDevice*>(binding.buddy_device.get()));
|
||||
}
|
||||
|
||||
for (auto [name, device] : m_settings_added)
|
||||
{
|
||||
free_device(static_cast<EvdevDevice*>(device.get()));
|
||||
}
|
||||
|
||||
for (auto [name, device] : m_motion_settings_added)
|
||||
{
|
||||
free_device(static_cast<EvdevDevice*>(device.get()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -266,17 +283,15 @@ std::unordered_map<u64, std::pair<u16, bool>> evdev_joystick_handler::GetButtonV
|
|||
std::shared_ptr<evdev_joystick_handler::EvdevDevice> evdev_joystick_handler::get_evdev_device(const std::string& device)
|
||||
{
|
||||
// Add device if not yet present
|
||||
const int pad_index = add_device(device, nullptr, true);
|
||||
if (pad_index < 0)
|
||||
std::shared_ptr<EvdevDevice> evdev_device = add_device(device, true);
|
||||
if (!evdev_device)
|
||||
return nullptr;
|
||||
|
||||
auto dev = bindings[pad_index];
|
||||
|
||||
// Check if our device is connected
|
||||
if (!update_device(dev.first))
|
||||
if (!update_device(evdev_device))
|
||||
return nullptr;
|
||||
|
||||
return std::static_pointer_cast<EvdevDevice>(dev.first);
|
||||
return evdev_device;
|
||||
}
|
||||
|
||||
void evdev_joystick_handler::get_next_button_press(const std::string& padId, const pad_callback& callback, const pad_fail_callback& fail_callback, bool get_blacklist, const std::vector<std::string>& buttons)
|
||||
|
|
@ -286,7 +301,7 @@ void evdev_joystick_handler::get_next_button_press(const std::string& padId, con
|
|||
|
||||
// Get our evdev device
|
||||
auto device = get_evdev_device(padId);
|
||||
if (!device || device->device == nullptr)
|
||||
if (!device || !device->device)
|
||||
{
|
||||
if (fail_callback)
|
||||
fail_callback(padId);
|
||||
|
|
@ -351,7 +366,7 @@ void evdev_joystick_handler::get_next_button_press(const std::string& padId, con
|
|||
{
|
||||
u16 value = 0;
|
||||
std::string name;
|
||||
} pressed_button;
|
||||
} pressed_button{};
|
||||
|
||||
for (const auto& [code, name] : button_list)
|
||||
{
|
||||
|
|
@ -447,6 +462,62 @@ void evdev_joystick_handler::get_next_button_press(const std::string& padId, con
|
|||
}
|
||||
}
|
||||
|
||||
void evdev_joystick_handler::get_motion_sensors(const std::string& padId, const motion_callback& callback, const motion_fail_callback& fail_callback, motion_preview_values preview_values, const std::array<AnalogSensor, 4>& sensors)
|
||||
{
|
||||
// Add device if not yet present
|
||||
auto device = add_motion_device(padId, true);
|
||||
if (!device || !update_device(device) || !device->device)
|
||||
{
|
||||
if (fail_callback)
|
||||
fail_callback(padId, std::move(preview_values));
|
||||
return;
|
||||
}
|
||||
|
||||
auto& dev = device->device;
|
||||
|
||||
// Try to fetch all new events from the joystick.
|
||||
bool is_dirty = false;
|
||||
int ret = LIBEVDEV_READ_STATUS_SUCCESS;
|
||||
while (ret >= 0)
|
||||
{
|
||||
input_event evt;
|
||||
|
||||
if (ret == LIBEVDEV_READ_STATUS_SYNC)
|
||||
{
|
||||
// Grab any pending sync event.
|
||||
ret = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL | LIBEVDEV_READ_FLAG_SYNC, &evt);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &evt);
|
||||
}
|
||||
|
||||
if (ret == LIBEVDEV_READ_STATUS_SUCCESS && evt.type == EV_ABS)
|
||||
{
|
||||
for (usz i = 0; i < sensors.size(); i++)
|
||||
{
|
||||
const AnalogSensor& sensor = sensors[i];
|
||||
|
||||
if (sensor.m_keyCode != evt.code)
|
||||
continue;
|
||||
|
||||
preview_values[i] = get_sensor_value(dev, sensor, evt);;
|
||||
is_dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
// -EAGAIN signifies no available events, not an actual *error*.
|
||||
if (ret != -EAGAIN)
|
||||
evdev_log.error("Failed to read latest event from motion device: %s [errno %d]", strerror(-ret), -ret);
|
||||
}
|
||||
|
||||
if (callback && is_dirty)
|
||||
callback(padId, std::move(preview_values));
|
||||
}
|
||||
|
||||
// https://github.com/dolphin-emu/dolphin/blob/master/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp
|
||||
// https://github.com/reicast/reicast-emulator/blob/master/core/linux-dist/evdev.cpp
|
||||
// http://www.infradead.org/~mchehab/kernel_docs_pdf/linux-input.pdf
|
||||
|
|
@ -596,21 +667,19 @@ u32 evdev_joystick_handler::GetButtonInfo(const input_event& evt, const std::sha
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> evdev_joystick_handler::ListDevices()
|
||||
std::vector<pad_list_entry> evdev_joystick_handler::list_devices()
|
||||
{
|
||||
Init();
|
||||
|
||||
std::unordered_map<std::string, u32> unique_names;
|
||||
std::vector<std::string> evdev_joystick_list;
|
||||
fs::dir devdir{"/dev/input/"};
|
||||
fs::dir_entry et;
|
||||
std::vector<pad_list_entry> evdev_joystick_list;
|
||||
|
||||
while (devdir.read(et))
|
||||
for (auto&& et : fs::dir{"/dev/input/"})
|
||||
{
|
||||
// Check if the entry starts with event (a 5-letter word)
|
||||
if (et.name.size() > 5 && et.name.compare(0, 5, "event") == 0)
|
||||
if (et.name.size() > 5 && et.name.starts_with("event"))
|
||||
{
|
||||
const int fd = open(("/dev/input/" + et.name).c_str(), O_RDWR | O_NONBLOCK);
|
||||
const int fd = open(("/dev/input/" + et.name).c_str(), O_RDONLY | O_NONBLOCK);
|
||||
struct libevdev* dev = NULL;
|
||||
const int rc = libevdev_new_from_fd(fd, &dev);
|
||||
if (rc < 0)
|
||||
|
|
@ -622,19 +691,32 @@ std::vector<std::string> evdev_joystick_handler::ListDevices()
|
|||
close(fd);
|
||||
continue;
|
||||
}
|
||||
if (libevdev_has_event_type(dev, EV_KEY) &&
|
||||
libevdev_has_event_type(dev, EV_ABS))
|
||||
|
||||
if (libevdev_has_event_type(dev, EV_ABS))
|
||||
{
|
||||
// It's a joystick.
|
||||
std::string name = get_device_name(dev);
|
||||
bool is_motion_device = false;
|
||||
bool is_pad_device = libevdev_has_event_type(dev, EV_KEY);
|
||||
|
||||
if (unique_names.find(name) == unique_names.end())
|
||||
unique_names.emplace(name, 1);
|
||||
else
|
||||
name = fmt::format("%d. %s", ++unique_names[name], name);
|
||||
if (!is_pad_device)
|
||||
{
|
||||
// Check if it's a motion device.
|
||||
is_motion_device = libevdev_has_property(dev, INPUT_PROP_ACCELEROMETER);
|
||||
}
|
||||
|
||||
evdev_joystick_list.push_back(name);
|
||||
if (is_pad_device || is_motion_device)
|
||||
{
|
||||
// It's a joystick or motion device.
|
||||
std::string name = get_device_name(dev);
|
||||
|
||||
if (unique_names.find(name) == unique_names.end())
|
||||
unique_names.emplace(name, 1);
|
||||
else
|
||||
name = fmt::format("%d. %s", ++unique_names[name], name);
|
||||
|
||||
evdev_joystick_list.emplace_back(name, is_motion_device);
|
||||
}
|
||||
}
|
||||
|
||||
libevdev_free(dev);
|
||||
close(fd);
|
||||
}
|
||||
|
|
@ -642,19 +724,18 @@ std::vector<std::string> evdev_joystick_handler::ListDevices()
|
|||
return evdev_joystick_list;
|
||||
}
|
||||
|
||||
int evdev_joystick_handler::add_device(const std::string& device, const std::shared_ptr<Pad>& pad, bool in_settings)
|
||||
std::shared_ptr<evdev_joystick_handler::EvdevDevice> evdev_joystick_handler::add_device(const std::string& device, bool in_settings)
|
||||
{
|
||||
if (in_settings && m_settings_added.count(device))
|
||||
return m_settings_added.at(device);
|
||||
|
||||
// Now we need to find the device with the same name, and make sure not to grab any duplicates.
|
||||
std::unordered_map<std::string, u32> unique_names;
|
||||
fs::dir devdir{ "/dev/input/" };
|
||||
fs::dir_entry et;
|
||||
while (devdir.read(et))
|
||||
|
||||
for (auto&& et : fs::dir{"/dev/input/"})
|
||||
{
|
||||
// Check if the entry starts with event (a 5-letter word)
|
||||
if (et.name.size() > 5 && et.name.compare(0, 5, "event") == 0)
|
||||
if (et.name.size() > 5 && et.name.starts_with("event"))
|
||||
{
|
||||
const std::string path = "/dev/input/" + et.name;
|
||||
const int fd = open(path.c_str(), O_RDWR | O_NONBLOCK);
|
||||
|
|
@ -677,26 +758,16 @@ int evdev_joystick_handler::add_device(const std::string& device, const std::sha
|
|||
else
|
||||
name = fmt::format("%d. %s", ++unique_names[name], name);
|
||||
|
||||
if (libevdev_has_event_type(dev, EV_KEY) &&
|
||||
libevdev_has_event_type(dev, EV_ABS) &&
|
||||
name == device)
|
||||
if (name == device &&
|
||||
libevdev_has_event_type(dev, EV_KEY) &&
|
||||
libevdev_has_event_type(dev, EV_ABS))
|
||||
{
|
||||
// It's a joystick. Now let's make sure we don't already have this one.
|
||||
if (std::any_of(bindings.begin(), bindings.end(), [&path](std::pair<std::shared_ptr<PadDevice>, std::shared_ptr<Pad>> binding)
|
||||
{
|
||||
EvdevDevice* device = static_cast<EvdevDevice*>(binding.first.get());
|
||||
return device && path == device->path;
|
||||
}))
|
||||
{
|
||||
libevdev_free(dev);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
// It's a joystick.
|
||||
|
||||
if (in_settings)
|
||||
{
|
||||
m_dev = std::make_shared<EvdevDevice>();
|
||||
m_settings_added[device] = bindings.size();
|
||||
m_dev = std::make_shared<EvdevDevice>();
|
||||
m_settings_added[device] = m_dev;
|
||||
|
||||
// Let's log axis information while we are in the settings in order to identify problems more easily.
|
||||
for (const auto& [code, axis_name] : axis_list)
|
||||
|
|
@ -704,8 +775,8 @@ int evdev_joystick_handler::add_device(const std::string& device, const std::sha
|
|||
if (const input_absinfo *info = libevdev_get_abs_info(dev, code))
|
||||
{
|
||||
const auto code_name = libevdev_event_code_get_name(EV_ABS, code);
|
||||
evdev_log.notice("Axis info for %s: %s (%s) => minimum=%d, maximum=%d, fuzz=%d, resolution=%d",
|
||||
name, code_name, axis_name, info->minimum, info->maximum, info->fuzz, info->resolution);
|
||||
evdev_log.notice("Axis info for %s: %s (%s) => minimum=%d, maximum=%d, fuzz=%d, flat=%d, resolution=%d",
|
||||
name, code_name, axis_name, info->minimum, info->maximum, info->fuzz, info->flat, info->resolution);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -714,14 +785,93 @@ int evdev_joystick_handler::add_device(const std::string& device, const std::sha
|
|||
m_dev->device = dev;
|
||||
m_dev->path = path;
|
||||
m_dev->has_rumble = libevdev_has_event_type(dev, EV_FF);
|
||||
bindings.emplace_back(m_dev, pad);
|
||||
return bindings.size() - 1;
|
||||
m_dev->has_motion = libevdev_has_property(dev, INPUT_PROP_ACCELEROMETER);
|
||||
|
||||
evdev_log.notice("Capability info for %s: rumble=%d, motion=%d", name, m_dev->has_rumble, m_dev->has_motion);
|
||||
|
||||
return m_dev;
|
||||
}
|
||||
libevdev_free(dev);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<evdev_joystick_handler::EvdevDevice> evdev_joystick_handler::add_motion_device(const std::string& device, bool in_settings)
|
||||
{
|
||||
if (device.empty())
|
||||
return nullptr;
|
||||
|
||||
if (in_settings && m_motion_settings_added.count(device))
|
||||
return m_motion_settings_added.at(device);
|
||||
|
||||
// Now we need to find the device with the same name, and make sure not to grab any duplicates.
|
||||
std::unordered_map<std::string, u32> unique_names;
|
||||
|
||||
for (auto&& et : fs::dir{"/dev/input/"})
|
||||
{
|
||||
// Check if the entry starts with event (a 5-letter word)
|
||||
if (et.name.size() > 5 && et.name.starts_with("event"))
|
||||
{
|
||||
const std::string path = "/dev/input/" + et.name;
|
||||
const int fd = open(path.c_str(), O_RDWR | O_NONBLOCK);
|
||||
struct libevdev* dev = NULL;
|
||||
const int 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)
|
||||
evdev_log.warning("Failed to connect to device at %s, the error was: %s", path, strerror(-rc));
|
||||
libevdev_free(dev);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string name = get_device_name(dev);
|
||||
|
||||
if (unique_names.find(name) == unique_names.end())
|
||||
unique_names.emplace(name, 1);
|
||||
else
|
||||
name = fmt::format("%d. %s", ++unique_names[name], name);
|
||||
|
||||
if (name == device &&
|
||||
libevdev_has_property(dev, INPUT_PROP_ACCELEROMETER) &&
|
||||
libevdev_has_event_type(dev, EV_ABS))
|
||||
{
|
||||
// Let's log axis information while we are in the settings in order to identify problems more easily.
|
||||
// Directional axes on this device (absolute and/or relative x, y, z) represent accelerometer data.
|
||||
// Some devices also report gyroscope data, which devices can report through the rotational axes (absolute and/or relative rx, ry, rz).
|
||||
// All other axes retain their meaning.
|
||||
// A device must not mix regular directional axes and accelerometer axes on the same event node.
|
||||
for (const auto& [code, axis_name] : axis_list)
|
||||
{
|
||||
if (const input_absinfo *info = libevdev_get_abs_info(dev, code))
|
||||
{
|
||||
const bool is_accel = code == ABS_X || code == ABS_Y || code == ABS_Z;
|
||||
const auto code_name = libevdev_event_code_get_name(EV_ABS, code);
|
||||
evdev_log.notice("Axis info for %s: %s (%s, %s) => minimum=%d, maximum=%d, fuzz=%d, flat=%d, resolution=%d",
|
||||
name, code_name, axis_name, is_accel ? "accelerometer" : "gyro", info->minimum, info->maximum, info->fuzz, info->flat, info->resolution);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<EvdevDevice> motion_device = std::make_shared<EvdevDevice>();
|
||||
motion_device->device = dev;
|
||||
motion_device->path = path;
|
||||
motion_device->has_motion = true;
|
||||
|
||||
if (in_settings)
|
||||
{
|
||||
m_motion_settings_added[device] = motion_device;
|
||||
}
|
||||
|
||||
return motion_device;
|
||||
}
|
||||
libevdev_free(dev);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PadHandlerBase::connection evdev_joystick_handler::update_connection(const std::shared_ptr<PadDevice>& device)
|
||||
|
|
@ -736,14 +886,16 @@ PadHandlerBase::connection evdev_joystick_handler::update_connection(const std::
|
|||
return connection::connected;
|
||||
}
|
||||
|
||||
void evdev_joystick_handler::get_mapping(const std::shared_ptr<PadDevice>& device, const std::shared_ptr<Pad>& pad)
|
||||
void evdev_joystick_handler::get_mapping(const pad_ensemble& binding)
|
||||
{
|
||||
m_dev = std::static_pointer_cast<EvdevDevice>(device);
|
||||
m_dev = std::static_pointer_cast<EvdevDevice>(binding.device);
|
||||
const auto& pad = binding.pad;
|
||||
|
||||
if (!m_dev || !pad)
|
||||
return;
|
||||
|
||||
auto& dev = m_dev->device;
|
||||
if (dev == nullptr)
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
// Try to fetch all new events from the joystick.
|
||||
|
|
@ -772,10 +924,77 @@ void evdev_joystick_handler::get_mapping(const std::shared_ptr<PadDevice>& devic
|
|||
// -EAGAIN signifies no available events, not an actual *error*.
|
||||
if (ret != -EAGAIN)
|
||||
evdev_log.error("Failed to read latest event from joystick: %s [errno %d]", strerror(-ret), -ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void evdev_joystick_handler::get_extended_info(const pad_ensemble& binding)
|
||||
{
|
||||
// We use this to get motion controls from our buddy device
|
||||
const auto& device = std::static_pointer_cast<EvdevDevice>(binding.buddy_device);
|
||||
const auto& pad = binding.pad;
|
||||
|
||||
if (!pad || !device || !update_device(device))
|
||||
return;
|
||||
|
||||
auto& dev = device->device;
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
// Try to fetch all new events from the joystick.
|
||||
input_event evt;
|
||||
int ret = LIBEVDEV_READ_STATUS_SUCCESS;
|
||||
while (ret >= 0)
|
||||
{
|
||||
if (ret == LIBEVDEV_READ_STATUS_SYNC)
|
||||
{
|
||||
// Grab any pending sync event.
|
||||
ret = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL | LIBEVDEV_READ_FLAG_SYNC, &evt);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &evt);
|
||||
}
|
||||
|
||||
if (ret == LIBEVDEV_READ_STATUS_SUCCESS && evt.type == EV_ABS)
|
||||
{
|
||||
for (AnalogSensor& sensor : pad->m_sensors)
|
||||
{
|
||||
if (sensor.m_keyCode != evt.code)
|
||||
continue;
|
||||
|
||||
sensor.m_value = get_sensor_value(dev, sensor, evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
// -EAGAIN signifies no available events, not an actual *error*.
|
||||
if (ret != -EAGAIN)
|
||||
evdev_log.error("Failed to read latest event from buddy device: %s [errno %d]", strerror(-ret), -ret);
|
||||
}
|
||||
}
|
||||
|
||||
u16 evdev_joystick_handler::get_sensor_value(const libevdev* dev, const AnalogSensor& sensor, const input_event& evt) const
|
||||
{
|
||||
if (dev)
|
||||
{
|
||||
const int min = libevdev_get_abs_minimum(dev, evt.code);
|
||||
const int max = libevdev_get_abs_maximum(dev, evt.code);
|
||||
|
||||
s16 value = ScaledInput(evt.value, min, max, 1023.0f);
|
||||
|
||||
if (sensor.m_mirrored)
|
||||
{
|
||||
value = 1023 - value;
|
||||
}
|
||||
|
||||
return Clamp0To1023(value + sensor.m_shift);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void evdev_joystick_handler::handle_input_event(const input_event& evt, const std::shared_ptr<Pad>& pad)
|
||||
{
|
||||
if (!pad)
|
||||
|
|
@ -815,7 +1034,8 @@ void evdev_joystick_handler::handle_input_event(const input_event& evt, const st
|
|||
evdev_log.error("FindAxisDirection = %d, Button Nr.%d, value = %d", direction, i, value);
|
||||
continue;
|
||||
}
|
||||
else if (direction != (m_is_negative ? 1 : 0))
|
||||
|
||||
if (direction != (m_is_negative ? 1 : 0))
|
||||
{
|
||||
button.m_value = 0;
|
||||
button.m_pressed = 0;
|
||||
|
|
@ -867,7 +1087,9 @@ void evdev_joystick_handler::handle_input_event(const input_event& evt, const st
|
|||
TranslateButtonPress(m_dev, button_code, pressed_min, m_dev->val_min[idx], true);
|
||||
}
|
||||
else // set to 0 to avoid remnant counter axis values
|
||||
{
|
||||
m_dev->val_min[idx] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// m_keyCodeMax is the mapped key for right or up
|
||||
|
|
@ -893,7 +1115,9 @@ void evdev_joystick_handler::handle_input_event(const input_event& evt, const st
|
|||
TranslateButtonPress(m_dev, button_code, pressed_max, m_dev->val_max[idx], true);
|
||||
}
|
||||
else // set to 0 to avoid remnant counter axis values
|
||||
{
|
||||
m_dev->val_max[idx] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// cancel out opposing values and get the resulting difference. if there was no change, use the old value.
|
||||
|
|
@ -901,6 +1125,8 @@ void evdev_joystick_handler::handle_input_event(const input_event& evt, const st
|
|||
}
|
||||
|
||||
const auto cfg = m_dev->config;
|
||||
if (!cfg)
|
||||
return;
|
||||
|
||||
u16 lx, ly, rx, ry;
|
||||
|
||||
|
|
@ -914,13 +1140,18 @@ void evdev_joystick_handler::handle_input_event(const input_event& evt, const st
|
|||
pad->m_sticks[3].m_value = 255 - ry;
|
||||
}
|
||||
|
||||
void evdev_joystick_handler::apply_pad_data(const std::shared_ptr<PadDevice>& device, const std::shared_ptr<Pad>& pad)
|
||||
void evdev_joystick_handler::apply_pad_data(const pad_ensemble& binding)
|
||||
{
|
||||
const auto& device = binding.device;
|
||||
const auto& pad = binding.pad;
|
||||
|
||||
EvdevDevice* evdev_device = static_cast<EvdevDevice*>(device.get());
|
||||
if (!evdev_device)
|
||||
return;
|
||||
|
||||
auto cfg = device->config;
|
||||
if (!cfg)
|
||||
return;
|
||||
|
||||
// Handle vibration
|
||||
const int idx_l = cfg->switch_vibration_motors ? 1 : 0;
|
||||
|
|
@ -940,8 +1171,12 @@ int evdev_joystick_handler::FindAxisDirection(const std::unordered_map<int, bool
|
|||
return -1;
|
||||
}
|
||||
|
||||
bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device, u8 player_id)
|
||||
bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, u8 player_id)
|
||||
{
|
||||
if (!pad || player_id >= g_cfg_input.player.size())
|
||||
return false;
|
||||
|
||||
const cfg_player* player_config = g_cfg_input.player[player_id];
|
||||
if (!pad)
|
||||
return false;
|
||||
|
||||
|
|
@ -949,11 +1184,11 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std
|
|||
|
||||
m_dev = std::make_shared<EvdevDevice>();
|
||||
|
||||
m_pad_configs[player_id].from_string(g_cfg_input.player[player_id]->config.to_string());
|
||||
m_pad_configs[player_id].from_string(player_config->config.to_string());
|
||||
m_dev->config = &m_pad_configs[player_id];
|
||||
m_dev->player_id = player_id;
|
||||
cfg_pad* cfg = m_dev->config;
|
||||
if (cfg == nullptr)
|
||||
if (!cfg)
|
||||
return false;
|
||||
|
||||
std::unordered_map<int, bool> axis_orientations;
|
||||
|
|
@ -990,6 +1225,17 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std
|
|||
return button;
|
||||
};
|
||||
|
||||
const auto find_motion_button = [&](const cfg_sensor& sensor) -> evdev_sensor
|
||||
{
|
||||
evdev_sensor e_sensor{};
|
||||
e_sensor.type = EV_ABS;
|
||||
e_sensor.mirrored = sensor.mirrored.get();
|
||||
e_sensor.shift = sensor.shift.get();
|
||||
const int key = FindKeyCode(motion_axis_list, sensor.axis, false);
|
||||
if (key >= 0) e_sensor.code = static_cast<u32>(key);
|
||||
return e_sensor;
|
||||
};
|
||||
|
||||
u32 pclass_profile = 0x0;
|
||||
|
||||
for (const auto product : input::get_products_by_class(cfg->device_class_type))
|
||||
|
|
@ -1052,20 +1298,44 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, const std
|
|||
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, m_dev->axis_right[1].code, m_dev->axis_right[0].code);
|
||||
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, m_dev->axis_right[3].code, m_dev->axis_right[2].code);
|
||||
|
||||
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512);
|
||||
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399);
|
||||
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Z, 512);
|
||||
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_G, 512);
|
||||
m_dev->axis_motion[0] = find_motion_button(cfg->motion_sensor_x);
|
||||
m_dev->axis_motion[1] = find_motion_button(cfg->motion_sensor_y);
|
||||
m_dev->axis_motion[2] = find_motion_button(cfg->motion_sensor_z);
|
||||
m_dev->axis_motion[3] = find_motion_button(cfg->motion_sensor_g);
|
||||
|
||||
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, m_dev->axis_motion[0].code, m_dev->axis_motion[0].mirrored, m_dev->axis_motion[0].shift, DEFAULT_MOTION_X);
|
||||
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, m_dev->axis_motion[1].code, m_dev->axis_motion[1].mirrored, m_dev->axis_motion[1].shift, DEFAULT_MOTION_Y);
|
||||
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Z, m_dev->axis_motion[2].code, m_dev->axis_motion[2].mirrored, m_dev->axis_motion[2].shift, DEFAULT_MOTION_Z);
|
||||
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_G, m_dev->axis_motion[3].code, m_dev->axis_motion[3].mirrored, m_dev->axis_motion[3].shift, DEFAULT_MOTION_G);
|
||||
|
||||
pad->m_vibrateMotors.emplace_back(true, 0);
|
||||
pad->m_vibrateMotors.emplace_back(false, 0);
|
||||
|
||||
m_dev->axis_orientations = axis_orientations;
|
||||
|
||||
if (add_device(device, pad, false) < 0)
|
||||
evdev_log.warning("evdev add_device in bindPadToDevice failed for device %s", device);
|
||||
if (auto evdev_device = add_device(player_config->device, false))
|
||||
{
|
||||
if (auto motion_device = add_motion_device(player_config->buddy_device, false))
|
||||
{
|
||||
m_bindings.emplace_back(pad, evdev_device, motion_device);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bindings.emplace_back(pad, evdev_device, nullptr);
|
||||
evdev_log.warning("evdev add_motion_device in bindPadToDevice failed for device %s", player_config->buddy_device.to_string());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
evdev_log.warning("evdev add_device in bindPadToDevice failed for device %s", player_config->device.to_string());
|
||||
}
|
||||
|
||||
for (auto& binding : m_bindings)
|
||||
{
|
||||
update_device(binding.device);
|
||||
update_device(binding.buddy_device);
|
||||
}
|
||||
|
||||
update_devs();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1074,7 +1344,7 @@ bool evdev_joystick_handler::check_button(const EvdevButton& b, const u32 code)
|
|||
return m_dev && b.code == code && b.type == m_dev->cur_type && b.dir == m_dev->cur_dir;
|
||||
}
|
||||
|
||||
bool evdev_joystick_handler::check_buttons(const std::vector<EvdevButton>& b, const u32 code)
|
||||
bool evdev_joystick_handler::check_buttons(const std::array<EvdevButton, 4>& b, const u32 code)
|
||||
{
|
||||
return std::any_of(b.begin(), b.end(), [this, code](const EvdevButton& b) { return check_button(b, code); });
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue