input: allow multiple key codes per button

This commit is contained in:
Megamouse 2023-06-13 01:19:32 +02:00
parent 16f869fe5a
commit d3be8ee2b7
14 changed files with 640 additions and 498 deletions

View File

@ -7,103 +7,21 @@
cfg_input g_cfg_input;
LOG_CHANNEL(input_log, "Input");
PadHandlerBase::PadHandlerBase(pad_handler type) : m_type(type)
{
}
// Search an unordered map for a string value and return found keycode
int PadHandlerBase::FindKeyCode(const std::unordered_map<u32, std::string>& map, const cfg::string& name, bool fallback)
std::set<u32> PadHandlerBase::narrow_set(const std::set<u64>& src)
{
const std::string def = name.def;
const std::string nam = name.to_string();
int def_code = -1;
if (src.empty())
return {};
for (auto it = map.begin(); it != map.end(); ++it)
std::set<u32> dst;
for (const u64& s : src)
{
if (it->second == nam)
return it->first;
if (fallback && it->second == def)
def_code = it->first;
dst.insert(::narrow<u32>(s));
}
if (fallback)
{
if (!nam.empty())
input_log.error("int FindKeyCode for [name = %s] returned with [def_code = %d] for [def = %s]", nam, def_code, def);
if (def_code < 0)
def_code = 0;
}
return def_code;
}
long PadHandlerBase::FindKeyCode(const std::unordered_map<u64, std::string>& map, const cfg::string& name, bool fallback)
{
const std::string def = name.def;
const std::string nam = name.to_string();
long def_code = -1;
for (auto it = map.begin(); it != map.end(); ++it)
{
if (it->second == nam)
return static_cast<long>(it->first);
if (fallback && it->second == def)
def_code = static_cast<long>(it->first);
}
if (fallback)
{
if (!nam.empty())
input_log.error("long FindKeyCode for [name = %s] returned with [def_code = %d] for [def = %s]", nam, def_code, def);
if (def_code < 0)
def_code = 0;
}
return def_code;
}
// Search an unordered map for a string value and return found keycode
int PadHandlerBase::FindKeyCodeByString(const std::unordered_map<u32, std::string>& map, const std::string& name, bool fallback)
{
for (auto it = map.begin(); it != map.end(); ++it)
{
if (it->second == name)
return it->first;
}
if (fallback)
{
if (!name.empty())
input_log.error("long FindKeyCodeByString for [name = %s] returned with 0", name);
return 0;
}
return -1;
}
// Search an unordered map for a string value and return found keycode
long PadHandlerBase::FindKeyCodeByString(const std::unordered_map<u64, std::string>& map, const std::string& name, bool fallback)
{
for (auto it = map.begin(); it != map.end(); ++it)
{
if (it->second == name)
return static_cast<long>(it->first);
}
if (fallback)
{
if (!name.empty())
input_log.error("long FindKeyCodeByString for [name = %s] returned with 0", name);
return 0;
}
return -1;
return dst;
}
// Get new multiplied value based on the multiplier
@ -351,7 +269,7 @@ PadHandlerBase::connection PadHandlerBase::get_next_button_press(const std::stri
auto device = get_device(pad_id);
const auto status = update_connection(device);
const connection status = update_connection(device);
if (status == connection::disconnected)
{
if (fail_callback)
@ -432,7 +350,7 @@ void PadHandlerBase::get_motion_sensors(const std::string& pad_id, const motion_
// Reset sensors
auto device = get_device(pad_id);
const auto status = update_connection(device);
const connection status = update_connection(device);
if (status == connection::disconnected)
{
if (fail_callback)
@ -536,11 +454,11 @@ bool PadHandlerBase::bindPadToDevice(std::shared_ptr<Pad> pad, u8 player_id)
return false;
}
std::array<u32, button::button_count> mapping = get_mapped_key_codes(pad_device, config);
std::array<std::set<u32>, button::button_count> mapping = get_mapped_key_codes(pad_device, config);
u32 pclass_profile = 0x0;
for (const auto& product : input::get_products_by_class(config->device_class_type))
for (const input::product_info& product : input::get_products_by_class(config->device_class_type))
{
if (product.vendor_id == config->vendor_id && product.product_id == config->product_id)
{
@ -599,50 +517,50 @@ bool PadHandlerBase::bindPadToDevice(std::shared_ptr<Pad> pad, u8 player_id)
return true;
}
std::array<u32, PadHandlerBase::button::button_count> PadHandlerBase::get_mapped_key_codes(const std::shared_ptr<PadDevice>& device, const cfg_pad* cfg)
std::array<std::set<u32>, PadHandlerBase::button::button_count> PadHandlerBase::get_mapped_key_codes(const std::shared_ptr<PadDevice>& device, const cfg_pad* cfg)
{
std::array<u32, button::button_count> mapping{};
std::array<std::set<u32>, button::button_count> mapping{};
if (!device || !cfg)
return mapping;
device->trigger_code_left = FindKeyCode(button_list, cfg->l2);
device->trigger_code_right = FindKeyCode(button_list, cfg->r2);
device->axis_code_left[0] = FindKeyCode(button_list, cfg->ls_left);
device->axis_code_left[1] = FindKeyCode(button_list, cfg->ls_right);
device->axis_code_left[2] = FindKeyCode(button_list, cfg->ls_down);
device->axis_code_left[3] = FindKeyCode(button_list, cfg->ls_up);
device->axis_code_right[0] = FindKeyCode(button_list, cfg->rs_left);
device->axis_code_right[1] = FindKeyCode(button_list, cfg->rs_right);
device->axis_code_right[2] = FindKeyCode(button_list, cfg->rs_down);
device->axis_code_right[3] = FindKeyCode(button_list, cfg->rs_up);
device->trigger_code_left = FindKeyCodes<u32, u64>(button_list, cfg->l2);
device->trigger_code_right = FindKeyCodes<u32, u64>(button_list, cfg->r2);
device->axis_code_left[0] = FindKeyCodes<u32, u64>(button_list, cfg->ls_left);
device->axis_code_left[1] = FindKeyCodes<u32, u64>(button_list, cfg->ls_right);
device->axis_code_left[2] = FindKeyCodes<u32, u64>(button_list, cfg->ls_down);
device->axis_code_left[3] = FindKeyCodes<u32, u64>(button_list, cfg->ls_up);
device->axis_code_right[0] = FindKeyCodes<u32, u64>(button_list, cfg->rs_left);
device->axis_code_right[1] = FindKeyCodes<u32, u64>(button_list, cfg->rs_right);
device->axis_code_right[2] = FindKeyCodes<u32, u64>(button_list, cfg->rs_down);
device->axis_code_right[3] = FindKeyCodes<u32, u64>(button_list, cfg->rs_up);
mapping[button::up] = FindKeyCode(button_list, cfg->up);
mapping[button::down] = FindKeyCode(button_list, cfg->down);
mapping[button::left] = FindKeyCode(button_list, cfg->left);
mapping[button::right] = FindKeyCode(button_list, cfg->right);
mapping[button::cross] = FindKeyCode(button_list, cfg->cross);
mapping[button::square] = FindKeyCode(button_list, cfg->square);
mapping[button::circle] = FindKeyCode(button_list, cfg->circle);
mapping[button::triangle] = FindKeyCode(button_list, cfg->triangle);
mapping[button::start] = FindKeyCode(button_list, cfg->start);
mapping[button::select] = FindKeyCode(button_list, cfg->select);
mapping[button::l1] = FindKeyCode(button_list, cfg->l1);
mapping[button::l2] = ::narrow<u32>(device->trigger_code_left);
mapping[button::l3] = FindKeyCode(button_list, cfg->l3);
mapping[button::r1] = FindKeyCode(button_list, cfg->r1);
mapping[button::r2] = ::narrow<u32>(device->trigger_code_right);
mapping[button::r3] = FindKeyCode(button_list, cfg->r3);
mapping[button::ls_left] = ::narrow<u32>(device->axis_code_left[0]);
mapping[button::ls_right] = ::narrow<u32>(device->axis_code_left[1]);
mapping[button::ls_down] = ::narrow<u32>(device->axis_code_left[2]);
mapping[button::ls_up] = ::narrow<u32>(device->axis_code_left[3]);
mapping[button::rs_left] = ::narrow<u32>(device->axis_code_right[0]);
mapping[button::rs_right] = ::narrow<u32>(device->axis_code_right[1]);
mapping[button::rs_down] = ::narrow<u32>(device->axis_code_right[2]);
mapping[button::rs_up] = ::narrow<u32>(device->axis_code_right[3]);
mapping[button::ps] = FindKeyCode(button_list, cfg->ps);
mapping[button::up] = FindKeyCodes<u32, u32>(button_list, cfg->up);
mapping[button::down] = FindKeyCodes<u32, u32>(button_list, cfg->down);
mapping[button::left] = FindKeyCodes<u32, u32>(button_list, cfg->left);
mapping[button::right] = FindKeyCodes<u32, u32>(button_list, cfg->right);
mapping[button::cross] = FindKeyCodes<u32, u32>(button_list, cfg->cross);
mapping[button::square] = FindKeyCodes<u32, u32>(button_list, cfg->square);
mapping[button::circle] = FindKeyCodes<u32, u32>(button_list, cfg->circle);
mapping[button::triangle] = FindKeyCodes<u32, u32>(button_list, cfg->triangle);
mapping[button::start] = FindKeyCodes<u32, u32>(button_list, cfg->start);
mapping[button::select] = FindKeyCodes<u32, u32>(button_list, cfg->select);
mapping[button::l1] = FindKeyCodes<u32, u32>(button_list, cfg->l1);
mapping[button::l2] = narrow_set(device->trigger_code_left);
mapping[button::l3] = FindKeyCodes<u32, u32>(button_list, cfg->l3);
mapping[button::r1] = FindKeyCodes<u32, u32>(button_list, cfg->r1);
mapping[button::r2] = narrow_set(device->trigger_code_right);
mapping[button::r3] = FindKeyCodes<u32, u32>(button_list, cfg->r3);
mapping[button::ls_left] = narrow_set(device->axis_code_left[0]);
mapping[button::ls_right] = narrow_set(device->axis_code_left[1]);
mapping[button::ls_down] = narrow_set(device->axis_code_left[2]);
mapping[button::ls_up] = narrow_set(device->axis_code_left[3]);
mapping[button::rs_left] = narrow_set(device->axis_code_right[0]);
mapping[button::rs_right] = narrow_set(device->axis_code_right[1]);
mapping[button::rs_down] = narrow_set(device->axis_code_right[2]);
mapping[button::rs_up] = narrow_set(device->axis_code_right[3]);
mapping[button::ps] = FindKeyCodes<u32, u32>(button_list, cfg->ps);
mapping[button::pressure_intensity_button] = FindKeyCode(button_list, cfg->pressure_intensity_button);
mapping[button::pressure_intensity_button] = FindKeyCodes<u32, u32>(button_list, cfg->pressure_intensity_button);
return mapping;
}
@ -655,7 +573,7 @@ void PadHandlerBase::get_mapping(const pad_ensemble& binding)
if (!device || !pad)
return;
const auto cfg = device->config;
const cfg_pad* cfg = device->config;
auto button_values = get_button_values(device);
@ -664,40 +582,70 @@ void PadHandlerBase::get_mapping(const pad_ensemble& binding)
const bool adjust_pressure = pad->get_pressure_intensity_enabled(cfg->pressure_intensity_toggle_mode.get());
// Translate any corresponding keycodes to our normal DS3 buttons and triggers
for (auto& btn : pad->m_buttons)
for (Button& btn : pad->m_buttons)
{
// Using a temporary buffer because the values can change during translation
Button tmp = btn;
tmp.m_value = button_values[btn.m_keyCode];
bool pressed{};
u16 value{};
TranslateButtonPress(device, tmp.m_keyCode, tmp.m_pressed, tmp.m_value);
// Modify pressure if necessary if the button was pressed
if (adjust_pressure && tmp.m_pressed)
for (u32 code : btn.m_key_codes)
{
tmp.m_value = pad->m_pressure_intensity;
bool press{};
u16 val = button_values[code];
TranslateButtonPress(device, code, press, val);
if (press)
{
// Modify pressure if necessary if the button was pressed
if (adjust_pressure)
{
val = pad->m_pressure_intensity;
}
value = std::max(value, val);
pressed = true;
}
}
btn = tmp;
btn.m_value = value;
btn.m_pressed = pressed;
}
// used to get the absolute value of an axis
s32 stick_val[4]{ 0 };
s32 stick_val[4]{};
// Translate any corresponding keycodes to our two sticks. (ignoring thresholds for now)
for (int i = 0; i < static_cast<int>(pad->m_sticks.size()); i++)
{
bool pressed;
bool pressed{};
u16 val_min{};
u16 val_max{};
// m_keyCodeMin is the mapped key for left or down
const u32 key_min = pad->m_sticks[i].m_keyCodeMin;
u16 val_min = button_values[key_min];
TranslateButtonPress(device, key_min, pressed, val_min, true);
// m_key_codes_min are the mapped keys for left or down
for (u32 key_min : pad->m_sticks[i].m_key_codes_min)
{
u16 val = button_values[key_min];
// m_keyCodeMax is the mapped key for right or up
const u32 key_max = pad->m_sticks[i].m_keyCodeMax;
u16 val_max = button_values[key_max];
TranslateButtonPress(device, key_max, pressed, val_max, true);
TranslateButtonPress(device, key_min, pressed, val, true);
if (pressed)
{
val_min = std::max(val_min, val);
}
}
// m_key_codes_max are the mapped keys for right or up
for (u32 key_max : pad->m_sticks[i].m_key_codes_max)
{
u16 val = button_values[key_max];
TranslateButtonPress(device, key_max, pressed, val, true);
if (pressed)
{
val_max = std::max(val_max, val);
}
}
// cancel out opposing values and get the resulting difference
stick_val[i] = val_max - val_min;
@ -741,7 +689,7 @@ void PadHandlerBase::process()
if (!device || !pad)
continue;
const auto status = update_connection(device);
const connection status = update_connection(device);
switch (status)
{

View File

@ -8,10 +8,13 @@
#include <cmath>
#include <functional>
#include <string>
#include <set>
#include <vector>
#include <memory>
#include <unordered_map>
LOG_CHANNEL(input_log, "Input");
class PadDevice
{
public:
@ -20,10 +23,10 @@ public:
u8 player_id{0};
u8 large_motor{0};
u8 small_motor{0};
u64 trigger_code_left = 0;
u64 trigger_code_right = 0;
std::array<u64, 4> axis_code_left{};
std::array<u64, 4> axis_code_right{};
std::set<u64> trigger_code_left{};
std::set<u64> trigger_code_right{};
std::array<std::set<u64>, 4> axis_code_left{};
std::array<std::set<u64>, 4> axis_code_right{};
};
struct pad_ensemble
@ -123,17 +126,76 @@ protected:
std::unordered_map<u32, std::string> button_list;
std::vector<u32> blacklist;
// Search an unordered map for a string value and return found keycode
static int FindKeyCode(const std::unordered_map<u32, std::string>& map, const cfg::string& name, bool fallback = true);
static std::set<u32> narrow_set(const std::set<u64>& src);
// Search an unordered map for a string value and return found keycode
static long FindKeyCode(const std::unordered_map<u64, std::string>& map, const cfg::string& name, bool fallback = true);
template <typename S, typename T>
static std::set<T> FindKeyCodes(const std::unordered_map<S, std::string>& map, const cfg::string& cfg_string, bool fallback = true)
{
std::set<T> key_codes;
const std::string& def = cfg_string.def;
const std::vector<std::string> names = cfg_pad::get_buttons(cfg_string);
T def_code = umax;
for (const std::string& nam : names)
{
for (const auto& [code, name] : map)
{
if (name == nam)
{
key_codes.insert(static_cast<T>(code));
}
if (fallback && name == def)
def_code = static_cast<T>(code);
}
}
if (!key_codes.empty())
{
return key_codes;
}
if (fallback)
{
if (!names.empty())
input_log.error("FindKeyCode for [name = %s] returned with [def_code = %d] for [def = %s]", cfg_string.to_string(), def_code, def);
if (def_code != umax)
{
return { def_code };
}
}
return {};
}
// Search an unordered map for a string value and return found keycode
static int FindKeyCodeByString(const std::unordered_map<u32, std::string>& map, const std::string& name, bool fallback = true);
template <typename S, typename T>
static std::set<T> FindKeyCodes(const std::unordered_map<S, std::string>& map, const std::vector<std::string>& names)
{
std::set<T> key_codes;
// Search an unordered map for a string value and return found keycode
static long FindKeyCodeByString(const std::unordered_map<u64, std::string>& map, const std::string& name, bool fallback = true);
for (const std::string& name : names)
{
for (const auto& [code, nam] : map)
{
if (nam == name)
{
key_codes.insert(static_cast<T>(code));
break;
}
}
}
if (!key_codes.empty())
{
return key_codes;
}
return {};
}
// Get new multiplied value based on the multiplier
static s32 MultipliedInput(s32 raw_value, s32 multiplier);
@ -225,7 +287,7 @@ private:
virtual pad_preview_values get_preview_values(const std::unordered_map<u64, u16>& /*data*/) { return {}; }
protected:
virtual std::array<u32, PadHandlerBase::button::button_count> get_mapped_key_codes(const std::shared_ptr<PadDevice>& device, const cfg_pad* cfg);
virtual std::array<std::set<u32>, PadHandlerBase::button::button_count> get_mapped_key_codes(const std::shared_ptr<PadDevice>& device, const cfg_pad* cfg);
virtual void get_mapping(const pad_ensemble& binding);
void TranslateButtonPress(const std::shared_ptr<PadDevice>& device, u64 keyCode, bool& pressed, u16& val, bool ignore_stick_threshold = false, bool ignore_trigger_threshold = false);
void init_configs();

View File

@ -6,6 +6,26 @@ LOG_CHANNEL(input_log, "Input");
extern std::string g_pad_profile_override;
std::vector<std::string> cfg_pad::get_buttons(const std::string& str)
{
std::vector<std::string> vec = fmt::split(str, {","});;
// Remove duplicates
std::sort(vec.begin(), vec.end());
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
return vec;
}
std::string cfg_pad::get_buttons(std::vector<std::string> vec)
{
// Remove duplicates
std::sort(vec.begin(), vec.end());
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
return fmt::merge(vec, ",");
}
bool cfg_input::load(const std::string& title_id, const std::string& profile, bool strict)
{
input_log.notice("Loading pad config (title_id='%s', profile='%s', strict=%d)", title_id, profile, strict);

View File

@ -25,6 +25,9 @@ struct cfg_pad final : cfg::node
cfg_pad() {};
cfg_pad(node* owner, const std::string& name) : cfg::node(owner, name) {}
static std::vector<std::string> get_buttons(const std::string& str);
static std::string get_buttons(std::vector<std::string> vec);
cfg::string ls_left{ this, "Left Stick Left", "" };
cfg::string ls_down{ this, "Left Stick Down", "" };
cfg::string ls_right{ this, "Left Stick Right", "" };

View File

@ -4,6 +4,7 @@
#include "util/endian.hpp"
#include "Emu/Io/pad_config_types.h"
#include <set>
#include <vector>
enum class pad_button : u8
@ -240,18 +241,19 @@ enum special_button_value
struct Button
{
u32 m_offset = 0;
u32 m_keyCode = 0;
std::set<u32> m_key_codes{};
u32 m_outKeyCode = 0;
u16 m_value = 0;
bool m_pressed = false;
u16 m_actual_value = 0; // only used in keyboard_pad_handler
bool m_analog = false; // only used in keyboard_pad_handler
bool m_trigger = false; // only used in keyboard_pad_handler
u16 m_actual_value = 0; // only used in keyboard_pad_handler
bool m_analog = false; // only used in keyboard_pad_handler
bool m_trigger = false; // only used in keyboard_pad_handler
std::set<u32> m_pressed_keys{}; // only used in keyboard_pad_handler
Button(u32 offset, u32 keyCode, u32 outKeyCode)
Button(u32 offset, std::set<u32> key_codes, u32 outKeyCode)
: m_offset(offset)
, m_keyCode(keyCode)
, m_key_codes(std::move(key_codes))
, m_outKeyCode(outKeyCode)
{
if (offset == CELL_PAD_BTN_OFFSET_DIGITAL1)
@ -279,14 +281,14 @@ struct Button
struct AnalogStick
{
u32 m_offset = 0;
u32 m_keyCodeMin = 0;
u32 m_keyCodeMax = 0;
std::set<u32> m_key_codes_min{};
std::set<u32> m_key_codes_max{};
u16 m_value = 128;
AnalogStick(u32 offset, u32 keyCodeMin, u32 keyCodeMax)
AnalogStick(u32 offset, std::set<u32> key_codes_min, std::set<u32> key_codes_max)
: m_offset(offset)
, m_keyCodeMin(keyCodeMin)
, m_keyCodeMax(keyCodeMax)
, m_key_codes_min(std::move(key_codes_min))
, m_key_codes_max(std::move(key_codes_max))
{}
};

View File

@ -113,10 +113,10 @@ bool evdev_joystick_handler::Init()
for (const auto& node : m_pos_axis_config.get_nodes())
{
if (*static_cast<cfg::_bool*>(node))
if (node && *static_cast<cfg::_bool*>(node))
{
const auto name = node->get_name();
const int code = libevdev_event_code_from_name(EV_ABS, name.c_str());
const std::string& name = node->get_name();
const int code = libevdev_event_code_from_name(EV_ABS, name.c_str());
if (code < 0)
evdev_log.error("Failed to read axis name from %s. [code = %d] [name = %s]", m_pos_axis_config.cfg_name, code, name);
else
@ -130,12 +130,14 @@ bool evdev_joystick_handler::Init()
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);
std::string name;
if (const char* raw_name = libevdev_get_name(dev))
name = raw_name;
if (name.empty())
{
if (unique)
if (const char* unique = libevdev_get_uniq(dev))
name = unique;
if (name.empty())
@ -151,8 +153,8 @@ bool evdev_joystick_handler::update_device(const std::shared_ptr<PadDevice>& dev
if (!evdev_device)
return false;
const auto& path = evdev_device->path;
libevdev*& dev = evdev_device->device;
const std::string& path = evdev_device->path;
libevdev*& dev = evdev_device->device;
const bool was_connected = dev != nullptr;
@ -206,18 +208,18 @@ void evdev_joystick_handler::close_devices()
}
};
for (auto& binding : m_bindings)
for (pad_ensemble& 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)
for (auto& [name, device] : m_settings_added)
{
free_device(static_cast<EvdevDevice*>(device.get()));
}
for (auto [name, device] : m_motion_settings_added)
for (auto& [name, device] : m_motion_settings_added)
{
free_device(static_cast<EvdevDevice*>(device.get()));
}
@ -229,14 +231,14 @@ std::unordered_map<u64, std::pair<u16, bool>> evdev_joystick_handler::GetButtonV
if (!device)
return button_values;
auto& dev = device->device;
libevdev* dev = device->device;
if (!Init())
return button_values;
for (const auto& entry : button_list)
{
const auto code = entry.first;
const u32 code = entry.first;
if (code == NO_BUTTON)
continue;
@ -251,8 +253,8 @@ std::unordered_map<u64, std::pair<u16, bool>> evdev_joystick_handler::GetButtonV
for (const auto& entry : axis_list)
{
const auto code = entry.first;
int val = 0;
const u32 code = entry.first;
int val = 0;
if (libevdev_fetch_event_value(dev, EV_ABS, code, &val) == 0)
continue;
@ -298,7 +300,7 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s
m_blacklist.clear();
// Get our evdev device
auto device = get_evdev_device(padId);
std::shared_ptr<EvdevDevice> device = get_evdev_device(padId);
if (!device || !device->device)
{
if (fail_callback)
@ -328,16 +330,36 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s
auto data = GetButtonValues(device);
auto find_value = [=, this](const std::string& name)
const auto find_value = [&, this](const std::string& str)
{
int key = FindKeyCodeByString(rev_axis_list, name, false);
const bool dir = key >= 0;
if (key < 0)
key = FindKeyCodeByString(axis_list, name, false);
if (key < 0)
key = FindKeyCodeByString(button_list, name);
auto it = data.find(static_cast<u64>(key));
return it != data.end() && dir == it->second.second ? it->second.first : 0;
const std::vector<std::string> names = cfg_pad::get_buttons(str);
u16 value{};
const auto set_value = [&value, &data](u32 code, bool dir)
{
if (const auto it = data.find(static_cast<u64>(code)); it != data.cend() && dir == it->second.second)
{
value = std::max(value, it->second.first);
}
};
for (const u32 code : FindKeyCodes<u32, u32>(rev_axis_list, names))
{
set_value(code, true);
}
for (const u32 code : FindKeyCodes<u32, u32>(axis_list, names))
{
set_value(code, false);
}
for (const u32 code : FindKeyCodes<u32, u32>(button_list, names))
{
set_value(code, false);
}
return value;
};
pad_preview_values preview_values{};
@ -469,7 +491,7 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s
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);
std::shared_ptr<EvdevDevice> device = add_motion_device(padId, true);
if (!device || !update_device(device) || !device->device)
{
if (fail_callback)
@ -477,7 +499,7 @@ void evdev_joystick_handler::get_motion_sensors(const std::string& padId, const
return;
}
auto& dev = device->device;
libevdev* dev = device->device;
// Try to fetch all new events from the joystick.
bool is_dirty = false;
@ -605,7 +627,7 @@ void evdev_joystick_handler::SetRumble(EvdevDevice* device, u8 large, u8 small)
void evdev_joystick_handler::SetPadData(const std::string& padId, u8 /*player_id*/, u8 large_motor, u8 small_motor, s32 /* r*/, s32 /* g*/, s32 /* b*/, bool /*player_led*/, bool /*battery_led*/, u32 /*battery_led_brightness*/)
{
// Get our evdev device
auto dev = get_evdev_device(padId);
std::shared_ptr<EvdevDevice> dev = get_evdev_device(padId);
if (!dev)
{
evdev_log.error("evdev TestVibration: Device [%s] not found! [large_motor = %d] [small_motor = %d]", padId, large_motor, small_motor);
@ -637,7 +659,7 @@ u32 evdev_joystick_handler::GetButtonInfo(const input_event& evt, const std::sha
if (button_list.find(code) == button_list.end())
{
evdev_log.error("Evdev button %s (%d) is unknown. Please add it to the button list.", libevdev_event_code_get_name(EV_KEY, code), code);
return -1;
return umax;
}
value = val > 0 ? 255 : 0;
@ -647,9 +669,10 @@ u32 evdev_joystick_handler::GetButtonInfo(const input_event& evt, const std::sha
{
if (!device || !device->device)
{
return -1;
return umax;
}
auto& dev = device->device;
libevdev* dev = device->device;
const int min = libevdev_get_abs_minimum(dev, code);
const int max = libevdev_get_abs_maximum(dev, code);
@ -667,7 +690,8 @@ u32 evdev_joystick_handler::GetButtonInfo(const input_event& evt, const std::sha
value = static_cast<u16>(std::abs(fvalue));
return code;
}
default: return -1;
default:
return umax;
}
}
@ -778,7 +802,7 @@ std::shared_ptr<evdev_joystick_handler::EvdevDevice> evdev_joystick_handler::add
{
if (const input_absinfo *info = libevdev_get_abs_info(dev, code))
{
const auto code_name = libevdev_event_code_get_name(EV_ABS, code);
const char* 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, flat=%d, resolution=%d",
name, code_name, axis_name, info->minimum, info->maximum, info->fuzz, info->flat, info->resolution);
}
@ -853,7 +877,7 @@ std::shared_ptr<evdev_joystick_handler::EvdevDevice> evdev_joystick_handler::add
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);
const char* 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);
}
@ -898,7 +922,7 @@ void evdev_joystick_handler::get_mapping(const pad_ensemble& binding)
if (!m_dev || !pad)
return;
auto& dev = m_dev->device;
libevdev* dev = m_dev->device;
if (!dev)
return;
@ -940,7 +964,7 @@ void evdev_joystick_handler::get_extended_info(const pad_ensemble& binding)
if (!pad || !device || !update_device(device))
return;
auto& dev = device->device;
libevdev* dev = device->device;
if (!dev)
return;
@ -1011,39 +1035,51 @@ void evdev_joystick_handler::handle_input_event(const input_event& evt, const st
if (button_code == NO_BUTTON || value < 0)
return;
const auto cfg = m_dev->config;
const cfg_pad* cfg = m_dev->config;
if (!cfg)
return;
auto axis_orientations = m_dev->axis_orientations;
// Find out if special buttons are pressed (introduced by RPCS3).
// These buttons will have a delay of one cycle, but whatever.
const bool adjust_pressure = pad->get_pressure_intensity_enabled(cfg->pressure_intensity_toggle_mode.get());
// We can only have one match for this physical event in our button sets.
const auto find_evdev_button = [this, &button_code, &evt](const std::set<u32>& indices) -> const EvdevButton*
{
for (u32 index : indices)
{
const EvdevButton& evdev_button = ::at32(m_dev->all_buttons, index);
if (evdev_button.code == button_code && evdev_button.type == evt.type)
{
return &evdev_button;
}
}
return nullptr;
};
// Translate any corresponding keycodes to our normal DS3 buttons and triggers
for (int i = 0; i < static_cast<int>(pad->m_buttons.size()); i++)
{
auto& button = pad->m_buttons[i];
Button& button = pad->m_buttons[i];
if (button.m_keyCode != button_code)
const EvdevButton* evdev_button = find_evdev_button(button.m_key_codes);
if (!evdev_button)
continue;
// Be careful to handle mapped axis specially
if (evt.type == EV_ABS)
{
// get axis direction and skip on error or set to 0 if the stick/hat is actually pointing to the other direction.
// maybe mimic on error, needs investigation. FindAxisDirection should ideally never return -1 anyway
const int direction = FindAxisDirection(axis_orientations, i);
m_dev->cur_dir = direction;
// get axis direction for TranslateButtonPress and skip on error.
m_dev->cur_dir = evdev_button->dir;
if (direction < 0)
if (evdev_button->dir < 0)
{
evdev_log.error("FindAxisDirection = %d, Button Nr.%d, value = %d", direction, i, value);
evdev_log.error("Invalid axis direction = %d, Button Nr.%d, value = %d", evdev_button->dir, i, value);
continue;
}
if (direction != (m_is_negative ? 1 : 0))
// Set to 0 if the stick / hat is actually pointing to the other direction.
if (evdev_button->dir != (m_is_negative ? 1 : 0))
{
button.m_value = 0;
button.m_pressed = 0;
@ -1051,19 +1087,19 @@ void evdev_joystick_handler::handle_input_event(const input_event& evt, const st
}
}
// Using a temporary buffer because the values can change during translation
Button tmp = button;
tmp.m_value = static_cast<u16>(value);
bool pressed{};
u16 val = static_cast<u16>(value);
TranslateButtonPress(m_dev, button_code, tmp.m_pressed, tmp.m_value);
TranslateButtonPress(m_dev, button_code, pressed, val);
// Modify pressure if necessary if the button was pressed
if (adjust_pressure && tmp.m_pressed)
if (adjust_pressure && pressed)
{
tmp.m_value = pad->m_pressure_intensity;
val = pad->m_pressure_intensity;
}
button = tmp;
button.m_value = val;
button.m_pressed = pressed;
}
// Translate any corresponding keycodes to our two sticks. (ignoring thresholds for now)
@ -1072,19 +1108,20 @@ void evdev_joystick_handler::handle_input_event(const input_event& evt, const st
bool pressed_min = false;
bool pressed_max = false;
// m_keyCodeMin is the mapped key for left or down
if (pad->m_sticks[idx].m_keyCodeMin == button_code)
// m_key_codes_min are the mapped keys for left or down
if (const EvdevButton* evdev_button = find_evdev_button(pad->m_sticks[idx].m_key_codes_min))
{
bool is_direction_min = false;
if (!m_is_button_or_trigger && evt.type == EV_ABS)
{
const int index = pad->m_buttons.size() + (idx * 2) + 1;
const int min_direction = FindAxisDirection(axis_orientations, index);
m_dev->cur_dir = min_direction;
const int min_direction = evdev_button->dir;
// We need to set the current direction for TranslateButtonPress
m_dev->cur_dir = min_direction;
if (min_direction < 0)
evdev_log.error("keyCodeMin FindAxisDirection = %d, Axis Nr.%d, Button Nr.%d, value = %d", min_direction, idx, index, value);
evdev_log.error("min_direction = %d, Axis Nr.%d, value = %d", min_direction, idx, value);
else
is_direction_min = m_is_negative == (min_direction == 1);
}
@ -1100,19 +1137,20 @@ void evdev_joystick_handler::handle_input_event(const input_event& evt, const st
}
}
// m_keyCodeMax is the mapped key for right or up
if (pad->m_sticks[idx].m_keyCodeMax == button_code)
// m_key_codes_max are the mapped keys for right or up
if (const EvdevButton* evdev_button = find_evdev_button(pad->m_sticks[idx].m_key_codes_max))
{
bool is_direction_max = false;
if (!m_is_button_or_trigger && evt.type == EV_ABS)
{
const int index = pad->m_buttons.size() + (idx * 2);
const int max_direction = FindAxisDirection(axis_orientations, index);
m_dev->cur_dir = max_direction;
const int max_direction = evdev_button->dir;
// We need to set the current direction for TranslateButtonPress
m_dev->cur_dir = max_direction;
if (max_direction < 0)
evdev_log.error("keyCodeMax FindAxisDirection = %d, Axis Nr.%d, Button Nr.%d, value = %d", max_direction, idx, index, value);
evdev_log.error("max_direction = %d, Axis Nr.%d, value = %d", max_direction, idx, value);
else
is_direction_max = m_is_negative == (max_direction == 1);
}
@ -1153,7 +1191,7 @@ void evdev_joystick_handler::apply_pad_data(const pad_ensemble& binding)
if (!evdev_device)
return;
auto cfg = device->config;
cfg_pad* cfg = device->config;
if (!cfg)
return;
@ -1165,16 +1203,6 @@ void evdev_joystick_handler::apply_pad_data(const pad_ensemble& binding)
SetRumble(evdev_device, force_large, force_small);
}
// Search axis_orientations map for the direction by index, returns -1 if not found, 0 for positive and 1 for negative
int evdev_joystick_handler::FindAxisDirection(const std::unordered_map<int, bool>& map, int index)
{
if (const auto it = map.find(index); it != map.end())
{
return it->second;
}
return -1;
}
bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, u8 player_id)
{
if (!pad || player_id >= g_cfg_input.player.size())
@ -1195,38 +1223,46 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, u8 player
if (!cfg)
return false;
std::unordered_map<int, bool> axis_orientations;
int i = 0; // increment to know the axis location
auto evdevbutton = [&](const cfg::string& name)
// We need to register EvdevButtons due to their axis directions.
const auto register_evdevbutton = [this](u32 code, bool is_axis, bool is_reverse) -> u32
{
EvdevButton button{ 0, -1, EV_ABS };
const u32 index = ::narrow<u32>(m_dev->all_buttons.size());
int key = FindKeyCode(axis_list, name, false);
if (key >= 0)
axis_orientations.emplace(i, false);
if (key < 0)
if (is_axis)
{
key = FindKeyCode(rev_axis_list, name, false);
if (key >= 0)
axis_orientations.emplace(i, true);
}
if (key < 0)
{
key = FindKeyCode(button_list, name);
button.type = EV_KEY;
m_dev->all_buttons.push_back(EvdevButton{ code, is_reverse ? 1 : 0, EV_ABS });
}
else
{
button.dir = axis_orientations[i];
m_dev->all_buttons.push_back(EvdevButton{ code, -1, EV_KEY });
}
button.code = static_cast<u32>(key);
return index;
};
i++;
return button;
const auto find_buttons = [&](const cfg::string& name) -> std::set<u32>
{
const std::vector<std::string> names = cfg_pad::get_buttons(name);
// In evdev we store indices to an EvdevButton vector in our pad objects instead of the usual key codes.
std::set<u32> indices;
for (const u32 code : FindKeyCodes<u32, u32>(axis_list, names))
{
indices.insert(register_evdevbutton(code, true, false));
}
for (const u32 code : FindKeyCodes<u32, u32>(rev_axis_list, names))
{
indices.insert(register_evdevbutton(code, true, true));
}
for (const u32 code : FindKeyCodes<u32, u32>(button_list, names))
{
indices.insert(register_evdevbutton(code, false, false));
}
return indices;
};
const auto find_motion_button = [&](const cfg_sensor& sensor) -> evdev_sensor
@ -1235,14 +1271,15 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, u8 player
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);
const std::set<u32> keys = FindKeyCodes<u32, u32>(motion_axis_list, sensor.axis);
if (!keys.empty()) e_sensor.code = *keys.begin(); // We should only have one key for each of our sensors
return e_sensor;
};
u32 pclass_profile = 0x0;
for (const auto product : input::get_products_by_class(cfg->device_class_type))
for (const input::product_info& product : input::get_products_by_class(cfg->device_class_type))
{
if (product.vendor_id == cfg->vendor_id && product.product_id == cfg->product_id)
{
@ -1262,45 +1299,45 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, u8 player
cfg->pressure_intensity
);
pad->m_buttons.emplace_back(special_button_offset, evdevbutton(cfg->pressure_intensity_button).code, special_button_value::pressure_intensity);
pad->m_buttons.emplace_back(special_button_offset, find_buttons(cfg->pressure_intensity_button), special_button_value::pressure_intensity);
pad->m_pressure_intensity_button_index = static_cast<s32>(pad->m_buttons.size()) - 1;
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(cfg->triangle).code, CELL_PAD_CTRL_TRIANGLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(cfg->circle).code, CELL_PAD_CTRL_CIRCLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(cfg->cross).code, CELL_PAD_CTRL_CROSS);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(cfg->square).code, CELL_PAD_CTRL_SQUARE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2,find_buttons(cfg->triangle), CELL_PAD_CTRL_TRIANGLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2,find_buttons(cfg->circle), CELL_PAD_CTRL_CIRCLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2,find_buttons(cfg->cross), CELL_PAD_CTRL_CROSS);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2,find_buttons(cfg->square), CELL_PAD_CTRL_SQUARE);
m_dev->trigger_left = evdevbutton(cfg->l2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev->trigger_left.code, CELL_PAD_CTRL_L2);
m_dev->trigger_left = find_buttons(cfg->l2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev->trigger_left, CELL_PAD_CTRL_L2);
m_dev->trigger_right = evdevbutton(cfg->r2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev->trigger_right.code, CELL_PAD_CTRL_R2);
m_dev->trigger_right = find_buttons(cfg->r2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev->trigger_right, CELL_PAD_CTRL_R2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(cfg->l1).code, CELL_PAD_CTRL_L1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, evdevbutton(cfg->r1).code, CELL_PAD_CTRL_R1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(cfg->start).code, CELL_PAD_CTRL_START);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(cfg->select).code, CELL_PAD_CTRL_SELECT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(cfg->l3).code, CELL_PAD_CTRL_L3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(cfg->r3).code, CELL_PAD_CTRL_R3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(cfg->ps).code, CELL_PAD_CTRL_PS);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(cfg->up).code, CELL_PAD_CTRL_UP);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(cfg->down).code, CELL_PAD_CTRL_DOWN);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(cfg->left).code, CELL_PAD_CTRL_LEFT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, evdevbutton(cfg->right).code, CELL_PAD_CTRL_RIGHT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_buttons(cfg->l1), CELL_PAD_CTRL_L1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_buttons(cfg->r1), CELL_PAD_CTRL_R1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_buttons(cfg->start), CELL_PAD_CTRL_START);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_buttons(cfg->select), CELL_PAD_CTRL_SELECT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_buttons(cfg->l3), CELL_PAD_CTRL_L3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_buttons(cfg->r3), CELL_PAD_CTRL_R3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_buttons(cfg->ps), CELL_PAD_CTRL_PS);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_buttons(cfg->up), CELL_PAD_CTRL_UP);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_buttons(cfg->down), CELL_PAD_CTRL_DOWN);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_buttons(cfg->left), CELL_PAD_CTRL_LEFT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_buttons(cfg->right), CELL_PAD_CTRL_RIGHT);
m_dev->axis_left[0] = evdevbutton(cfg->ls_right);
m_dev->axis_left[1] = evdevbutton(cfg->ls_left);
m_dev->axis_left[2] = evdevbutton(cfg->ls_up);
m_dev->axis_left[3] = evdevbutton(cfg->ls_down);
m_dev->axis_right[0] = evdevbutton(cfg->rs_right);
m_dev->axis_right[1] = evdevbutton(cfg->rs_left);
m_dev->axis_right[2] = evdevbutton(cfg->rs_up);
m_dev->axis_right[3] = evdevbutton(cfg->rs_down);
m_dev->axis_left[0] = find_buttons(cfg->ls_right);
m_dev->axis_left[1] = find_buttons(cfg->ls_left);
m_dev->axis_left[2] = find_buttons(cfg->ls_up);
m_dev->axis_left[3] = find_buttons(cfg->ls_down);
m_dev->axis_right[0] = find_buttons(cfg->rs_right);
m_dev->axis_right[1] = find_buttons(cfg->rs_left);
m_dev->axis_right[2] = find_buttons(cfg->rs_up);
m_dev->axis_right[3] = find_buttons(cfg->rs_down);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, m_dev->axis_left[1].code, m_dev->axis_left[0].code);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, m_dev->axis_left[3].code, m_dev->axis_left[2].code);
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_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, m_dev->axis_left[1], m_dev->axis_left[0]);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, m_dev->axis_left[3], m_dev->axis_left[2]);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, m_dev->axis_right[1], m_dev->axis_right[0]);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, m_dev->axis_right[3], m_dev->axis_right[2]);
m_dev->axis_motion[0] = find_motion_button(cfg->motion_sensor_x);
m_dev->axis_motion[1] = find_motion_button(cfg->motion_sensor_y);
@ -1315,11 +1352,9 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, u8 player
pad->m_vibrateMotors.emplace_back(true, 0);
pad->m_vibrateMotors.emplace_back(false, 0);
m_dev->axis_orientations = axis_orientations;
if (auto evdev_device = add_device(player_config->device, false))
if (std::shared_ptr<EvdevDevice> evdev_device = add_device(player_config->device, false))
{
if (auto motion_device = add_motion_device(player_config->buddy_device, false))
if (std::shared_ptr<EvdevDevice> motion_device = add_motion_device(player_config->buddy_device, false))
{
m_bindings.emplace_back(pad, evdev_device, motion_device);
}
@ -1334,7 +1369,7 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, u8 player
evdev_log.warning("evdev add_device in bindPadToDevice failed for device %s", player_config->device.to_string());
}
for (auto& binding : m_bindings)
for (pad_ensemble& binding : m_bindings)
{
update_device(binding.device);
update_device(binding.buddy_device);
@ -1343,34 +1378,46 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, u8 player
return true;
}
bool evdev_joystick_handler::check_button(const EvdevButton& b, const u32 code)
bool evdev_joystick_handler::check_button_set(const std::set<u32>& indices, const u32 code)
{
return m_dev && b.code == code && b.type == m_dev->cur_type && b.dir == m_dev->cur_dir;
if (!m_dev)
return false;
for (u32 index : indices)
{
const EvdevButton& button = ::at32(m_dev->all_buttons, index);
if (button.code == code && button.type == m_dev->cur_type && button.dir == m_dev->cur_dir)
{
return true;
}
}
return false;
}
bool evdev_joystick_handler::check_buttons(const std::array<EvdevButton, 4>& b, const u32 code)
bool evdev_joystick_handler::check_button_sets(const std::array<std::set<u32>, 4>& sets, const u32 code)
{
return std::any_of(b.begin(), b.end(), [this, code](const EvdevButton& b) { return check_button(b, code); });
return std::any_of(sets.begin(), sets.end(), [this, code](const std::set<u32>& indices) { return check_button_set(indices, code); });
};
bool evdev_joystick_handler::get_is_left_trigger(const std::shared_ptr<PadDevice>& /*device*/, u64 keyCode)
{
return check_button(m_dev->trigger_left, static_cast<u32>(keyCode));
return check_button_set(m_dev->trigger_left, static_cast<u32>(keyCode));
}
bool evdev_joystick_handler::get_is_right_trigger(const std::shared_ptr<PadDevice>& /*device*/, u64 keyCode)
{
return check_button(m_dev->trigger_right, static_cast<u32>(keyCode));
return check_button_set(m_dev->trigger_right, static_cast<u32>(keyCode));
}
bool evdev_joystick_handler::get_is_left_stick(const std::shared_ptr<PadDevice>& /*device*/, u64 keyCode)
{
return check_buttons(m_dev->axis_left, static_cast<u32>(keyCode));
return check_button_sets(m_dev->axis_left, static_cast<u32>(keyCode));
}
bool evdev_joystick_handler::get_is_right_stick(const std::shared_ptr<PadDevice>& /*device*/, u64 keyCode)
{
return check_buttons(m_dev->axis_right, static_cast<u32>(keyCode));
return check_button_sets(m_dev->axis_right, static_cast<u32>(keyCode));
}
#endif

