Skip to content

Commit

Permalink
HelpComponent: Display different help icons depending on controller
Browse files Browse the repository at this point in the history
Before this commit, all buttons shown in the help component would use
the SNES layout, which wouldn't match when having plugged in an Xbox
or Sony Playstation controller.

If there are different kinds of controllers plugged in, the input
mapping shown will be of the last used or inserted.

The intention here is to help solving #442, or at least most of it.
  • Loading branch information
sylt committed Nov 28, 2022
1 parent 0c4b42d commit 56235c4
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 13 deletions.
19 changes: 18 additions & 1 deletion es-core/src/InputManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ int SDL_USER_CECBUTTONUP = -1;

InputManager* InputManager::mInstance = NULL;

InputManager::InputManager() : mKeyboardInputConfig(NULL)
InputManager::InputManager() : mKeyboardInputConfig(NULL), mLastUsedKeyboardOrController(DEVICE_KEYBOARD)
{
}

Expand Down Expand Up @@ -111,6 +111,8 @@ void InputManager::addJoystickByDeviceIndex(int id)
int numAxes = SDL_JoystickNumAxes(joy);
mPrevAxisValues[joyId] = new int[numAxes];
std::fill(mPrevAxisValues[joyId], mPrevAxisValues[joyId] + numAxes, 0); //initialize array to 0

mLastUsedKeyboardOrController = joyId;
}

void InputManager::removeJoystickByJoystickID(SDL_JoystickID joyId)
Expand Down Expand Up @@ -198,6 +200,9 @@ int InputManager::getButtonCountByDevice(SDL_JoystickID id)

InputConfig* InputManager::getInputConfigByDevice(int device)
{
if(device != DEVICE_CEC)
mLastUsedKeyboardOrController = device;

if(device == DEVICE_KEYBOARD)
return mKeyboardInputConfig;
else if(device == DEVICE_CEC)
Expand All @@ -206,6 +211,18 @@ InputConfig* InputManager::getInputConfigByDevice(int device)
return mInputConfigs[device];
}

InputConfig* InputManager::getInputConfigForLastUsedDevice() const
{
if(mLastUsedKeyboardOrController == DEVICE_KEYBOARD)
return mKeyboardInputConfig;

const auto it = mInputConfigs.find(mLastUsedKeyboardOrController);
if(it != mInputConfigs.end())
return it->second;

return nullptr; // Could happen if last used controller was unplugged
}

bool InputManager::parseEvent(const SDL_Event& ev, Window* window)
{
bool causedEvent = false;
Expand Down
2 changes: 2 additions & 0 deletions es-core/src/InputManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class InputManager
std::map<SDL_JoystickID, InputConfig*> mInputConfigs;
InputConfig* mKeyboardInputConfig;
InputConfig* mCECInputConfig;
int mLastUsedKeyboardOrController;

std::map<SDL_JoystickID, int*> mPrevAxisValues;

Expand Down Expand Up @@ -56,6 +57,7 @@ class InputManager
std::string getDeviceGUIDString(int deviceId);

InputConfig* getInputConfigByDevice(int deviceId);
InputConfig* getInputConfigForLastUsedDevice() const;

bool parseEvent(const SDL_Event& ev, Window* window);
};
Expand Down
59 changes: 48 additions & 11 deletions es-core/src/components/HelpComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
#include "components/ComponentGrid.h"
#include "components/ImageComponent.h"
#include "components/TextComponent.h"
#include "resources/TextureResource.h"
#include "utils/StringUtil.h"
#include "Log.h"
#include "Settings.h"
#include "InputManager.h"

#define OFFSET_X 12 // move the entire thing right by this amount (px)
#define OFFSET_Y 12 // move the entire thing up by this amount (px)

#define ICON_TEXT_SPACING 8 // space between [icon] and [text] (px)
#define ENTRY_SPACING 16 // space between [text] and next [icon] (px)

