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