FullscreenUI: Use icon font for bindings

This commit is contained in:
Stenzek
2023-11-26 21:34:00 +10:00
parent 43c0ce0b3e
commit c1d0419361
17 changed files with 798 additions and 511 deletions

View File

@@ -398,9 +398,9 @@ std::optional<InputBindingKey> DInputSource::ParseKeyString(const std::string_vi
return std::nullopt;
}
std::string DInputSource::ConvertKeyToString(InputBindingKey key)
TinyString DInputSource::ConvertKeyToString(InputBindingKey key)
{
std::string ret;
TinyString ret;
if (key.source_type == InputSourceType::DInput)
{
@@ -408,23 +408,28 @@ std::string DInputSource::ConvertKeyToString(InputBindingKey key)
{
const char* modifier =
(key.modifier == InputModifier::FullAxis ? "Full" : (key.modifier == InputModifier::Negate ? "-" : "+"));
ret = fmt::format("DInput-{}/{}Axis{}{}", u32(key.source_index), modifier, u32(key.data), key.invert ? "~" : "");
ret.fmt("DInput-{}/{}Axis{}{}", u32(key.source_index), modifier, u32(key.data), key.invert ? "~" : "");
}
else if (key.source_subtype == InputSubclass::ControllerButton && key.data >= MAX_NUM_BUTTONS)
{
const u32 hat_num = (key.data - MAX_NUM_BUTTONS) / NUM_HAT_DIRECTIONS;
const u32 hat_dir = (key.data - MAX_NUM_BUTTONS) % NUM_HAT_DIRECTIONS;
ret = fmt::format("DInput-{}/Hat{}{}", u32(key.source_index), hat_num, s_hat_directions[hat_dir]);
ret.fmt("DInput-{}/Hat{}{}", u32(key.source_index), hat_num, s_hat_directions[hat_dir]);
}
else if (key.source_subtype == InputSubclass::ControllerButton)
{
ret = fmt::format("DInput-{}/Button{}", u32(key.source_index), u32(key.data));
ret.fmt("DInput-{}/Button{}", u32(key.source_index), u32(key.data));
}
}
return ret;
}
TinyString DInputSource::ConvertKeyToIcon(InputBindingKey key)
{
return {};
}
void DInputSource::CheckForStateChanges(size_t index, const DIJOYSTATE& new_state)
{
ControllerData& cd = m_controllers[index];

View File

@@ -48,7 +48,8 @@ public:
std::optional<InputBindingKey> ParseKeyString(const std::string_view& device,
const std::string_view& binding) override;
std::string ConvertKeyToString(InputBindingKey key) override;
TinyString ConvertKeyToString(InputBindingKey key) override;
TinyString ConvertKeyToIcon(InputBindingKey key) override;
private:
template<typename T>

View File

@@ -554,7 +554,11 @@ bool ImGuiManager::AddIconFonts(float size)
0xf545, 0xf545, 0xf547, 0xf548, 0xf552, 0xf552, 0xf57a, 0xf57a, 0xf5a2, 0xf5a2, 0xf5aa, 0xf5aa, 0xf5e7, 0xf5e7,
0xf65d, 0xf65e, 0xf6a9, 0xf6a9, 0xf7c2, 0xf7c2, 0xf807, 0xf807, 0xf815, 0xf815, 0xf818, 0xf818, 0xf84c, 0xf84c,
0xf8cc, 0xf8cc, 0x0, 0x0};
static constexpr ImWchar range_pf[] = { 0x2196,0x2199,0x219e,0x21a1,0x21b0,0x21b3,0x21ba,0x21c3,0x21c7,0x21ca,0x21d0,0x21d4,0x21e0,0x21e3,0x21ed,0x21ee,0x21f7,0x21f8,0x220b,0x220b,0x227a,0x227d,0x23ce,0x23ce,0x23f4,0x23f7,0x2427,0x243a,0x243c,0x243c,0x243e,0x243e,0x2460,0x246b,0x24f5,0x24fd,0x24ff,0x24ff,0x278a,0x278b,0x27fc,0x27fc,0xff21,0xff3a,0x0,0x0 };
static constexpr ImWchar range_pf[] = {0x2196, 0x2199, 0x219e, 0x21a1, 0x21b0, 0x21b3, 0x21ba, 0x21c3, 0x21c7, 0x21ca,
0x21d0, 0x21d4, 0x21dc, 0x21dd, 0x21e0, 0x21e3, 0x21ed, 0x21ee, 0x21f7, 0x21f8,
0x21fa, 0x21fb, 0x227a, 0x227d, 0x23f4, 0x23f7, 0x2427, 0x243a, 0x243c, 0x243c,
0x243e, 0x243e, 0x2460, 0x246b, 0x24f5, 0x24fd, 0x24ff, 0x24ff, 0x278a, 0x278e,
0x27fc, 0x27fc, 0xe001, 0xe001, 0xff21, 0xff3a, 0x0, 0x0};
{
ImFontConfig cfg;

View File

@@ -14,6 +14,8 @@
#include "imgui_manager.h"
#include "input_source.h"
#include "IconsPromptFont.h"
#include "fmt/core.h"
#include <array>
@@ -105,6 +107,7 @@ static std::optional<InputBindingKey> ParseSensorKey(const std::string_view& sou
static std::vector<std::string_view> SplitChord(const std::string_view& binding);
static bool SplitBinding(const std::string_view& binding, std::string_view* source, std::string_view* sub_binding);
static void PrettifyInputBindingPart(const std::string_view binding, SmallString& ret, bool& changed);
static void AddBindings(const std::vector<std::string>& bindings, const InputEventHandler& handler);
static bool IsAxisHandler(const InputEventHandler& handler);
@@ -333,7 +336,7 @@ std::string InputManager::ConvertInputBindingKeyToString(InputBindingInfo::Type
}
else if (key.source_type < InputSourceType::Count && s_input_sources[static_cast<u32>(key.source_type)])
{
return s_input_sources[static_cast<u32>(key.source_type)]->ConvertKeyToString(key);
return std::string(s_input_sources[static_cast<u32>(key.source_type)]->ConvertKeyToString(key));
}
}
@@ -367,6 +370,116 @@ std::string InputManager::ConvertInputBindingKeysToString(InputBindingInfo::Type
return ss.str();
}
bool InputManager::PrettifyInputBinding(std::string& binding)
{
if (binding.empty())
return false;
const std::string_view binding_view(binding);
SmallString ret;
bool changed = false;
std::string_view::size_type last = 0;
std::string_view::size_type next;
while ((next = binding_view.find('&', last)) != std::string_view::npos)
{
if (last != next)
{
const std::string_view part = StringUtil::StripWhitespace(binding_view.substr(last, next - last));
if (!part.empty())
{
if (!ret.empty())
ret.append(" + ");
PrettifyInputBindingPart(part, ret, changed);
}
}
last = next + 1;
}
if (last < (binding_view.size() - 1))
{
const std::string_view part = StringUtil::StripWhitespace(binding_view.substr(last));
if (!part.empty())
{
if (!ret.empty())
ret.append(" + ");
PrettifyInputBindingPart(part, ret, changed);
}
}
if (changed)
binding = ret.view();
return changed;
}
void InputManager::PrettifyInputBindingPart(const std::string_view binding, SmallString& ret, bool& changed)
{
std::string_view source, sub_binding;
if (!SplitBinding(binding, &source, &sub_binding))
return;
// lameee, string matching
if (StringUtil::StartsWith(source, "Keyboard"))
{
std::optional<InputBindingKey> key = ParseHostKeyboardKey(source, sub_binding);
const char* icon = key.has_value() ? ConvertHostKeyboardCodeToIcon(key->data) : nullptr;
if (icon)
{
ret.append(icon);
changed = true;
return;
}
}
else if (StringUtil::StartsWith(source, "Pointer"))
{
const std::optional<InputBindingKey> key = ParsePointerKey(source, sub_binding);
if (key.has_value())
{
if (key->source_subtype == InputSubclass::PointerButton)
{
static constexpr const char* button_icons[] = {
ICON_PF_MOUSE_BUTTON_1, ICON_PF_MOUSE_BUTTON_2, ICON_PF_MOUSE_BUTTON_3,
ICON_PF_MOUSE_BUTTON_4, ICON_PF_MOUSE_BUTTON_5,
};
if (key->data < std::size(button_icons))
{
ret.append(button_icons[key->data]);
changed = true;
return;
}
}
}
}
else if (StringUtil::StartsWith(source, "Sensor"))
{
}
else
{
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
{
if (s_input_sources[i])
{
std::optional<InputBindingKey> key = s_input_sources[i]->ParseKeyString(source, sub_binding);
if (key.has_value())
{
const TinyString icon = s_input_sources[i]->ConvertKeyToIcon(key.value());
if (!icon.empty())
{
ret.append(icon);
changed = true;
return;
}
break;
}
}
}
}
ret.append(binding);
}
void InputManager::AddBindings(const std::vector<std::string>& bindings, const InputEventHandler& handler)
{
for (const std::string& binding : bindings)

View File

@@ -207,6 +207,9 @@ std::optional<u32> ConvertHostKeyboardStringToCode(const std::string_view& str);
/// Converts a key code from an identifier to a human-readable string.
std::optional<std::string> ConvertHostKeyboardCodeToString(u32 code);
/// Converts a key code from an identifier to an icon which can be drawn.
const char* ConvertHostKeyboardCodeToIcon(u32 code);
/// Creates a key for a host-specific key code.
InputBindingKey MakeHostKeyboardKey(u32 key_code);
@@ -230,6 +233,9 @@ std::string ConvertInputBindingKeyToString(InputBindingInfo::Type binding_type,
std::string ConvertInputBindingKeysToString(InputBindingInfo::Type binding_type, const InputBindingKey* keys,
size_t num_keys);
/// Represents a binding with icon fonts, if available.
bool PrettifyInputBinding(std::string& binding);
/// Returns a list of all hotkeys.
std::vector<const HotkeyInfo*> GetHotkeyList();

View File

@@ -10,6 +10,7 @@
#include <utility>
#include <vector>
#include "common/small_string.h"
#include "common/types.h"
#include "input_manager.h"
@@ -30,7 +31,8 @@ public:
virtual std::optional<InputBindingKey> ParseKeyString(const std::string_view& device,
const std::string_view& binding) = 0;
virtual std::string ConvertKeyToString(InputBindingKey key) = 0;
virtual TinyString ConvertKeyToString(InputBindingKey key) = 0;
virtual TinyString ConvertKeyToIcon(InputBindingKey key) = 0;
/// Enumerates available devices. Returns a pair of the prefix (e.g. SDL-0) and the device name.
virtual std::vector<std::pair<std::string, std::string>> EnumerateDevices() = 0;

View File

@@ -14,6 +14,8 @@
#include "common/path.h"
#include "common/string_util.h"
#include "IconsPromptFont.h"
#include <cmath>
#ifdef __APPLE__
@@ -32,6 +34,14 @@ static constexpr const char* s_sdl_axis_names[] = {
"LeftTrigger", // SDL_CONTROLLER_AXIS_TRIGGERLEFT
"RightTrigger", // SDL_CONTROLLER_AXIS_TRIGGERRIGHT
};
static constexpr const char* s_sdl_axis_icons[][2] = {
{ICON_PF_LEFT_ANALOG_LEFT, ICON_PF_LEFT_ANALOG_RIGHT}, // SDL_CONTROLLER_AXIS_LEFTX
{ICON_PF_LEFT_ANALOG_UP, ICON_PF_LEFT_ANALOG_DOWN}, // SDL_CONTROLLER_AXIS_LEFTY
{ICON_PF_RIGHT_ANALOG_LEFT, ICON_PF_RIGHT_ANALOG_RIGHT}, // SDL_CONTROLLER_AXIS_RIGHTX
{ICON_PF_RIGHT_ANALOG_UP, ICON_PF_RIGHT_ANALOG_DOWN}, // SDL_CONTROLLER_AXIS_RIGHTY
{nullptr, ICON_PF_LEFT_TRIGGER_PULL}, // SDL_CONTROLLER_AXIS_TRIGGERLEFT
{nullptr, ICON_PF_RIGHT_TRIGGER_PULL}, // SDL_CONTROLLER_AXIS_TRIGGERRIGHT
};
static constexpr const GenericInputBinding s_sdl_generic_binding_axis_mapping[][2] = {
{GenericInputBinding::LeftStickLeft, GenericInputBinding::LeftStickRight}, // SDL_CONTROLLER_AXIS_LEFTX
{GenericInputBinding::LeftStickUp, GenericInputBinding::LeftStickDown}, // SDL_CONTROLLER_AXIS_LEFTY
@@ -64,6 +74,23 @@ static constexpr const char* s_sdl_button_names[] = {
"Paddle4", // SDL_CONTROLLER_BUTTON_PADDLE4
"Touchpad", // SDL_CONTROLLER_BUTTON_TOUCHPAD
};
static constexpr const char* s_sdl_button_icons[] = {
ICON_PF_BUTTON_A, // SDL_CONTROLLER_BUTTON_A
ICON_PF_BUTTON_B, // SDL_CONTROLLER_BUTTON_B
ICON_PF_BUTTON_X, // SDL_CONTROLLER_BUTTON_X
ICON_PF_BUTTON_Y, // SDL_CONTROLLER_BUTTON_Y
ICON_PF_SHARE_CAPTURE, // SDL_CONTROLLER_BUTTON_BACK
ICON_PF_XBOX, // SDL_CONTROLLER_BUTTON_GUIDE
ICON_PF_BURGER_MENU, // SDL_CONTROLLER_BUTTON_START
ICON_PF_LEFT_ANALOG_CLICK, // SDL_CONTROLLER_BUTTON_LEFTSTICK
ICON_PF_RIGHT_ANALOG_CLICK, // SDL_CONTROLLER_BUTTON_RIGHTSTICK
ICON_PF_LEFT_SHOULDER_LB, // SDL_CONTROLLER_BUTTON_LEFTSHOULDER
ICON_PF_RIGHT_SHOULDER_RB, // SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
ICON_PF_XBOX_DPAD_UP, // SDL_CONTROLLER_BUTTON_DPAD_UP
ICON_PF_XBOX_DPAD_DOWN, // SDL_CONTROLLER_BUTTON_DPAD_DOWN
ICON_PF_XBOX_DPAD_LEFT, // SDL_CONTROLLER_BUTTON_DPAD_LEFT
ICON_PF_XBOX_DPAD_RIGHT, // SDL_CONTROLLER_BUTTON_DPAD_RIGHT
};
static constexpr const GenericInputBinding s_sdl_generic_binding_button_mapping[] = {
GenericInputBinding::Cross, // SDL_CONTROLLER_BUTTON_A
GenericInputBinding::Circle, // SDL_CONTROLLER_BUTTON_B
@@ -416,9 +443,9 @@ std::optional<InputBindingKey> SDLInputSource::ParseKeyString(const std::string_
return std::nullopt;
}
std::string SDLInputSource::ConvertKeyToString(InputBindingKey key)
TinyString SDLInputSource::ConvertKeyToString(InputBindingKey key)
{
std::string ret;
TinyString ret;
if (key.source_type == InputSourceType::SDL)
{
@@ -428,40 +455,64 @@ std::string SDLInputSource::ConvertKeyToString(InputBindingKey key)
(key.modifier == InputModifier::FullAxis ? "Full" : (key.modifier == InputModifier::Negate ? "-" : "+"));
if (key.data < std::size(s_sdl_axis_names))
{
ret = fmt::format("SDL-{}/{}{}", static_cast<u32>(key.source_index), modifier, s_sdl_axis_names[key.data]);
ret.fmt("SDL-{}/{}{}", static_cast<u32>(key.source_index), modifier, s_sdl_axis_names[key.data]);
}
else
{
ret = fmt::format("SDL-{}/{}Axis{}{}", static_cast<u32>(key.source_index), modifier,
key.data - static_cast<u32>(std::size(s_sdl_axis_names)), key.invert ? "~" : "");
ret.fmt("SDL-{}/{}Axis{}{}", static_cast<u32>(key.source_index), modifier,
key.data - static_cast<u32>(std::size(s_sdl_axis_names)), key.invert ? "~" : "");
}
}
else if (key.source_subtype == InputSubclass::ControllerButton)
{
if (key.data < std::size(s_sdl_button_names))
{
ret = fmt::format("SDL-{}/{}", static_cast<u32>(key.source_index), s_sdl_button_names[key.data]);
ret.fmt("SDL-{}/{}", static_cast<u32>(key.source_index), s_sdl_button_names[key.data]);
}
else
{
ret = fmt::format("SDL-{}/Button{}", static_cast<u32>(key.source_index),
key.data - static_cast<u32>(std::size(s_sdl_button_names)));
ret.fmt("SDL-{}/Button{}", static_cast<u32>(key.source_index),
key.data - static_cast<u32>(std::size(s_sdl_button_names)));
}
}
else if (key.source_subtype == InputSubclass::ControllerHat)
{
const u32 hat_index = key.data / static_cast<u32>(std::size(s_sdl_hat_direction_names));
const u32 hat_direction = key.data % static_cast<u32>(std::size(s_sdl_hat_direction_names));
ret = fmt::format("SDL-{}/Hat{}{}", static_cast<u32>(key.source_index), hat_index,
s_sdl_hat_direction_names[hat_direction]);
ret.fmt("SDL-{}/Hat{}{}", static_cast<u32>(key.source_index), hat_index,
s_sdl_hat_direction_names[hat_direction]);
}
else if (key.source_subtype == InputSubclass::ControllerMotor)
{
ret = fmt::format("SDL-{}/{}Motor", static_cast<u32>(key.source_index), key.data ? "Large" : "Small");
ret.fmt("SDL-{}/{}Motor", static_cast<u32>(key.source_index), key.data ? "Large" : "Small");
}
else if (key.source_subtype == InputSubclass::ControllerHaptic)
{
ret = fmt::format("SDL-{}/Haptic", static_cast<u32>(key.source_index));
ret.fmt("SDL-{}/Haptic", static_cast<u32>(key.source_index));
}
}
return ret;
}
TinyString SDLInputSource::ConvertKeyToIcon(InputBindingKey key)
{
TinyString ret;
if (key.source_type == InputSourceType::SDL)
{
if (key.source_subtype == InputSubclass::ControllerAxis)
{
if (key.data < std::size(s_sdl_axis_icons) && key.modifier != InputModifier::FullAxis)
{
ret.fmt("SDL-{} {}", static_cast<u32>(key.source_index),
s_sdl_axis_icons[key.data][key.modifier == InputModifier::None]);
}
}
else if (key.source_subtype == InputSubclass::ControllerButton)
{
if (key.data < std::size(s_sdl_button_icons))
ret.fmt("SDL-{} {}", static_cast<u32>(key.source_index), s_sdl_button_icons[key.data]);
}
}

View File

@@ -34,7 +34,8 @@ public:
std::optional<InputBindingKey> ParseKeyString(const std::string_view& device,
const std::string_view& binding) override;
std::string ConvertKeyToString(InputBindingKey key) override;
TinyString ConvertKeyToString(InputBindingKey key) override;
TinyString ConvertKeyToIcon(InputBindingKey key) override;
bool ProcessSDLEvent(const SDL_Event* event);

View File

@@ -89,7 +89,12 @@ std::optional<InputBindingKey> Win32RawInputSource::ParseKeyString(const std::st
return std::nullopt;
}
std::string Win32RawInputSource::ConvertKeyToString(InputBindingKey key)
TinyString Win32RawInputSource::ConvertKeyToString(InputBindingKey key)
{
return {};
}
TinyString Win32RawInputSource::ConvertKeyToIcon(InputBindingKey key)
{
return {};
}

View File

@@ -32,7 +32,8 @@ public:
std::optional<InputBindingKey> ParseKeyString(const std::string_view& device,
const std::string_view& binding) override;
std::string ConvertKeyToString(InputBindingKey key) override;
TinyString ConvertKeyToString(InputBindingKey key) override;
TinyString ConvertKeyToIcon(InputBindingKey key) override;
private:
struct MouseState

View File

@@ -1,16 +1,20 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "xinput_source.h"
#include "input_manager.h"
#include "common/assert.h"
#include "common/log.h"
#include "common/string_util.h"
#include "core/host.h"
#include "input_manager.h"
#include "IconsPromptFont.h"
#include <cmath>
Log_SetChannel(XInputSource);
const char* XInputSource::s_axis_names[XInputSource::NUM_AXES] = {
static const char* s_axis_names[XInputSource::NUM_AXES] = {
"LeftX", // AXIS_LEFTX
"LeftY", // AXIS_LEFTY
"RightX", // AXIS_RIGHTX
@@ -18,6 +22,14 @@ const char* XInputSource::s_axis_names[XInputSource::NUM_AXES] = {
"LeftTrigger", // AXIS_TRIGGERLEFT
"RightTrigger", // AXIS_TRIGGERRIGHT
};
static constexpr const char* s_axis_icons[][2] = {
{ICON_PF_LEFT_ANALOG_LEFT, ICON_PF_LEFT_ANALOG_RIGHT}, // AXIS_LEFTX
{ICON_PF_LEFT_ANALOG_UP, ICON_PF_LEFT_ANALOG_DOWN}, // AXIS_LEFTY
{ICON_PF_RIGHT_ANALOG_LEFT, ICON_PF_RIGHT_ANALOG_RIGHT}, // AXIS_RIGHTX
{ICON_PF_RIGHT_ANALOG_UP, ICON_PF_RIGHT_ANALOG_DOWN}, // AXIS_RIGHTY
{nullptr, ICON_PF_LEFT_TRIGGER_PULL}, // AXIS_TRIGGERLEFT
{nullptr, ICON_PF_RIGHT_TRIGGER_PULL}, // AXIS_TRIGGERRIGHT
};
static const GenericInputBinding s_xinput_generic_binding_axis_mapping[][2] = {
{GenericInputBinding::LeftStickLeft, GenericInputBinding::LeftStickRight}, // AXIS_LEFTX
{GenericInputBinding::LeftStickUp, GenericInputBinding::LeftStickDown}, // AXIS_LEFTY
@@ -27,7 +39,7 @@ static const GenericInputBinding s_xinput_generic_binding_axis_mapping[][2] = {
{GenericInputBinding::Unknown, GenericInputBinding::R2}, // AXIS_TRIGGERRIGHT
};
const char* XInputSource::s_button_names[XInputSource::NUM_BUTTONS] = {
static const char* s_button_names[XInputSource::NUM_BUTTONS] = {
"DPadUp", // XINPUT_GAMEPAD_DPAD_UP
"DPadDown", // XINPUT_GAMEPAD_DPAD_DOWN
"DPadLeft", // XINPUT_GAMEPAD_DPAD_LEFT
@@ -44,7 +56,7 @@ const char* XInputSource::s_button_names[XInputSource::NUM_BUTTONS] = {
"Y", // XINPUT_GAMEPAD_Y
"Guide", // XINPUT_GAMEPAD_GUIDE
};
const u16 XInputSource::s_button_masks[XInputSource::NUM_BUTTONS] = {
static const u16 s_button_masks[XInputSource::NUM_BUTTONS] = {
XINPUT_GAMEPAD_DPAD_UP,
XINPUT_GAMEPAD_DPAD_DOWN,
XINPUT_GAMEPAD_DPAD_LEFT,
@@ -61,6 +73,23 @@ const u16 XInputSource::s_button_masks[XInputSource::NUM_BUTTONS] = {
XINPUT_GAMEPAD_Y,
0x400, // XINPUT_GAMEPAD_GUIDE
};
static constexpr const char* s_button_icons[] = {
ICON_PF_XBOX_DPAD_UP, // XINPUT_GAMEPAD_DPAD_UP
ICON_PF_XBOX_DPAD_DOWN, // XINPUT_GAMEPAD_DPAD_DOWN
ICON_PF_XBOX_DPAD_LEFT, // XINPUT_GAMEPAD_DPAD_LEFT
ICON_PF_XBOX_DPAD_RIGHT, // XINPUT_GAMEPAD_DPAD_RIGHT
ICON_PF_BURGER_MENU, // XINPUT_GAMEPAD_START
ICON_PF_SHARE_CAPTURE, // XINPUT_GAMEPAD_BACK
ICON_PF_LEFT_ANALOG_CLICK, // XINPUT_GAMEPAD_LEFT_THUMB
ICON_PF_RIGHT_ANALOG_CLICK, // XINPUT_GAMEPAD_RIGHT_THUMB
ICON_PF_LEFT_SHOULDER_LB, // XINPUT_GAMEPAD_LEFT_SHOULDER
ICON_PF_RIGHT_SHOULDER_RB, // XINPUT_GAMEPAD_RIGHT_SHOULDER
ICON_PF_BUTTON_A, // XINPUT_GAMEPAD_A
ICON_PF_BUTTON_B, // XINPUT_GAMEPAD_B
ICON_PF_BUTTON_X, // XINPUT_GAMEPAD_X
ICON_PF_BUTTON_Y, // XINPUT_GAMEPAD_Y
ICON_PF_XBOX, // XINPUT_GAMEPAD_GUIDE
};
static const GenericInputBinding s_xinput_generic_binding_button_mapping[] = {
GenericInputBinding::DPadUp, // XINPUT_GAMEPAD_DPAD_UP
GenericInputBinding::DPadDown, // XINPUT_GAMEPAD_DPAD_DOWN
@@ -287,24 +316,48 @@ std::optional<InputBindingKey> XInputSource::ParseKeyString(const std::string_vi
return std::nullopt;
}
std::string XInputSource::ConvertKeyToString(InputBindingKey key)
TinyString XInputSource::ConvertKeyToString(InputBindingKey key)
{
std::string ret;
TinyString ret;
if (key.source_type == InputSourceType::XInput)
{
if (key.source_subtype == InputSubclass::ControllerAxis && key.data < std::size(s_axis_names))
{
const char modifier = key.modifier == InputModifier::Negate ? '-' : '+';
ret = fmt::format("XInput-{}/{}{}", static_cast<u32>(key.source_index), modifier, s_axis_names[key.data]);
ret.fmt("XInput-{}/{}{}", static_cast<u32>(key.source_index), modifier, s_axis_names[key.data]);
}
else if (key.source_subtype == InputSubclass::ControllerButton && key.data < std::size(s_button_names))
{
ret = fmt::format("XInput-{}/{}", static_cast<u32>(key.source_index), s_button_names[key.data]);
ret.fmt("XInput-{}/{}", static_cast<u32>(key.source_index), s_button_names[key.data]);
}
else if (key.source_subtype == InputSubclass::ControllerMotor)
{
ret = fmt::format("XInput-{}/{}Motor", static_cast<u32>(key.source_index), key.data ? "Large" : "Small");
ret.fmt("XInput-{}/{}Motor", static_cast<u32>(key.source_index), key.data ? "Large" : "Small");
}
}
return ret;
}
TinyString XInputSource::ConvertKeyToIcon(InputBindingKey key)
{
TinyString ret;
if (key.source_type == InputSourceType::SDL)
{
if (key.source_subtype == InputSubclass::ControllerAxis)
{
if (key.data < std::size(s_axis_icons) && key.modifier != InputModifier::FullAxis)
{
ret.fmt("XInput-{} {}", static_cast<u32>(key.source_index),
s_axis_icons[key.data][key.modifier == InputModifier::None]);
}
}
else if (key.source_subtype == InputSubclass::ControllerButton)
{
if (key.data < std::size(s_button_icons))
ret.fmt("XInput-{} {}", static_cast<u32>(key.source_index), s_button_icons[key.data]);
}
}
@@ -384,8 +437,7 @@ void XInputSource::HandleControllerConnection(u32 index)
cd.has_small_motor = caps.Vibration.wRightMotorSpeed != 0;
cd.last_state = {};
InputManager::OnInputDeviceConnected(fmt::format("XInput-{}", index),
fmt::format("XInput Controller {}", index));
InputManager::OnInputDeviceConnected(fmt::format("XInput-{}", index), fmt::format("XInput Controller {}", index));
}
void XInputSource::HandleControllerDisconnection(u32 index)

View File

@@ -15,6 +15,23 @@ class SettingsInterface;
class XInputSource final : public InputSource
{
public:
enum : u32
{
NUM_CONTROLLERS = XUSER_MAX_COUNT, // 4
NUM_BUTTONS = 15,
};
enum : u32
{
AXIS_LEFTX,
AXIS_LEFTY,
AXIS_RIGHTX,
AXIS_RIGHTY,
AXIS_LEFTTRIGGER,
AXIS_RIGHTTRIGGER,
NUM_AXES,
};
XInputSource();
~XInputSource();
@@ -33,26 +50,10 @@ public:
std::optional<InputBindingKey> ParseKeyString(const std::string_view& device,
const std::string_view& binding) override;
std::string ConvertKeyToString(InputBindingKey key) override;
TinyString ConvertKeyToString(InputBindingKey key) override;
TinyString ConvertKeyToIcon(InputBindingKey key) override;
private:
enum : u32
{
NUM_CONTROLLERS = XUSER_MAX_COUNT, // 4
NUM_BUTTONS = 15,
};
enum : u32
{
AXIS_LEFTX,
AXIS_LEFTY,
AXIS_RIGHTX,
AXIS_RIGHTY,
AXIS_LEFTTRIGGER,
AXIS_RIGHTTRIGGER,
NUM_AXES,
};
struct ControllerData
{
XINPUT_STATE last_state;
@@ -74,8 +75,4 @@ private:
DWORD(WINAPI* m_xinput_get_state)(DWORD, XINPUT_STATE*) = nullptr;
DWORD(WINAPI* m_xinput_set_state)(DWORD, XINPUT_VIBRATION*) = nullptr;
DWORD(WINAPI* m_xinput_get_capabilities)(DWORD, DWORD, XINPUT_CAPABILITIES*) = nullptr;
static const char* s_axis_names[NUM_AXES];
static const char* s_button_names[NUM_BUTTONS];
static const u16 s_button_masks[NUM_BUTTONS];
};