static const std::map<std::string, const char*> ICON_PATH_MAP {
static const HelpComponent::IconPathMap DEFAULT_ICON_PATH_MAP {
{ "up/down", ":/help/dpad_updown.svg" },
{ "left/right", ":/help/dpad_leftright.svg" },
{ "up/down/left/right", ":/help/dpad_all.svg" },
Expand All @@ -29,6 +29,20 @@ static const std::map<std::string, const char*> ICON_PATH_MAP {
{ "select", ":/help/button_select.svg" }
};

static const HelpComponent::IconPathMap NO_ICON_OVERRIDES {};
static const HelpComponent::IconPathMap XBOX_ICON_OVERRIDES {
{ "a", ":/help/button_b.svg" },
{ "b", ":/help/button_a.svg" },
{ "x", ":/help/button_y.svg" },
{ "y", ":/help/button_x.svg" },
};
static const HelpComponent::IconPathMap PLAYSTATION_ICON_OVERRIDES {
{ "a", ":/help/button_circle.svg" },
{ "b", ":/help/button_x.svg" },
{ "x", ":/help/button_triangle.svg" },
{ "y", ":/help/button_square.svg" },
};

HelpComponent::HelpComponent(Window* window) : GuiComponent(window)
{
}
Expand Down Expand Up @@ -67,12 +81,15 @@ void HelpComponent::updateGrid()
std::vector< std::shared_ptr<ImageComponent> > icons;
std::vector< std::shared_ptr<TextComponent> > labels;

const auto& iconOverrides =
getIconOverridesForInput(InputManager::getInstance()->getInputConfigForLastUsedDevice());

float width = 0;
const float height = Math::round(font->getLetterHeight() * 1.25f);
for(auto it = mPrompts.cbegin(); it != mPrompts.cend(); it++)
{
auto icon = std::make_shared<ImageComponent>(mWindow);
icon->setImage(getIconTexture(it->first.c_str()));
icon->setImage(getIconTexture(it->first.c_str(), iconOverrides));
icon->setColorShift(mStyle.iconColor);
icon->setResize(0, height);
icons.push_back(icon);
Expand Down Expand Up @@ -100,26 +117,46 @@ void HelpComponent::updateGrid()
mGrid->setOrigin(mStyle.origin);
}

std::shared_ptr<TextureResource> HelpComponent::getIconTexture(const char* name)
const HelpComponent::IconPathMap& HelpComponent::getIconOverridesForInput(InputConfig* inputConfig)
{
auto it = mIconCache.find(name);
if(it != mIconCache.cend())
return it->second;
if(!inputConfig)
return NO_ICON_OVERRIDES;

const auto& deviceName = inputConfig->getDeviceName();
if(strcasestr(deviceName.c_str(), "xbox"))
return XBOX_ICON_OVERRIDES;

if(strcasestr(deviceName.c_str(), "sony") || strcasestr(deviceName.c_str(), "playstation"))
return PLAYSTATION_ICON_OVERRIDES;

auto pathLookup = ICON_PATH_MAP.find(name);
if(pathLookup == ICON_PATH_MAP.cend())
return NO_ICON_OVERRIDES;
}

std::shared_ptr<TextureResource> HelpComponent::getIconTexture(const char* name, const IconPathMap& iconOverrides)
{
auto pathLookup = DEFAULT_ICON_PATH_MAP.find(name);
if(pathLookup == DEFAULT_ICON_PATH_MAP.cend())
{
LOG(LogError) << "Unknown help icon \"" << name << "\"!";
return nullptr;
}

auto overrideIt = iconOverrides.find(name);
if(overrideIt != iconOverrides.end())
pathLookup = overrideIt;

auto it = mIconCache.find(pathLookup->second);
if(it != mIconCache.cend())
return it->second;

if(!ResourceManager::getInstance()->fileExists(pathLookup->second))
{
LOG(LogError) << "Help icon \"" << name << "\" - corresponding image file \"" << pathLookup->second << "\" misisng!";
LOG(LogError) << "Help icon \"" << name << "\" - corresponding image file \"" << pathLookup->second << "\" missing!";
return nullptr;
}

std::shared_ptr<TextureResource> tex = TextureResource::get(pathLookup->second);
mIconCache[std::string(name)] = tex;
mIconCache[std::string(pathLookup->second)] = tex;
return tex;
}

Expand Down
8 changes: 7 additions & 1 deletion es-core/src/components/HelpComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

#include "GuiComponent.h"
#include "HelpStyle.h"
#include "resources/TextureResource.h"

#include <string>

class ComponentGrid;
class ImageComponent;
Expand All @@ -22,8 +25,11 @@ class HelpComponent : public GuiComponent

void setStyle(const HelpStyle& style);

using IconPathMap = std::map<std::string /*name*/, const char* /*path*/>;

private:
std::shared_ptr<TextureResource> getIconTexture(const char* name);
const IconPathMap& getIconOverridesForInput(InputConfig* inputConfig);
std::shared_ptr<TextureResource> getIconTexture(const char* name, const IconPathMap& iconOverrides);
std::map< std::string, std::shared_ptr<TextureResource> > mIconCache;

std::shared_ptr<ComponentGrid> mGrid;
Expand Down

0 comments on commit 56235c4

Please sign in to comment.