diff --git a/core/input/input.cpp b/core/input/input.cpp index 357e4c06c1d..8d0686cce4d 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -831,21 +831,9 @@ void Input::joy_button(int p_device, int p_button, bool p_pressed) { return; } - const Map::Element *el = map_db[joy.mapping].buttons.find(p_button); - if (!el) { - //don't process un-mapped events for now, it could mess things up badly for devices with additional buttons/axis - //return _button_event(p_last_id, p_device, p_button, p_pressed); - return; - } + JoyEvent map = _get_mapped_button_event(map_db[joy.mapping], p_button); - JoyEvent map = el->get(); if (map.type == TYPE_BUTTON) { - //fake additional axis event for triggers - if (map.index == JOY_L2 || map.index == JOY_R2) { - float value = p_pressed ? 1.0f : 0.0f; - int axis = map.index == JOY_L2 ? JOY_ANALOG_L2 : JOY_ANALOG_R2; - _axis_event(p_device, axis, value); - } _button_event(p_device, map.index, p_pressed); return; } @@ -901,13 +889,7 @@ void Input::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) { return; }; - const Map::Element *el = map_db[joy.mapping].axis.find(p_axis); - if (!el) { - //return _axis_event(p_last_id, p_device, p_axis, p_value); - return; - }; - - JoyEvent map = el->get(); + JoyEvent map = _get_mapped_axis_event(map_db[joy.mapping], p_axis); if (map.type == TYPE_BUTTON) { //send axis event for triggers @@ -976,12 +958,26 @@ void Input::joy_hat(int p_device, int p_val) { _THREAD_SAFE_METHOD_; const Joypad &joy = joy_names[p_device]; - const JoyEvent *map; + JoyEvent map[HAT_MAX]; - if (joy.mapping == -1) { - map = hat_map_default; - } else { - map = map_db[joy.mapping].hat; + map[HAT_UP].type = TYPE_BUTTON; + map[HAT_UP].index = SDL_BUTTON_DPAD_UP; + map[HAT_UP].value = 0; + + map[HAT_RIGHT].type = TYPE_BUTTON; + map[HAT_RIGHT].index = SDL_BUTTON_DPAD_RIGHT; + map[HAT_RIGHT].value = 0; + + map[HAT_DOWN].type = TYPE_BUTTON; + map[HAT_DOWN].index = SDL_BUTTON_DPAD_DOWN; + map[HAT_DOWN].value = 0; + + map[HAT_LEFT].type = TYPE_BUTTON; + map[HAT_LEFT].index = SDL_BUTTON_DPAD_LEFT; + map[HAT_LEFT].value = 0; + + if (joy.mapping != -1) { + _get_mapped_hat_events(map_db[joy.mapping], 0, map); }; int cur_val = joy_names[p_device].hat_current; @@ -1025,50 +1021,145 @@ void Input::_axis_event(int p_device, int p_axis, float p_value) { parse_input_event(ievent); }; -Input::JoyEvent Input::_find_to_event(String p_to) { +Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, int p_button) { - // string names of the SDL buttons in the same order as input_event.h godot buttons - static const char *buttons[] = { "a", "b", "x", "y", "leftshoulder", "rightshoulder", "lefttrigger", "righttrigger", "leftstick", "rightstick", "back", "start", "dpup", "dpdown", "dpleft", "dpright", "guide", nullptr }; + JoyEvent event; + event.type = TYPE_MAX; - static const char *axis[] = { "leftx", "lefty", "rightx", "righty", nullptr }; + for (int i = 0; i < mapping.bindings.size(); i++) { + const SDLExtendedJoyBind binding = mapping.bindings[i]; + if (binding.inputType == TYPE_BUTTON && binding.input.button == p_button) { + event.type = binding.outputType; + switch (binding.outputType) { + case TYPE_BUTTON: + event.index = binding.output.button; + break; + case TYPE_AXIS: + event.index = binding.output.axis.axis; + break; + default: + ERR_PRINT_ONCE("Joypad button mapping error."); + } + } + } + return event; +} - JoyEvent ret; - ret.type = -1; - ret.index = 0; +Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, int p_axis) { - int i = 0; - while (buttons[i]) { + JoyEvent event; + event.type = TYPE_MAX; - if (p_to == buttons[i]) { - ret.type = TYPE_BUTTON; - ret.index = i; - ret.value = 0; - return ret; - }; - ++i; - }; + for (int i = 0; i < mapping.bindings.size(); i++) { + const SDLExtendedJoyBind binding = mapping.bindings[i]; + if (binding.inputType == TYPE_AXIS && binding.input.axis.axis == p_axis) { + event.type = binding.outputType; + switch (binding.outputType) { + case TYPE_BUTTON: + event.index = binding.output.button; + break; + case TYPE_AXIS: + event.index = binding.output.axis.axis; + break; + default: + ERR_PRINT_ONCE("Joypad button mapping error."); + } + } + } + return event; +} - i = 0; - while (axis[i]) { +void Input::_get_mapped_hat_events(const JoyDeviceMapping &mapping, int p_hat, JoyEvent r_events[]) { - if (p_to == axis[i]) { - ret.type = TYPE_AXIS; - ret.index = i; - ret.value = 0; - return ret; - }; - ++i; - }; + for (int i = 0; i < mapping.bindings.size(); i++) { + const SDLExtendedJoyBind binding = mapping.bindings[i]; + if (binding.inputType == TYPE_HAT && binding.input.hat.hat == p_hat) { - return ret; + int index; + switch (binding.input.hat.hat_mask) { + case HAT_MASK_UP: + index = 0; + break; + case HAT_MASK_RIGHT: + index = 1; + break; + case HAT_MASK_DOWN: + index = 2; + break; + case HAT_MASK_LEFT: + index = 3; + break; + default: + ERR_PRINT_ONCE("Joypad button mapping error."); + continue; + } + + r_events[index].type = binding.outputType; + switch (binding.outputType) { + case TYPE_BUTTON: + r_events[index].index = binding.output.button; + break; + case TYPE_AXIS: + r_events[index].index = binding.output.axis.axis; + break; + default: + ERR_PRINT_ONCE("Joypad button mapping error."); + } + } + } +} + +static const char *sdl_buttons[] = { + "a", + "b", + "x", + "y", + "back", + "guide", + "start", + "leftstick", + "rightstick", + "leftshoulder", + "rightshoulder", + "dpup", + "dpdown", + "dpleft", + "dpright", + nullptr }; +Input::SDLJoyButton Input::_get_output_button(String output) { + + for (int i = 0; sdl_buttons[i]; i++) { + if (output == sdl_buttons[i]) + return SDLJoyButton(i); + } + return SDLJoyButton::SDL_INVALID_BUTTON; +} + +static const char *sdl_axes[] = { + "leftx", + "lefty", + "rightx", + "righty", + "lefttrigger", + "righttrigger", + nullptr +}; + +Input::SDLJoyAxis Input::_get_output_axis(String output) { + + for (int i = 0; sdl_axes[i]; i++) { + if (output == sdl_axes[i]) + return SDLJoyAxis(i); + } + return SDLJoyAxis::SDL_INVALID_AXIS; +} + void Input::parse_mapping(String p_mapping) { _THREAD_SAFE_METHOD_; JoyDeviceMapping mapping; - for (int i = 0; i < HAT_MAX; ++i) - mapping.hat[i].index = 1024 + i; Vector entry = p_mapping.split(","); if (entry.size() < 2) { @@ -1087,45 +1178,83 @@ void Input::parse_mapping(String p_mapping) { if (entry[idx] == "") continue; - String from = entry[idx].get_slice(":", 1).replace(" ", ""); - String to = entry[idx].get_slice(":", 0).replace(" ", ""); + String output = entry[idx].get_slice(":", 0).replace(" ", ""); + String input = entry[idx].get_slice(":", 1).replace(" ", ""); + ERR_CONTINUE_MSG(output.length() < 1 || input.length() < 2, + String(entry[idx] + "\nInvalid device mapping entry: " + entry[idx])); - JoyEvent to_event = _find_to_event(to); - if (to_event.type == -1) + if (output == "platform") continue; - String etype = from.substr(0, 1); - if (etype == "a") { + JoyAxisRange output_range = FULL_AXIS; + if (output[0] == '+' || output[0] == '-') { + ERR_CONTINUE_MSG(output.length() < 2, String(entry[idx] + "\nInvalid output: " + entry[idx])); + output = output.right(1); + if (output[0] == '+') + output_range = POSITIVE_HALF_AXIS; + else if (output[0] == '-') + output_range = NEGATIVE_HALF_AXIS; + } - int aid = from.substr(1, from.length() - 1).to_int(); - mapping.axis[aid] = to_event; + JoyAxisRange input_range = FULL_AXIS; + if (input[0] == '+') { + input_range = POSITIVE_HALF_AXIS; + input = input.right(1); + } else if (input[0] == '-') { + input_range = NEGATIVE_HALF_AXIS; + input = input.right(1); + } + bool invert_axis = false; + if (input[input.length() - 1] == '~') + invert_axis = true; - } else if (etype == "b") { + SDLJoyButton output_button = _get_output_button(output); + SDLJoyAxis output_axis = _get_output_axis(output); + ERR_CONTINUE_MSG(output_button == SDL_INVALID_BUTTON && output_axis == SDL_INVALID_AXIS, + String(entry[idx] + "\nUnrecognised output string: " + output)); + ERR_CONTINUE_MSG(output_button != SDL_INVALID_BUTTON && output_axis != SDL_INVALID_AXIS, + String("BUG: Output string matched both button and axis: " + output)); - int bid = from.substr(1, from.length() - 1).to_int(); - mapping.buttons[bid] = to_event; + SDLExtendedJoyBind binding; + if (output_button != SDL_INVALID_BUTTON) { + binding.outputType = TYPE_BUTTON; + binding.output.button = output_button; + } else if (output_axis != SDL_INVALID_AXIS) { + binding.outputType = TYPE_AXIS; + binding.output.axis.axis = output_axis; + binding.output.axis.range = output_range; + } - } else if (etype == "h") { + switch (input[0]) { + case 'b': + binding.inputType = TYPE_BUTTON; + binding.input.button = input.right(1).to_int(); + break; + case 'a': + binding.inputType = TYPE_AXIS; + binding.input.axis.axis = input.right(1).to_int(); + binding.input.axis.range = input_range; + if (invert_axis) { + int int_range = static_cast(input_range); + int_range = -int_range; + binding.input.axis.range = static_cast(int_range); + } + break; + case 'h': + ERR_CONTINUE_MSG(input.length() != 4 || input[2] != '.', + String(entry[idx] + "\nInvalid hat input: " + input)); + binding.inputType = TYPE_HAT; + binding.input.hat.hat = input.substr(1, 1).to_int(); + binding.input.hat.hat_mask = static_cast(input.right(3).to_int()); + break; + default: + ERR_CONTINUE_MSG(true, String(entry[idx] + "\nUnrecognised input string: " + input)); + } - int hat_value = from.get_slice(".", 1).to_int(); - switch (hat_value) { - case 1: - mapping.hat[HAT_UP] = to_event; - break; - case 2: - mapping.hat[HAT_RIGHT] = to_event; - break; - case 4: - mapping.hat[HAT_DOWN] = to_event; - break; - case 8: - mapping.hat[HAT_LEFT] = to_event; - break; - }; - }; + mapping.bindings.push_back(binding); }; + map_db.push_back(mapping); - //printf("added mapping with uuid %ls\n", mapping.uid.c_str()); }; void Input::add_joy_mapping(String p_mapping, bool p_update_existing) { @@ -1268,22 +1397,6 @@ Input::Input() { event_dispatch_function = nullptr; default_shape = CURSOR_ARROW; - hat_map_default[HAT_UP].type = TYPE_BUTTON; - hat_map_default[HAT_UP].index = JOY_DPAD_UP; - hat_map_default[HAT_UP].value = 0; - - hat_map_default[HAT_RIGHT].type = TYPE_BUTTON; - hat_map_default[HAT_RIGHT].index = JOY_DPAD_RIGHT; - hat_map_default[HAT_RIGHT].value = 0; - - hat_map_default[HAT_DOWN].type = TYPE_BUTTON; - hat_map_default[HAT_DOWN].index = JOY_DPAD_DOWN; - hat_map_default[HAT_DOWN].value = 0; - - hat_map_default[HAT_LEFT].type = TYPE_BUTTON; - hat_map_default[HAT_LEFT].index = JOY_DPAD_LEFT; - hat_map_default[HAT_LEFT].value = 0; - fallback_mapping = -1; // Parse default mappings. diff --git a/core/input/input.h b/core/input/input.h index 2e136dbf020..f95dff47a96 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -183,26 +183,91 @@ private: TYPE_MAX, }; + enum SDLJoyButton { + SDL_INVALID_BUTTON = -1, + SDL_BUTTON_A, + SDL_BUTTON_B, + SDL_BUTTON_X, + SDL_BUTTON_Y, + SDL_BUTTON_BACK, + SDL_BUTTON_GUIDE, + SDL_BUTTON_START, + SDL_BUTTON_LEFTSTICK, + SDL_BUTTON_RIGHTSTICK, + SDL_BUTTON_LEFTSHOULDER, + SDL_BUTTON_RIGHTSHOULDER, + SDL_BUTTON_DPAD_UP, + SDL_BUTTON_DPAD_DOWN, + SDL_BUTTON_DPAD_LEFT, + SDL_BUTTON_DPAD_RIGHT, + SDL_BUTTON_MAX + }; + + enum SDLJoyAxis { + SDL_INVALID_AXIS = -1, + SDL_AXIS_LEFTX, + SDL_AXIS_LEFTY, + SDL_AXIS_RIGHTX, + SDL_AXIS_RIGHTY, + SDL_AXIS_TRIGGERLEFT, + SDL_AXIS_TRIGGERRIGHT, + SDL_AXIS_MAX, + }; + + enum JoyAxisRange { + NEGATIVE_HALF_AXIS = -1, + FULL_AXIS = 0, + POSITIVE_HALF_AXIS = 1 + }; + struct JoyEvent { int type; int index; int value; }; - struct JoyDeviceMapping { + struct SDLExtendedJoyBind { + JoyType inputType; + union { + int button; - String uid; - String name; - Map buttons; - Map axis; - JoyEvent hat[HAT_MAX]; + struct { + int axis; + JoyAxisRange range; + } axis; + + struct { + int hat; + HatMask hat_mask; + } hat; + + } input; + + JoyType outputType; + union { + SDLJoyButton button; + + struct { + SDLJoyAxis axis; + JoyAxisRange range; + } axis; + + } output; }; - JoyEvent hat_map_default[HAT_MAX]; + struct JoyDeviceMapping { + String uid; + String name; + Vector bindings; + }; Vector map_db; - JoyEvent _find_to_event(String p_to); + JoyEvent _get_mapped_button_event(const JoyDeviceMapping &mapping, int p_button); + JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, int p_axis); + void _get_mapped_hat_events(const JoyDeviceMapping &mapping, int p_hat, JoyEvent r_events[HAT_MAX]); + SDLJoyButton _get_output_button(String output); + SDLJoyAxis _get_output_axis(String output); void _button_event(int p_device, int p_index, bool p_pressed); void _axis_event(int p_device, int p_axis, float p_value); float _handle_deadzone(int p_device, int p_axis, float p_value); diff --git a/core/input/input_builders.py b/core/input/input_builders.py index 53b90f2073b..748ec061330 100644 --- a/core/input/input_builders.py +++ b/core/input/input_builders.py @@ -42,18 +42,7 @@ def make_default_controller_mappings(target, source, env): src_path, current_platform, platform_mappings[current_platform][guid] ) ) - valid_mapping = True - for input_map in line_parts[2:]: - if "+" in input_map or "-" in input_map or "~" in input_map: - g.write( - "// WARNING - DISCARDED UNSUPPORTED MAPPING TYPE FROM DATABASE {}: {} {}\n".format( - src_path, current_platform, line - ) - ) - valid_mapping = False - break - if valid_mapping: - platform_mappings[current_platform][guid] = line + platform_mappings[current_platform][guid] = line platform_variables = { "Linux": "#if X11_ENABLED",