Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

evdev: add motion controls #12502

Merged
merged 1 commit into from
Aug 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions rpcs3/Emu/Io/Null/NullPadHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ class NullPadHandler final : public PadHandlerBase
cfg->from_default();
}

std::vector<std::string> ListDevices() override
std::vector<pad_list_entry> list_devices() override
{
std::vector<std::string> nulllist;
nulllist.emplace_back("Default Null Device");
std::vector<pad_list_entry> nulllist;
nulllist.emplace_back("Default Null Device", false);
return nulllist;
}

bool bindPadToDevice(std::shared_ptr<Pad> /*pad*/, const std::string& /*device*/, u8 /*player_id*/) override
bool bindPadToDevice(std::shared_ptr<Pad> /*pad*/, u8 /*player_id*/) override
{
return true;
}
Expand Down
145 changes: 102 additions & 43 deletions rpcs3/Emu/Io/PadHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,19 +112,19 @@ s32 PadHandlerBase::MultipliedInput(s32 raw_value, s32 multiplier)
}

// Get new scaled value between 0 and 255 based on its minimum and maximum
float PadHandlerBase::ScaledInput(s32 raw_value, int minimum, int maximum)
f32 PadHandlerBase::ScaledInput(s32 raw_value, int minimum, int maximum, f32 range)
{
// value based on max range converted to [0, 1]
const float val = static_cast<float>(std::clamp(raw_value, minimum, maximum) - minimum) / (abs(maximum) + abs(minimum));
return 255.0f * val;
const f32 val = static_cast<f32>(std::clamp(raw_value, minimum, maximum) - minimum) / (abs(maximum) + abs(minimum));
return range * val;
}

// Get new scaled value between -255 and 255 based on its minimum and maximum
float PadHandlerBase::ScaledInput2(s32 raw_value, int minimum, int maximum)
f32 PadHandlerBase::ScaledInput2(s32 raw_value, int minimum, int maximum, f32 range)
{
// value based on max range converted to [0, 1]
const float val = static_cast<float>(std::clamp(raw_value, minimum, maximum) - minimum) / (abs(maximum) + abs(minimum));
return (510.0f * val) - 255.0f;
const f32 val = static_cast<f32>(std::clamp(raw_value, minimum, maximum) - minimum) / (abs(maximum) + abs(minimum));
return (2.0f * range * val) - range;
}

// Get normalized trigger value based on the range defined by a threshold
Expand All @@ -140,7 +140,7 @@ u16 PadHandlerBase::NormalizeTriggerInput(u16 value, int threshold) const
}
else
{
const s32 val = static_cast<s32>(static_cast<float>(trigger_max) * (value - threshold) / (trigger_max - threshold));
const s32 val = static_cast<s32>(static_cast<f32>(trigger_max) * (value - threshold) / (trigger_max - threshold));
return static_cast<u16>(ScaledInput(val, trigger_min, trigger_max));
}
}
Expand All @@ -154,15 +154,15 @@ u16 PadHandlerBase::NormalizeDirectedInput(s32 raw_value, s32 threshold, s32 max
return static_cast<u16>(0);
}

const float val = static_cast<float>(std::clamp(raw_value, 0, maximum)) / maximum; // value based on max range converted to [0, 1]
const f32 val = static_cast<f32>(std::clamp(raw_value, 0, maximum)) / maximum; // value based on max range converted to [0, 1]

