Skip to content

Commit

Permalink
input+button: use new platform-specific controller icon images
Browse files Browse the repository at this point in the history
  • Loading branch information
vgmoose committed Mar 25, 2024
1 parent 60d7e78 commit 858a4ac
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 55 deletions.
63 changes: 36 additions & 27 deletions src/Button.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@ CST_Color Button::colors[2] = {
Button::Button(std::string message, int button, bool dark, int size, int width)
: physical(button)
, dark(dark)
, icon(getUnicode(button), (size / SCALER) * 1.25, &colors[dark], ICON)
, icon(getControllerButtonImageForPlatform(button, !dark, false))
, text(message, (size / SCALER), &colors[dark])
{

super::append(&text);
super::append(&icon);

// on initialization, store the last gamepad info
myLastSeenGamepad = InputEvents::lastGamepadKey;

icon.resize(text.height*1.5, text.height*1.5);

fixedWidth = width;

updateBounds();
Expand Down Expand Up @@ -58,33 +63,26 @@ void Button::updateText(const char* inc_text)
updateBounds();
}

const char* Button::getUnicode(int button)
std::string Button::getControllerButtonImageForPlatform(int button, bool isGray, bool isOutline)
{
switch (button)
{
case A_BUTTON:
return "\ue0a0";
case B_BUTTON:
return "\ue0a1";
case Y_BUTTON:
return "\ue0a2";
case X_BUTTON:
return "\ue0a3";
case START_BUTTON:
return "\ue0a4";
case SELECT_BUTTON:
return "\ue0a5";
case L_BUTTON:
return "\ue0a6";
case R_BUTTON:
return "\ue0a7";
case ZL_BUTTON:
return "\ue0a8";
case ZR_BUTTON:
return "\ue0a9";
default:
break;
// grab the current gamepad info
GamepadInfo& gamepad = InputEvents::getLastGamepadInfo();
// find the button index in the gamepad.buttons array
// TODO: use a hashmap instead of an array
if (gamepad.buttons != nullptr) {
for (int i = 0; i < TOTAL_BUTTONS; i++)
{
if (gamepad.buttons[i] == button)
{
auto outlineSuffix = isOutline ? "_outline" : "";
auto graySuffix = isGray ? "_gray" : "";
auto retVal = RAMFS "res/controllers/buttons/" + gamepad.prefix + "_" + gamepad.names[i] + outlineSuffix + graySuffix + ".svg";
return retVal;
}
}
}
// if we didn't find it, return an empty string
printf("Button %d not found in gamepad, returning empty string\n", button);
return "";
}

Expand All @@ -97,7 +95,18 @@ bool Button::process(InputEvents* event)
return true;
}

return super::process(event);
bool ret = false;

// if the last gamepad is different from the current one, update the button image
if (myLastSeenGamepad != InputEvents::lastGamepadKey)
{
auto newPath = getControllerButtonImageForPlatform(this->physical, !dark, false);
icon.loadPath(newPath);
icon.resize(text.height*1.5, text.height*1.5);
myLastSeenGamepad = InputEvents::lastGamepadKey;
}

return super::process(event) || ret;
}

const std::string Button::getText()
Expand Down
7 changes: 4 additions & 3 deletions src/Button.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ class Button : public Element
void updateText(const char* inc_text);
const std::string getText();

std::string myLastSeenGamepad = "";

TextElement text;
static std::string getControllerButtonImageForPlatform(int button, bool isGray, bool isOutline);

private:
static CST_Color colors[2];
const char* getUnicode(int button);

/// the physical button to activate this button
int physical = -1;

Expand All @@ -29,5 +30,5 @@ class Button : public Element
// whether the button is dark or light themed
bool dark = false;

TextElement icon;
ImageElement icon;
};
70 changes: 45 additions & 25 deletions src/InputEvents.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
#include "InputEvents.hpp"
#include "RootDisplay.hpp"
#include <string>
#include <map>

int TOTAL_BUTTONS = 18;

// computer key mappings
CST_Keycode key_buttons[] = { SDLK_a, SDLK_b, SDLK_x, SDLK_y, SDLK_UP, SDLK_DOWN, SDLK_LEFT, SDLK_RIGHT, SDLK_RETURN, SDLK_l, SDLK_r, SDLK_z, SDLK_BACKSPACE, SDLK_UP, SDLK_DOWN, SDLK_q };

