Implemented rebinding inputs from UI (controller only so far) and built minimal UI for doing so

This commit is contained in:
Mr-Wiseguy
2024-01-15 21:06:52 -05:00
parent 457bc878e9
commit 6ebc7256eb
7 changed files with 426 additions and 116 deletions
+202 -79
View File
@@ -7,6 +7,7 @@
#include "SDL.h"
#include "rt64_layer.h"
constexpr float axis_threshold = 0.5f;
static struct {
const Uint8* keys = nullptr;
@@ -16,21 +17,57 @@ static struct {
std::vector<SDL_GameController*> cur_controllers{};
} InputState;
std::atomic<recomp::InputDevice> scanning_device = recomp::InputDevice::COUNT;
std::atomic<recomp::InputField> scanned_input;
enum class InputType {
None = 0, // Using zero for None ensures that default initialized InputFields are unbound.
Keyboard,
Mouse,
ControllerDigital,
ControllerAnalog // Axis input_id values are the SDL value + 1
};
void set_scanned_input(recomp::InputField value) {
scanning_device.store(recomp::InputDevice::COUNT);
scanned_input.store(value);
}
recomp::InputField recomp::get_scanned_input() {
recomp::InputField ret = scanned_input.load();
scanned_input.store({});
return ret;
}
void recomp::start_scanning_input(recomp::InputDevice device) {
scanned_input.store({});
scanning_device.store(device);
}
void queue_if_enabled(SDL_Event* event) {
if (!recomp::all_input_disabled()) {
recomp::queue_event(*event);
}
}
bool sdl_event_filter(void* userdata, SDL_Event* event) {
switch (event->type) {
case SDL_EventType::SDL_KEYDOWN:
{
SDL_KeyboardEvent* keyevent = (SDL_KeyboardEvent*)event;
SDL_KeyboardEvent* keyevent = &event->key;
if (keyevent->keysym.scancode == SDL_Scancode::SDL_SCANCODE_RETURN && (keyevent->keysym.mod & SDL_Keymod::KMOD_ALT)) {
RT64ChangeWindow();
}
if (scanning_device == recomp::InputDevice::Keyboard) {
set_scanned_input({(uint32_t)InputType::Keyboard, keyevent->keysym.scancode});
}
}
recomp::queue_event(*event);
queue_if_enabled(event);
break;
case SDL_EventType::SDL_CONTROLLERDEVICEADDED:
{
SDL_ControllerDeviceEvent* controller_event = (SDL_ControllerDeviceEvent*)event;
SDL_ControllerDeviceEvent* controller_event = &event->cdevice;
SDL_GameController* controller = SDL_GameControllerOpen(controller_event->which);
printf("Controller added: %d\n", controller_event->which);
if (controller != nullptr) {
@@ -41,7 +78,7 @@ bool sdl_event_filter(void* userdata, SDL_Event* event) {
break;
case SDL_EventType::SDL_CONTROLLERDEVICEREMOVED:
{
SDL_ControllerDeviceEvent* controller_event = (SDL_ControllerDeviceEvent*)event;
SDL_ControllerDeviceEvent* controller_event = &event->cdevice;
printf("Controller removed: %d\n", controller_event->which);
std::erase(InputState.controller_ids, controller_event->which);
}
@@ -51,13 +88,33 @@ bool sdl_event_filter(void* userdata, SDL_Event* event) {
return true;
case SDL_EventType::SDL_MOUSEWHEEL:
{
SDL_MouseWheelEvent* wheel_event = (SDL_MouseWheelEvent*)event;
SDL_MouseWheelEvent* wheel_event = &event->wheel;
InputState.mouse_wheel_pos.fetch_add(wheel_event->y * (wheel_event->direction == SDL_MOUSEWHEEL_FLIPPED ? -1 : 1));
}
recomp::queue_event(*event);
queue_if_enabled(event);
break;
case SDL_EventType::SDL_CONTROLLERBUTTONDOWN:
if (scanning_device == recomp::InputDevice::Controller) {
SDL_ControllerButtonEvent* button_event = &event->cbutton;
set_scanned_input({(uint32_t)InputType::ControllerDigital, button_event->button});
}
queue_if_enabled(event);
break;
case SDL_EventType::SDL_CONTROLLERAXISMOTION:
if (scanning_device == recomp::InputDevice::Controller) {
SDL_ControllerAxisEvent* axis_event = &event->caxis;
float axis_value = axis_event->value * (1/32768.0f);
if (axis_value > axis_threshold) {
set_scanned_input({(uint32_t)InputType::ControllerAnalog, axis_event->axis + 1});
}
else if (axis_value < -axis_threshold) {
set_scanned_input({(uint32_t)InputType::ControllerAnalog, -axis_event->axis - 1});
}
}
queue_if_enabled(event);
break;
default:
recomp::queue_event(*event);
queue_if_enabled(event);
break;
}
return false;
@@ -71,13 +128,6 @@ void recomp::handle_events() {
}
}
enum class DeviceType {
Keyboard,
Mouse,
ControllerDigital,
ControllerAnalog // Axis input_id values are the SDL value + 1
};
constexpr SDL_GameControllerButton SDL_CONTROLLER_BUTTON_SOUTH = SDL_CONTROLLER_BUTTON_A;
constexpr SDL_GameControllerButton SDL_CONTROLLER_BUTTON_EAST = SDL_CONTROLLER_BUTTON_B;
constexpr SDL_GameControllerButton SDL_CONTROLLER_BUTTON_WEST = SDL_CONTROLLER_BUTTON_X;
@@ -85,117 +135,117 @@ constexpr SDL_GameControllerButton SDL_CONTROLLER_BUTTON_NORTH = SDL_CONTROLLER_
const recomp::DefaultN64Mappings recomp::default_n64_keyboard_mappings = {
.a = {
{.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_SPACE}
{.input_type = (uint32_t)InputType::Keyboard, .input_id = SDL_SCANCODE_SPACE}
},
.b = {
{.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_LSHIFT}
{.input_type = (uint32_t)InputType::Keyboard, .input_id = SDL_SCANCODE_LSHIFT}
},
.l = {
{.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_E}
{.input_type = (uint32_t)InputType::Keyboard, .input_id = SDL_SCANCODE_E}
},
.r = {
{.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_R}
{.input_type = (uint32_t)InputType::Keyboard, .input_id = SDL_SCANCODE_R}
},
.z = {
{.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_Q}
{.input_type = (uint32_t)InputType::Keyboard, .input_id = SDL_SCANCODE_Q}
},
.start = {
{.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_RETURN}
{.input_type = (uint32_t)InputType::Keyboard, .input_id = SDL_SCANCODE_RETURN}
},
.c_left = {
{.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_LEFT}
{.input_type = (uint32_t)InputType::Keyboard, .input_id = SDL_SCANCODE_LEFT}
},
.c_right = {
{.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_RIGHT}
{.input_type = (uint32_t)InputType::Keyboard, .input_id = SDL_SCANCODE_RIGHT}
},
.c_up = {
{.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_UP}
{.input_type = (uint32_t)InputType::Keyboard, .input_id = SDL_SCANCODE_UP}
},
.c_down = {
{.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_DOWN}
{.input_type = (uint32_t)InputType::Keyboard, .input_id = SDL_SCANCODE_DOWN}
},
.dpad_left = {
{.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_J}
{.input_type = (uint32_t)InputType::Keyboard, .input_id = SDL_SCANCODE_J}
},
.dpad_right = {
{.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_L}
{.input_type = (uint32_t)InputType::Keyboard, .input_id = SDL_SCANCODE_L}
},
.dpad_up = {
{.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_I}
{.input_type = (uint32_t)InputType::Keyboard, .input_id = SDL_SCANCODE_I}
},
.dpad_down = {
{.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_K}
{.input_type = (uint32_t)InputType::Keyboard, .input_id = SDL_SCANCODE_K}
},
.analog_left = {
{.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_A}
{.input_type = (uint32_t)InputType::Keyboard, .input_id = SDL_SCANCODE_A}
},
.analog_right = {
{.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_D}
{.input_type = (uint32_t)InputType::Keyboard, .input_id = SDL_SCANCODE_D}
},
.analog_up = {
{.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_W}
{.input_type = (uint32_t)InputType::Keyboard, .input_id = SDL_SCANCODE_W}
},
.analog_down = {
{.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_S}
{.input_type = (uint32_t)InputType::Keyboard, .input_id = SDL_SCANCODE_S}
},
};
const recomp::DefaultN64Mappings recomp::default_n64_controller_mappings = {
.a = {
{.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_SOUTH},
{.input_type = (uint32_t)InputType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_SOUTH},
},
.b = {
{.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_EAST},
{.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_WEST},
{.input_type = (uint32_t)InputType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_EAST},
{.input_type = (uint32_t)InputType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_WEST},
},
.l = {
{.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
{.input_type = (uint32_t)InputType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
},
.r = {
{.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
{.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = SDL_CONTROLLER_AXIS_TRIGGERRIGHT + 1},
{.input_type = (uint32_t)InputType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
{.input_type = (uint32_t)InputType::ControllerAnalog, .input_id = SDL_CONTROLLER_AXIS_TRIGGERRIGHT + 1},
},
.z = {
{.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = SDL_CONTROLLER_AXIS_TRIGGERLEFT + 1},
{.input_type = (uint32_t)InputType::ControllerAnalog, .input_id = SDL_CONTROLLER_AXIS_TRIGGERLEFT + 1},
},
.start = {
{.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_START},
{.input_type = (uint32_t)InputType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_START},
},
.c_left = {
{.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = -(SDL_CONTROLLER_AXIS_RIGHTX + 1)},
{.input_type = (uint32_t)InputType::ControllerAnalog, .input_id = -(SDL_CONTROLLER_AXIS_RIGHTX + 1)},
},
.c_right = {
{.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = SDL_CONTROLLER_AXIS_RIGHTX + 1},
{.input_type = (uint32_t)InputType::ControllerAnalog, .input_id = SDL_CONTROLLER_AXIS_RIGHTX + 1},
},
.c_up = {
{.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = -(SDL_CONTROLLER_AXIS_RIGHTY + 1)},
{.input_type = (uint32_t)InputType::ControllerAnalog, .input_id = -(SDL_CONTROLLER_AXIS_RIGHTY + 1)},
},
.c_down = {
{.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = SDL_CONTROLLER_AXIS_RIGHTY + 1},
{.input_type = (uint32_t)InputType::ControllerAnalog, .input_id = SDL_CONTROLLER_AXIS_RIGHTY + 1},
},
.dpad_left = {
{.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_DPAD_LEFT},
{.input_type = (uint32_t)InputType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_DPAD_LEFT},
},
.dpad_right = {
{.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
{.input_type = (uint32_t)InputType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
},
.dpad_up = {
{.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_DPAD_UP},
{.input_type = (uint32_t)InputType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_DPAD_UP},
},
.dpad_down = {
{.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_DPAD_DOWN},
{.input_type = (uint32_t)InputType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_DPAD_DOWN},
},
.analog_left = {
{.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = -(SDL_CONTROLLER_AXIS_LEFTX + 1)},
{.input_type = (uint32_t)InputType::ControllerAnalog, .input_id = -(SDL_CONTROLLER_AXIS_LEFTX + 1)},
},
.analog_right = {
{.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = SDL_CONTROLLER_AXIS_LEFTX + 1},
{.input_type = (uint32_t)InputType::ControllerAnalog, .input_id = SDL_CONTROLLER_AXIS_LEFTX + 1},
},
.analog_up = {
{.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = -(SDL_CONTROLLER_AXIS_LEFTY + 1)},
{.input_type = (uint32_t)InputType::ControllerAnalog, .input_id = -(SDL_CONTROLLER_AXIS_LEFTY + 1)},
},
.analog_down = {
{.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = SDL_CONTROLLER_AXIS_LEFTY + 1},
{.input_type = (uint32_t)InputType::ControllerAnalog, .input_id = SDL_CONTROLLER_AXIS_LEFTY + 1},
},
};
@@ -264,27 +314,21 @@ float controller_axis_state(int32_t input_id) {
}
float recomp::get_input_analog(const recomp::InputField& field) {
switch ((DeviceType)field.device_type) {
case DeviceType::Keyboard:
{
switch ((InputType)field.input_type) {
case InputType::Keyboard:
if (InputState.keys && field.input_id >= 0 && field.input_id < InputState.numkeys) {
return InputState.keys[field.input_id] ? 1.0f : 0.0f;
}
return 0.0f;
}
case DeviceType::ControllerDigital:
{
case InputType::ControllerDigital:
return controller_button_state(field.input_id) ? 1.0f : 0.0f;
}
case DeviceType::ControllerAnalog:
{
case InputType::ControllerAnalog:
return controller_axis_state(field.input_id);
}
case DeviceType::Mouse:
{
case InputType::Mouse:
// TODO mouse support
return 0.0f;
}
case InputType::None:
return false;
}
}
@@ -297,28 +341,22 @@ float recomp::get_input_analog(const std::span<const recomp::InputField> fields)
}
bool recomp::get_input_digital(const recomp::InputField& field) {
switch ((DeviceType)field.device_type) {
case DeviceType::Keyboard:
{
switch ((InputType)field.input_type) {
case InputType::Keyboard:
if (InputState.keys && field.input_id >= 0 && field.input_id < InputState.numkeys) {
return InputState.keys[field.input_id] != 0;
}
return false;
}
case DeviceType::ControllerDigital:
{
case InputType::ControllerDigital:
return controller_button_state(field.input_id);
}
case DeviceType::ControllerAnalog:
{
case InputType::ControllerAnalog:
// TODO adjustable threshold
return controller_axis_state(field.input_id) >= 0.5f;
}
case DeviceType::Mouse:
{
return controller_axis_state(field.input_id) >= axis_threshold;
case InputType::Mouse:
// TODO mouse support
return false;
}
case InputType::None:
return false;
}
}
@@ -334,3 +372,88 @@ bool recomp::game_input_disabled() {
// Disable input if any menu is open.
return recomp::get_current_menu() != recomp::Menu::None;
}
bool recomp::all_input_disabled() {
// Disable all input if an input is being polled.
return scanning_device != recomp::InputDevice::COUNT;
}
std::string controller_button_to_string(SDL_GameControllerButton button) {
switch (button) {
case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_A:
return "\u21A7";
case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_B:
return "\u21A6";
case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_X:
return "\u21A4";
case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_Y:
return "\u21A5";
case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_BACK:
return "\u21FA";
// case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_GUIDE:
// return "";
case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_START:
return "\u21FB";
case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSTICK:
return "\u21BA";
case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSTICK:
return "\u21BB";
case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
return "\u2198";
case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
return "\u2199";
case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_UP:
return "\u219F";
case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_DOWN:
return "\u21A1";
case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_LEFT:
return "\u219E";
case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
return "\u21A0";
// case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_MISC1:
// return "";
// case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE1:
// return "";
// case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE2:
// return "";
// case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE3:
// return "";
// case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_PADDLE4:
// return "";
case SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_TOUCHPAD:
return "\u21E7";
}
return "Button " + std::to_string(button);
}
std::string controller_axis_to_string(int axis) {
bool positive = axis > 0;
SDL_GameControllerAxis actual_axis = SDL_GameControllerAxis(abs(axis) - 1);
switch (actual_axis) {
case SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTX:
return positive ? "\u21C0" : "\u21BC";
case SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTY:
return positive ? "\u21C2" : "\u21BE";
case SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTX:
return positive ? "\u21C1" : "\u21BD";
case SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTY:
return positive ? "\u21C3" : "\u21BF";
case SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERLEFT:
return positive ? "\u219A" : "\u21DC";
case SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
return positive ? "\u219B" : "\u21DD";
}
return "Axis " + std::to_string(actual_axis) + (positive ? '+' : '-');
}
std::string recomp::InputField::to_string() const {
switch ((InputType)input_type) {
case InputType::None:
return "";
case InputType::ControllerDigital:
return controller_button_to_string((SDL_GameControllerButton)input_id);
case InputType::ControllerAnalog:
return controller_axis_to_string(input_id);
}
return std::to_string(input_type) + "," + std::to_string(input_id);
}