if (threshold <= 0)
{
return static_cast<u16>(255.0f * val);
}
else
{
const float thresh = static_cast<float>(threshold) / maximum; // threshold converted to [0, 1]
const f32 thresh = static_cast<f32>(threshold) / maximum; // threshold converted to [0, 1]
return static_cast<u16>(255.0f * std::min(1.0f, (val - thresh) / (1.0f - thresh)));
}
}
Expand All @@ -186,14 +186,14 @@ u16 PadHandlerBase::NormalizeStickInput(u16 raw_value, int threshold, int multip
// return is new x and y values in 0-255 range
std::tuple<u16, u16> PadHandlerBase::NormalizeStickDeadzone(s32 inX, s32 inY, u32 deadzone) const
{
const float dz_range = deadzone / static_cast<float>(std::abs(thumb_max)); // NOTE: thumb_max should be positive anyway
const f32 dz_range = deadzone / static_cast<f32>(std::abs(thumb_max)); // NOTE: thumb_max should be positive anyway

float X = inX / 255.0f;
float Y = inY / 255.0f;
f32 X = inX / 255.0f;
f32 Y = inY / 255.0f;

if (dz_range > 0.f)
{
const float mag = std::min(sqrtf(X * X + Y * Y), 1.f);
const f32 mag = std::min(sqrtf(X * X + Y * Y), 1.f);

if (mag <= 0)
{
Expand All @@ -202,15 +202,15 @@ std::tuple<u16, u16> PadHandlerBase::NormalizeStickDeadzone(s32 inX, s32 inY, u3

if (mag > dz_range)
{
const float pos = std::lerp(0.13f, 1.f, (mag - dz_range) / (1 - dz_range));
const float scale = pos / mag;
const f32 pos = std::lerp(0.13f, 1.f, (mag - dz_range) / (1 - dz_range));
const f32 scale = pos / mag;
X = X * scale;
Y = Y * scale;
}
else
{
const float pos = std::lerp(0.f, 0.13f, mag / dz_range);
const float scale = pos / mag;
const f32 pos = std::lerp(0.f, 0.13f, mag / dz_range);
const f32 scale = pos / mag;
X = X * scale;
Y = Y * scale;
}
Expand All @@ -231,7 +231,7 @@ u16 PadHandlerBase::Clamp0To1023(f32 input)
}

// input has to be [-1,1]. result will be [0,255]
u16 PadHandlerBase::ConvertAxis(float value)
u16 PadHandlerBase::ConvertAxis(f32 value)
{
return static_cast<u16>((value + 1.0)*(255.0 / 2.0));
}
Expand Down Expand Up @@ -280,6 +280,11 @@ bool PadHandlerBase::has_rumble() const
return b_has_rumble;
}

bool PadHandlerBase::has_motion() const
{
return b_has_motion;
}

bool PadHandlerBase::has_deadzones() const
{
return b_has_deadzones;
Expand Down Expand Up @@ -338,8 +343,13 @@ void PadHandlerBase::get_next_button_press(const std::string& pad_id, const pad_

// Check for each button in our list if its corresponding (maybe remapped) button or axis was pressed.
// Return the new value if the button was pressed (aka. its value was bigger than 0 or the defined threshold)
// Use a pair to get all the legally pressed buttons and use the one with highest value (prioritize first)
std::pair<u16, std::string> pressed_button = { 0, "" };
// Get all the legally pressed buttons and use the one with highest value (prioritize first)
struct
{
u16 value = 0;
std::string name;
} pressed_button{};

for (const auto& [keycode, name] : button_list)
{
const u16& value = data[keycode];
Expand All @@ -358,8 +368,10 @@ void PadHandlerBase::get_next_button_press(const std::string& pad_id, const pad_
blacklist.emplace_back(keycode);
input_log.error("%s Calibration: Added key [ %d = %s ] to blacklist. Value = %d", m_type, keycode, name, value);
}
else if (value > pressed_button.first)
pressed_button = { value, name };
else if (value > pressed_button.value)
{
pressed_button = { .value = value, .name = name };
}
}
}

Expand All @@ -375,13 +387,48 @@ void PadHandlerBase::get_next_button_press(const std::string& pad_id, const pad_

if (callback)
{
if (pressed_button.first > 0)
return callback(pressed_button.first, pressed_button.second, pad_id, battery_level, preview_values);
if (pressed_button.value > 0)
return callback(pressed_button.value, pressed_button.name, pad_id, battery_level, preview_values);
else
return callback(0, "", pad_id, battery_level, preview_values);
}
}

return;
void PadHandlerBase::get_motion_sensors(const std::string& pad_id, const motion_callback& callback, const motion_fail_callback& fail_callback, motion_preview_values preview_values, const std::array<AnalogSensor, 4>& /*sensors*/)
{
if (!b_has_motion)
{
return;
}

// Reset sensors
auto device = get_device(pad_id);

const auto status = update_connection(device);
if (status == connection::disconnected)
{
if (fail_callback)
fail_callback(pad_id, std::move(preview_values));
return;
}

if (status == connection::no_data || !callback)
{
return;
}

// Get the current motion values
std::shared_ptr<Pad> pad = std::make_shared<Pad>(m_type, 0, 0, 0);
pad->m_sensors.resize(preview_values.size(), AnalogSensor(0, 0, 0, 0, 0));
pad_ensemble binding{pad, device, nullptr};
get_extended_info(binding);

for (usz i = 0; i < preview_values.size(); i++)
{
preview_values[i] = pad->m_sensors[i].m_value;
}

callback(pad_id, std::move(preview_values));
}

void PadHandlerBase::convert_stick_values(u16& x_out, u16& y_out, const s32& x_in, const s32& y_in, const s32& deadzone, const s32& padsquircling) const
Expand Down Expand Up @@ -431,27 +478,33 @@ void PadHandlerBase::TranslateButtonPress(const std::shared_ptr<PadDevice>& devi
}
}

bool PadHandlerBase::bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device, u8 player_id)
bool PadHandlerBase::bindPadToDevice(std::shared_ptr<Pad> pad, u8 player_id)
{
if (!pad)
if (!pad || player_id >= g_cfg_input.player.size())
{
return false;
}

std::shared_ptr<PadDevice> pad_device = get_device(device);
const cfg_player* player_config = g_cfg_input.player[player_id];
if (!player_config)
{
return false;
}

std::shared_ptr<PadDevice> pad_device = get_device(player_config->device);
if (!pad_device)
{
input_log.error("PadHandlerBase::bindPadToDevice: no PadDevice found for device '%s'", device);
input_log.error("PadHandlerBase::bindPadToDevice: no PadDevice found for device '%s'", player_config->device.to_string());
return false;
}

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());
pad_device->config = &m_pad_configs[player_id];
pad_device->player_id = player_id;
cfg_pad* config = pad_device->config;
if (config == nullptr)
{
input_log.error("PadHandlerBase::bindPadToDevice: no profile found for device %d '%s'", bindings.size(), device);
input_log.error("PadHandlerBase::bindPadToDevice: no profile found for device %d '%s'", m_bindings.size(), player_config->device.to_string());
return false;
}

Expand Down Expand Up @@ -505,15 +558,15 @@ bool PadHandlerBase::bindPadToDevice(std::shared_ptr<Pad> pad, const std::string
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, mapping[button::rs_left], mapping[button::rs_right]);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, mapping[button::rs_down], mapping[button::rs_up]);

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);
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 0, 0, 0, DEFAULT_MOTION_X);
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 0, 0, 0, DEFAULT_MOTION_Y);
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Z, 0, 0, 0, DEFAULT_MOTION_Z);
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_G, 0, 0, 0, DEFAULT_MOTION_G);

