mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-04 16:32:39 +00:00
Initial controller support
This commit is contained in:
parent
4c0c3d30d7
commit
675559b1ba
@ -704,19 +704,21 @@ void setDefaultValues() {
|
|||||||
constexpr std::string_view GetDefaultKeyboardConfig() {
|
constexpr std::string_view GetDefaultKeyboardConfig() {
|
||||||
return R"(#Feeling lost? Check out the Help section!
|
return R"(#Feeling lost? Check out the Help section!
|
||||||
|
|
||||||
|
#Keyboard bindings
|
||||||
|
|
||||||
triangle = f
|
triangle = f
|
||||||
circle = space
|
circle = space
|
||||||
cross = e
|
cross = e
|
||||||
square = r
|
square = r
|
||||||
|
|
||||||
up = w, lalt
|
pad_up = w, lalt
|
||||||
up = mousewheelup
|
pad_up = mousewheelup
|
||||||
down = s, lalt
|
pad_down = s, lalt
|
||||||
down = mousewheeldown
|
pad_down = mousewheeldown
|
||||||
left = a, lalt
|
pad_left = a, lalt
|
||||||
left = mousewheelleft
|
pad_left = mousewheelleft
|
||||||
right = d, lalt
|
pad_right = d, lalt
|
||||||
right = mousewheelright
|
pad_right = mousewheelright
|
||||||
|
|
||||||
l1 = rightbutton, lshift
|
l1 = rightbutton, lshift
|
||||||
r1 = leftbutton
|
r1 = leftbutton
|
||||||
@ -726,21 +728,45 @@ l3 = x
|
|||||||
r3 = q
|
r3 = q
|
||||||
r3 = middlebutton
|
r3 = middlebutton
|
||||||
|
|
||||||
key_toggle = i, lalt
|
|
||||||
|
|
||||||
options = escape
|
options = escape
|
||||||
touchpad = g
|
touchpad = g
|
||||||
|
|
||||||
|
key_toggle = i, lalt
|
||||||
mouse_to_joystick = right
|
mouse_to_joystick = right
|
||||||
mouse_movement_params = 0.5, 1, 0.125
|
mouse_movement_params = 0.5, 1, 0.125
|
||||||
|
|
||||||
leftjoystick_halfmode = lctrl
|
leftjoystick_halfmode = lctrl
|
||||||
|
|
||||||
axis_left_x_minus = a
|
axis_left_x_minus = a
|
||||||
axis_left_x_plus = d
|
axis_left_x_plus = d
|
||||||
axis_left_y_minus = w
|
axis_left_y_minus = w
|
||||||
axis_left_y_plus = s
|
axis_left_y_plus = s
|
||||||
|
|
||||||
|
#Controller bindings
|
||||||
|
|
||||||
|
triangle = triangle
|
||||||
|
cross = cross
|
||||||
|
square = square
|
||||||
|
circle = circle
|
||||||
|
|
||||||
|
l1 = l1
|
||||||
|
l2 = l2
|
||||||
|
l3 = l3
|
||||||
|
r1 = r1
|
||||||
|
r2 = r2
|
||||||
|
r3 = r3
|
||||||
|
|
||||||
|
pad_up = pad_up
|
||||||
|
pad_down = pad_down
|
||||||
|
pad_left = pad_left
|
||||||
|
pad_right = pad_right
|
||||||
|
|
||||||
|
options = options
|
||||||
|
|
||||||
|
axis_left_x = axis_left_x
|
||||||
|
axis_left_y = axis_left_y
|
||||||
|
|
||||||
|
axis_right_x = axis_right_x
|
||||||
|
axis_right_y = axis_right_y
|
||||||
)";
|
)";
|
||||||
}
|
}
|
||||||
std::filesystem::path GetFoolproofKbmConfigFile(const std::string& game_id) {
|
std::filesystem::path GetFoolproofKbmConfigFile(const std::string& game_id) {
|
||||||
@ -748,7 +774,7 @@ std::filesystem::path GetFoolproofKbmConfigFile(const std::string& game_id) {
|
|||||||
// If that doesn't exist either, generate that from getDefaultConfig() and try again
|
// If that doesn't exist either, generate that from getDefaultConfig() and try again
|
||||||
// If even the folder is missing, we start with that.
|
// If even the folder is missing, we start with that.
|
||||||
|
|
||||||
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "kbmConfig";
|
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "inputConfig";
|
||||||
const auto config_file = config_dir / (game_id + ".ini");
|
const auto config_file = config_dir / (game_id + ".ini");
|
||||||
const auto default_config_file = config_dir / "default.ini";
|
const auto default_config_file = config_dir / "default.ini";
|
||||||
|
|
||||||
|
@ -98,7 +98,62 @@ ControllerOutput output_array[] = {
|
|||||||
void ToggleMouseEnabled() {
|
void ToggleMouseEnabled() {
|
||||||
mouse_enabled ^= true;
|
mouse_enabled ^= true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// parsing related functions
|
// parsing related functions
|
||||||
|
u32 GetAxisInputId(AxisMapping a) {
|
||||||
|
//LOG_INFO(Input, "Parsing an axis...");
|
||||||
|
if (a.axis == Axis::AxisMax || a.value != 0) {
|
||||||
|
LOG_ERROR(Input, "Invalid axis given!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
u32 value = (u32)a.axis + 0x80000000;
|
||||||
|
LOG_DEBUG(Input, "Listening to {0:X}", value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 GetOrbisToSdlButtonKeycode(u32 cbutton) {
|
||||||
|
switch (cbutton) {
|
||||||
|
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE:
|
||||||
|
return SDL_GAMEPAD_BUTTON_EAST;
|
||||||
|
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE:
|
||||||
|
return SDL_GAMEPAD_BUTTON_NORTH;
|
||||||
|
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE:
|
||||||
|
return SDL_GAMEPAD_BUTTON_WEST;
|
||||||
|
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS:
|
||||||
|
return SDL_GAMEPAD_BUTTON_SOUTH;
|
||||||
|
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L1:
|
||||||
|
return SDL_GAMEPAD_BUTTON_LEFT_SHOULDER;
|
||||||
|
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1:
|
||||||
|
return SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER;
|
||||||
|
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3:
|
||||||
|
return SDL_GAMEPAD_BUTTON_LEFT_STICK;
|
||||||
|
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3:
|
||||||
|
return SDL_GAMEPAD_BUTTON_RIGHT_STICK;
|
||||||
|
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP:
|
||||||
|
return SDL_GAMEPAD_BUTTON_DPAD_UP;
|
||||||
|
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN:
|
||||||
|
return SDL_GAMEPAD_BUTTON_DPAD_DOWN;
|
||||||
|
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT:
|
||||||
|
return SDL_GAMEPAD_BUTTON_DPAD_LEFT;
|
||||||
|
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT:
|
||||||
|
return SDL_GAMEPAD_BUTTON_DPAD_RIGHT;
|
||||||
|
case OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS:
|
||||||
|
return SDL_GAMEPAD_BUTTON_START;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ((u32)-1) - 0x10000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u32 GetControllerButtonInputId(u32 cbutton) {
|
||||||
|
if((cbutton & (OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD |
|
||||||
|
LEFTJOYSTICK_HALFMODE |
|
||||||
|
RIGHTJOYSTICK_HALFMODE)) != 0) {
|
||||||
|
//LOG_ERROR(Input, "You can't use this as a button input!");
|
||||||
|
return (u32)-1;
|
||||||
|
}
|
||||||
|
return GetOrbisToSdlButtonKeycode(cbutton) + 0x10000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// syntax: 'name, name,name' or 'name,name' or 'name'
|
// syntax: 'name, name,name' or 'name,name' or 'name'
|
||||||
InputBinding GetBindingFromString(std::string& line) {
|
InputBinding GetBindingFromString(std::string& line) {
|
||||||
@ -113,21 +168,41 @@ InputBinding GetBindingFromString(std::string& line) {
|
|||||||
tokens.push_back(token);
|
tokens.push_back(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for invalid tokens and map valid ones to keys
|
// Check and process tokens
|
||||||
for (const auto& t : tokens) {
|
for (const auto& t : tokens) {
|
||||||
if (string_to_keyboard_key_map.find(t) == string_to_keyboard_key_map.end()) {
|
if (string_to_keyboard_key_map.find(t) != string_to_keyboard_key_map.end()) {
|
||||||
return InputBinding(0, 0, 0); // Skip by setting all keys to 0
|
// Map to keyboard key
|
||||||
|
u32 key_id = string_to_keyboard_key_map.at(t);
|
||||||
|
if (!key1) key1 = key_id;
|
||||||
|
else if (!key2) key2 = key_id;
|
||||||
|
else if (!key3) key3 = key_id;
|
||||||
|
}
|
||||||
|
else if (string_to_axis_map.find(t) != string_to_axis_map.end()) {
|
||||||
|
// Map to axis input ID
|
||||||
|
u32 axis_id = GetAxisInputId(string_to_axis_map.at(t));
|
||||||
|
if (axis_id == (u32)-1) {
|
||||||
|
return InputBinding(0, 0, 0);
|
||||||
|
}
|
||||||
|
if (!key1) key1 = axis_id;
|
||||||
|
else if (!key2) key2 = axis_id;
|
||||||
|
else if (!key3) key3 = axis_id;
|
||||||
|
}
|
||||||
|
else if (string_to_cbutton_map.find(t) != string_to_cbutton_map.end()) {
|
||||||
|
// Map to controller button input ID
|
||||||
|
u32 cbutton_id = GetControllerButtonInputId(string_to_cbutton_map.at(t));
|
||||||
|
if (cbutton_id == (u32)-1) {
|
||||||
|
return InputBinding(0, 0, 0);
|
||||||
|
}
|
||||||
|
if (!key1) key1 = cbutton_id;
|
||||||
|
else if (!key2) key2 = cbutton_id;
|
||||||
|
else if (!key3) key3 = cbutton_id;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Invalid token found; return default binding
|
||||||
|
return InputBinding(0, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign values to keys if all tokens were valid
|
|
||||||
if (tokens.size() > 0)
|
|
||||||
key1 = string_to_keyboard_key_map.at(tokens[0]);
|
|
||||||
if (tokens.size() > 1)
|
|
||||||
key2 = string_to_keyboard_key_map.at(tokens[1]);
|
|
||||||
if (tokens.size() > 2)
|
|
||||||
key3 = string_to_keyboard_key_map.at(tokens[2]);
|
|
||||||
|
|
||||||
return InputBinding(key1, key2, key3);
|
return InputBinding(key1, key2, key3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,8 +251,8 @@ void ParseInputConfig(const std::string game_id = "") {
|
|||||||
// Split the line by '='
|
// Split the line by '='
|
||||||
std::size_t equal_pos = line.find('=');
|
std::size_t equal_pos = line.find('=');
|
||||||
if (equal_pos == std::string::npos) {
|
if (equal_pos == std::string::npos) {
|
||||||
LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount,
|
LOG_WARNING(Input, "Invalid format at line: {}, data: \"{}\", skipping line.",
|
||||||
line);
|
lineCount, line);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +260,6 @@ void ParseInputConfig(const std::string game_id = "") {
|
|||||||
std::string input_string = line.substr(equal_pos + 1);
|
std::string input_string = line.substr(equal_pos + 1);
|
||||||
std::size_t comma_pos = input_string.find(',');
|
std::size_t comma_pos = input_string.find(',');
|
||||||
|
|
||||||
// special check for mouse to joystick input
|
|
||||||
if (output_string == "mouse_to_joystick") {
|
if (output_string == "mouse_to_joystick") {
|
||||||
if (input_string == "left") {
|
if (input_string == "left") {
|
||||||
mouse_joystick_binding = 1;
|
mouse_joystick_binding = 1;
|
||||||
@ -196,13 +270,12 @@ void ParseInputConfig(const std::string game_id = "") {
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// key toggle
|
|
||||||
if (output_string == "key_toggle") {
|
if (output_string == "key_toggle") {
|
||||||
if (comma_pos != std::string::npos) {
|
if (comma_pos != std::string::npos) {
|
||||||
// handle key-to-key toggling (separate list?)
|
// handle key-to-key toggling (separate list?)
|
||||||
InputBinding toggle_keys = GetBindingFromString(input_string);
|
InputBinding toggle_keys = GetBindingFromString(input_string);
|
||||||
if (toggle_keys.KeyCount() != 2) {
|
if (toggle_keys.KeyCount() != 2) {
|
||||||
LOG_ERROR(Input,
|
LOG_WARNING(Input,
|
||||||
"Syntax error: Please provide exactly 2 keys: "
|
"Syntax error: Please provide exactly 2 keys: "
|
||||||
"first is the toggler, the second is the key to toggle: {}",
|
"first is the toggler, the second is the key to toggle: {}",
|
||||||
line);
|
line);
|
||||||
@ -214,7 +287,7 @@ void ParseInputConfig(const std::string game_id = "") {
|
|||||||
connections.insert(connections.end(), toggle_connection);
|
connections.insert(connections.end(), toggle_connection);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
LOG_ERROR(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount,
|
LOG_WARNING(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount,
|
||||||
line);
|
line);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -225,12 +298,8 @@ void ParseInputConfig(const std::string game_id = "") {
|
|||||||
|
|
||||||
// Check for invalid input (in case there's an unexpected format)
|
// Check for invalid input (in case there's an unexpected format)
|
||||||
if (ss.fail()) {
|
if (ss.fail()) {
|
||||||
LOG_ERROR(Input, "Failed to parse mouse movement parameters from line: {}", line);
|
LOG_WARNING(Input, "Failed to parse mouse movement parameters from line: {}", line);
|
||||||
} else {
|
|
||||||
// LOG_DEBUG(Input, "Mouse movement parameters parsed: {} {} {}",
|
|
||||||
// mouse_deadzone_offset, mouse_speed, mouse_speed_offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,7 +310,7 @@ void ParseInputConfig(const std::string game_id = "") {
|
|||||||
auto axis_it = string_to_axis_map.find(output_string);
|
auto axis_it = string_to_axis_map.find(output_string);
|
||||||
|
|
||||||
if (binding.IsEmpty()) {
|
if (binding.IsEmpty()) {
|
||||||
LOG_DEBUG(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount,
|
LOG_WARNING(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount,
|
||||||
line);
|
line);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -251,12 +320,15 @@ void ParseInputConfig(const std::string game_id = "") {
|
|||||||
connections.insert(connections.end(), connection);
|
connections.insert(connections.end(), connection);
|
||||||
|
|
||||||
} else if (axis_it != string_to_axis_map.end()) {
|
} else if (axis_it != string_to_axis_map.end()) {
|
||||||
|
int value_to_set = (binding.key3 & 0x80000000) != 0 ? 0 :
|
||||||
|
(axis_it->second.axis == Axis::TriggerLeft || axis_it->second.axis == Axis::TriggerRight) ?
|
||||||
|
127 : axis_it->second.value;
|
||||||
connection = BindingConnection(
|
connection = BindingConnection(
|
||||||
binding, GetOutputPointer(ControllerOutput(0, axis_it->second.axis)),
|
binding, GetOutputPointer(ControllerOutput(0, axis_it->second.axis)),
|
||||||
axis_it->second.value);
|
value_to_set);
|
||||||
connections.insert(connections.end(), connection);
|
connections.insert(connections.end(), connection);
|
||||||
} else {
|
} else {
|
||||||
LOG_DEBUG(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount,
|
LOG_WARNING(Input, "Invalid format at line: {}, data: \"{}\", skipping line.", lineCount,
|
||||||
line);
|
line);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -270,7 +342,7 @@ void ParseInputConfig(const std::string game_id = "") {
|
|||||||
u32 GetMouseWheelEvent(const SDL_Event& event) {
|
u32 GetMouseWheelEvent(const SDL_Event& event) {
|
||||||
if (event.type != SDL_EVENT_MOUSE_WHEEL && event.type != SDL_EVENT_MOUSE_WHEEL_OFF) {
|
if (event.type != SDL_EVENT_MOUSE_WHEEL && event.type != SDL_EVENT_MOUSE_WHEEL_OFF) {
|
||||||
LOG_DEBUG(Input, "Something went wrong with wheel input parsing!");
|
LOG_DEBUG(Input, "Something went wrong with wheel input parsing!");
|
||||||
return 0;
|
return (u32)-1;
|
||||||
}
|
}
|
||||||
if (event.wheel.y > 0) {
|
if (event.wheel.y > 0) {
|
||||||
return SDL_MOUSE_WHEEL_UP;
|
return SDL_MOUSE_WHEEL_UP;
|
||||||
@ -285,6 +357,7 @@ u32 GetMouseWheelEvent(const SDL_Event& event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32 InputBinding::GetInputIDFromEvent(const SDL_Event& e) {
|
u32 InputBinding::GetInputIDFromEvent(const SDL_Event& e) {
|
||||||
|
int value_mask;
|
||||||
switch (e.type) {
|
switch (e.type) {
|
||||||
case SDL_EVENT_KEY_DOWN:
|
case SDL_EVENT_KEY_DOWN:
|
||||||
case SDL_EVENT_KEY_UP:
|
case SDL_EVENT_KEY_UP:
|
||||||
@ -295,6 +368,15 @@ u32 InputBinding::GetInputIDFromEvent(const SDL_Event& e) {
|
|||||||
case SDL_EVENT_MOUSE_WHEEL:
|
case SDL_EVENT_MOUSE_WHEEL:
|
||||||
case SDL_EVENT_MOUSE_WHEEL_OFF:
|
case SDL_EVENT_MOUSE_WHEEL_OFF:
|
||||||
return GetMouseWheelEvent(e);
|
return GetMouseWheelEvent(e);
|
||||||
|
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
|
||||||
|
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
||||||
|
return (u32)e.gbutton.button + 0x10000000; // I believe this range is unused
|
||||||
|
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|
||||||
|
// todo: somehow put this value into the correct connection
|
||||||
|
// solution 1: add it to the keycode as a 0x0FF00000 (a bit hacky but works I guess?)
|
||||||
|
// I guess in software developement, there really is nothing more permanent than a temporary solution
|
||||||
|
value_mask = (u32)((e.gaxis.value / 256 + 128) << 20); // +-32000 to +-128 to 0-255
|
||||||
|
return (u32)e.gaxis.axis + 0x80000000 + value_mask; // they are pushed to the end of the sorted array
|
||||||
default:
|
default:
|
||||||
return (u32)-1;
|
return (u32)-1;
|
||||||
}
|
}
|
||||||
@ -306,6 +388,10 @@ void ControllerOutput::SetControllerOutputController(GameController* c) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ToggleKeyInList(u32 key) {
|
void ToggleKeyInList(u32 key) {
|
||||||
|
if ((key & 0x80000000) != 0) {
|
||||||
|
LOG_ERROR(Input, "Toggling analog inputs is not supported!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto it = std::find(toggled_keys.begin(), toggled_keys.end(), key);
|
auto it = std::find(toggled_keys.begin(), toggled_keys.end(), key);
|
||||||
if (it == toggled_keys.end()) {
|
if (it == toggled_keys.end()) {
|
||||||
toggled_keys.insert(toggled_keys.end(), key);
|
toggled_keys.insert(toggled_keys.end(), key);
|
||||||
@ -327,13 +413,16 @@ void ControllerOutput::AddUpdate(bool pressed, u32 param) {
|
|||||||
new_button_state |= pressed;
|
new_button_state |= pressed;
|
||||||
new_param = param;
|
new_param = param;
|
||||||
} else if (axis != Axis::AxisMax) {
|
} else if (axis != Axis::AxisMax) {
|
||||||
float multiplier = 1.0;
|
|
||||||
switch (axis) {
|
switch (axis) {
|
||||||
case Axis::TriggerLeft:
|
case Axis::TriggerLeft:
|
||||||
case Axis::TriggerRight:
|
case Axis::TriggerRight:
|
||||||
|
// if it's a button input, then we know the value to set, so the param is 0.
|
||||||
|
// if it's an analog input, then the param isn't 0
|
||||||
|
// warning: doesn't work yet
|
||||||
new_param = SDL_clamp((pressed ? (s32)param : 0) + new_param, 0, 127);
|
new_param = SDL_clamp((pressed ? (s32)param : 0) + new_param, 0, 127);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
// todo: do the same as above
|
||||||
new_param = SDL_clamp((pressed ? (s32)param : 0) + new_param, -127, 127);
|
new_param = SDL_clamp((pressed ? (s32)param : 0) + new_param, -127, 127);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -401,6 +490,28 @@ void ControllerOutput::FinalizeUpdate() {
|
|||||||
// Updates the list of pressed keys with the given input.
|
// Updates the list of pressed keys with the given input.
|
||||||
// Returns whether the list was updated or not.
|
// Returns whether the list was updated or not.
|
||||||
bool UpdatePressedKeys(u32 value, bool is_pressed) {
|
bool UpdatePressedKeys(u32 value, bool is_pressed) {
|
||||||
|
// Skip invalid inputs
|
||||||
|
if (value == (u32)-1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((value & 0x80000000) != 0) {
|
||||||
|
// analog input, it gets added when it first sends an event,
|
||||||
|
// and from there, it only changes the parameter
|
||||||
|
// reverse iterate until we get out of the 0x8000000 range, if found,
|
||||||
|
// update the parameter, if not, add it to the end
|
||||||
|
//LOG_DEBUG(Input, "Updating an analog input...");
|
||||||
|
u32 value_to_search = value & 0xF00FFFFF;
|
||||||
|
for (auto& it = --pressed_keys.end(); (it->first & 0x80000000) != 0; it--) {
|
||||||
|
if ((it->first & 0xF00FFFFF) == value_to_search) {
|
||||||
|
it->first = value;
|
||||||
|
LOG_DEBUG(Input, "New value for {:X}: {:x}", value, value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//LOG_DEBUG(Input, "Input activated for the first time, adding it to the list");
|
||||||
|
pressed_keys.insert(pressed_keys.end(), {value, false});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (is_pressed) {
|
if (is_pressed) {
|
||||||
// Find the correct position for insertion to maintain order
|
// Find the correct position for insertion to maintain order
|
||||||
auto it =
|
auto it =
|
||||||
@ -425,9 +536,11 @@ bool UpdatePressedKeys(u32 value, bool is_pressed) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Check if a given binding's all keys are currently active.
|
// Check if a given binding's all keys are currently active.
|
||||||
bool IsInputActive(const InputBinding& i) {
|
// For now it also extracts the analog inputs' parameters.
|
||||||
// Extract keys from InputBinding and ignore unused (0) or virtually pressed keys
|
bool IsInputActive(BindingConnection& connection) {
|
||||||
std::list<uint32_t> input_keys = {i.key1, i.key2, i.key3};
|
InputBinding i = connection.binding;
|
||||||
|
// Extract keys from InputBinding and ignore unused (0) or toggled keys
|
||||||
|
std::list<u32> input_keys = {i.key1, i.key2, i.key3};
|
||||||
input_keys.remove(0);
|
input_keys.remove(0);
|
||||||
for (auto key = input_keys.begin(); key != input_keys.end();) {
|
for (auto key = input_keys.begin(); key != input_keys.end();) {
|
||||||
if (std::find(toggled_keys.begin(), toggled_keys.end(), *key) != toggled_keys.end()) {
|
if (std::find(toggled_keys.begin(), toggled_keys.end(), *key) != toggled_keys.end()) {
|
||||||
@ -436,20 +549,23 @@ bool IsInputActive(const InputBinding& i) {
|
|||||||
++key; // Increment only if no erase happened
|
++key; // Increment only if no erase happened
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (input_keys.empty()) {
|
||||||
|
LOG_DEBUG(Input, "No actual inputs to check, returning true");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Iterator for pressed_keys, starting from the beginning
|
// Iterator for pressed_keys, starting from the beginning
|
||||||
auto pressed_it = pressed_keys.begin();
|
auto pressed_it = pressed_keys.begin();
|
||||||
auto pressed_end = pressed_keys.end();
|
|
||||||
|
|
||||||
// Store pointers to flags in pressed_keys that need to be set if all keys are active
|
// Store pointers to flags in pressed_keys that need to be set if all keys are active
|
||||||
std::list<bool*> flags_to_set;
|
std::list<bool*> flags_to_set;
|
||||||
|
|
||||||
// Check if all keys in input_keys are active
|
// Check if all keys in input_keys are active
|
||||||
for (uint32_t key : input_keys) {
|
for (u32 key : input_keys) {
|
||||||
bool key_found = false;
|
bool key_found = false;
|
||||||
|
|
||||||
// Search for the current key in pressed_keys starting from the last checked position
|
// Search for the current key in pressed_keys starting from the last checked position
|
||||||
while (pressed_it != pressed_end && pressed_it->first <= key) {
|
while (pressed_it != pressed_keys.end() && (pressed_it->first & 0x80000000) == 0) {
|
||||||
if (pressed_it->first == key) {
|
if (pressed_it->first == key) {
|
||||||
|
|
||||||
key_found = true;
|
key_found = true;
|
||||||
@ -460,6 +576,20 @@ bool IsInputActive(const InputBinding& i) {
|
|||||||
}
|
}
|
||||||
++pressed_it;
|
++pressed_it;
|
||||||
}
|
}
|
||||||
|
if (!key_found && (key & 0x80000000) != 0) {
|
||||||
|
// reverse iterate over the analog inputs, as they can't be sorted
|
||||||
|
auto& rev_it = --pressed_keys.end();
|
||||||
|
for (auto rev_it = --pressed_keys.end(); (rev_it->first & 0x80000000) != 0; rev_it--) {
|
||||||
|
if ((rev_it->first & 0xF00FFFFF) == (key & 0xF00FFFFF)) {
|
||||||
|
connection.parameter = (u32)((s32)((rev_it->first & 0x0FF00000) >> 20) - 128);
|
||||||
|
LOG_DEBUG(Input, "Extracted the following param: {:X} from {:X}",
|
||||||
|
(s32)connection.parameter, rev_it->first);
|
||||||
|
key_found = true;
|
||||||
|
flags_to_set.push_back(&rev_it->second);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!key_found) {
|
if (!key_found) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -493,7 +623,8 @@ void ActivateOutputsFromInputs() {
|
|||||||
it.ResetUpdate();
|
it.ResetUpdate();
|
||||||
}
|
}
|
||||||
for (auto& it : connections) {
|
for (auto& it : connections) {
|
||||||
it.output->AddUpdate(IsInputActive(it.binding), it.parameter);
|
bool active = IsInputActive(it);
|
||||||
|
it.output->AddUpdate(active, it.parameter);
|
||||||
}
|
}
|
||||||
for (auto& it : output_array) {
|
for (auto& it : output_array) {
|
||||||
it.FinalizeUpdate();
|
it.FinalizeUpdate();
|
||||||
|
@ -49,12 +49,14 @@ const std::map<std::string, u32> string_to_cbutton_map = {
|
|||||||
{"r1", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1},
|
{"r1", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1},
|
||||||
{"l3", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3},
|
{"l3", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3},
|
||||||
{"r3", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3},
|
{"r3", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3},
|
||||||
|
{"pad_up", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP},
|
||||||
|
{"pad_down", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN},
|
||||||
|
{"pad_left", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT},
|
||||||
|
{"pad_right", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT},
|
||||||
{"options", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS},
|
{"options", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS},
|
||||||
|
|
||||||
|
// these are outputs only (touchpad can only be bound to itself)
|
||||||
{"touchpad", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD},
|
{"touchpad", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD},
|
||||||
{"up", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP},
|
|
||||||
{"down", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN},
|
|
||||||
{"left", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT},
|
|
||||||
{"right", OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT},
|
|
||||||
{"leftjoystick_halfmode", LEFTJOYSTICK_HALFMODE},
|
{"leftjoystick_halfmode", LEFTJOYSTICK_HALFMODE},
|
||||||
{"rightjoystick_halfmode", RIGHTJOYSTICK_HALFMODE},
|
{"rightjoystick_halfmode", RIGHTJOYSTICK_HALFMODE},
|
||||||
};
|
};
|
||||||
@ -67,8 +69,15 @@ const std::map<std::string, AxisMapping> string_to_axis_map = {
|
|||||||
{"axis_right_x_minus", {Input::Axis::RightX, -127}},
|
{"axis_right_x_minus", {Input::Axis::RightX, -127}},
|
||||||
{"axis_right_y_plus", {Input::Axis::RightY, 127}},
|
{"axis_right_y_plus", {Input::Axis::RightY, 127}},
|
||||||
{"axis_right_y_minus", {Input::Axis::RightY, -127}},
|
{"axis_right_y_minus", {Input::Axis::RightY, -127}},
|
||||||
{"l2", {Axis::TriggerLeft, 127}},
|
|
||||||
{"r2", {Axis::TriggerRight, 127}},
|
{"l2", {Axis::TriggerLeft, 0}},
|
||||||
|
{"r2", {Axis::TriggerRight, 0}},
|
||||||
|
|
||||||
|
// should only use these to bind analog inputs to analog outputs
|
||||||
|
{"axis_left_x", {Input::Axis::LeftX, 0}},
|
||||||
|
{"axis_left_y", {Input::Axis::LeftY, 0}},
|
||||||
|
{"axis_right_x", {Input::Axis::RightX, 0}},
|
||||||
|
{"axis_right_y", {Input::Axis::RightY, 0}},
|
||||||
};
|
};
|
||||||
const std::map<std::string, u32> string_to_keyboard_key_map = {
|
const std::map<std::string, u32> string_to_keyboard_key_map = {
|
||||||
{"a", SDLK_A},
|
{"a", SDLK_A},
|
||||||
@ -248,8 +257,8 @@ public:
|
|||||||
inline bool IsEmpty() {
|
inline bool IsEmpty() {
|
||||||
return key1 == 0 && key2 == 0 && key3 == 0;
|
return key1 == 0 && key2 == 0 && key3 == 0;
|
||||||
}
|
}
|
||||||
std::string ToString() const {
|
std::string ToString() {
|
||||||
return fmt::format("({}, {}, {})", key1, key2, key3);
|
return fmt::format("({:X}, {:X}, {:X})", key1, key2, key3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns a u32 based on the event type (keyboard, mouse buttons, or wheel)
|
// returns a u32 based on the event type (keyboard, mouse buttons, or wheel)
|
||||||
|
@ -116,14 +116,20 @@ void WindowSDL::waitEvent() {
|
|||||||
case SDL_EVENT_KEY_UP:
|
case SDL_EVENT_KEY_UP:
|
||||||
OnKeyboardMouseInput(&event);
|
OnKeyboardMouseInput(&event);
|
||||||
break;
|
break;
|
||||||
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
|
|
||||||
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
|
||||||
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|
|
||||||
case SDL_EVENT_GAMEPAD_ADDED:
|
case SDL_EVENT_GAMEPAD_ADDED:
|
||||||
case SDL_EVENT_GAMEPAD_REMOVED:
|
case SDL_EVENT_GAMEPAD_REMOVED:
|
||||||
|
controller->TryOpenSDLController();
|
||||||
|
break;
|
||||||
case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN:
|
case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN:
|
||||||
case SDL_EVENT_GAMEPAD_TOUCHPAD_UP:
|
case SDL_EVENT_GAMEPAD_TOUCHPAD_UP:
|
||||||
case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION:
|
case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION:
|
||||||
|
controller->SetTouchpadState(event.gtouchpad.finger,
|
||||||
|
event.type != SDL_EVENT_GAMEPAD_TOUCHPAD_UP,
|
||||||
|
event.gtouchpad.x, event.gtouchpad.y);
|
||||||
|
break;
|
||||||
|
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
|
||||||
|
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
||||||
|
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|
||||||
OnGamepadEvent(&event);
|
OnGamepadEvent(&event);
|
||||||
break;
|
break;
|
||||||
case SDL_EVENT_QUIT:
|
case SDL_EVENT_QUIT:
|
||||||
@ -205,99 +211,17 @@ void WindowSDL::OnKeyboardMouseInput(const SDL_Event* event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WindowSDL::OnGamepadEvent(const SDL_Event* event) {
|
void WindowSDL::OnGamepadEvent(const SDL_Event* event) {
|
||||||
using Libraries::Pad::OrbisPadButtonDataOffset;
|
|
||||||
|
|
||||||
u32 button = 0;
|
bool input_down = event->type == SDL_EVENT_GAMEPAD_AXIS_MOTION ||
|
||||||
Input::Axis axis = Input::Axis::AxisMax;
|
event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN ||
|
||||||
switch (event->type) {
|
event->type == SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN ||
|
||||||
case SDL_EVENT_GAMEPAD_ADDED:
|
event->type == SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION;
|
||||||
case SDL_EVENT_GAMEPAD_REMOVED:
|
u32 input_id = Input::InputBinding::GetInputIDFromEvent(*event);
|
||||||
controller->TryOpenSDLController();
|
|
||||||
break;
|
|
||||||
case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN:
|
|
||||||
case SDL_EVENT_GAMEPAD_TOUCHPAD_UP:
|
|
||||||
case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION:
|
|
||||||
controller->SetTouchpadState(event->gtouchpad.finger,
|
|
||||||
event->type != SDL_EVENT_GAMEPAD_TOUCHPAD_UP,
|
|
||||||
event->gtouchpad.x, event->gtouchpad.y);
|
|
||||||
break;
|
|
||||||
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
|
|
||||||
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
|
||||||
button = sdlGamepadToOrbisButton(event->gbutton.button);
|
|
||||||
if (button != 0) {
|
|
||||||
if (event->gbutton.button == SDL_GAMEPAD_BUTTON_BACK) {
|
|
||||||
std::string backButtonBehavior = Config::getBackButtonBehavior();
|
|
||||||
if (backButtonBehavior != "none") {
|
|
||||||
float x = backButtonBehavior == "left"
|
|
||||||
? 0.25f
|
|
||||||
: (backButtonBehavior == "right" ? 0.75f : 0.5f);
|
|
||||||
// trigger a touchpad event so that the touchpad emulation for back button works
|
|
||||||
controller->SetTouchpadState(0, true, x, 0.5f);
|
|
||||||
controller->CheckButton(0, button,
|
|
||||||
event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
controller->CheckButton(0, button, event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|
|
||||||
axis = event->gaxis.axis == SDL_GAMEPAD_AXIS_LEFTX ? Input::Axis::LeftX
|
|
||||||
: event->gaxis.axis == SDL_GAMEPAD_AXIS_LEFTY ? Input::Axis::LeftY
|
|
||||||
: event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHTX ? Input::Axis::RightX
|
|
||||||
: event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHTY ? Input::Axis::RightY
|
|
||||||
: event->gaxis.axis == SDL_GAMEPAD_AXIS_LEFT_TRIGGER ? Input::Axis::TriggerLeft
|
|
||||||
: event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER ? Input::Axis::TriggerRight
|
|
||||||
: Input::Axis::AxisMax;
|
|
||||||
if (axis != Input::Axis::AxisMax) {
|
|
||||||
if (event->gaxis.axis == SDL_GAMEPAD_AXIS_LEFT_TRIGGER ||
|
|
||||||
event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) {
|
|
||||||
controller->Axis(0, axis, Input::GetAxis(0, 0x8000, event->gaxis.value));
|
|
||||||
|
|
||||||
} else {
|
bool inputs_changed = Input::UpdatePressedKeys(input_id, input_down);
|
||||||
controller->Axis(0, axis, Input::GetAxis(-0x8000, 0x8000, event->gaxis.value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int WindowSDL::sdlGamepadToOrbisButton(u8 button) {
|
if (inputs_changed) {
|
||||||
using Libraries::Pad::OrbisPadButtonDataOffset;
|
Input::ActivateOutputsFromInputs();
|
||||||
|
|
||||||
switch (button) {
|
|
||||||
case SDL_GAMEPAD_BUTTON_DPAD_DOWN:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_DOWN;
|
|
||||||
case SDL_GAMEPAD_BUTTON_DPAD_UP:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_UP;
|
|
||||||
case SDL_GAMEPAD_BUTTON_DPAD_LEFT:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_LEFT;
|
|
||||||
case SDL_GAMEPAD_BUTTON_DPAD_RIGHT:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_RIGHT;
|
|
||||||
case SDL_GAMEPAD_BUTTON_SOUTH:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CROSS;
|
|
||||||
case SDL_GAMEPAD_BUTTON_NORTH:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TRIANGLE;
|
|
||||||
case SDL_GAMEPAD_BUTTON_WEST:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_SQUARE;
|
|
||||||
case SDL_GAMEPAD_BUTTON_EAST:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_CIRCLE;
|
|
||||||
case SDL_GAMEPAD_BUTTON_START:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_OPTIONS;
|
|
||||||
case SDL_GAMEPAD_BUTTON_TOUCHPAD:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD;
|
|
||||||
case SDL_GAMEPAD_BUTTON_BACK:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_TOUCH_PAD;
|
|
||||||
case SDL_GAMEPAD_BUTTON_LEFT_SHOULDER:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L1;
|
|
||||||
case SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R1;
|
|
||||||
case SDL_GAMEPAD_BUTTON_LEFT_STICK:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_L3;
|
|
||||||
case SDL_GAMEPAD_BUTTON_RIGHT_STICK:
|
|
||||||
return OrbisPadButtonDataOffset::ORBIS_PAD_BUTTON_R3;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user