Expand All @@ -24,8 +21,6 @@ int pad_buttons[] = { 1, 2, 3, 4, 0, 0, 0, 0, 8, 5, 6, 5, 7 };
// our own "buttons" that correspond to the above SDL ones
unsigned int nintendo_buttons[] = { A_BUTTON, B_BUTTON, X_BUTTON, Y_BUTTON, UP_BUTTON, DOWN_BUTTON, LEFT_BUTTON, RIGHT_BUTTON, START_BUTTON, L_BUTTON, R_BUTTON, ZL_BUTTON, SELECT_BUTTON, UP_BUTTON, DOWN_BUTTON, LEFT_BUTTON, RIGHT_BUTTON, ZR_BUTTON };

unsigned int* ie_buttons = nintendo_buttons;

// human readable lowercase names for the buttons (used by the UI)
std::string nintendoButtonNames[] = { "a", "b", "x", "y", "up", "down", "left", "right", "plus", "l", "r", "zl", "minus", "up", "down", "left", "right", "zr" };

Expand All @@ -46,29 +41,23 @@ std::string nunchukButtonNames[] = { "a", "b", "1", "2", "up", "down", "left", "
// if true, don't count key inputs (PC/usb keyboard) as button events for us
bool InputEvents::bypassKeyEvents = false;

struct GamepadInfo {
unsigned int* buttons;
std::string* names;
std::string prefix;
std::string controller_type;

public:
GamepadInfo(unsigned int* buttons, std::string* names, std::string prefix, std::string controller_type)
: buttons(buttons), names(names), prefix(prefix), controller_type(controller_type) {}
};
auto defaultKeyName = "WiiU Gamepad";
std::string InputEvents::lastGamepadKey = defaultKeyName;
unsigned int* currentButtons = nintendo_buttons;
std::string* currentButtonNames = nintendoButtonNames;

// map of controller name to buttons, names, prefix, and controller type
std::map<std::string, GamepadInfo> gamepadMap = {
/* Non-controller types, like keyboard */
{ "Keyboard", GamepadInfo(nullptr, keyButtonNames, "keyboard", "key") },
{ "Keyboard", GamepadInfo(nintendo_buttons, keyButtonNames, "keyboard", "key") },
/* These 5 names are returned by the wiiu SDL2 port */
{ "WiiU Gamepad", GamepadInfo(nintendo_buttons, nintendoButtonNames, "wiiu", "gamepad") },
{ "WiiU Pro Controller", { nintendo_buttons, nintendoButtonNames, "wiiu", "pro" } },
{ "Wii Remote", { wii_buttons, wiiButtonNames, "wii", "remote" } },
{ "Wii Remote and Nunchuk", { nunchuk_buttons, nunchukButtonNames, "wii", "nunchuk" } },
{ "Wii Classic Controller", { nintendo_buttons, nintendoButtonNames, "wii", "classic"} },
{ "WiiU Gamepad", GamepadInfo(nintendo_buttons, nintendoButtonNames, "wiiu_button", "gamepad") },
{ "WiiU Pro Controller", { nintendo_buttons, nintendoButtonNames, "wiiu_button", "pro" } },
{ "Wii Remote", { wii_buttons, wiiButtonNames, "wii_button", "remote" } },
{ "Wii Remote and Nunchuk", { nunchuk_buttons, nunchukButtonNames, "wii_button", "nunchuk" } },
{ "Wii Classic Controller", { nintendo_buttons, nintendoButtonNames, "wii_button", "classic"} },
/* The switch SDL2 port only returns this string for all controller types*/
{ "Switch Controller", { nintendo_buttons, nintendoButtonNames, "switch", "pro" } },
{ "Switch Controller", { nintendo_buttons, nintendoButtonNames, "switch_button", "pro" } },
/* For PC platforms, more specific Switch controller types can be recognized */
// { "Pro Controller", { nintendo_buttons, nintendoButtonNames, "switch" } },
// { "Joy-Con (L)", { nintendo_buttons, nintendoButtonNames, "switch" } },
Expand Down Expand Up @@ -103,6 +92,32 @@ bool InputEvents::processSDLEvents()
// process joystick hotplugging events
processJoystickHotplugging(&event);

std::string curControllerName= lastGamepadKey;

// get the controller name
if (this->type == SDL_KEYDOWN || this->type == SDL_KEYUP) {
// keyboard event
lastGamepadKey = "Keyboard";
} else if (this->type == SDL_JOYBUTTONDOWN || this->type == SDL_JOYBUTTONUP) {
SDL_Joystick* joystickId = SDL_JoystickFromInstanceID(event.jbutton.which);
if (joystickId != NULL) {
std::string controllerName = SDL_JoystickName(joystickId);
lastGamepadKey = defaultKeyName; // default in case no match is found
if (!controllerName.empty() && gamepadMap.find(controllerName) != gamepadMap.end()){
lastGamepadKey = controllerName;
}
}
}
if (curControllerName != lastGamepadKey) {
printf("Switched to controller profile: %s\n", lastGamepadKey.c_str());
GamepadInfo& gamepadInfo = gamepadMap[lastGamepadKey];
if (gamepadInfo.buttons != nullptr) {
currentButtons = gamepadInfo.buttons;
}
// keyButtonNames = gamepadInfo.names;
// TODO: callback to update all buttons on the UI
}

this->isScrolling = false;

#ifdef PC
Expand Down Expand Up @@ -281,15 +296,15 @@ bool InputEvents::held(int buttons)
if ((this->type == SDL_KEYDOWN || this->type == SDL_KEYUP) && !InputEvents::bypassKeyEvents)
{
for (int x = 0; x < TOTAL_BUTTONS; x++)
if (key_buttons[x] == keyCode && (buttons & ie_buttons[x]))
if (key_buttons[x] == keyCode && (buttons & currentButtons[x]))
return true;
}

// if it's a controller event
else if (this->type == SDL_JOYBUTTONDOWN || this->type == SDL_JOYBUTTONUP)
{
for (int x = 0; x < TOTAL_BUTTONS; x++)
if (pad_buttons[x] == keyCode && (buttons & ie_buttons[x]))
if (pad_buttons[x] == keyCode && (buttons & currentButtons[x]))
return true;
}

Expand Down Expand Up @@ -355,7 +370,7 @@ void InputEvents::processJoystickHotplugging(SDL_Event *event)
case SDL_JOYDEVICEADDED:
j = SDL_JoystickOpen(event->jdevice.which);
if (j)
printf("Added joystick device: %s\n", SDL_JoystickName(j));
printf("Added joystick device: %s, with ID %d\n", SDL_JoystickName(j), SDL_JoystickInstanceID(j));
break;
case SDL_JOYDEVICEREMOVED:
j = SDL_JoystickFromInstanceID(event->jdevice.which);
Expand All @@ -370,3 +385,8 @@ void InputEvents::processJoystickHotplugging(SDL_Event *event)
}
#endif
}