pad->m_vibrateMotors.emplace_back(true, 0);
pad->m_vibrateMotors.emplace_back(false, 0);

bindings.emplace_back(pad_device, pad);
m_bindings.emplace_back(pad, pad_device, nullptr);

return true;
}
Expand Down Expand Up @@ -555,8 +608,11 @@ std::array<u32, PadHandlerBase::button::button_count> PadHandlerBase::get_mapped
return mapping;
}

void PadHandlerBase::get_mapping(const std::shared_ptr<PadDevice>& device, const std::shared_ptr<Pad>& pad)
void PadHandlerBase::get_mapping(const pad_ensemble& binding)
{
const auto& device = binding.device;
const auto& pad = binding.pad;

if (!device || !pad)
return;

Expand Down Expand Up @@ -638,10 +694,10 @@ void PadHandlerBase::get_mapping(const std::shared_ptr<PadDevice>& device, const

void PadHandlerBase::ThreadProc()
{
for (usz i = 0; i < bindings.size(); ++i)
for (usz i = 0; i < m_bindings.size(); ++i)
{
auto& device = bindings[i].first;
auto& pad = bindings[i].second;
auto& device = m_bindings[i].device;
auto& pad = m_bindings[i].pad;

if (!device || !pad)
continue;
Expand All @@ -663,7 +719,10 @@ void PadHandlerBase::ThreadProc()
}

if (status == connection::no_data)
{
// TODO: don't skip entirely if buddy device has data
continue;
}

break;
}
Expand All @@ -683,8 +742,8 @@ void PadHandlerBase::ThreadProc()
break;
}

get_mapping(device, pad);
get_extended_info(device, pad);
apply_pad_data(device, pad);
get_mapping(m_bindings[i]);
get_extended_info(m_bindings[i]);
apply_pad_data(m_bindings[i]);
}
}
Loading