-
-
Notifications
You must be signed in to change notification settings - Fork 289
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ui: Support changing controller/keyboard mappings
- Loading branch information
Showing
16 changed files
with
1,054 additions
and
209 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
enable_rumble: | ||
type: bool | ||
default: true | ||
# steel_battalion_mapping: | ||
# ... | ||
controller_mapping: | ||
a: | ||
type: integer | ||
default: 0 | ||
b: | ||
type: integer | ||
default: 1 | ||
x: | ||
type: integer | ||
default: 2 | ||
y: | ||
type: integer | ||
default: 3 | ||
back: | ||
type: integer | ||
default: 4 | ||
guide: | ||
type: integer | ||
default: 5 | ||
start: | ||
type: integer | ||
default: 6 | ||
lstick_btn: | ||
type: integer | ||
default: 7 | ||
rstick_btn: | ||
type: integer | ||
default: 8 | ||
lshoulder: | ||
type: integer | ||
default: 9 | ||
rshoulder: | ||
type: integer | ||
default: 10 | ||
dpad_up: | ||
type: integer | ||
default: 11 | ||
dpad_down: | ||
type: integer | ||
default: 12 | ||
dpad_left: | ||
type: integer | ||
default: 13 | ||
dpad_right: | ||
type: integer | ||
default: 14 | ||
axis_left_x: | ||
type: integer | ||
default: 0 | ||
axis_left_y: | ||
type: integer | ||
default: 1 | ||
axis_right_x: | ||
type: integer | ||
default: 2 | ||
axis_right_y: | ||
type: integer | ||
default: 3 | ||
axis_trigger_left: | ||
type: integer | ||
default: 4 | ||
axis_trigger_right: | ||
type: integer | ||
default: 5 | ||
invert_axis_left_x: | ||
type: bool | ||
default: false | ||
invert_axis_left_y: | ||
type: bool | ||
default: false | ||
invert_axis_right_x: | ||
type: bool | ||
default: false | ||
invert_axis_right_y: | ||
type: bool | ||
default: false |
Submodule genconfig
updated
4 files
+27 −7 | cnode.h | |
+5 −2 | example/Makefile | |
+1 −1 | example/main.cpp | |
+10 −6 | gen_config.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
/* | ||
* xemu Controller Binding Management | ||
* | ||
* Copyright (C) 2020-2023 Matt Borgerson | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include "qemu/osdep.h" | ||
#include "ui/xemu-toml.hh" | ||
#include "xemu-controllers.h" | ||
#include "xemu-settings.h" | ||
#include <assert.h> | ||
#include <locale.h> | ||
#include <string> | ||
#include <toml++/toml.h> | ||
|
||
#define DEFINE_CONFIG_TREE | ||
#include "xemu-controller-binding.h" | ||
|
||
std::pair<bool, bool> | ||
ControllerKeyboardRebindingMap::ConsumeRebindEvent(SDL_Event *event) | ||
{ | ||
if (event->type == SDL_KEYDOWN) { | ||
*(xemu_keyboard_scancode_map[table_row]) = event->key.keysym.scancode; | ||
|
||
return { true, true }; | ||
} | ||
|
||
return { false, false }; | ||
} | ||
#include <iostream> | ||
|
||
std::pair<bool, bool> | ||
ControllerGamepadRebindingMap::ConsumeRebindEvent(SDL_Event *event) | ||
{ | ||
if (event->type == SDL_CONTROLLERDEVICEREMOVED) { | ||
if (state->sdl_joystick_id == event->cdevice.which) { | ||
return { false, true }; | ||
} | ||
} else if (event->type == SDL_CONTROLLERBUTTONUP && table_row < 15 && | ||
seen_key_down) { | ||
// Bind on controller up ensures the UI does not immediately respond | ||
// once the new binding is applied | ||
|
||
if (state->sdl_joystick_id != event->cbutton.which) { | ||
return { false, false }; | ||
} | ||
|
||
int *button_map[15] = { | ||
&state->controller_map.controller_mapping.a, | ||
&state->controller_map.controller_mapping.b, | ||
&state->controller_map.controller_mapping.x, | ||
&state->controller_map.controller_mapping.y, | ||
&state->controller_map.controller_mapping.back, | ||
&state->controller_map.controller_mapping.guide, | ||
&state->controller_map.controller_mapping.start, | ||
&state->controller_map.controller_mapping.lstick_btn, | ||
&state->controller_map.controller_mapping.rstick_btn, | ||
&state->controller_map.controller_mapping.lshoulder, | ||
&state->controller_map.controller_mapping.rshoulder, | ||
&state->controller_map.controller_mapping.dpad_up, | ||
&state->controller_map.controller_mapping.dpad_down, | ||
&state->controller_map.controller_mapping.dpad_left, | ||
&state->controller_map.controller_mapping.dpad_right, | ||
}; | ||
|
||
*(button_map[table_row]) = event->cbutton.button; | ||
|
||
return { true, true }; | ||
} else if (event->type == SDL_CONTROLLERBUTTONDOWN && table_row < 15) { | ||
// If we are rebinding with a controller, we should not consume the key | ||
// up event from activating the button | ||
seen_key_down = true; | ||
} else if (event->type == SDL_CONTROLLERAXISMOTION && table_row >= 15) { | ||
// FIXME: Allow face buttons to map to axes | ||
if (state->sdl_joystick_id != event->caxis.which) { | ||
return { false, false }; | ||
} | ||
|
||
int *axis_map[6] = { | ||
&state->controller_map.controller_mapping.axis_left_x, | ||
&state->controller_map.controller_mapping.axis_left_y, | ||
&state->controller_map.controller_mapping.axis_right_x, | ||
&state->controller_map.controller_mapping.axis_right_y, | ||
&state->controller_map.controller_mapping.axis_trigger_left, | ||
&state->controller_map.controller_mapping.axis_trigger_right, | ||
}; | ||
|
||
*(axis_map[table_row - 15]) = event->caxis.axis; | ||
|
||
return { true, true }; | ||
} | ||
|
||
return { false, false }; | ||
} | ||
|
||
static const char *get_binding_path() | ||
{ | ||
static const char *binding_path = nullptr; | ||
|
||
if (!binding_path) { | ||
binding_path = | ||
g_strdup_printf("%s/bindings", xemu_settings_get_base_path()); | ||
qemu_mkdir(binding_path); | ||
} | ||
|
||
return binding_path; | ||
} | ||
|
||
void xemu_settings_load_controller_binding(const char *guid, | ||
struct controller_binding *cb) | ||
{ | ||
const char *base_path = get_binding_path(); | ||
controller_binding_tree.reset_to_defaults(); | ||
|
||
assert(strlen(guid) > 0); | ||
char *binding_path = g_strdup_printf("%s/%s.toml", base_path, guid); | ||
|
||
bool success = true; | ||
|
||
auto err = | ||
xemu_toml::load_toml_config(binding_path, controller_binding_tree); | ||
g_free(binding_path); | ||
controller_binding_tree.store_to_struct(cb); | ||
|
||
if (err) { | ||
success = false; | ||
auto error_msg = std::visit( | ||
xemu_toml::overloaded{ | ||
[](xemu_toml::file_not_found) { | ||
return std::string("Binding file not found, starting with " | ||
"default settings.\n"); | ||
}, | ||
[](xemu_toml::failed_to_open) { | ||
return std::string("Failed to open binding file for " | ||
"reading. Check permissions.\n"); | ||
}, | ||
[](xemu_toml::failed_to_read) { | ||
return std::string("Failed to read binding file.\n"); | ||
}, | ||
[](toml::parse_error &err) { | ||
std::ostringstream oss; | ||
oss << "Error parsing config file at " << err.source().begin | ||
<< ":\n" | ||
<< " " << err.description() << "\n" | ||
<< "Please fix the error or delete the file to " | ||
"continue.\n"; | ||
return oss.str(); | ||
}, | ||
}, | ||
*err); | ||
|
||
fprintf(stderr, "%s", error_msg.c_str()); | ||
} | ||
|
||
if (!success) { | ||
xemu_settings_save_controller_binding(guid, cb); | ||
} | ||
} | ||
|
||
void xemu_settings_save_controller_binding(const char *guid, | ||
struct controller_binding *cb) | ||
{ | ||
const char *base_path = get_binding_path(); | ||
|
||
assert(strlen(guid) > 0); | ||
char *binding_path = g_strdup_printf("%s/%s.toml", base_path, guid); | ||
|
||
auto err = | ||
xemu_toml::save_toml_config(binding_path, controller_binding_tree, cb); | ||
g_free(binding_path); | ||
if (err) { | ||
fprintf( | ||
stderr, | ||
"Failed to open binding file for writing. Check permissions.\n"); | ||
} | ||
} |
Oops, something went wrong.