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; cfg_input g_cfg_input;
LOG_CHANNEL(input_log, "Input");
PadHandlerBase::PadHandlerBase(pad_handler type) : m_type(type) PadHandlerBase::PadHandlerBase(pad_handler type) : m_type(type)
{ {
} }
// Search an unordered map for a string value and return found keycode std::set<u32> PadHandlerBase::narrow_set(const std::set<u64>& src)
int PadHandlerBase::FindKeyCode(const std::unordered_map<u32, std::string>& map, const cfg::string& name, bool fallback)
{ {
const std::string def = name.def; if (src.empty())
const std::string nam = name.to_string(); return {};
int def_code = -1;
for (auto it = map.begin(); it != map.end(); ++it) std::set<u32> dst;
for (const u64& s : src)
{ {
if (it->second == nam) dst.insert(::narrow<u32>(s));
return it->first;
if (fallback && it->second == def)
def_code = it->first;
} }
return dst;
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;
} }
// Get new multiplied value based on the multiplier // 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); auto device = get_device(pad_id);
const auto status = update_connection(device); const connection status = update_connection(device);
if (status == connection::disconnected) if (status == connection::disconnected)
{ {
if (fail_callback) if (fail_callback)
@ -432,7 +350,7 @@ void PadHandlerBase::get_motion_sensors(const std::string& pad_id, const motion_
// Reset sensors // Reset sensors
auto device = get_device(pad_id); auto device = get_device(pad_id);
const auto status = update_connection(device); const connection status = update_connection(device);
if (status == connection::disconnected) if (status == connection::disconnected)
{ {
if (fail_callback) if (fail_callback)
@ -536,11 +454,11 @@ bool PadHandlerBase::bindPadToDevice(std::shared_ptr<Pad> pad, u8 player_id)
return false; 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; 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) 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; 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) if (!device || !cfg)
return mapping; return mapping;
device->trigger_code_left = FindKeyCode(button_list, cfg->l2); device->trigger_code_left = FindKeyCodes<u32, u64>(button_list, cfg->l2);
device->trigger_code_right = FindKeyCode(button_list, cfg->r2); device->trigger_code_right = FindKeyCodes<u32, u64>(button_list, cfg->r2);
device->axis_code_left[0] = FindKeyCode(button_list, cfg->ls_left); device->axis_code_left[0] = FindKeyCodes<u32, u64>(button_list, cfg->ls_left);
device->axis_code_left[1] = FindKeyCode(button_list, cfg->ls_right); device->axis_code_left[1] = FindKeyCodes<u32, u64>(button_list, cfg->ls_right);
device->axis_code_left[2] = FindKeyCode(button_list, cfg->ls_down); device->axis_code_left[2] = FindKeyCodes<u32, u64>(button_list, cfg->ls_down);
device->axis_code_left[3] = FindKeyCode(button_list, cfg->ls_up); device->axis_code_left[3] = FindKeyCodes<u32, u64>(button_list, cfg->ls_up);
device->axis_code_right[0] = FindKeyCode(button_list, cfg->rs_left); device->axis_code_right[0] = FindKeyCodes<u32, u64>(button_list, cfg->rs_left);
device->axis_code_right[1] = FindKeyCode(button_list, cfg->rs_right); device->axis_code_right[1] = FindKeyCodes<u32, u64>(button_list, cfg->rs_right);
device->axis_code_right[2] = FindKeyCode(button_list, cfg->rs_down); device->axis_code_right[2] = FindKeyCodes<u32, u64>(button_list, cfg->rs_down);
device->axis_code_right[3] = FindKeyCode(button_list, cfg->rs_up); device->axis_code_right[3] = FindKeyCodes<u32, u64>(button_list, cfg->rs_up);
mapping[button::up] = FindKeyCode(button_list, cfg->up); mapping[button::up] = FindKeyCodes<u32, u32>(button_list, cfg->up);
mapping[button::down] = FindKeyCode(button_list, cfg->down); mapping[button::down] = FindKeyCodes<u32, u32>(button_list, cfg->down);
mapping[button::left] = FindKeyCode(button_list, cfg->left); mapping[button::left] = FindKeyCodes<u32, u32>(button_list, cfg->left);
mapping[button::right] = FindKeyCode(button_list, cfg->right); mapping[button::right] = FindKeyCodes<u32, u32>(button_list, cfg->right);
mapping[button::cross] = FindKeyCode(button_list, cfg->cross); mapping[button::cross] = FindKeyCodes<u32, u32>(button_list, cfg->cross);
mapping[button::square] = FindKeyCode(button_list, cfg->square); mapping[button::square] = FindKeyCodes<u32, u32>(button_list, cfg->square);
mapping[button::circle] = FindKeyCode(button_list, cfg->circle); mapping[button::circle] = FindKeyCodes<u32, u32>(button_list, cfg->circle);
mapping[button::triangle] = FindKeyCode(button_list, cfg->triangle); mapping[button::triangle] = FindKeyCodes<u32, u32>(button_list, cfg->triangle);
mapping[button::start] = FindKeyCode(button_list, cfg->start); mapping[button::start] = FindKeyCodes<u32, u32>(button_list, cfg->start);
mapping[button::select] = FindKeyCode(button_list, cfg->select); mapping[button::select] = FindKeyCodes<u32, u32>(button_list, cfg->select);
mapping[button::l1] = FindKeyCode(button_list, cfg->l1); mapping[button::l1] = FindKeyCodes<u32, u32>(button_list, cfg->l1);
mapping[button::l2] = ::narrow<u32>(device->trigger_code_left); mapping[button::l2] = narrow_set(device->trigger_code_left);
mapping[button::l3] = FindKeyCode(button_list, cfg->l3); mapping[button::l3] = FindKeyCodes<u32, u32>(button_list, cfg->l3);
mapping[button::r1] = FindKeyCode(button_list, cfg->r1); mapping[button::r1] = FindKeyCodes<u32, u32>(button_list, cfg->r1);
mapping[button::r2] = ::narrow<u32>(device->trigger_code_right); mapping[button::r2] = narrow_set(device->trigger_code_right);
mapping[button::r3] = FindKeyCode(button_list, cfg->r3); mapping[button::r3] = FindKeyCodes<u32, u32>(button_list, cfg->r3);
mapping[button::ls_left] = ::narrow<u32>(device->axis_code_left[0]); mapping[button::ls_left] = narrow_set(device->axis_code_left[0]);
mapping[button::ls_right] = ::narrow<u32>(device->axis_code_left[1]); mapping[button::ls_right] = narrow_set(device->axis_code_left[1]);
mapping[button::ls_down] = ::narrow<u32>(device->axis_code_left[2]); mapping[button::ls_down] = narrow_set(device->axis_code_left[2]);
mapping[button::ls_up] = ::narrow<u32>(device->axis_code_left[3]); mapping[button::ls_up] = narrow_set(device->axis_code_left[3]);
mapping[button::rs_left] = ::narrow<u32>(device->axis_code_right[0]); mapping[button::rs_left] = narrow_set(device->axis_code_right[0]);
mapping[button::rs_right] = ::narrow<u32>(device->axis_code_right[1]); mapping[button::rs_right] = narrow_set(device->axis_code_right[1]);
mapping[button::rs_down] = ::narrow<u32>(device->axis_code_right[2]); mapping[button::rs_down] = narrow_set(device->axis_code_right[2]);
mapping[button::rs_up] = ::narrow<u32>(device->axis_code_right[3]); mapping[button::rs_up] = narrow_set(device->axis_code_right[3]);
mapping[button::ps] = FindKeyCode(button_list, cfg->ps); 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; return mapping;
} }
@ -655,7 +573,7 @@ void PadHandlerBase::get_mapping(const pad_ensemble& binding)
if (!device || !pad) if (!device || !pad)
return; return;
const auto cfg = device->config; const cfg_pad* cfg = device->config;
auto button_values = get_button_values(device); 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()); 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 // 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 bool pressed{};
Button tmp = btn; u16 value{};
tmp.m_value = button_values[btn.m_keyCode];
TranslateButtonPress(device, tmp.m_keyCode, tmp.m_pressed, tmp.m_value); for (u32 code : btn.m_key_codes)
{
bool press{};
u16 val = button_values[code];
TranslateButtonPress(device, code, press, val);
if (press)
{
// Modify pressure if necessary if the button was pressed // Modify pressure if necessary if the button was pressed
if (adjust_pressure && tmp.m_pressed) if (adjust_pressure)
{ {
tmp.m_value = pad->m_pressure_intensity; val = pad->m_pressure_intensity;
} }
btn = tmp; value = std::max(value, val);
pressed = true;
}
}
btn.m_value = value;
btn.m_pressed = pressed;
} }
// used to get the absolute value of an axis // 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) // 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++) 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 // m_key_codes_min are the mapped keys for left or down
const u32 key_min = pad->m_sticks[i].m_keyCodeMin; for (u32 key_min : pad->m_sticks[i].m_key_codes_min)
u16 val_min = button_values[key_min]; {
TranslateButtonPress(device, key_min, pressed, val_min, true); u16 val = button_values[key_min];
// m_keyCodeMax is the mapped key for right or up TranslateButtonPress(device, key_min, pressed, val, true);
const u32 key_max = pad->m_sticks[i].m_keyCodeMax;
u16 val_max = button_values[key_max]; if (pressed)
TranslateButtonPress(device, key_max, pressed, val_max, true); {
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 // cancel out opposing values and get the resulting difference
stick_val[i] = val_max - val_min; stick_val[i] = val_max - val_min;
@ -741,7 +689,7 @@ void PadHandlerBase::process()
if (!device || !pad) if (!device || !pad)
continue; continue;
const auto status = update_connection(device); const connection status = update_connection(device);
switch (status) switch (status)
{ {

View file

@ -8,10 +8,13 @@
#include <cmath> #include <cmath>
#include <functional> #include <functional>
#include <string> #include <string>
#include <set>
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <unordered_map> #include <unordered_map>
LOG_CHANNEL(input_log, "Input");
class PadDevice class PadDevice
{ {
public: public:
@ -20,10 +23,10 @@ public:
u8 player_id{0}; u8 player_id{0};
u8 large_motor{0}; u8 large_motor{0};
u8 small_motor{0}; u8 small_motor{0};
u64 trigger_code_left = 0; std::set<u64> trigger_code_left{};
u64 trigger_code_right = 0; std::set<u64> trigger_code_right{};
std::array<u64, 4> axis_code_left{}; std::array<std::set<u64>, 4> axis_code_left{};
std::array<u64, 4> axis_code_right{}; std::array<std::set<u64>, 4> axis_code_right{};
}; };
struct pad_ensemble struct pad_ensemble
@ -123,17 +126,76 @@ protected:
std::unordered_map<u32, std::string> button_list; std::unordered_map<u32, std::string> button_list;
std::vector<u32> blacklist; std::vector<u32> blacklist;
// Search an unordered map for a string value and return found keycode static std::set<u32> narrow_set(const std::set<u64>& src);
static int FindKeyCode(const std::unordered_map<u32, std::string>& map, const cfg::string& name, bool fallback = true);
// Search an unordered map for a string value and return found keycode // 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 // 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 for (const std::string& name : names)
static long FindKeyCodeByString(const std::unordered_map<u64, std::string>& map, const std::string& name, bool fallback = true); {
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 // Get new multiplied value based on the multiplier
static s32 MultipliedInput(s32 raw_value, s32 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 {}; } virtual pad_preview_values get_preview_values(const std::unordered_map<u64, u16>& /*data*/) { return {}; }
protected: 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); 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 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(); void init_configs();

View file

@ -6,6 +6,26 @@ LOG_CHANNEL(input_log, "Input");
extern std::string g_pad_profile_override; 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) 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); 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() {};
cfg_pad(node* owner, const std::string& name) : cfg::node(owner, name) {} 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_left{ this, "Left Stick Left", "" };
cfg::string ls_down{ this, "Left Stick Down", "" }; cfg::string ls_down{ this, "Left Stick Down", "" };
cfg::string ls_right{ this, "Left Stick Right", "" }; cfg::string ls_right{ this, "Left Stick Right", "" };

View file

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

View file

@ -113,9 +113,9 @@ bool evdev_joystick_handler::Init()
for (const auto& node : m_pos_axis_config.get_nodes()) 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 std::string& name = node->get_name();
const int code = libevdev_event_code_from_name(EV_ABS, name.c_str()); const int code = libevdev_event_code_from_name(EV_ABS, name.c_str());
if (code < 0) 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); evdev_log.error("Failed to read axis name from %s. [code = %d] [name = %s]", m_pos_axis_config.cfg_name, code, name);
@ -130,12 +130,14 @@ bool evdev_joystick_handler::Init()
std::string evdev_joystick_handler::get_device_name(const libevdev* dev) std::string evdev_joystick_handler::get_device_name(const libevdev* dev)
{ {
std::string name = libevdev_get_name(dev); std::string name;
const auto unique = libevdev_get_uniq(dev);
if (const char* raw_name = libevdev_get_name(dev))
name = raw_name;
if (name.empty()) if (name.empty())
{ {
if (unique) if (const char* unique = libevdev_get_uniq(dev))
name = unique; name = unique;
if (name.empty()) if (name.empty())
@ -151,7 +153,7 @@ bool evdev_joystick_handler::update_device(const std::shared_ptr<PadDevice>& dev
if (!evdev_device) if (!evdev_device)
return false; return false;
const auto& path = evdev_device->path; const std::string& path = evdev_device->path;
libevdev*& dev = evdev_device->device; libevdev*& dev = evdev_device->device;
const bool was_connected = dev != nullptr; 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.device.get()));
free_device(static_cast<EvdevDevice*>(binding.buddy_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())); 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())); 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) if (!device)
return button_values; return button_values;
auto& dev = device->device; libevdev* dev = device->device;
if (!Init()) if (!Init())
return button_values; return button_values;
for (const auto& entry : button_list) for (const auto& entry : button_list)
{ {
const auto code = entry.first; const u32 code = entry.first;
if (code == NO_BUTTON) if (code == NO_BUTTON)
continue; continue;
@ -251,7 +253,7 @@ std::unordered_map<u64, std::pair<u16, bool>> evdev_joystick_handler::GetButtonV
for (const auto& entry : axis_list) for (const auto& entry : axis_list)
{ {
const auto code = entry.first; const u32 code = entry.first;
int val = 0; int val = 0;
if (libevdev_fetch_event_value(dev, EV_ABS, code, &val) == 0) if (libevdev_fetch_event_value(dev, EV_ABS, code, &val) == 0)
@ -298,7 +300,7 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s
m_blacklist.clear(); m_blacklist.clear();
// Get our evdev device // Get our evdev device
auto device = get_evdev_device(padId); std::shared_ptr<EvdevDevice> device = get_evdev_device(padId);
if (!device || !device->device) if (!device || !device->device)
{ {
if (fail_callback) if (fail_callback)
@ -328,16 +330,36 @@ PadHandlerBase::connection evdev_joystick_handler::get_next_button_press(const s
auto data = GetButtonValues(device); 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 std::vector<std::string> names = cfg_pad::get_buttons(str);
const bool dir = key >= 0;
if (key < 0) u16 value{};
key = FindKeyCodeByString(axis_list, name, false);
if (key < 0) const auto set_value = [&value, &data](u32 code, bool dir)
key = FindKeyCodeByString(button_list, name); {
auto it = data.find(static_cast<u64>(key)); if (const auto it = data.find(static_cast<u64>(code)); it != data.cend() && dir == it->second.second)
return it != data.end() && dir == it->second.second ? it->second.first : 0; {
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{}; 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) 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 // 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 (!device || !update_device(device) || !device->device)
{ {
if (fail_callback) if (fail_callback)
@ -477,7 +499,7 @@ void evdev_joystick_handler::get_motion_sensors(const std::string& padId, const
return; return;
} }
auto& dev = device->device; libevdev* dev = device->device;
// Try to fetch all new events from the joystick. // Try to fetch all new events from the joystick.
bool is_dirty = false; 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*/) 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 // Get our evdev device
auto dev = get_evdev_device(padId); std::shared_ptr<EvdevDevice> dev = get_evdev_device(padId);
if (!dev) if (!dev)
{ {
evdev_log.error("evdev TestVibration: Device [%s] not found! [large_motor = %d] [small_motor = %d]", padId, large_motor, small_motor); 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()) 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); 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; 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) 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 min = libevdev_get_abs_minimum(dev, code);
const int max = libevdev_get_abs_maximum(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)); value = static_cast<u16>(std::abs(fvalue));
return code; 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)) 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", 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); 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)) 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 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", 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); 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) if (!m_dev || !pad)
return; return;
auto& dev = m_dev->device; libevdev* dev = m_dev->device;
if (!dev) if (!dev)
return; return;
@ -940,7 +964,7 @@ void evdev_joystick_handler::get_extended_info(const pad_ensemble& binding)
if (!pad || !device || !update_device(device)) if (!pad || !device || !update_device(device))
return; return;
auto& dev = device->device; libevdev* dev = device->device;
if (!dev) if (!dev)
return; 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) if (button_code == NO_BUTTON || value < 0)
return; return;
const auto cfg = m_dev->config; const cfg_pad* cfg = m_dev->config;
if (!cfg) if (!cfg)
return; return;
auto axis_orientations = m_dev->axis_orientations;
// Find out if special buttons are pressed (introduced by RPCS3). // Find out if special buttons are pressed (introduced by RPCS3).
// These buttons will have a delay of one cycle, but whatever. // 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()); 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 // Translate any corresponding keycodes to our normal DS3 buttons and triggers
for (int i = 0; i < static_cast<int>(pad->m_buttons.size()); i++) 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; continue;
// Be careful to handle mapped axis specially // Be careful to handle mapped axis specially
if (evt.type == EV_ABS) 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. // get axis direction for TranslateButtonPress and skip on error.
// maybe mimic on error, needs investigation. FindAxisDirection should ideally never return -1 anyway m_dev->cur_dir = evdev_button->dir;
const int direction = FindAxisDirection(axis_orientations, i);
m_dev->cur_dir = direction;
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; 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_value = 0;
button.m_pressed = 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 bool pressed{};
Button tmp = button; u16 val = static_cast<u16>(value);
tmp.m_value = 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 // 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) // 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_min = false;
bool pressed_max = false; bool pressed_max = false;
// m_keyCodeMin is the mapped key for left or down // m_key_codes_min are the mapped keys for left or down
if (pad->m_sticks[idx].m_keyCodeMin == button_code) if (const EvdevButton* evdev_button = find_evdev_button(pad->m_sticks[idx].m_key_codes_min))
{ {
bool is_direction_min = false; bool is_direction_min = false;
if (!m_is_button_or_trigger && evt.type == EV_ABS) if (!m_is_button_or_trigger && evt.type == EV_ABS)
{ {
const int index = pad->m_buttons.size() + (idx * 2) + 1; const int min_direction = evdev_button->dir;
const int min_direction = FindAxisDirection(axis_orientations, index);
// We need to set the current direction for TranslateButtonPress
m_dev->cur_dir = min_direction; m_dev->cur_dir = min_direction;
if (min_direction < 0) 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 else
is_direction_min = m_is_negative == (min_direction == 1); 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 // m_key_codes_max are the mapped keys for right or up
if (pad->m_sticks[idx].m_keyCodeMax == button_code) if (const EvdevButton* evdev_button = find_evdev_button(pad->m_sticks[idx].m_key_codes_max))
{ {
bool is_direction_max = false; bool is_direction_max = false;
if (!m_is_button_or_trigger && evt.type == EV_ABS) if (!m_is_button_or_trigger && evt.type == EV_ABS)
{ {
const int index = pad->m_buttons.size() + (idx * 2); const int max_direction = evdev_button->dir;
const int max_direction = FindAxisDirection(axis_orientations, index);
// We need to set the current direction for TranslateButtonPress
m_dev->cur_dir = max_direction; m_dev->cur_dir = max_direction;
if (max_direction < 0) 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 else
is_direction_max = m_is_negative == (max_direction == 1); 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) if (!evdev_device)
return; return;
auto cfg = device->config; cfg_pad* cfg = device->config;
if (!cfg) if (!cfg)
return; return;
@ -1165,16 +1203,6 @@ void evdev_joystick_handler::apply_pad_data(const pad_ensemble& binding)
SetRumble(evdev_device, force_large, force_small); 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) bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, u8 player_id)
{ {
if (!pad || player_id >= g_cfg_input.player.size()) 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) if (!cfg)
return false; return false;
std::unordered_map<int, bool> axis_orientations; // We need to register EvdevButtons due to their axis directions.
int i = 0; // increment to know the axis location const auto register_evdevbutton = [this](u32 code, bool is_axis, bool is_reverse) -> u32
auto evdevbutton = [&](const cfg::string& name)
{ {
EvdevButton button{ 0, -1, EV_ABS }; const u32 index = ::narrow<u32>(m_dev->all_buttons.size());
int key = FindKeyCode(axis_list, name, false); if (is_axis)
if (key >= 0)
axis_orientations.emplace(i, false);
if (key < 0)
{ {
key = FindKeyCode(rev_axis_list, name, false); m_dev->all_buttons.push_back(EvdevButton{ code, is_reverse ? 1 : 0, EV_ABS });
if (key >= 0)
axis_orientations.emplace(i, true);
}
if (key < 0)
{
key = FindKeyCode(button_list, name);
button.type = EV_KEY;
} }
else 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++; const auto find_buttons = [&](const cfg::string& name) -> std::set<u32>
return button; {
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 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.type = EV_ABS;
e_sensor.mirrored = sensor.mirrored.get(); e_sensor.mirrored = sensor.mirrored.get();
e_sensor.shift = sensor.shift.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; return e_sensor;
}; };
u32 pclass_profile = 0x0; 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) 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 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_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,find_buttons(cfg->triangle), 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,find_buttons(cfg->circle), 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,find_buttons(cfg->cross), 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->square), CELL_PAD_CTRL_SQUARE);
m_dev->trigger_left = evdevbutton(cfg->l2); m_dev->trigger_left = find_buttons(cfg->l2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev->trigger_left.code, CELL_PAD_CTRL_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); m_dev->trigger_right = find_buttons(cfg->r2);
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev->trigger_right.code, CELL_PAD_CTRL_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, find_buttons(cfg->l1), 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_DIGITAL2, find_buttons(cfg->r1), 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, find_buttons(cfg->start), 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, find_buttons(cfg->select), 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, find_buttons(cfg->l3), 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, find_buttons(cfg->r3), 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, find_buttons(cfg->ps), 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, find_buttons(cfg->up), 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, find_buttons(cfg->down), 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, find_buttons(cfg->left), 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_DIGITAL1, find_buttons(cfg->right), CELL_PAD_CTRL_RIGHT);
m_dev->axis_left[0] = evdevbutton(cfg->ls_right); m_dev->axis_left[0] = find_buttons(cfg->ls_right);
m_dev->axis_left[1] = evdevbutton(cfg->ls_left); m_dev->axis_left[1] = find_buttons(cfg->ls_left);
m_dev->axis_left[2] = evdevbutton(cfg->ls_up); m_dev->axis_left[2] = find_buttons(cfg->ls_up);
m_dev->axis_left[3] = evdevbutton(cfg->ls_down); m_dev->axis_left[3] = find_buttons(cfg->ls_down);
m_dev->axis_right[0] = evdevbutton(cfg->rs_right); m_dev->axis_right[0] = find_buttons(cfg->rs_right);
m_dev->axis_right[1] = evdevbutton(cfg->rs_left); m_dev->axis_right[1] = find_buttons(cfg->rs_left);
m_dev->axis_right[2] = evdevbutton(cfg->rs_up); m_dev->axis_right[2] = find_buttons(cfg->rs_up);
m_dev->axis_right[3] = evdevbutton(cfg->rs_down); 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_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].code, m_dev->axis_left[2].code); 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].code, m_dev->axis_right[0].code); 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].code, m_dev->axis_right[2].code); 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[0] = find_motion_button(cfg->motion_sensor_x);
m_dev->axis_motion[1] = find_motion_button(cfg->motion_sensor_y); 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(true, 0);
pad->m_vibrateMotors.emplace_back(false, 0); pad->m_vibrateMotors.emplace_back(false, 0);
m_dev->axis_orientations = axis_orientations; if (std::shared_ptr<EvdevDevice> evdev_device = add_device(player_config->device, false))
if (auto 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); 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()); 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.device);
update_device(binding.buddy_device); update_device(binding.buddy_device);
@ -1343,34 +1378,46 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr<Pad> pad, u8 player
return true; 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;
}
} }
bool evdev_joystick_handler::check_buttons(const std::array<EvdevButton, 4>& b, const u32 code) return false;
}
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) 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) 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) 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) 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 #endif