View File

@ -341,9 +341,9 @@ class evdev_joystick_handler final : public PadHandlerBase
struct EvdevButton
{
u32 code = 0;
int dir = 0;
int type = 0;
u32 code = 0; // key code of our button or axis
int dir = 0; // dir is -1 in case of a button, 0 in case of a regular axis and 1 in case of a reverse axis
int type = 0; // EV_KEY or EV_ABS
};
struct evdev_sensor : public EvdevButton
@ -356,14 +356,14 @@ class evdev_joystick_handler final : public PadHandlerBase
{
libevdev* device{ nullptr };
std::string path;
std::unordered_map<int, bool> axis_orientations; // value is true if key was found in rev_axis_list
std::array<s32, 4> stick_val{};
std::array<u16, 4> val_min{};
std::array<u16, 4> val_max{};
EvdevButton trigger_left{};
EvdevButton trigger_right{};
std::array<EvdevButton, 4> axis_left{};
std::array<EvdevButton, 4> axis_right{};
std::vector<EvdevButton> all_buttons;
std::set<u32> trigger_left{};
std::set<u32> trigger_right{};
std::array<std::set<u32>, 4> axis_left{};
std::array<std::set<u32>, 4> axis_right{};
std::array<evdev_sensor, 4> axis_motion{};
int cur_dir = 0;
int cur_type = 0;
@ -397,20 +397,17 @@ private:
std::unordered_map<u64, std::pair<u16, bool>> GetButtonValues(const std::shared_ptr<EvdevDevice>& device);
void SetRumble(EvdevDevice* device, u8 large, u8 small);
// Search axis_orientations map for the direction by index, returns -1 if not found, 0 for positive and 1 for negative
int FindAxisDirection(const std::unordered_map<int, bool>& map, int index);
positive_axis m_pos_axis_config;
std::vector<u32> m_positive_axis;
std::vector<std::string> m_blacklist;
std::unordered_map<std::string, std::shared_ptr<evdev_joystick_handler::EvdevDevice>> m_settings_added;
std::unordered_map<std::string, std::shared_ptr<evdev_joystick_handler::EvdevDevice>> m_motion_settings_added;
std::shared_ptr<EvdevDevice> m_dev;
bool m_is_button_or_trigger;
bool m_is_negative;
bool m_is_button_or_trigger{};
bool m_is_negative{};
bool check_button(const EvdevButton& b, const u32 code);
bool check_buttons(const std::array<EvdevButton, 4>& b, const u32 code);
bool check_button_set(const std::set<u32>& indices, const u32 code);
bool check_button_sets(const std::array<std::set<u32>, 4>& sets, const u32 code);
void handle_input_event(const input_event& evt, const std::shared_ptr<Pad>& pad);

View File

@ -6,8 +6,6 @@
#include <QApplication>
LOG_CHANNEL(input_log, "Input");
inline std::string sstr(const QString& _in) { return _in.toStdString(); }
constexpr auto qstr = QString::fromStdString;
@ -85,7 +83,7 @@ void keyboard_pad_handler::Key(const u32 code, bool pressed, u16 value)
{
Button& pressure_intensity_button = pad.m_buttons[pad.m_pressure_intensity_button_index];
if (pressure_intensity_button.m_keyCode == code)
if (pressure_intensity_button.m_key_codes.contains(code))
{
pressure_intensity_button.m_pressed = pressed;
pressure_intensity_button.m_value = value;
@ -97,9 +95,31 @@ void keyboard_pad_handler::Key(const u32 code, bool pressed, u16 value)
// Handle buttons
for (Button& button : pad.m_buttons)
{
if (button.m_keyCode != code)
if (!button.m_key_codes.contains(code))
continue;
// Make sure we keep this button pressed until all related keys are released.
if (pressed)
{
button.m_pressed_keys.insert(code);
if (button.m_pressed_keys.size() > 1)
{
// This button was already pressed by another key. Ignore this key press.
continue;
}
}
else
{
button.m_pressed_keys.erase(code);
if (!button.m_pressed_keys.empty())
{
// This button is still pressed by another key. Ignore this key release.
continue;
}
}
button.m_actual_value = pressed ? value : 0;
bool update_button = true;
@ -133,8 +153,8 @@ void keyboard_pad_handler::Key(const u32 code, bool pressed, u16 value)
// Handle sticks
for (usz i = 0; i < pad.m_sticks.size(); i++)
{
const bool is_max = pad.m_sticks[i].m_keyCodeMax == code;
const bool is_min = pad.m_sticks[i].m_keyCodeMin == code;
const bool is_max = pad.m_sticks[i].m_key_codes_max.contains(code);
const bool is_min = pad.m_sticks[i].m_key_codes_min.contains(code);
if (!is_max && !is_min)
{
@ -697,9 +717,17 @@ std::string keyboard_pad_handler::GetKeyName(const u32& keyCode)
return sstr(QKeySequence(keyCode).toString(QKeySequence::NativeText));
}
u32 keyboard_pad_handler::GetKeyCode(const std::string& keyName)
std::set<u32> keyboard_pad_handler::GetKeyCodes(const cfg::string& cfg_string)
{
return GetKeyCode(qstr(keyName));
std::set<u32> key_codes;
for (const std::string& key_name : cfg_pad::get_buttons(cfg_string))
{
if (u32 code = GetKeyCode(QString::fromStdString(key_name)); code != Qt::NoButton)
{
key_codes.insert(code);
}
}
return key_codes;
}
u32 keyboard_pad_handler::GetKeyCode(const QString& keyName)
@ -731,7 +759,7 @@ u32 keyboard_pad_handler::GetKeyCode(const QString& keyName)
#endif
const QKeySequence seq(keyName);
u32 key_code = 0;
u32 key_code = Qt::NoButton;
if (seq.count() == 1)
key_code = seq[0];
@ -812,18 +840,25 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr<Pad> pad, u8 player_i
m_r_stick_multiplier = cfg->rstickmultiplier;
m_pressure_intensity_toggle_mode = cfg->pressure_intensity_toggle_mode.get();
const auto find_key = [this](const cfg::string& name)
const auto find_keys = [this](const cfg::string& name)
{
int key = FindKeyCode(mouse_list, name, false);
if (key < 0)
key = GetKeyCode(name);
if (key < 0)
key = 0;
else if (!m_mouse_move_used && (key == mouse::move_left || key == mouse::move_right || key == mouse::move_up || key == mouse::move_down))
m_mouse_move_used = true;
else if (!m_mouse_wheel_used && (key == mouse::wheel_left || key == mouse::wheel_right || key == mouse::wheel_up || key == mouse::wheel_down))
m_mouse_wheel_used = true;
return key;
std::set<u32> keys = FindKeyCodes<u32, u32>(mouse_list, name, false);
if (keys.empty())
{
keys = GetKeyCodes(name);
}
if (!keys.empty())
{
if (!m_mouse_move_used && (keys.contains(mouse::move_left) || keys.contains(mouse::move_right) || keys.contains(mouse::move_up) || keys.contains(mouse::move_down)))
{
m_mouse_move_used = true;
}
else if (!m_mouse_wheel_used && (keys.contains(mouse::wheel_left) || keys.contains(mouse::wheel_right) || keys.contains(mouse::wheel_up) || keys.contains(mouse::wheel_down)))
{
m_mouse_wheel_used = true;
}
}
return keys;
};
u32 pclass_profile = 0x0;
@ -849,31 +884,31 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr<Pad> pad, u8 player_i
cfg->pressure_intensity
);
pad->m_buttons.emplace_back(special_button_offset, find_key(cfg->pressure_intensity_button), special_button_value::pressure_intensity);
pad->m_buttons.emplace_back(special_button_offset, find_keys(cfg->pressure_intensity_button), special_button_value::pressure_intensity);
pad->m_pressure_intensity_button_index = static_cast<s32>(pad->m_buttons.size()) - 1;
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(cfg->left), CELL_PAD_CTRL_LEFT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(cfg->down), CELL_PAD_CTRL_DOWN);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(cfg->right), CELL_PAD_CTRL_RIGHT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(cfg->up), CELL_PAD_CTRL_UP);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(cfg->start), CELL_PAD_CTRL_START);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(cfg->r3), CELL_PAD_CTRL_R3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(cfg->l3), CELL_PAD_CTRL_L3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(cfg->select), CELL_PAD_CTRL_SELECT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(cfg->ps), CELL_PAD_CTRL_PS);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(cfg->square), CELL_PAD_CTRL_SQUARE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(cfg->cross), CELL_PAD_CTRL_CROSS);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(cfg->circle), CELL_PAD_CTRL_CIRCLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(cfg->triangle), CELL_PAD_CTRL_TRIANGLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(cfg->r1), CELL_PAD_CTRL_R1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(cfg->l1), CELL_PAD_CTRL_L1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(cfg->r2), CELL_PAD_CTRL_R2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(cfg->l2), CELL_PAD_CTRL_L2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_keys(cfg->left), CELL_PAD_CTRL_LEFT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_keys(cfg->down), CELL_PAD_CTRL_DOWN);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_keys(cfg->right), CELL_PAD_CTRL_RIGHT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_keys(cfg->up), CELL_PAD_CTRL_UP);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_keys(cfg->start), CELL_PAD_CTRL_START);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_keys(cfg->r3), CELL_PAD_CTRL_R3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_keys(cfg->l3), CELL_PAD_CTRL_L3);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_keys(cfg->select), CELL_PAD_CTRL_SELECT);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_keys(cfg->ps), CELL_PAD_CTRL_PS);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_keys(cfg->square), CELL_PAD_CTRL_SQUARE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_keys(cfg->cross), CELL_PAD_CTRL_CROSS);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_keys(cfg->circle), CELL_PAD_CTRL_CIRCLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_keys(cfg->triangle), CELL_PAD_CTRL_TRIANGLE);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_keys(cfg->r1), CELL_PAD_CTRL_R1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_keys(cfg->l1), CELL_PAD_CTRL_L1);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_keys(cfg->r2), CELL_PAD_CTRL_R2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_keys(cfg->l2), CELL_PAD_CTRL_L2);
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, find_key(cfg->ls_left), find_key(cfg->ls_right));
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, find_key(cfg->ls_up), find_key(cfg->ls_down));
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, find_key(cfg->rs_left), find_key(cfg->rs_right));
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, find_key(cfg->rs_up), find_key(cfg->rs_down));
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, find_keys(cfg->ls_left), find_keys(cfg->ls_right));
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, find_keys(cfg->ls_up), find_keys(cfg->ls_down));
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, find_keys(cfg->rs_left), find_keys(cfg->rs_right));
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, find_keys(cfg->rs_up), find_keys(cfg->rs_down));
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);
@ -891,8 +926,8 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr<Pad> pad, u8 player_i
void keyboard_pad_handler::process()
{
static const double stick_interval = 10.0;
static const double button_interval = 10.0;
constexpr double stick_interval = 10.0;
constexpr double button_interval = 10.0;
const auto now = steady_clock::now();
@ -914,7 +949,7 @@ void keyboard_pad_handler::process()
if (m_mouse_move_used && m_mouse_movement_mode == mouse_movement_mode::relative)
{
static const double mouse_interval = 30.0;
constexpr double mouse_interval = 30.0;
const double elapsed_left = std::chrono::duration_cast<std::chrono::microseconds>(now - m_last_mouse_move_left).count() / 1000.0;
const double elapsed_right = std::chrono::duration_cast<std::chrono::microseconds>(now - m_last_mouse_move_right).count() / 1000.0;
@ -987,7 +1022,7 @@ void keyboard_pad_handler::process()
if (update_buttons)
{
for (auto& button : pad.m_buttons)
for (Button& button : pad.m_buttons)
{
if (button.m_analog)
{

View File

@ -93,7 +93,7 @@ public:
static QStringList GetKeyNames(const QKeyEvent* keyEvent);
static std::string GetKeyName(const QKeyEvent* keyEvent);
static std::string GetKeyName(const u32& keyCode);
static u32 GetKeyCode(const std::string& keyName);
static std::set<u32> GetKeyCodes(const cfg::string& cfg_string);
static u32 GetKeyCode(const QString& keyName);
static int native_scan_code_from_string(const std::string& key);

View File

@ -2,8 +2,6 @@
#include "mm_joystick_handler.h"
#include "Emu/Io/pad_config.h"
LOG_CHANNEL(input_log, "Input");
mm_joystick_handler::mm_joystick_handler() : PadHandlerBase(pad_handler::mm)
{
init_configs();
@ -113,62 +111,70 @@ std::vector<pad_list_entry> mm_joystick_handler::list_devices()
return devices;
}
u64 mm_joystick_handler::find_key(const std::string& name) const
template <typename T>
std::set<T> mm_joystick_handler::find_keys(const cfg::string& cfg_string) const
{
long key = FindKeyCodeByString(axis_list, name, false);
if (key < 0)
key = FindKeyCodeByString(pov_list, name, false);
if (key < 0)
key = FindKeyCodeByString(button_list, name);
return static_cast<u64>(key);
return find_keys<T>(cfg_pad::get_buttons(cfg_string));
}
std::array<u32, PadHandlerBase::button::button_count> mm_joystick_handler::get_mapped_key_codes(const std::shared_ptr<PadDevice>& device, const cfg_pad* cfg)
template <typename T>
std::set<T> mm_joystick_handler::find_keys(const std::vector<std::string>& names) const
{
std::array<u32, button::button_count> mapping{};
std::set<T> keys;
for (const T& k : FindKeyCodes<u64, T>(axis_list, names)) keys.insert(k);
for (const T& k : FindKeyCodes<u64, T>(pov_list, names)) keys.insert(k);
for (const T& k : FindKeyCodes<u64, T>(button_list, names)) keys.insert(k);
return keys;
}
std::array<std::set<u32>, PadHandlerBase::button::button_count> mm_joystick_handler::get_mapped_key_codes(const std::shared_ptr<PadDevice>& device, const cfg_pad* cfg)
{
std::array<std::set<u32>, button::button_count> mapping{};
MMJOYDevice* joy_device = static_cast<MMJOYDevice*>(device.get());
if (!joy_device || !cfg)
return mapping;
joy_device->trigger_code_left = find_key(cfg->l2);
joy_device->trigger_code_right = find_key(cfg->r2);
joy_device->axis_code_left[0] = find_key(cfg->ls_left);
joy_device->axis_code_left[1] = find_key(cfg->ls_right);
joy_device->axis_code_left[2] = find_key(cfg->ls_down);
joy_device->axis_code_left[3] = find_key(cfg->ls_up);
joy_device->axis_code_right[0] = find_key(cfg->rs_left);
joy_device->axis_code_right[1] = find_key(cfg->rs_right);
joy_device->axis_code_right[2] = find_key(cfg->rs_down);
joy_device->axis_code_right[3] = find_key(cfg->rs_up);
joy_device->trigger_code_left = find_keys<u64>(cfg->l2);
joy_device->trigger_code_right = find_keys<u64>(cfg->r2);
joy_device->axis_code_left[0] = find_keys<u64>(cfg->ls_left);
joy_device->axis_code_left[1] = find_keys<u64>(cfg->ls_right);
joy_device->axis_code_left[2] = find_keys<u64>(cfg->ls_down);
joy_device->axis_code_left[3] = find_keys<u64>(cfg->ls_up);
joy_device->axis_code_right[0] = find_keys<u64>(cfg->rs_left);
joy_device->axis_code_right[1] = find_keys<u64>(cfg->rs_right);
joy_device->axis_code_right[2] = find_keys<u64>(cfg->rs_down);
joy_device->axis_code_right[3] = find_keys<u64>(cfg->rs_up);
mapping[button::up] = static_cast<u32>(find_key(cfg->up));
mapping[button::down] = static_cast<u32>(find_key(cfg->down));
mapping[button::left] = static_cast<u32>(find_key(cfg->left));
mapping[button::right] = static_cast<u32>(find_key(cfg->right));
mapping[button::cross] = static_cast<u32>(find_key(cfg->cross));
mapping[button::square] = static_cast<u32>(find_key(cfg->square));
mapping[button::circle] = static_cast<u32>(find_key(cfg->circle));
mapping[button::triangle] = static_cast<u32>(find_key(cfg->triangle));
mapping[button::l1] = static_cast<u32>(find_key(cfg->l1));
mapping[button::l2] = static_cast<u32>(joy_device->trigger_code_left);
mapping[button::l3] = static_cast<u32>(find_key(cfg->l3));
mapping[button::r1] = static_cast<u32>(find_key(cfg->r1));
mapping[button::r2] = static_cast<u32>(joy_device->trigger_code_right);
mapping[button::r3] = static_cast<u32>(find_key(cfg->r3));
mapping[button::start] = static_cast<u32>(find_key(cfg->start));
mapping[button::select] = static_cast<u32>(find_key(cfg->select));
mapping[button::ps] = static_cast<u32>(find_key(cfg->ps));
mapping[button::ls_left] = static_cast<u32>(joy_device->axis_code_left[0]);
mapping[button::ls_right] = static_cast<u32>(joy_device->axis_code_left[1]);
mapping[button::ls_down] = static_cast<u32>(joy_device->axis_code_left[2]);
mapping[button::ls_up] = static_cast<u32>(joy_device->axis_code_left[3]);
mapping[button::rs_left] = static_cast<u32>(joy_device->axis_code_right[0]);
mapping[button::rs_right] = static_cast<u32>(joy_device->axis_code_right[1]);
mapping[button::rs_down] = static_cast<u32>(joy_device->axis_code_right[2]);
mapping[button::rs_up] = static_cast<u32>(joy_device->axis_code_right[3]);
mapping[button::up] = find_keys<u32>(cfg->up);
mapping[button::down] = find_keys<u32>(cfg->down);
mapping[button::left] = find_keys<u32>(cfg->left);
mapping[button::right] = find_keys<u32>(cfg->right);
mapping[button::cross] = find_keys<u32>(cfg->cross);
mapping[button::square] = find_keys<u32>(cfg->square);
mapping[button::circle] = find_keys<u32>(cfg->circle);
mapping[button::triangle] = find_keys<u32>(cfg->triangle);
mapping[button::l1] = find_keys<u32>(cfg->l1);
mapping[button::l2] = narrow_set(joy_device->trigger_code_left);
mapping[button::l3] = find_keys<u32>(cfg->l3);
mapping[button::r1] = find_keys<u32>(cfg->r1);
mapping[button::r2] = narrow_set(joy_device->trigger_code_right);
mapping[button::r3] = find_keys<u32>(cfg->r3);
mapping[button::start] = find_keys<u32>(cfg->start);
mapping[button::select] = find_keys<u32>(cfg->select);
mapping[button::ps] = find_keys<u32>(cfg->ps);
mapping[button::ls_left] = narrow_set(joy_device->axis_code_left[0]);
mapping[button::ls_right] = narrow_set(joy_device->axis_code_left[1]);
mapping[button::ls_down] = narrow_set(joy_device->axis_code_left[2]);
mapping[button::ls_up] = narrow_set(joy_device->axis_code_left[3]);
mapping[button::rs_left] = narrow_set(joy_device->axis_code_right[0]);
mapping[button::rs_right] = narrow_set(joy_device->axis_code_right[1]);
mapping[button::rs_down] = narrow_set(joy_device->axis_code_right[2]);
mapping[button::rs_up] = narrow_set(joy_device->axis_code_right[3]);
mapping[button::pressure_intensity_button] = static_cast<u32>(find_key(cfg->pressure_intensity_button));
mapping[button::pressure_intensity_button] = find_keys<u32>(cfg->pressure_intensity_button);
return mapping;
}
@ -230,9 +236,8 @@ PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std:
std::string name;
} pressed_button{};
for (const auto& button : axis_list)
for (const auto& [keycode, name] : axis_list)
{
u64 keycode = button.first;
u16 value = data[keycode];
if (!get_blacklist && std::find(m_blacklist.cbegin(), m_blacklist.cend(), keycode) != m_blacklist.cend())
@ -242,20 +247,19 @@ PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std:
{
if (get_blacklist)
{
m_blacklist.emplace_back(keycode);
input_log.error("MMJOY Calibration: Added axis [ %d = %s ] to blacklist. Value = %d", keycode, button.second, value);
m_blacklist.push_back(keycode);
input_log.error("MMJOY Calibration: Added axis [ %d = %s ] to blacklist. Value = %d", keycode, name, value);
}
else if (value > pressed_button.value)
{
pressed_button = { .value = value, .name = button.second };
pressed_button = { .value = value, .name = name };
}
}
}
for (const auto& button : pov_list)
for (const auto& [keycode, name] : pov_list)
{
u64 keycode = button.first;
u16 value = data[keycode];
const u16 value = data[keycode];
if (!get_blacklist && std::find(m_blacklist.cbegin(), m_blacklist.cend(), keycode) != m_blacklist.cend())
continue;
@ -264,20 +268,18 @@ PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std:
{
if (get_blacklist)
{
m_blacklist.emplace_back(keycode);
input_log.error("MMJOY Calibration: Added pov [ %d = %s ] to blacklist. Value = %d", keycode, button.second, value);
m_blacklist.push_back(keycode);
input_log.error("MMJOY Calibration: Added pov [ %d = %s ] to blacklist. Value = %d", keycode, name, value);
}
else if (value > pressed_button.value)
{
pressed_button = { .value = value, .name = button.second };
pressed_button = { .value = value, .name = name };
}
}
}
for (const auto& button : button_list)
for (const auto& [keycode, name] : button_list)
{
const u64 keycode = button.first;
if (keycode == NO_BUTTON)
continue;
@ -290,12 +292,12 @@ PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std:
{
if (get_blacklist)
{
m_blacklist.emplace_back(keycode);
input_log.error("MMJOY Calibration: Added button [ %d = %s ] to blacklist. Value = %d", keycode, button.second, value);
m_blacklist.push_back(keycode);
input_log.error("MMJOY Calibration: Added button [ %d = %s ] to blacklist. Value = %d", keycode, name, value);
}
else if (value > pressed_button.value)
{
pressed_button = { .value = value, .name = button.second };
pressed_button = { .value = value, .name = name };
}
}
}
@ -312,12 +314,24 @@ PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std:
pad_preview_values preview_values{};
if (buttons.size() == 10)
{
preview_values[0] = data[find_key(buttons[0])];
preview_values[1] = data[find_key(buttons[1])];
preview_values[2] = data[find_key(buttons[3])] - data[find_key(buttons[2])];
preview_values[3] = data[find_key(buttons[5])] - data[find_key(buttons[4])];
preview_values[4] = data[find_key(buttons[7])] - data[find_key(buttons[6])];
preview_values[5] = data[find_key(buttons[9])] - data[find_key(buttons[8])];
const auto get_key_value = [this, &data](const std::string& str) -> u16
{
u16 value{};
for (u32 key_code : find_keys<u32>(cfg_pad::get_buttons(str)))
{
if (const auto it = data.find(key_code); it != data.cend())
{
value = std::max(value, it->second);
}
}
return value;
};
preview_values[0] = get_key_value(buttons[0]);
preview_values[1] = get_key_value(buttons[1]);
preview_values[2] = get_key_value(buttons[3]) - get_key_value(buttons[2]);
preview_values[3] = get_key_value(buttons[5]) - get_key_value(buttons[4]);
preview_values[4] = get_key_value(buttons[7]) - get_key_value(buttons[6]);
preview_values[5] = get_key_value(buttons[9]) - get_key_value(buttons[8]);
}
if (pressed_button.value > 0)
@ -492,25 +506,25 @@ std::shared_ptr<PadDevice> mm_joystick_handler::get_device(const std::string& de
bool mm_joystick_handler::get_is_left_trigger(const std::shared_ptr<PadDevice>& device, u64 keyCode)
{
const MMJOYDevice* dev = static_cast<MMJOYDevice*>(device.get());
return dev && dev->trigger_code_left == keyCode;
return dev && dev->trigger_code_left.contains(keyCode);
}
bool mm_joystick_handler::get_is_right_trigger(const std::shared_ptr<PadDevice>& device, u64 keyCode)
{
const MMJOYDevice* dev = static_cast<MMJOYDevice*>(device.get());
return dev && dev->trigger_code_right == keyCode;
return dev && dev->trigger_code_right.contains(keyCode);
}
bool mm_joystick_handler::get_is_left_stick(const std::shared_ptr<PadDevice>& device, u64 keyCode)
{
const MMJOYDevice* dev = static_cast<MMJOYDevice*>(device.get());
return dev && std::find(dev->axis_code_left.cbegin(), dev->axis_code_left.cend(), keyCode) != dev->axis_code_left.cend();
return dev && std::any_of(dev->axis_code_left.cbegin(), dev->axis_code_left.cend(), [&keyCode](const std::set<u64>& s){ return s.contains(keyCode); });
}
bool mm_joystick_handler::get_is_right_stick(const std::shared_ptr<PadDevice>& device, u64 keyCode)
{
const MMJOYDevice* dev = static_cast<MMJOYDevice*>(device.get());
return dev && std::find(dev->axis_code_right.cbegin(), dev->axis_code_right.cend(), keyCode) != dev->axis_code_right.cend();
return dev && std::any_of(dev->axis_code_right.cbegin(), dev->axis_code_right.cend(), [&keyCode](const std::set<u64>& s){ return s.contains(keyCode); });
}
PadHandlerBase::connection mm_joystick_handler::update_connection(const std::shared_ptr<PadDevice>& device)

View File

@ -126,9 +126,13 @@ private:
std::vector<u64> m_blacklist;
std::unordered_map<int, MMJOYDevice> m_devices;
u64 find_key(const std::string& name) const;
template <typename T>
std::set<T> find_keys(const std::vector<std::string>& names) const;
std::array<u32, PadHandlerBase::button::button_count> get_mapped_key_codes(const std::shared_ptr<PadDevice>& device, const cfg_pad* cfg) override;
template <typename T>
std::set<T> find_keys(const cfg::string& cfg_string) const;
std::array<std::set<u32>, PadHandlerBase::button::button_count> get_mapped_key_codes(const std::shared_ptr<PadDevice>& device, const cfg_pad* cfg) override;
std::shared_ptr<PadDevice> get_device(const std::string& device) override;
bool get_is_left_trigger(const std::shared_ptr<PadDevice>& device, u64 keyCode) override;
bool get_is_right_trigger(const std::shared_ptr<PadDevice>& device, u64 keyCode) override;

View File

@ -24,7 +24,6 @@
#include "Utilities/Thread.h"
#include "util/atomic.hpp"
LOG_CHANNEL(input_log, "Input");
LOG_CHANNEL(sys_log, "SYS");
extern bool is_input_allowed();

View File

@ -53,6 +53,15 @@ inline bool CreateConfigFile(const QString& dir, const QString& name)
return true;
}
void pad_settings_dialog::pad_button::insert_key(const std::string& key)
{
std::vector<std::string> buttons = cfg_pad::get_buttons(keys);
buttons.push_back(key);
keys = cfg_pad::get_buttons(std::move(buttons));
text = QString::fromStdString(keys).replace(",", ", ");
}
pad_settings_dialog::pad_settings_dialog(std::shared_ptr<gui_settings> gui_settings, QWidget *parent, const GameInfo *game)
: QDialog(parent)
, ui(new Ui::pad_settings_dialog)
@ -291,7 +300,7 @@ void pad_settings_dialog::InitButtons()
connect(m_pad_buttons, &QButtonGroup::idClicked, this, &pad_settings_dialog::OnPadButtonClicked);
connect(&m_timer, &QTimer::timeout, this, [this]()
connect(&m_remap_timer, &QTimer::timeout, this, [this]()
{
if (--m_seconds <= 0)
{
@ -414,7 +423,7 @@ void pad_settings_dialog::InitButtons()
{
SwitchPadInfo(pad_name, true);
if (!m_enable_buttons && !m_timer.isActive())
if (!m_enable_buttons && !m_remap_timer.isActive())
{
SwitchButtons(true);
}
@ -449,8 +458,7 @@ void pad_settings_dialog::InitButtons()
if (m_button_id > button_ids::id_pad_begin && m_button_id < button_ids::id_pad_end)
{
m_cfg_entries[m_button_id].key = name;
m_cfg_entries[m_button_id].text = qstr(name);
m_cfg_entries[m_button_id].insert_key(name);
ReactivateButtons();
}
};
@ -536,10 +544,10 @@ void pad_settings_dialog::InitButtons()
const std::vector<std::string> buttons =
{
m_cfg_entries[button_ids::id_pad_l2].key, m_cfg_entries[button_ids::id_pad_r2].key, m_cfg_entries[button_ids::id_pad_lstick_left].key,
m_cfg_entries[button_ids::id_pad_lstick_right].key, m_cfg_entries[button_ids::id_pad_lstick_down].key, m_cfg_entries[button_ids::id_pad_lstick_up].key,
m_cfg_entries[button_ids::id_pad_rstick_left].key, m_cfg_entries[button_ids::id_pad_rstick_right].key, m_cfg_entries[button_ids::id_pad_rstick_down].key,
m_cfg_entries[button_ids::id_pad_rstick_up].key
m_cfg_entries[button_ids::id_pad_l2].keys, m_cfg_entries[button_ids::id_pad_r2].keys, m_cfg_entries[button_ids::id_pad_lstick_left].keys,
m_cfg_entries[button_ids::id_pad_lstick_right].keys, m_cfg_entries[button_ids::id_pad_lstick_down].keys, m_cfg_entries[button_ids::id_pad_lstick_up].keys,
m_cfg_entries[button_ids::id_pad_rstick_left].keys, m_cfg_entries[button_ids::id_pad_rstick_right].keys, m_cfg_entries[button_ids::id_pad_rstick_down].keys,
m_cfg_entries[button_ids::id_pad_rstick_up].keys
};
const PadHandlerBase::connection status = m_handler->get_next_button_press(m_device_name,
@ -629,7 +637,7 @@ void pad_settings_dialog::switch_pad_info(int index, pad_device_info info, bool
ui->chooseDevice->setItemText(index, is_connected ? qstr(info.name) : (qstr(info.name) + Disconnected_suffix));
}
if (!is_connected && m_timer.isActive() && ui->chooseDevice->currentIndex() == index)
if (!is_connected && m_remap_timer.isActive() && ui->chooseDevice->currentIndex() == index)
{
ReactivateButtons();
}
@ -699,7 +707,7 @@ void pad_settings_dialog::ReloadButtons()
void pad_settings_dialog::ReactivateButtons()
{
m_timer.stop();
m_remap_timer.stop();
m_seconds = MAX_SECONDS;
if (m_button_id == button_ids::id_pad_begin)
@ -844,8 +852,7 @@ void pad_settings_dialog::keyPressEvent(QKeyEvent *keyEvent)
}
else
{
m_cfg_entries[m_button_id].key = keyboard_pad_handler::GetKeyName(keyEvent);
m_cfg_entries[m_button_id].text = qstr(m_cfg_entries[m_button_id].key);
m_cfg_entries[m_button_id].insert_key(keyboard_pad_handler::GetKeyName(keyEvent));
}
ReactivateButtons();
@ -872,8 +879,7 @@ void pad_settings_dialog::mouseReleaseEvent(QMouseEvent* event)
}
else
{
m_cfg_entries[m_button_id].key = (static_cast<keyboard_pad_handler*>(m_handler.get()))->GetMouseName(event);
m_cfg_entries[m_button_id].text = qstr(m_cfg_entries[m_button_id].key);
m_cfg_entries[m_button_id].insert_key((static_cast<keyboard_pad_handler*>(m_handler.get()))->GetMouseName(event));
}
ReactivateButtons();
@ -934,8 +940,8 @@ void pad_settings_dialog::wheelEvent(QWheelEvent *event)
key = mouse::wheel_down;
}
}
m_cfg_entries[m_button_id].key = (static_cast<keyboard_pad_handler*>(m_handler.get()))->GetMouseName(key);
m_cfg_entries[m_button_id].text = qstr(m_cfg_entries[m_button_id].key);
m_cfg_entries[m_button_id].insert_key((static_cast<keyboard_pad_handler*>(m_handler.get()))->GetMouseName(key));
ReactivateButtons();
}
@ -985,8 +991,7 @@ void pad_settings_dialog::mouseMoveEvent(QMouseEvent* event)
if (key != 0)
{
m_cfg_entries[m_button_id].key = (static_cast<keyboard_pad_handler*>(m_handler.get()))->GetMouseName(key);
m_cfg_entries[m_button_id].text = qstr(m_cfg_entries[m_button_id].key);
m_cfg_entries[m_button_id].insert_key((static_cast<keyboard_pad_handler*>(m_handler.get()))->GetMouseName(key));
ReactivateButtons();
}
}
@ -1006,8 +1011,9 @@ bool pad_settings_dialog::eventFilter(QObject* object, QEvent* event)
{
if (const int button_id = m_pad_buttons->id(button); m_cfg_entries.contains(button_id))
{
m_cfg_entries[button_id].key.clear();
m_cfg_entries[button_id].text.clear();
pad_button& button = m_cfg_entries[button_id];
button.keys.clear();
button.text.clear();
UpdateLabels();
return true;
@ -1172,16 +1178,16 @@ void pad_settings_dialog::UpdateLabels(bool is_reset)
ui->gb_battery->setVisible(m_enable_battery || m_enable_led);
}
for (auto& entry : m_cfg_entries)
for (auto& [id, button] : m_cfg_entries)
{
if (is_reset)
{
entry.second.key = *entry.second.cfg_text;
entry.second.text = qstr(entry.second.key);
button.keys = *button.cfg_text;
button.text = qstr(button.keys);
}
// The button has to contain at least one character, because it would be square'ish otherwise
m_pad_buttons->button(entry.first)->setText(entry.second.text.isEmpty() ? QStringLiteral("-") : entry.second.text);
m_pad_buttons->button(id)->setText(button.text.isEmpty() ? QStringLiteral("-") : button.text);
}
}
@ -1271,7 +1277,7 @@ void pad_settings_dialog::OnPadButtonClicked(int id)
m_pad_buttons->button(m_button_id)->setPalette(QPalette(Qt::blue));
m_pad_buttons->button(m_button_id)->grabMouse();
SwitchButtons(false); // disable all buttons, needed for using Space, Enter and other specific buttons
m_timer.start(1000);
m_remap_timer.start(1000);
}
void pad_settings_dialog::OnTabChanged(int index)
@ -1487,7 +1493,7 @@ void pad_settings_dialog::ChangeHandler()
}
// Handle running timers
if (m_timer.isActive())
if (m_remap_timer.isActive())
{
ReactivateButtons();
}
@ -1717,7 +1723,7 @@ void pad_settings_dialog::ApplyCurrentPlayerConfig(int new_player_id)
return;
}
m_duplicate_buttons[m_last_player_id] = "";
m_duplicate_buttons[m_last_player_id].clear();
auto& player = g_cfg_input.player[m_last_player_id];
m_last_player_id = new_player_id;
@ -1726,16 +1732,19 @@ void pad_settings_dialog::ApplyCurrentPlayerConfig(int new_player_id)
if (m_handler->m_type != pad_handler::null)
{
std::set<std::string> unique_keys;
for (const auto& entry : m_cfg_entries)
for (const auto& [id, button] : m_cfg_entries)
{
// Let's ignore special keys, unless we're using a keyboard
if (entry.first == button_ids::id_pressure_intensity && m_handler->m_type != pad_handler::keyboard)
if (id == button_ids::id_pressure_intensity && m_handler->m_type != pad_handler::keyboard)
continue;
if (const auto& [it, ok] = unique_keys.insert(entry.second.key); !ok)
for (const std::string& key : cfg_pad::get_buttons(button.keys))
{
m_duplicate_buttons[m_last_player_id] = entry.second.key;
break;
if (const auto& [it, ok] = unique_keys.insert(key); !ok)
{
m_duplicate_buttons[m_last_player_id] = key;
break;
}
}
}
}
@ -1743,7 +1752,7 @@ void pad_settings_dialog::ApplyCurrentPlayerConfig(int new_player_id)
// Apply buttons
for (const auto& entry : m_cfg_entries)
{
entry.second.cfg_text->from_string(entry.second.key);
entry.second.cfg_text->from_string(entry.second.keys);
}
// Apply rest of config

View File

@ -80,8 +80,10 @@ class pad_settings_dialog : public QDialog
struct pad_button
{
cfg::string* cfg_text = nullptr;
std::string key;
std::string keys;
QString text;
void insert_key(const std::string& key);
};
const QString Disconnected_suffix = tr(" (disconnected)");
@ -152,7 +154,7 @@ private:
// Remap Timer
const int MAX_SECONDS = 5;
int m_seconds = MAX_SECONDS;
QTimer m_timer;
QTimer m_remap_timer;
// Mouse Move
QPoint m_last_pos;