Thank you for that! I have been looking and looking, and couldn’t find this anywhere.
Do you know by chance if I can do the same for gamepad keys?
The InKeyEvent knows if input was a gamepad key or not, but so far my best option has been to hash the string and compare that as how I do here (feels tedious):
UENUM(BlueprintType)
enum class EMyGamepadKey : uint8
{
invalid,
left_shoulder,
right_shoulder,
left_trigger,
right_trigger,
face_button_top,
face_button_bottom,
face_button_left,
face_button_right,
left_thumbstick_up,
left_thumbstick_down,
left_thumbstick_left,
left_thumbstick_right,
right_thumbstick_up,
right_thumbstick_down,
right_thumbstick_left,
right_thumbstick_right,
data_pad_up,
data_pad_down,
data_pad_left,
data_pad_right,
special_left,
special_right
};
UCLASS()
class UMyGamepadKeyConverter final : public UObject
{
GENERATED_BODY()
private:
// Hard topic. Some help:
// https://stackoverflow.com/questions/2111667/compile-time-string-hashing
static constexpr size_t MyCompileTimeHash(const std::string_view Str)
{
size_t Hash = sizeof(size_t) == 8 ? 0xcbf29ce484222325 : 0x811c9dc5;
constexpr size_t Prime = sizeof(size_t) == 8 ? 0x00000100000001b3 : 0x01000193;
const char* Input = Str.data();
while (*Input) {
Hash ^= static_cast<size_t>(*Input);
Hash *= Prime;
++Input;
}
return Hash;
}
public:
UFUNCTION(BlueprintCallable)
static inline EMyGamepadKey GetGamepadKeyFromString(const FString& GamepadKeyString)
{
// String hash library
static constexpr std::string_view String_Ls = "Gamepad Left Shoulder";
static constexpr std::string_view String_Rs = "Gamepad Right Shoulder";
static constexpr std::string_view String_Lt = "Gamepad Left Trigger";
static constexpr std::string_view String_Rt = "Gamepad Right Trigger";
static constexpr std::string_view String_Fbt = "Gamepad Face Button Top";
static constexpr std::string_view String_Fbb = "Gamepad Face Button Bottom";
static constexpr std::string_view String_Fbl = "Gamepad Face Button Left";
static constexpr std::string_view String_Fbr = "Gamepad Face Button Right";
static constexpr std::string_view String_Ltu = "Gamepad Left Thumbstick Up";
static constexpr std::string_view String_Ltd = "Gamepad Left Thumbstick Down";
static constexpr std::string_view String_Ltl = "Gamepad Left Thumbstick Left";
static constexpr std::string_view String_Ltr = "Gamepad Left Thumbstick Right";
static constexpr std::string_view String_Rtu = "Gamepad Right Thumbstick Up";
static constexpr std::string_view String_Rtd = "Gamepad Right Thumbstick Down";
static constexpr std::string_view String_Rtl = "Gamepad Right Thumbstick Left";
static constexpr std::string_view String_Rtr = "Gamepad Right Thumbstick Right";
static constexpr std::string_view String_Dpu = "Gamepad D-pad Up";
static constexpr std::string_view String_Dpd = "Gamepad D-pad Down";
static constexpr std::string_view String_Dpl = "Gamepad D-pad Left";
static constexpr std::string_view String_Dpr = "Gamepad D-pad Right";
static constexpr std::string_view String_Sl = "Gamepad Special Left";
static constexpr std::string_view String_Sr = "Gamepad Special Right";
static constexpr size_t Ls = MyCompileTimeHash(String_Ls);
static constexpr size_t Rs = MyCompileTimeHash(String_Rs);
static constexpr size_t Lt = MyCompileTimeHash(String_Lt);
static constexpr size_t Rt = MyCompileTimeHash(String_Rt);
static constexpr size_t Fbt = MyCompileTimeHash(String_Fbt);
static constexpr size_t Fbb = MyCompileTimeHash(String_Fbb);
static constexpr size_t Fbl = MyCompileTimeHash(String_Fbl);
static constexpr size_t Fbr = MyCompileTimeHash(String_Fbr);
static constexpr size_t Ltu = MyCompileTimeHash(String_Ltu);
static constexpr size_t Ltd = MyCompileTimeHash(String_Ltd);
static constexpr size_t Ltl = MyCompileTimeHash(String_Ltl);
static constexpr size_t Ltr = MyCompileTimeHash(String_Ltr);
static constexpr size_t Rtu = MyCompileTimeHash(String_Rtu);
static constexpr size_t Rtd = MyCompileTimeHash(String_Rtd);
static constexpr size_t Rtl = MyCompileTimeHash(String_Rtl);
static constexpr size_t Rtr = MyCompileTimeHash(String_Rtr);
static constexpr size_t Dpu = MyCompileTimeHash(String_Dpu);
static constexpr size_t Dpd = MyCompileTimeHash(String_Dpd);
static constexpr size_t Dpl = MyCompileTimeHash(String_Dpl);
static constexpr size_t Dpr = MyCompileTimeHash(String_Dpr);
static constexpr size_t Sl = MyCompileTimeHash(String_Sl);
static constexpr size_t Sr = MyCompileTimeHash(String_Sr);
// Hashing the argument
const TCHAR* Ptr = GetData(GamepadKeyString);
const std::string_view Input = StringCast<ANSICHAR>(Ptr).Get();
switch (MyCompileTimeHash(Input))
{
case Ls: return EMyGamepadKey::left_shoulder;
case Rs: return EMyGamepadKey::right_shoulder;
case Lt: return EMyGamepadKey::left_trigger;
case Rt: return EMyGamepadKey::right_trigger;
case Fbt: return EMyGamepadKey::face_button_top;
case Fbb: return EMyGamepadKey::face_button_bottom;
case Fbl: return EMyGamepadKey::face_button_left;
case Fbr: return EMyGamepadKey::face_button_right;
case Ltu: return EMyGamepadKey::left_thumbstick_up;
case Ltd: return EMyGamepadKey::left_thumbstick_down;
case Ltl: return EMyGamepadKey::left_thumbstick_left;
case Ltr: return EMyGamepadKey::left_thumbstick_right;
case Rtu: return EMyGamepadKey::right_thumbstick_up;
case Rtd: return EMyGamepadKey::right_thumbstick_down;
case Rtl: return EMyGamepadKey::right_thumbstick_left;
case Rtr: return EMyGamepadKey::right_thumbstick_right;
case Dpu: return EMyGamepadKey::data_pad_up;
case Dpd: return EMyGamepadKey::data_pad_down;
case Dpl: return EMyGamepadKey::data_pad_left;
case Dpr: return EMyGamepadKey::data_pad_right;
case Sl: return EMyGamepadKey::special_left;
case Sr: return EMyGamepadKey::special_right;
default:
return EMyGamepadKey::invalid;
}
}
};
Sorry for the long code - just wanted to be exact. And maybe it’s useful to others as well.
And yes, the string is fragile - but it would probably be okay if I at least use the TEXT()
macro?