Skip to content

Commit 4124f10

Browse files
authored
Merge pull request #15392 from Tovarichtch/fixfsuaeinputs
fix fs-uae inputs
2 parents 831c8ce + 6b1b600 commit 4124f10

4 files changed

Lines changed: 147 additions & 19 deletions

File tree

package/batocera/core/batocera-configgen/configgen/configgen/generators/fsuae/fsuaeControllers.py

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,18 @@
1010
from ...Emulator import Emulator
1111

1212

13+
def _build_long_config_name(name, buttons, axes, hats):
14+
# e.g.: "Xbox Wireless Controller", 11, 6, 1 → "xbox_wireless_controller_11_6_1_0_linux"
15+
name = name.split('#')[0].lower().strip()
16+
for c in name:
17+
if not c.isalnum() and c != '_':
18+
name = name.replace(c, '_')
19+
# collapse consecutive underscores
20+
while '__' in name:
21+
name = name.replace('__', '_')
22+
name = name.strip('_')
23+
return f"{name}_{buttons}_{axes}_{hats}_0_linux"
24+
1325
# Create the controller configuration file
1426
def generateControllerConfig(system: Emulator, playersControllers: Controllers) -> None:
1527

@@ -36,37 +48,46 @@ def generateControllerConfig(system: Emulator, playersControllers: Controllers)
3648
mkdir_if_not_exists(confDirectory)
3749

3850
for pad in playersControllers:
39-
configFileName = confDirectory / f"{pad.guid}_linux.conf"
40-
f = configFileName.open("w")
41-
42-
# fs-uae-controller
43-
f.write("[fs-uae-controller]\n")
44-
f.write(f"name = {pad.real_name}\n")
45-
f.write("platform = linux\n")
46-
f.write("\n")
47-
48-
# events
49-
f.write("[default]\n")
50-
f.write("include = universal_gamepad\n")
51+
# Build mapping lines to reuse for both config files
52+
mapping_lines = []
5153

5254
for x in pad.inputs:
5355
input = pad.inputs[x]
5456
#f.write(f"# undefined key: name={input.name}, type={input.type}, id={input.id}, value={input.value}\n")
5557

5658
if input.name in fsuaeMapping:
5759
if input.type == "button":
58-
f.write(f"button_{input.id} = {fsuaeMapping[input.name]}\n")
60+
mapping_lines.append(f"button_{input.id} = {fsuaeMapping[input.name]}\n")
5961
elif input.type == "hat":
6062
if input.value in fsuaeHatMapping:
61-
f.write(f"hat_{input.id}_{fsuaeHatMapping[input.value]} = {fsuaeMapping[input.name]}\n")
63+
mapping_lines.append(f"hat_{input.id}_{fsuaeHatMapping[input.value]} = {fsuaeMapping[input.name]}\n")
6264
elif input.type == "axis":
6365
if input.value == "1":
6466
axis_valstr = "pos"
6567
revaxis_valstr = "neg"
6668
else:
6769
axis_valstr = "neg"
6870
revaxis_valstr = "pos"
69-
f.write(f"axis_{input.id}_{axis_valstr} = {fsuaeMapping[input.name]}\n")
71+
mapping_lines.append(f"axis_{input.id}_{axis_valstr} = {fsuaeMapping[input.name]}\n")
7072
if input.name in fsuaeReverseAxisMapping and fsuaeReverseAxisMapping[input.name] in fsuaeMapping:
71-
f.write(f"axis_{input.id}_{revaxis_valstr} = {fsuaeMapping[fsuaeReverseAxisMapping[input.name]]}\n")
72-
f.close()
73+
mapping_lines.append(f"axis_{input.id}_{revaxis_valstr} = {fsuaeMapping[fsuaeReverseAxisMapping[input.name]]}\n")
74+
75+
# Write config for both GUID lookup (joystick config) and long-name lookup (menu config)
76+
long_name = _build_long_config_name(pad.real_name, pad.button_count, pad.axis_count, pad.hat_count)
77+
for config_name in [pad.guid.lower(), long_name]:
78+
configFileName = confDirectory / f"{config_name}.conf"
79+
f = configFileName.open("w")
80+
81+
# fs-uae-controller
82+
f.write("[fs-uae-controller]\n")
83+
f.write(f"name = {pad.real_name}\n")
84+
f.write("platform = linux\n")
85+
f.write("\n")
86+
87+
# events
88+
f.write("[default]\n")
89+
f.write("include = universal_gamepad\n")
90+
91+
for line in mapping_lines:
92+
f.write(line)
93+
f.close()

package/batocera/core/batocera-configgen/configgen/configgen/generators/fsuae/fsuaeGenerator.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from typing import TYPE_CHECKING
88

