mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-08-19 06:52:36 +00:00
add left/right joystick remapping
This commit is contained in:
@@ -18,35 +18,57 @@ namespace Libs::Graphics {
|
||||
|
||||
namespace {
|
||||
|
||||
struct ControlInfo {
|
||||
std::string_view name;
|
||||
uint32_t button = 0;
|
||||
Controller::Axis axis = Controller::Axis::AxisMax;
|
||||
bool positive = false;
|
||||
};
|
||||
|
||||
static constexpr std::array CONTROL_INFO = {
|
||||
ControlInfo {"L3", Controller::PAD_BUTTON_L3},
|
||||
ControlInfo {"R3", Controller::PAD_BUTTON_R3},
|
||||
ControlInfo {"Options", Controller::PAD_BUTTON_OPTIONS},
|
||||
ControlInfo {"Up", Controller::PAD_BUTTON_UP},
|
||||
ControlInfo {"Right", Controller::PAD_BUTTON_RIGHT},
|
||||
ControlInfo {"Down", Controller::PAD_BUTTON_DOWN},
|
||||
ControlInfo {"Left", Controller::PAD_BUTTON_LEFT},
|
||||
ControlInfo {"L2", Controller::PAD_BUTTON_L2},
|
||||
ControlInfo {"R2", Controller::PAD_BUTTON_R2},
|
||||
ControlInfo {"L1", Controller::PAD_BUTTON_L1},
|
||||
ControlInfo {"R1", Controller::PAD_BUTTON_R1},
|
||||
ControlInfo {"Triangle", Controller::PAD_BUTTON_TRIANGLE},
|
||||
ControlInfo {"Circle", Controller::PAD_BUTTON_CIRCLE},
|
||||
ControlInfo {"Cross", Controller::PAD_BUTTON_CROSS},
|
||||
ControlInfo {"Square", Controller::PAD_BUTTON_SQUARE},
|
||||
ControlInfo {"TouchPad", Controller::PAD_BUTTON_TOUCH_PAD},
|
||||
ControlInfo {"LeftStickLeft", 0, Controller::Axis::LeftX, false},
|
||||
ControlInfo {"LeftStickRight", 0, Controller::Axis::LeftX, true},
|
||||
ControlInfo {"LeftStickUp", 0, Controller::Axis::LeftY, false},
|
||||
ControlInfo {"LeftStickDown", 0, Controller::Axis::LeftY, true},
|
||||
ControlInfo {"RightStickLeft", 0, Controller::Axis::RightX, false},
|
||||
ControlInfo {"RightStickRight", 0, Controller::Axis::RightX, true},
|
||||
ControlInfo {"RightStickUp", 0, Controller::Axis::RightY, false},
|
||||
ControlInfo {"RightStickDown", 0, Controller::Axis::RightY, true},
|
||||
};
|
||||
|
||||
constexpr std::size_t INVALID_CONTROL = CONTROL_INFO.size();
|
||||
|
||||
struct Binding {
|
||||
SDL_Keycode key = SDLK_UNKNOWN;
|
||||
uint8_t mouse_button = 0;
|
||||
uint32_t pad_button = 0;
|
||||
std::size_t control = INVALID_CONTROL;
|
||||
};
|
||||
|
||||
static constexpr std::array PAD_BUTTONS = {
|
||||
std::pair {std::string_view("L3"), Controller::PAD_BUTTON_L3},
|
||||
std::pair {std::string_view("R3"), Controller::PAD_BUTTON_R3},
|
||||
std::pair {std::string_view("Options"), Controller::PAD_BUTTON_OPTIONS},
|
||||
std::pair {std::string_view("Up"), Controller::PAD_BUTTON_UP},
|
||||
std::pair {std::string_view("Right"), Controller::PAD_BUTTON_RIGHT},
|
||||
std::pair {std::string_view("Down"), Controller::PAD_BUTTON_DOWN},
|
||||
std::pair {std::string_view("Left"), Controller::PAD_BUTTON_LEFT},
|
||||
std::pair {std::string_view("L2"), Controller::PAD_BUTTON_L2},
|
||||
std::pair {std::string_view("R2"), Controller::PAD_BUTTON_R2},
|
||||
std::pair {std::string_view("L1"), Controller::PAD_BUTTON_L1},
|
||||
std::pair {std::string_view("R1"), Controller::PAD_BUTTON_R1},
|
||||
std::pair {std::string_view("Triangle"), Controller::PAD_BUTTON_TRIANGLE},
|
||||
std::pair {std::string_view("Circle"), Controller::PAD_BUTTON_CIRCLE},
|
||||
std::pair {std::string_view("Cross"), Controller::PAD_BUTTON_CROSS},
|
||||
std::pair {std::string_view("Square"), Controller::PAD_BUTTON_SQUARE},
|
||||
std::pair {std::string_view("TouchPad"), Controller::PAD_BUTTON_TOUCH_PAD},
|
||||
};
|
||||
std::size_t ControlFromName(std::string_view name) {
|
||||
const auto info = std::find_if(CONTROL_INFO.begin(), CONTROL_INFO.end(),
|
||||
[name](const auto& item) { return item.name == name; });
|
||||
return static_cast<std::size_t>(std::distance(CONTROL_INFO.begin(), info));
|
||||
}
|
||||
|
||||
uint32_t PadButtonFromName(std::string_view name) {
|
||||
const auto button = std::find_if(PAD_BUTTONS.begin(), PAD_BUTTONS.end(),
|
||||
[name](const auto& item) { return item.first == name; });
|
||||
return button != PAD_BUTTONS.end() ? button->second : 0;
|
||||
const ControlInfo& Info(std::size_t control) {
|
||||
EXIT_IF(control >= CONTROL_INFO.size());
|
||||
return CONTROL_INFO[control];
|
||||
}
|
||||
|
||||
SDL_Keycode NormalizeKey(SDL_Keycode key) {
|
||||
@@ -74,7 +96,7 @@ uint8_t MouseButtonFromName(std::string_view name) {
|
||||
}
|
||||
|
||||
bool Conflicts(const Binding& first, const Binding& second) {
|
||||
return first.pad_button == second.pad_button ||
|
||||
return first.control == second.control ||
|
||||
(first.key != SDLK_UNKNOWN && first.key == second.key) ||
|
||||
(first.mouse_button != 0 && first.mouse_button == second.mouse_button);
|
||||
}
|
||||
@@ -88,7 +110,7 @@ public:
|
||||
|
||||
Binding binding;
|
||||
if (split != std::string_view::npos) {
|
||||
binding.pad_button = PadButtonFromName(entry.substr(0, split));
|
||||
binding.control = ControlFromName(entry.substr(0, split));
|
||||
const auto host_input = entry.substr(split + 1);
|
||||
binding.mouse_button = MouseButtonFromName(host_input);
|
||||
if (binding.mouse_button == 0) {
|
||||
@@ -98,7 +120,7 @@ public:
|
||||
|
||||
const bool reserved =
|
||||
binding.key == SDLK_ESCAPE || binding.key == SDLK_SPACE || binding.key == SDLK_F1;
|
||||
if (binding.pad_button == 0 || reserved ||
|
||||
if (binding.control == INVALID_CONTROL || reserved ||
|
||||
(binding.key == SDLK_UNKNOWN && binding.mouse_button == 0)) {
|
||||
EXIT("Invalid input mapping: %s\n", value.c_str());
|
||||
}
|
||||
@@ -107,19 +129,19 @@ public:
|
||||
}
|
||||
[[nodiscard]] bool Custom() const { return m_custom; }
|
||||
|
||||
[[nodiscard]] uint32_t FindKey(int key_code) const {
|
||||
[[nodiscard]] std::size_t FindKey(int key_code) const {
|
||||
key_code = NormalizeKey(static_cast<SDL_Keycode>(key_code));
|
||||
const auto binding =
|
||||
std::find_if(m_bindings.begin(), m_bindings.begin() + m_size,
|
||||
[key_code](const auto& item) { return item.key == key_code; });
|
||||
return binding != m_bindings.begin() + m_size ? binding->pad_button : 0;
|
||||
return binding != m_bindings.begin() + m_size ? binding->control : INVALID_CONTROL;
|
||||
}
|
||||
|
||||
[[nodiscard]] uint32_t FindMouseButton(uint8_t mouse_button) const {
|
||||
[[nodiscard]] std::size_t FindMouseButton(uint8_t mouse_button) const {
|
||||
const auto binding = std::find_if(
|
||||
m_bindings.begin(), m_bindings.begin() + m_size,
|
||||
[mouse_button](const auto& item) { return item.mouse_button == mouse_button; });
|
||||
return binding != m_bindings.begin() + m_size ? binding->pad_button : 0;
|
||||
return binding != m_bindings.begin() + m_size ? binding->control : INVALID_CONTROL;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -135,9 +157,9 @@ private:
|
||||
m_bindings[m_size++] = binding;
|
||||
}
|
||||
|
||||
std::array<Binding, PAD_BUTTONS.size()> m_bindings {};
|
||||
std::size_t m_size = 0;
|
||||
bool m_custom;
|
||||
std::array<Binding, CONTROL_INFO.size()> m_bindings {};
|
||||
std::size_t m_size = 0;
|
||||
bool m_custom;
|
||||
};
|
||||
|
||||
const InputMap& GetInputMap() {
|
||||
@@ -191,6 +213,33 @@ void SetStickAxis(Controller::Axis axis, bool negative, bool positive) {
|
||||
Controller::ControllerAxis(Controller::HOST_INPUT_CONTROLLER_ID, axis, value);
|
||||
}
|
||||
|
||||
void SetControl(std::size_t control, bool down) {
|
||||
if (control == INVALID_CONTROL) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& info = Info(control);
|
||||
if (info.button != 0) {
|
||||
SetButton(info.button, down);
|
||||
return;
|
||||
}
|
||||
|
||||
struct AxisKeys {
|
||||
bool negative = false;
|
||||
bool positive = false;
|
||||
};
|
||||
static std::array<AxisKeys, 4> axes;
|
||||
|
||||
const auto axis = static_cast<std::size_t>(info.axis);
|
||||
EXIT_IF(axis >= axes.size());
|
||||
if (info.positive) {
|
||||
axes[axis].positive = down;
|
||||
} else {
|
||||
axes[axis].negative = down;
|
||||
}
|
||||
SetStickAxis(info.axis, axes[axis].negative, axes[axis].positive);
|
||||
}
|
||||
|
||||
void DefaultKeyboardInput(int key_code, bool down) {
|
||||
static StickKeys left;
|
||||
static StickKeys right;
|
||||
@@ -240,7 +289,7 @@ void HostInputInit() {
|
||||
void HostInputKey(int key_code, bool down) {
|
||||
const auto& map = GetInputMap();
|
||||
if (map.Custom()) {
|
||||
SetButton(map.FindKey(key_code), down);
|
||||
SetControl(map.FindKey(key_code), down);
|
||||
} else {
|
||||
DefaultKeyboardInput(key_code, down);
|
||||
}
|
||||
@@ -249,7 +298,7 @@ void HostInputKey(int key_code, bool down) {
|
||||
void HostInputMouseButton(uint8_t mouse_button, bool down) {
|
||||
const auto& map = GetInputMap();
|
||||
if (map.Custom() && mouse_button != 0) {
|
||||
SetButton(map.FindMouseButton(mouse_button), down);
|
||||
SetControl(map.FindMouseButton(mouse_button), down);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,17 +18,25 @@ namespace {
|
||||
|
||||
constexpr int BINDING_COLUMN = 1;
|
||||
|
||||
struct PadButton {
|
||||
struct PadControl {
|
||||
const char* id;
|
||||
const char* label;
|
||||
const char* default_binding;
|
||||
};
|
||||
|
||||
constexpr PadButton PAD_BUTTONS[] = {
|
||||
constexpr PadControl PAD_CONTROLS[] = {
|
||||
{"Up", "D-pad Up", "Up"},
|
||||
{"Down", "D-pad Down", "Down"},
|
||||
{"Left", "D-pad Left", "Left"},
|
||||
{"Right", "D-pad Right", "Right"},
|
||||
{"LeftStickUp", "Left stick Up", "W"},
|
||||
{"LeftStickDown", "Left stick Down", "S"},
|
||||
{"LeftStickLeft", "Left stick Left", "A"},
|
||||
{"LeftStickRight", "Left stick Right", "D"},
|
||||
{"RightStickUp", "Right stick Up", "T"},
|
||||
{"RightStickDown", "Right stick Down", "G"},
|
||||
{"RightStickLeft", "Right stick Left", "F"},
|
||||
{"RightStickRight", "Right stick Right", "H"},
|
||||
{"Triangle", "Triangle", "I"},
|
||||
{"Circle", "Circle", "L"},
|
||||
{"Cross", "Cross", "J"},
|
||||
@@ -190,16 +198,14 @@ QHash<QString, QString> ParseMapping(const QStringList& mapping) {
|
||||
InputMappingDialog::InputMappingDialog(const QStringList& mapping, QWidget* parent)
|
||||
: QDialog(parent), m_customized(!mapping.isEmpty()) {
|
||||
setWindowTitle(tr("Input Mapping"));
|
||||
resize(440, 520);
|
||||
resize(460, 650);
|
||||
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
layout->addWidget(new QLabel(tr("Map keyboard or mouse input to DualSense buttons.\n"
|
||||
"Defaults: left stick W/A/S/D, right stick T/F/G/H."),
|
||||
this));
|
||||
layout->addWidget(new QLabel(tr("Map keyboard or mouse input to DualSense controls."), this));
|
||||
|
||||
m_bindings = new QTreeWidget(this);
|
||||
m_bindings->setColumnCount(2);
|
||||
m_bindings->setHeaderLabels({tr("DualSense button"), tr("Host input")});
|
||||
m_bindings->setHeaderLabels({tr("DualSense control"), tr("Host input")});
|
||||
m_bindings->setRootIsDecorated(false);
|
||||
m_bindings->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_bindings->header()->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||
@@ -207,12 +213,12 @@ InputMappingDialog::InputMappingDialog(const QStringList& mapping, QWidget* pare
|
||||
layout->addWidget(m_bindings);
|
||||
|
||||
const auto parsed = ParseMapping(mapping);
|
||||
for (const auto& button: PAD_BUTTONS) {
|
||||
for (const auto& control: PAD_CONTROLS) {
|
||||
auto* item = new QTreeWidgetItem(m_bindings);
|
||||
item->setText(0, tr(button.label));
|
||||
item->setData(0, Qt::UserRole, QString::fromLatin1(button.id));
|
||||
SetBinding(item, m_customized ? parsed.value(QString::fromLatin1(button.id))
|
||||
: QString::fromLatin1(button.default_binding));
|
||||
item->setText(0, tr(control.label));
|
||||
item->setData(0, Qt::UserRole, QString::fromLatin1(control.id));
|
||||
SetBinding(item, m_customized ? parsed.value(QString::fromLatin1(control.id))
|
||||
: QString::fromLatin1(control.default_binding));
|
||||
}
|
||||
m_bindings->setCurrentItem(m_bindings->topLevelItem(0));
|
||||
|
||||
@@ -286,7 +292,7 @@ void InputMappingDialog::ClearBinding() {
|
||||
void InputMappingDialog::RestoreDefaults() {
|
||||
for (int index = 0; index < m_bindings->topLevelItemCount(); index++) {
|
||||
SetBinding(m_bindings->topLevelItem(index),
|
||||
QString::fromLatin1(PAD_BUTTONS[index].default_binding));
|
||||
QString::fromLatin1(PAD_CONTROLS[index].default_binding));
|
||||
}
|
||||
m_customized = false;
|
||||
}
|
||||
|
||||
+1
-1
@@ -67,7 +67,7 @@ static void PrintUsage() {
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
::printf(" --redzone Protect the guest SysV red zone.\n");
|
||||
#endif
|
||||
::printf(" --keymap <Pad=Key> DualSense mapping; may be repeated.\n");
|
||||
::printf(" --keymap <Control=Input> DualSense mapping; may be repeated.\n");
|
||||
::printf(" --rd Enable RenderDoc capture.\n");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user