View file

@ -341,9 +341,9 @@ class evdev_joystick_handler final : public PadHandlerBase
struct EvdevButton struct EvdevButton
{ {
u32 code = 0; u32 code = 0; // key code of our button or axis
int dir = 0; 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; int type = 0; // EV_KEY or EV_ABS
}; };
struct evdev_sensor : public EvdevButton struct evdev_sensor : public EvdevButton
@ -356,14 +356,14 @@ class evdev_joystick_handler final : public PadHandlerBase
{ {
libevdev* device{ nullptr }; libevdev* device{ nullptr };
std::string path; 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<s32, 4> stick_val{};
std::array<u16, 4> val_min{}; std::array<u16, 4> val_min{};
std::array<u16, 4> val_max{}; std::array<u16, 4> val_max{};
EvdevButton trigger_left{}; std::vector<EvdevButton> all_buttons;
EvdevButton trigger_right{}; std::set<u32> trigger_left{};
std::array<EvdevButton, 4> axis_left{}; std::set<u32> trigger_right{};
std::array<EvdevButton, 4> axis_right{}; std::array<std::set<u32>, 4> axis_left{};
std::array<std::set<u32>, 4> axis_right{};
std::array<evdev_sensor, 4> axis_motion{}; std::array<evdev_sensor, 4> axis_motion{};
int cur_dir = 0; int cur_dir = 0;
int cur_type = 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); std::unordered_map<u64, std::pair<u16, bool>> GetButtonValues(const std::shared_ptr<EvdevDevice>& device);
void SetRumble(EvdevDevice* device, u8 large, u8 small); 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; positive_axis m_pos_axis_config;
std::vector<u32> m_positive_axis; std::vector<u32> m_positive_axis;
std::vector<std::string> m_blacklist; 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_settings_added;
std::unordered_map<std::string, std::shared_ptr<evdev_joystick_handler::EvdevDevice>> m_motion_settings_added; std::unordered_map<std::string, std::shared_ptr<evdev_joystick_handler::EvdevDevice>> m_motion_settings_added;
std::shared_ptr<EvdevDevice> m_dev; std::shared_ptr<EvdevDevice> m_dev;
bool m_is_button_or_trigger; bool m_is_button_or_trigger{};
bool m_is_negative; bool m_is_negative{};
bool check_button(const EvdevButton& b, const u32 code); bool check_button_set(const std::set<u32>& indices, const u32 code);
bool check_buttons(const std::array<EvdevButton, 4>& b, 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); void handle_input_event(const input_event& evt, const std::shared_ptr<Pad>& pad);

View file

@ -6,8 +6,6 @@
#include <QApplication> #include <QApplication>
LOG_CHANNEL(input_log, "Input");
inline std::string sstr(const QString& _in) { return _in.toStdString(); } inline std::string sstr(const QString& _in) { return _in.toStdString(); }
constexpr auto qstr = QString::fromStdString; 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]; 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_pressed = pressed;
pressure_intensity_button.m_value = value; pressure_intensity_button.m_value = value;
@ -97,9 +95,31 @@ void keyboard_pad_handler::Key(const u32 code, bool pressed, u16 value)
// Handle buttons // Handle buttons
for (Button& button : pad.m_buttons) for (Button& button : pad.m_buttons)
{ {
if (button.m_keyCode != code) if (!button.m_key_codes.contains(code))
continue; 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; button.m_actual_value = pressed ? value : 0;
bool update_button = true; bool update_button = true;
@ -133,8 +153,8 @@ void keyboard_pad_handler::Key(const u32 code, bool pressed, u16 value)
// Handle sticks // Handle sticks
for (usz i = 0; i < pad.m_sticks.size(); i++) for (usz i = 0; i < pad.m_sticks.size(); i++)
{ {
const bool is_max = pad.m_sticks[i].m_keyCodeMax == code; const bool is_max = pad.m_sticks[i].m_key_codes_max.contains(code);
const bool is_min = pad.m_sticks[i].m_keyCodeMin == code; const bool is_min = pad.m_sticks[i].m_key_codes_min.contains(code);
if (!is_max && !is_min) 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)); 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) u32 keyboard_pad_handler::GetKeyCode(const QString& keyName)
@ -731,7 +759,7 @@ u32 keyboard_pad_handler::GetKeyCode(const QString& keyName)
#endif #endif
const QKeySequence seq(keyName); const QKeySequence seq(keyName);
u32 key_code = 0; u32 key_code = Qt::NoButton;
if (seq.count() == 1) if (seq.count() == 1)
key_code = seq[0]; 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_r_stick_multiplier = cfg->rstickmultiplier;
m_pressure_intensity_toggle_mode = cfg->pressure_intensity_toggle_mode.get(); 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)
{
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)))
{ {
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; 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)) }
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; m_mouse_wheel_used = true;
return key; }
}
return keys;
}; };
u32 pclass_profile = 0x0; u32 pclass_profile = 0x0;
@ -849,31 +884,31 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr<Pad> pad, u8 player_i
cfg->pressure_intensity 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_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_keys(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_keys(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_keys(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_keys(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_keys(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_keys(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_keys(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_keys(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_DIGITAL1, find_keys(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_keys(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_keys(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_keys(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_keys(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_keys(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_keys(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_keys(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_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_X, find_keys(cfg->ls_left), find_keys(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_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_key(cfg->rs_left), find_key(cfg->rs_right)); 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_key(cfg->rs_up), find_key(cfg->rs_down)); 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_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_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() void keyboard_pad_handler::process()
{ {
static const double stick_interval = 10.0; constexpr double stick_interval = 10.0;
static const double button_interval = 10.0; constexpr double button_interval = 10.0;
const auto now = steady_clock::now(); 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) 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_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; 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) if (update_buttons)
{ {
for (auto& button : pad.m_buttons) for (Button& button : pad.m_buttons)
{ {
if (button.m_analog) if (button.m_analog)
{ {

View file

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

View file

@ -2,8 +2,6 @@
#include "mm_joystick_handler.h" #include "mm_joystick_handler.h"
#include "Emu/Io/pad_config.h" #include "Emu/Io/pad_config.h"
LOG_CHANNEL(input_log, "Input");
mm_joystick_handler::mm_joystick_handler() : PadHandlerBase(pad_handler::mm) mm_joystick_handler::mm_joystick_handler() : PadHandlerBase(pad_handler::mm)
{ {
init_configs(); init_configs();
@ -113,62 +111,70 @@ std::vector<pad_list_entry> mm_joystick_handler::list_devices()
return 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); return find_keys<T>(cfg_pad::get_buttons(cfg_string));
if (key < 0)
key = FindKeyCodeByString(pov_list, name, false);
if (key < 0)
key = FindKeyCodeByString(button_list, name);
return static_cast<u64>(key);
} }
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()); MMJOYDevice* joy_device = static_cast<MMJOYDevice*>(device.get());
if (!joy_device || !cfg) if (!joy_device || !cfg)
return mapping; return mapping;
joy_device->trigger_code_left = find_key(cfg->l2); joy_device->trigger_code_left = find_keys<u64>(cfg->l2);
joy_device->trigger_code_right = find_key(cfg->r2); joy_device->trigger_code_right = find_keys<u64>(cfg->r2);
joy_device->axis_code_left[0] = find_key(cfg->ls_left); joy_device->axis_code_left[0] = find_keys<u64>(cfg->ls_left);
joy_device->axis_code_left[1] = find_key(cfg->ls_right); joy_device->axis_code_left[1] = find_keys<u64>(cfg->ls_right);
joy_device->axis_code_left[2] = find_key(cfg->ls_down); joy_device->axis_code_left[2] = find_keys<u64>(cfg->ls_down);
joy_device->axis_code_left[3] = find_key(cfg->ls_up); joy_device->axis_code_left[3] = find_keys<u64>(cfg->ls_up);
joy_device->axis_code_right[0] = find_key(cfg->rs_left); joy_device->axis_code_right[0] = find_keys<u64>(cfg->rs_left);
joy_device->axis_code_right[1] = find_key(cfg->rs_right); joy_device->axis_code_right[1] = find_keys<u64>(cfg->rs_right);
joy_device->axis_code_right[2] = find_key(cfg->rs_down); joy_device->axis_code_right[2] = find_keys<u64>(cfg->rs_down);
joy_device->axis_code_right[3] = find_key(cfg->rs_up); joy_device->axis_code_right[3] = find_keys<u64>(cfg->rs_up);
mapping[button::up] = static_cast<u32>(find_key(cfg->up)); mapping[button::up] = find_keys<u32>(cfg->up);
mapping[button::down] = static_cast<u32>(find_key(cfg->down)); mapping[button::down] = find_keys<u32>(cfg->down);
mapping[button::left] = static_cast<u32>(find_key(cfg->left)); mapping[button::left] = find_keys<u32>(cfg->left);
mapping[button::right] = static_cast<u32>(find_key(cfg->right)); mapping[button::right] = find_keys<u32>(cfg->right);
mapping[button::cross] = static_cast<u32>(find_key(cfg->cross)); mapping[button::cross] = find_keys<u32>(cfg->cross);
mapping[button::square] = static_cast<u32>(find_key(cfg->square)); mapping[button::square] = find_keys<u32>(cfg->square);
mapping[button::circle] = static_cast<u32>(find_key(cfg->circle)); mapping[button::circle] = find_keys<u32>(cfg->circle);
mapping[button::triangle] = static_cast<u32>(find_key(cfg->triangle)); mapping[button::triangle] = find_keys<u32>(cfg->triangle);
mapping[button::l1] = static_cast<u32>(find_key(cfg->l1)); mapping[button::l1] = find_keys<u32>(cfg->l1);
mapping[button::l2] = static_cast<u32>(joy_device->trigger_code_left); mapping[button::l2] = narrow_set(joy_device->trigger_code_left);
mapping[button::l3] = static_cast<u32>(find_key(cfg->l3)); mapping[button::l3] = find_keys<u32>(cfg->l3);
mapping[button::r1] = static_cast<u32>(find_key(cfg->r1)); mapping[button::r1] = find_keys<u32>(cfg->r1);
mapping[button::r2] = static_cast<u32>(joy_device->trigger_code_right); mapping[button::r2] = narrow_set(joy_device->trigger_code_right);
mapping[button::r3] = static_cast<u32>(find_key(cfg->r3)); mapping[button::r3] = find_keys<u32>(cfg->r3);
mapping[button::start] = static_cast<u32>(find_key(cfg->start)); mapping[button::start] = find_keys<u32>(cfg->start);
mapping[button::select] = static_cast<u32>(find_key(cfg->select)); mapping[button::select] = find_keys<u32>(cfg->select);
mapping[button::ps] = static_cast<u32>(find_key(cfg->ps)); mapping[button::ps] = find_keys<u32>(cfg->ps);
mapping[button::ls_left] = static_cast<u32>(joy_device->axis_code_left[0]); mapping[button::ls_left] = narrow_set(joy_device->axis_code_left[0]);
mapping[button::ls_right] = static_cast<u32>(joy_device->axis_code_left[1]); mapping[button::ls_right] = narrow_set(joy_device->axis_code_left[1]);
mapping[button::ls_down] = static_cast<u32>(joy_device->axis_code_left[2]); mapping[button::ls_down] = narrow_set(joy_device->axis_code_left[2]);
mapping[button::ls_up] = static_cast<u32>(joy_device->axis_code_left[3]); mapping[button::ls_up] = narrow_set(joy_device->axis_code_left[3]);
mapping[button::rs_left] = static_cast<u32>(joy_device->axis_code_right[0]); mapping[button::rs_left] = narrow_set(joy_device->axis_code_right[0]);
mapping[button::rs_right] = static_cast<u32>(joy_device->axis_code_right[1]); mapping[button::rs_right] = narrow_set(joy_device->axis_code_right[1]);
mapping[button::rs_down] = static_cast<u32>(joy_device->axis_code_right[2]); mapping[button::rs_down] = narrow_set(joy_device->axis_code_right[2]);
mapping[button::rs_up] = static_cast<u32>(joy_device->axis_code_right[3]); 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; return mapping;
} }
@ -230,9 +236,8 @@ PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std:
std::string name; std::string name;
} pressed_button{}; } pressed_button{};
for (const auto& button : axis_list) for (const auto& [keycode, name] : axis_list)
{ {
u64 keycode = button.first;
u16 value = data[keycode]; u16 value = data[keycode];
if (!get_blacklist && std::find(m_blacklist.cbegin(), m_blacklist.cend(), keycode) != m_blacklist.cend()) 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) if (get_blacklist)
{ {
m_blacklist.emplace_back(keycode); m_blacklist.push_back(keycode);
input_log.error("MMJOY Calibration: Added axis [ %d = %s ] to blacklist. Value = %d", keycode, button.second, value); input_log.error("MMJOY Calibration: Added axis [ %d = %s ] to blacklist. Value = %d", keycode, name, value);
} }
else if (value > pressed_button.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; const u16 value = data[keycode];
u16 value = data[keycode];
if (!get_blacklist && std::find(m_blacklist.cbegin(), m_blacklist.cend(), keycode) != m_blacklist.cend()) if (!get_blacklist && std::find(m_blacklist.cbegin(), m_blacklist.cend(), keycode) != m_blacklist.cend())
continue; continue;
@ -264,20 +268,18 @@ PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std:
{ {
if (get_blacklist) if (get_blacklist)
{ {
m_blacklist.emplace_back(keycode); m_blacklist.push_back(keycode);
input_log.error("MMJOY Calibration: Added pov [ %d = %s ] to blacklist. Value = %d", keycode, button.second, value); input_log.error("MMJOY Calibration: Added pov [ %d = %s ] to blacklist. Value = %d", keycode, name, value);
} }
else if (value > pressed_button.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) if (keycode == NO_BUTTON)
continue; continue;
@ -290,12 +292,12 @@ PadHandlerBase::connection mm_joystick_handler::get_next_button_press(const std:
{ {
if (get_blacklist) if (get_blacklist)
{ {
m_blacklist.emplace_back(keycode); m_blacklist.push_back(keycode);
input_log.error("MMJOY Calibration: Added button [ %d = %s ] to blacklist. Value = %d", keycode, button.second, value); input_log.error("MMJOY Calibration: Added button [ %d = %s ] to blacklist. Value = %d", keycode, name, value);
} }
else if (value > pressed_button.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{}; pad_preview_values preview_values{};
if (buttons.size() == 10) if (buttons.size() == 10)
{ {
preview_values[0] = data[find_key(buttons[0])]; const auto get_key_value = [this, &data](const std::string& str) -> u16
preview_values[1] = data[find_key(buttons[1])]; {
preview_values[2] = data[find_key(buttons[3])] - data[find_key(buttons[2])]; u16 value{};
preview_values[3] = data[find_key(buttons[5])] - data[find_key(buttons[4])]; for (u32 key_code : find_keys<u32>(cfg_pad::get_buttons(str)))
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])]; 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) 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) bool mm_joystick_handler::get_is_left_trigger(const std::shared_ptr<PadDevice>& device, u64 keyCode)
{ {
const MMJOYDevice* dev = static_cast<MMJOYDevice*>(device.get()); 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) bool mm_joystick_handler::get_is_right_trigger(const std::shared_ptr<PadDevice>& device, u64 keyCode)
{ {
const MMJOYDevice* dev = static_cast<MMJOYDevice*>(device.get()); 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) bool mm_joystick_handler::get_is_left_stick(const std::shared_ptr<PadDevice>& device, u64 keyCode)
{ {
const MMJOYDevice* dev = static_cast<MMJOYDevice*>(device.get()); 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) bool mm_joystick_handler::get_is_right_stick(const std::shared_ptr<PadDevice>& device, u64 keyCode)
{ {
const MMJOYDevice* dev = static_cast<MMJOYDevice*>(device.get()); 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) 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::vector<u64> m_blacklist;
std::unordered_map<int, MMJOYDevice> m_devices; 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; 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_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; 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 "Utilities/Thread.h"
#include "util/atomic.hpp" #include "util/atomic.hpp"
LOG_CHANNEL(input_log, "Input");
LOG_CHANNEL(sys_log, "SYS"); LOG_CHANNEL(sys_log, "SYS");
extern bool is_input_allowed(); extern bool is_input_allowed();

View file

@ -53,6 +53,15 @@ inline bool CreateConfigFile(const QString& dir, const QString& name)
return true; 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) pad_settings_dialog::pad_settings_dialog(std::shared_ptr<gui_settings> gui_settings, QWidget *parent, const GameInfo *game)
: QDialog(parent) : QDialog(parent)
, ui(new Ui::pad_settings_dialog) , 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_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) if (--m_seconds <= 0)
{ {
@ -414,7 +423,7 @@ void pad_settings_dialog::InitButtons()
{ {
SwitchPadInfo(pad_name, true); SwitchPadInfo(pad_name, true);
if (!m_enable_buttons && !m_timer.isActive()) if (!m_enable_buttons && !m_remap_timer.isActive())
{ {
SwitchButtons(true); 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) 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].insert_key(name);
m_cfg_entries[m_button_id].text = qstr(name);
ReactivateButtons(); ReactivateButtons();
} }
}; };
@ -536,10 +544,10 @@ void pad_settings_dialog::InitButtons()
const std::vector<std::string> buttons = 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_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].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_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].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_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].key m_cfg_entries[button_ids::id_pad_rstick_up].keys
}; };
const PadHandlerBase::connection status = m_handler->get_next_button_press(m_device_name, 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)); 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(); ReactivateButtons();
} }
@ -699,7 +707,7 @@ void pad_settings_dialog::ReloadButtons()
void pad_settings_dialog::ReactivateButtons() void pad_settings_dialog::ReactivateButtons()
{ {
m_timer.stop(); m_remap_timer.stop();
m_seconds = MAX_SECONDS; m_seconds = MAX_SECONDS;
if (m_button_id == button_ids::id_pad_begin) if (m_button_id == button_ids::id_pad_begin)
@ -844,8 +852,7 @@ void pad_settings_dialog::keyPressEvent(QKeyEvent *keyEvent)
} }
else else
{ {
m_cfg_entries[m_button_id].key = keyboard_pad_handler::GetKeyName(keyEvent); m_cfg_entries[m_button_id].insert_key(keyboard_pad_handler::GetKeyName(keyEvent));
m_cfg_entries[m_button_id].text = qstr(m_cfg_entries[m_button_id].key);
} }
ReactivateButtons(); ReactivateButtons();
@ -872,8 +879,7 @@ void pad_settings_dialog::mouseReleaseEvent(QMouseEvent* event)
} }
else else
{ {
m_cfg_entries[m_button_id].key = (static_cast<keyboard_pad_handler*>(m_handler.get()))->GetMouseName(event); m_cfg_entries[m_button_id].insert_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);
} }
ReactivateButtons(); ReactivateButtons();
@ -934,8 +940,8 @@ void pad_settings_dialog::wheelEvent(QWheelEvent *event)
key = mouse::wheel_down; 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(); ReactivateButtons();
} }
@ -985,8 +991,7 @@ void pad_settings_dialog::mouseMoveEvent(QMouseEvent* event)
if (key != 0) 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].insert_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);
ReactivateButtons(); 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)) if (const int button_id = m_pad_buttons->id(button); m_cfg_entries.contains(button_id))
{ {
m_cfg_entries[button_id].key.clear(); pad_button& button = m_cfg_entries[button_id];
m_cfg_entries[button_id].text.clear(); button.keys.clear();
button.text.clear();
UpdateLabels(); UpdateLabels();
return true; return true;
@ -1172,16 +1178,16 @@ void pad_settings_dialog::UpdateLabels(bool is_reset)
ui->gb_battery->setVisible(m_enable_battery || m_enable_led); 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) if (is_reset)
{ {
entry.second.key = *entry.second.cfg_text; button.keys = *button.cfg_text;
entry.second.text = qstr(entry.second.key); button.text = qstr(button.keys);
} }
// The button has to contain at least one character, because it would be square'ish otherwise // 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)->setPalette(QPalette(Qt::blue));
m_pad_buttons->button(m_button_id)->grabMouse(); m_pad_buttons->button(m_button_id)->grabMouse();
SwitchButtons(false); // disable all buttons, needed for using Space, Enter and other specific buttons 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) void pad_settings_dialog::OnTabChanged(int index)
@ -1487,7 +1493,7 @@ void pad_settings_dialog::ChangeHandler()
} }
// Handle running timers // Handle running timers
if (m_timer.isActive()) if (m_remap_timer.isActive())
{ {
ReactivateButtons(); ReactivateButtons();
} }
@ -1717,7 +1723,7 @@ void pad_settings_dialog::ApplyCurrentPlayerConfig(int new_player_id)
return; 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]; auto& player = g_cfg_input.player[m_last_player_id];
m_last_player_id = new_player_id; m_last_player_id = new_player_id;
@ -1726,24 +1732,27 @@ void pad_settings_dialog::ApplyCurrentPlayerConfig(int new_player_id)
if (m_handler->m_type != pad_handler::null) if (m_handler->m_type != pad_handler::null)
{ {
std::set<std::string> unique_keys; 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 // 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; 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; if (const auto& [it, ok] = unique_keys.insert(key); !ok)
{
m_duplicate_buttons[m_last_player_id] = key;
break; break;
} }
} }
} }
}
// Apply buttons // Apply buttons
for (const auto& entry : m_cfg_entries) 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 // Apply rest of config

View file

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