FullscreenUI: Use icon font for bindings
This commit is contained in:
@@ -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];
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 {};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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];
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user