99
from ... import Command
10+
from ...controller import generate_sdl_game_controller_config
1011
from ..Generator import Generator
1112
from . import fsuaeControllers
1213
from .fsuaePaths import FSUAE_BIOS_DIR, FSUAE_CONFIG_DIR, FSUAE_SAVES
@@ -108,4 +109,9 @@ def generate(self, system, rom, playersControllers, metadata, guns, wheels, game
108109
for n, pad in enumerate(playersControllers[:4]):
109110
commandArray.append(f"--joystick_port_{n}={pad.real_name}")
110111

111-
return Command.Command(array=commandArray)
112+
# SDL GameController mappings for virtual mouse (right stick + R3 click)
113+
env = {
114+
"SDL_GAMECONTROLLERCONFIG": generate_sdl_game_controller_config(playersControllers)
115+
}
116+
117+
return Command.Command(array=commandArray, env=env)
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
--- a/libfsemu/src/ml/input.c
2+
+++ b/libfsemu/src/ml/input.c
3+
@@ -203,7 +203,7 @@
4+
{
5+
FS_ML_INIT_ONCE;
6+
7+
- SDL_Init(SDL_INIT_JOYSTICK);
8+
+ SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
9+
10+
fs_log("[INPUT] fs_ml_input_init\n");
11+
12+
@@ -336,6 +336,15 @@
13+
}
14+
15+
g_fs_ml_sdl_joystick_index_map[instance_id] = k;
16+
+
17+
+ if (SDL_IsGameController(i)) {
18+
+ SDL_GameController *gc = SDL_GameControllerOpen(i);
19+
+ if (gc) {
20+
+ fs_log("[INPUT] Device #%d opened as GameController: %s\n",
21+
+ i, SDL_GameControllerName(gc));
22+
+ }
23+
+ }
24+
+
25+
k += 1;
26+
}
27+
28+
--- a/libfsemu/src/ml/sdl.c
29+
+++ b/libfsemu/src/ml/sdl.c
30+
@@ -886,6 +886,32 @@
31+
g_fs_ml_video_height = height;
32+
}
33+
34+
+static int g_virtual_mouse_rx = 0;
35+
+static int g_virtual_mouse_ry = 0;
36+
+#define VIRTUAL_MOUSE_DEADZONE 8000
37+
+#define VIRTUAL_MOUSE_SPEED 10.0f
38+
+
39+
+static void process_virtual_mouse(void)
40+
+{
41+
+ int xrel = 0, yrel = 0;
42+
+ if (abs(g_virtual_mouse_rx) > VIRTUAL_MOUSE_DEADZONE) {
43+
+ xrel = (int)((float)g_virtual_mouse_rx / 32767.0f * VIRTUAL_MOUSE_SPEED);
44+
+ }
45+
+ if (abs(g_virtual_mouse_ry) > VIRTUAL_MOUSE_DEADZONE) {
46+
+ yrel = (int)((float)g_virtual_mouse_ry / 32767.0f * VIRTUAL_MOUSE_SPEED);
47+
+ }
48+
+ if (xrel != 0 || yrel != 0) {
49+
+ fs_ml_event *me = fs_ml_alloc_event();
50+
+ me->type = FS_ML_MOUSEMOTION;
51+
+ me->motion.device = g_fs_ml_first_mouse_index;
52+
+ me->motion.xrel = xrel;
53+
+ me->motion.yrel = yrel;
54+
+ me->motion.x = FS_ML_NO_ABSOLUTE_MOUSE_POS;
55+
+ me->motion.y = FS_ML_NO_ABSOLUTE_MOUSE_POS;
56+
+ fs_ml_post_event(me);
57+
+ }
58+
+}
59+
+
60+
int fs_ml_event_loop(void)
61+
{
62+
// printf("fs_ml_event_loop\n");
63+
@@ -1034,6 +1060,25 @@
64+
new_event->key.keysym.mod = event.key.keysym.mod;
65+
new_event->key.state = event.key.state;
66+
}
67+
+ else if (event.type == SDL_CONTROLLERAXISMOTION) {
68+
+ if (event.caxis.axis == SDL_CONTROLLER_AXIS_RIGHTX) {
69+
+ g_virtual_mouse_rx = event.caxis.value;
70+
+ } else if (event.caxis.axis == SDL_CONTROLLER_AXIS_RIGHTY) {
71+
+ g_virtual_mouse_ry = event.caxis.value;
72+
+ }
73+
+ }
74+
+ else if (event.type == SDL_CONTROLLERBUTTONDOWN ||
75+
+ event.type == SDL_CONTROLLERBUTTONUP) {
76+
+ if (event.cbutton.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK) {
77+
+ int pressed = (event.type == SDL_CONTROLLERBUTTONDOWN);
78+
+ new_event = fs_ml_alloc_event();
79+
+ new_event->type = pressed ? FS_ML_MOUSEBUTTONDOWN
80+
+ : FS_ML_MOUSEBUTTONUP;
81+
+ new_event->button.device = g_fs_ml_first_mouse_index;
82+
+ new_event->button.button = FS_ML_BUTTON_LEFT;
83+
+ new_event->button.state = pressed;
84+
+ }
85+
+ }
86+
else if (event.type == SDL_JOYBUTTONDOWN) {
87+
if (g_fs_log_input) {
88+
fs_log("SDL_JOYBUTTONDOWN which %d button %d state %d\n",
89+
@@ -1171,6 +1216,7 @@
90+
fs_ml_post_event(new_event);
91+
}
92+
}
93+
+ process_virtual_mouse();
94+
return result;
95+
}
96+

package/batocera/emulators/fsuae/fsuae.mk

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,12 @@ define FSUAE_INSTALL_EVMAPY
2929
$(TARGET_DIR)/usr/share/evmapy/
3030
endef
3131

32-
FSUAE_POST_INSTALL_TARGET_HOOKS = FSUAE_INSTALL_EVMAPY
32+
define FSUAE_INSTALL_INPUT_DATA
33+
mkdir -p $(TARGET_DIR)/usr/share/fs-uae/input
34+
cp -r $(@D)/share/fs-uae/input/* $(TARGET_DIR)/usr/share/fs-uae/input/
35+
endef
36+
37+
FSUAE_POST_INSTALL_TARGET_HOOKS += FSUAE_INSTALL_EVMAPY FSUAE_INSTALL_INPUT_DATA
3338

3439
$(eval $(autotools-package))
3540
$(eval $(emulator-info-package))

0 commit comments

Comments
 (0)