1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include <uae/uae.h>
9 #include <fs/emu.h>
10 #include <fs/emu/actions.h>
11 #include "fs-uae.h"
12 #include "config-common.h"
13 #include "options.h"
14
15 fs_uae_input_port g_fs_uae_input_ports[FS_UAE_NUM_INPUT_PORTS] = {};
16
17 #define NO_ACTION 65536
18
19 #define COMMON_ACTIONS \
20 { "menu_alt", FS_EMU_ACTION_MENU_ALT }, \
21 { "pause", FS_EMU_ACTION_PAUSE }
22
23 #define CUSTOM_ACTIONS \
24 { "left", NO_ACTION }, \
25 { "right", NO_ACTION }, \
26 { "up", NO_ACTION }, \
27 { "down", NO_ACTION }, \
28 { "1", NO_ACTION }, \
29 { "2", NO_ACTION }
30
31 #define END_ACTIONS { NULL, 0 }
32
33 static fs_emu_input_mapping g_joystick_port_0_mapping[] = {
34 { "left", INPUTEVENT_JOY1_LEFT },
35 { "right", INPUTEVENT_JOY1_RIGHT },
36 { "up", INPUTEVENT_JOY1_UP },
37 { "down", INPUTEVENT_JOY1_DOWN },
38 { "1", INPUTEVENT_JOY1_FIRE_BUTTON },
39 { "2", INPUTEVENT_JOY1_2ND_BUTTON },
40 { "3", INPUTEVENT_JOY1_3RD_BUTTON },
41 { "red", INPUTEVENT_JOY1_CD32_RED },
42 { "yellow", INPUTEVENT_JOY1_CD32_YELLOW },
43 { "green", INPUTEVENT_JOY1_CD32_GREEN },
44 { "blue", INPUTEVENT_JOY1_CD32_BLUE },
45 { "rewind", INPUTEVENT_JOY1_CD32_RWD },
46 { "forward", INPUTEVENT_JOY1_CD32_FFW },
47 { "play", INPUTEVENT_JOY1_CD32_PLAY },
48 { "autofire", INPUTEVENT_JOY1_AUTOFIRE_BUTTON },
49 { "toggle_autofire", INPUTEVENT_AMIGA_JOYPORT_0_AUTOFIRE },
50 COMMON_ACTIONS,
51 END_ACTIONS
52 };
53
54 static fs_emu_input_mapping g_joystick_port_1_mapping[] = {
55 { "left", INPUTEVENT_JOY2_LEFT },
56 { "right", INPUTEVENT_JOY2_RIGHT },
57 { "up", INPUTEVENT_JOY2_UP },
58 { "down", INPUTEVENT_JOY2_DOWN },
59 { "1", INPUTEVENT_JOY2_FIRE_BUTTON },
60 { "2", INPUTEVENT_JOY2_2ND_BUTTON },
61 { "3", INPUTEVENT_JOY2_3RD_BUTTON },
62 { "red", INPUTEVENT_JOY2_CD32_RED },
63 { "yellow", INPUTEVENT_JOY2_CD32_YELLOW },
64 { "green", INPUTEVENT_JOY2_CD32_GREEN },
65 { "blue", INPUTEVENT_JOY2_CD32_BLUE },
66 { "rewind", INPUTEVENT_JOY2_CD32_RWD },
67 { "forward", INPUTEVENT_JOY2_CD32_FFW },
68 { "play", INPUTEVENT_JOY2_CD32_PLAY },
69 { "autofire", INPUTEVENT_JOY2_AUTOFIRE_BUTTON },
70 { "toggle_autofire", INPUTEVENT_AMIGA_JOYPORT_1_AUTOFIRE },
71 COMMON_ACTIONS,
72 END_ACTIONS
73 };
74
75 static fs_emu_input_mapping g_parallel_port_1st_mapping[] = {
76 { "left", INPUTEVENT_PAR_JOY1_LEFT },
77 { "right", INPUTEVENT_PAR_JOY1_RIGHT },
78 { "up", INPUTEVENT_PAR_JOY1_UP },
79 { "down", INPUTEVENT_PAR_JOY1_DOWN },
80 { "1", INPUTEVENT_PAR_JOY1_FIRE_BUTTON },
81 { "2", INPUTEVENT_PAR_JOY1_2ND_BUTTON },
82 { "autofire", INPUTEVENT_PAR_JOY1_AUTOFIRE_BUTTON },
83 { "toggle_autofire", INPUTEVENT_AMIGA_JOYPORT_2_AUTOFIRE },
84 COMMON_ACTIONS,
85 END_ACTIONS
86 };
87
88 static fs_emu_input_mapping g_parallel_port_2nd_mapping[] = {
89 { "left", INPUTEVENT_PAR_JOY2_LEFT },
90 { "right", INPUTEVENT_PAR_JOY2_RIGHT },
91 { "up", INPUTEVENT_PAR_JOY2_UP },
92 { "down", INPUTEVENT_PAR_JOY2_DOWN },
93 { "1", INPUTEVENT_PAR_JOY2_FIRE_BUTTON },
94 { "2", INPUTEVENT_PAR_JOY2_2ND_BUTTON },
95 { "autofire", INPUTEVENT_PAR_JOY2_AUTOFIRE_BUTTON },
96 { "toggle_autofire", INPUTEVENT_AMIGA_JOYPORT_3_AUTOFIRE },
97 COMMON_ACTIONS,
98 END_ACTIONS
99 };
100
101 static fs_emu_input_mapping g_port_4_mapping[] = {
102 CUSTOM_ACTIONS,
103 END_ACTIONS
104 };
105
106 static fs_emu_input_mapping g_port_5_mapping[] = {
107 CUSTOM_ACTIONS,
108 END_ACTIONS
109 };
110
111 static fs_emu_input_mapping g_port_6_mapping[] = {
112 CUSTOM_ACTIONS,
113 END_ACTIONS
114 };
115
116 static fs_emu_input_mapping g_port_7_mapping[] = {
117 CUSTOM_ACTIONS,
118 END_ACTIONS
119 };
120
121 static fs_emu_input_mapping *g_joystick_mappings[] = {
122 g_joystick_port_0_mapping,
123 g_joystick_port_1_mapping,
124 g_parallel_port_1st_mapping,
125 g_parallel_port_2nd_mapping,
126 /* Custom ports (maps to UAE actions, if configured) */
127 g_port_4_mapping,
128 g_port_5_mapping,
129 g_port_6_mapping,
130 g_port_7_mapping,
131 };
132
fs_uae_read_override_actions_for_port(int port)133 void fs_uae_read_override_actions_for_port(int port)
134 {
135 fs_log("fs_uae_read_override_actions_for_port %d\n", port);
136 fs_emu_input_mapping *mapping = g_joystick_mappings[port];
137 for (int i = 0; mapping[i].name != NULL; i++) {
138 const char* name = mapping[i].name;
139 if (strcmp(name, "1") == 0) {
140 name = "primary";
141 } else if (strcmp(name, "2") == 0) {
142 name = "secondary";
143 }
144 char *key = g_strdup_printf("joystick_port_%d_%s", port, name);
145 const char *value = fs_config_get_const_string(key);
146 if (value == NULL) {
147 continue;
148 }
149 fs_log("check %s = %s\n", key, value);
150 int action = fs_emu_input_action_from_string(value);
151 if (action > -1) {
152 fs_log("override %s => %s (%d)\n", key, value, action);
153 mapping[i].action = action;
154 }
155 free(key);
156 }
157 }
158
map_mouse(const char * device_name,int port)159 static void map_mouse(const char *device_name, int port)
160 {
161 fs_log("mapping mouse to port %d\n", port);
162 if (port == 0) {
163 fs_emu_configure_mouse(device_name, INPUTEVENT_MOUSE1_HORIZ,
164 INPUTEVENT_MOUSE1_VERT, INPUTEVENT_JOY1_FIRE_BUTTON,
165 INPUTEVENT_JOY1_3RD_BUTTON, INPUTEVENT_JOY1_2ND_BUTTON,
166 INPUTEVENT_MOUSE1_WHEEL);
167 } else if (port == 1) {
168 fs_emu_configure_mouse(device_name, INPUTEVENT_MOUSE2_HORIZ,
169 INPUTEVENT_MOUSE2_VERT, INPUTEVENT_JOY2_FIRE_BUTTON,
170 INPUTEVENT_JOY2_3RD_BUTTON, INPUTEVENT_JOY2_2ND_BUTTON,
171 0);
172 }
173 else {
174 fs_log("WARNING: cannot map mouse to this port\n");
175 }
176 }
177
auto_joystick(fs_uae_input_port * p,int port,int mode,const char * type)178 static void auto_joystick(
179 fs_uae_input_port *p, int port, int mode, const char *type)
180 {
181 fs_emu_log("trying to auto-configure joystick in port %d\n", port);
182 p->new_mode = mode;
183 int result = fs_emu_configure_joystick(
184 "JOYSTICK", type, g_joystick_mappings[port], 1,
185 g_fs_uae_input_ports[port].device, MAX_DEVICE_NAME_LEN, false);
186 if (!result) {
187 result = fs_emu_configure_joystick(
188 "JOYSTICK #2", type, g_joystick_mappings[port], 1,
189 g_fs_uae_input_ports[port].device, MAX_DEVICE_NAME_LEN, false);
190 }
191 if (!result) {
192 fs_emu_log("could not auto-configure joystick,"
193 "using keyboard emulation\n");
194 strcpy(p->device, "KEYBOARD");
195 }
196 }
197
configure_joystick_port(int port,const char * value,const char * port_name,const char * joy_dev)198 static void configure_joystick_port(
199 int port, const char *value, const char *port_name, const char *joy_dev)
200 {
201 fs_emu_log("configuring joystick port %d (%s)\n", port, value);
202 fs_uae_input_port *p = g_fs_uae_input_ports + port;
203
204 const char *auto_type = "amiga";
205 int auto_mode = AMIGA_JOYPORT_DJOY;
206 if (g_fs_uae_amiga_model == MODEL_CD32) {
207 auto_type = "cd32";
208 auto_mode = AMIGA_JOYPORT_CD32JOY;
209 }
210 char *key = g_strdup_printf("joystick_port_%d_mode", port);
211 const char *mode_string = fs_config_get_const_string(key);
212 free(key);
213
214 if (g_ascii_strcasecmp(value, "nothing") == 0
215 || g_ascii_strcasecmp(value, "none") == 0) {
216 fs_emu_log("nothing connected to port\n");
217 strcpy(p->device, "");
218 p->new_mode = AMIGA_JOYPORT_NONE;
219 } else if (g_ascii_strcasecmp(value, "auto") == 0 && port < 2) {
220 if (port == 0) {
221 if (!mode_string
222 || g_ascii_strcasecmp(mode_string, "mouse") == 0) {
223 p->new_mode = AMIGA_JOYPORT_MOUSE;
224 strcpy(p->device, "MOUSE");
225 } else if (g_ascii_strcasecmp(mode_string, "joystick") == 0) {
226 auto_joystick(p, port, AMIGA_JOYPORT_DJOY, "amiga");
227 } else if (g_ascii_strcasecmp(mode_string, "cd32 gamepad") == 0) {
228 auto_joystick(p, port, AMIGA_JOYPORT_CD32JOY, "cd32");
229 }
230 } else {
231 auto_joystick(p, port, auto_mode, auto_type);
232 #if 0
233 fs_emu_log("trying to auto-configure joystick 1 in port 1\n");
234 p->new_mode = auto_mode;
235 int result = fs_emu_configure_joystick("JOYSTICK", auto_type,
236 g_joystick_mappings[port], 1,
237 g_fs_uae_input_ports[port].device, MAX_DEVICE_NAME_LEN);
238 if (!result) {
239 fs_emu_log("could not auto-configure joystick 1, "
240 "using keyboard emulation\n");
241 strcpy(p->device, "KEYBOARD");
242 }
243 #endif
244 }
245 } else if (g_ascii_strcasecmp(value, "dummy mouse") == 0) {
246 p->new_mode = AMIGA_JOYPORT_MOUSE;
247 } else if (g_ascii_strcasecmp(value, "dummy joystick") == 0) {
248 p->new_mode = AMIGA_JOYPORT_DJOY;
249 } else if (g_ascii_strcasecmp(value, "mouse") == 0) {
250 strcpy(p->device, "MOUSE");
251 p->new_mode = AMIGA_JOYPORT_MOUSE;
252 }
253 // deprecated
254 else if (g_ascii_strcasecmp(value, "amiga_mouse") == 0) {
255 p->new_mode = AMIGA_JOYPORT_MOUSE;
256 }
257 // deprecated
258 else if (g_ascii_strcasecmp(value, "amiga_joystick") == 0) {
259 p->new_mode = AMIGA_JOYPORT_DJOY;
260 } else {
261 p->new_mode = auto_mode;
262 fs_emu_configure_joystick(value, auto_type,
263 g_joystick_mappings[port], 1,
264 p->device, MAX_DEVICE_NAME_LEN, false);
265 }
266
267 if (mode_string) {
268 char *mode_lower = g_ascii_strdown(mode_string, -1);
269 if (strcmp(mode_lower, "joystick") == 0) {
270 p->new_mode = AMIGA_JOYPORT_DJOY;
271 } else if (strcmp(mode_lower, "mouse") == 0) {
272 p->new_mode = AMIGA_JOYPORT_MOUSE;
273 } else if (strcmp(mode_lower, "cd32 gamepad") == 0) {
274 p->new_mode = AMIGA_JOYPORT_CD32JOY;
275 } else if (strcmp(mode_lower, "nothing") == 0) {
276 p->new_mode = AMIGA_JOYPORT_NONE;
277 } else if (strcmp(mode_lower, "none") == 0) {
278 p->new_mode = AMIGA_JOYPORT_NONE;
279 } else if (strcmp(mode_lower, "custom") == 0) {
280 // FIXME: custom is not fully implemented as its own type
281 p->new_mode = AMIGA_JOYPORT_DJOY;
282 } else {
283 fs_log("unknown joystick port mode: %s\n", mode_lower);
284 }
285 free(mode_lower);
286 }
287
288 if (port < 4) {
289 // port 4 is "custom joystick"
290 key = g_strdup_printf("joystick_port_%d_autofire", port);
291 if (fs_config_get_boolean(key) == 1) {
292 p->new_autofire_mode = 1;
293 p->autofire_mode = 1;
294 amiga_set_joystick_port_autofire(port, 1);
295 }
296 free(key);
297 } else {
298 /* This is a fake joystick, can be used to map keyboard pressed
299 * for example, mode is not set throught input actions, since
300 * this need not be synchronized in net play. */
301 p->mode = p->new_mode;
302 }
303 }
304
fs_uae_configure_input()305 void fs_uae_configure_input()
306 {
307 fs_uae_configure_mouse();
308 fs_emu_log("configuring joystick ports:\n");
309 amiga_set_option("joyport0", "none");
310 amiga_set_option("joyport1", "none");
311
312 fs_uae_configure_actions();
313
314 char *value;
315 value = fs_config_get_string("joystick_port_1");
316 if (!value) {
317 value = g_strdup("auto");
318 }
319 configure_joystick_port(1, value, "joyport1", "joy1");
320 g_free(value);
321 value = fs_config_get_string("joystick_port_0");
322 if (!value) {
323 value = g_strdup("auto");
324 }
325 configure_joystick_port(0, value, "joyport0", "joy0");
326 g_free(value);
327
328 for (int i = 2; i < FS_UAE_NUM_INPUT_PORTS; i++) {
329 gchar *key = g_strdup_printf("joystick_port_%d", i);
330 value = fs_config_get_string(key);
331 g_free(key);
332 if (value == NULL) {
333 value = g_strdup("nothing");
334 }
335 gchar *key2 = g_strdup_printf("joyport%d", i);
336 gchar *key3 = g_strdup_printf("joy%d", i);
337 configure_joystick_port(i, value, key2, key3);
338 g_free(key3);
339 g_free(key2);
340 g_free(value);
341 }
342 }
343
fs_uae_reconfigure_input_ports_amiga()344 void fs_uae_reconfigure_input_ports_amiga()
345 {
346 fs_emu_log("fs_uae_reconfigure_input_ports_amiga\n");
347 int modes = INPUTEVENT_AMIGA_JOYPORT_MODE_0_LAST -
348 INPUTEVENT_AMIGA_JOYPORT_MODE_0_NONE + 1;
349 //for (int i = 0; i < FS_UAE_NUM_INPUT_PORTS; i++) {
350 // only the 4 real ports are reconfigured via input events, the 5th
351 // custom joystick port is a local virtual joystick for mapping custom
352 // input events only
353 for (int i = 0; i < 4; i++) {
354 fs_uae_input_port *port = g_fs_uae_input_ports + i;
355 if (port->new_mode != port->mode) {
356 fs_log("sending event to set port %d to mode %d\n", i, port->new_mode);
357 int action = INPUTEVENT_AMIGA_JOYPORT_MODE_0_NONE + modes * i + \
358 port->new_mode;
359 fs_emu_queue_action(action, 1);
360 }
361 if (port->new_autofire_mode != port->autofire_mode) {
362 fs_log("sending event to set port %d to autofire mode %d\n", i,
363 port->new_autofire_mode);
364 int action = INPUTEVENT_AMIGA_JOYPORT_0_AUTOFIRE + i;
365 fs_emu_queue_action(action, 1);
366 }
367 }
368 }
369
fs_uae_reconfigure_input_ports_host()370 void fs_uae_reconfigure_input_ports_host()
371 {
372 fs_emu_log("fs_uae_reconfigure_input_ports_host\n");
373 fs_emu_reset_input_mapping();
374 fs_uae_map_keyboard();
375
376 int mouse_mapped_to_port = -1;
377
378 for (int i = 0; i < FS_UAE_NUM_INPUT_PORTS; i++) {
379 fs_uae_input_port *port = g_fs_uae_input_ports + i;
380
381 fs_log("configuring joystick port %d\n", i);
382 if (port->mode == AMIGA_JOYPORT_NONE) {
383 fs_log("* nothing in port\n");
384 fs_log("* FIXME\n");
385 }
386 else if (port->mode == AMIGA_JOYPORT_MOUSE) {
387 fs_log("* amiga mouse\n");
388 // if (strcmp(port->device, "MOUSE") == 0) {
389 // fs_log("* using host mouse\n");
390 fs_log("* using device %s\n", port->device);
391 map_mouse(port->device, i);
392 mouse_mapped_to_port = i;
393 // }
394 // else {
395 // fs_log("* not mapping host device to amiga mouse\n");
396 // }
397 }
398 else if (port->mode == AMIGA_JOYPORT_DJOY) {
399 fs_log("* amiga joystick\n");
400 if (strcmp(port->device, "MOUSE") == 0) {
401 fs_log("* cannot map mouse to joystick\n");
402 }
403 else {
404 fs_log("* using device %s\n", port->device);
405 fs_emu_configure_joystick(port->device, "amiga",
406 g_joystick_mappings[i], 1, NULL, 0, true);
407 }
408 }
409 else if (port->mode == AMIGA_JOYPORT_CD32JOY) {
410 fs_log("* amiga cd32 gamepad\n");
411 if (strcmp(port->device, "MOUSE") == 0) {
412 fs_log("* cannot map mouse to cd32 gamepad\n");
413 }
414 else {
415 fs_log("* using device %s\n", port->device);
416 fs_emu_configure_joystick(port->device, "cd32",
417 g_joystick_mappings[i], 1, NULL, 0, true);
418 }
419 }
420 }
421
422 fs_uae_input_port *port0 = g_fs_uae_input_ports;
423
424 #if 0
425 int autoswitch = fs_config_get_boolean("joystick_port_0_autoswitch");
426 if (autoswitch == FS_CONFIG_NONE) {
427 autoswitch = 0;
428 }
429
430 if (!autoswitch) {
431 if (mouse_mapped_to_port == -1 && port0->mode != AMIGA_JOYPORT_NONE) {
432 // there is a device in port 0, but mouse is not use in either
433 // port
434 fs_log("additionally mapping mouse buttons to port 0\n");
435 fs_emu_configure_mouse("MOUSE", 0, 0, INPUTEVENT_JOY1_FIRE_BUTTON,
436 0, INPUTEVENT_JOY1_2ND_BUTTON, 0);
437 }
438 }
439 #endif
440
441 int autoswitch = fs_config_get_boolean(OPTION_JOYSTICK_PORT_0_AUTOSWITCH);
442 if (autoswitch != 0) {
443 if (mouse_mapped_to_port == -1 && port0->mode == AMIGA_JOYPORT_DJOY) {
444 fs_log("additionally mapping mouse to port 0\n");
445 map_mouse("mouse", 0);
446 }
447 }
448
449 #if 0
450 if (autoswitch && !fs_emu_netplay_enabled()) {
451 // auto-select for other devices when not in netplay mode
452
453 if (mouse_mapped_to_port == -1) {
454 // FIXME: device "9" is a bit of a hack here, should promote
455 fs_emu_configure_mouse("MOUSE",
456 0, 0, INPUTEVENT_AMIGA_JOYPORT_0_DEVICE_9, 0, 0, 0);
457 }
458
459 int count;
460 fs_emu_input_device *input_device = fs_emu_get_input_devices(&count);
461 for (int i = 0; i < count; i++) {
462 //printf("---- %d %s\n", i, input_device->name);
463 //printf("usage: %d\n", input_device->usage);
464 if (input_device->usage) {
465 // this device is used, so we don't want auto-select for this
466 // device
467 input_device++;
468 continue;
469 }
470
471 if (strcmp(input_device->name, "KEYBOARD") == 0) {
472 continue;
473 }
474
475 int input_event = INPUTEVENT_AMIGA_JOYPORT_0_DEVICE_0 + i;
476 fs_emu_input_mapping mapping[] = {
477 { "1", input_event },
478 { NULL, 0 },
479 };
480 fs_emu_configure_joystick(input_device->name, "amiga",
481 mapping, 0, NULL, 0);
482 input_device++;
483 };
484 }
485 #endif
486
487 fs_emu_map_custom_actions();
488 }
489