GamepadInfo& InputEvents::getLastGamepadInfo()
{
return gamepadMap[lastGamepadKey];
}
20 changes: 20 additions & 0 deletions src/InputEvents.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ typedef uint32_t CST_Keycode;
typedef uint16_t CST_Keymod;
#endif
#include <functional>
#include <string>

#define TOTAL_BUTTONS 18

// clang-format off
#define LEFT_BUTTON 0b00000000000001
Expand Down Expand Up @@ -56,6 +59,21 @@ typedef uint16_t CST_Keymod;
#define SDL_DOWN_STICK (SDL_GameControllerButton)19
// clang-format on

struct GamepadInfo {
unsigned int* buttons;
std::string* names;
std::string prefix;
std::string controller_type;

public:
GamepadInfo(unsigned int* buttons, std::string* names, std::string prefix, std::string controller_type)
: buttons(buttons), names(names), prefix(prefix), controller_type(controller_type) {}
GamepadInfo()
: buttons(nullptr), names(nullptr), prefix(""), controller_type("")
{
}
};

class InputEvents
{
public:
Expand Down Expand Up @@ -105,6 +123,8 @@ class InputEvents
int curFrame = 0;

static bool bypassKeyEvents;
static GamepadInfo& getLastGamepadInfo();
static std::string lastGamepadKey;

std::function<void()> quitaction = NULL; //Called for an SDL_Quit event, usually caused by a SIGINT

Expand Down

0 comments on commit 858a4ac

Please sign in to comment.