1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 
5 #define FSE_INTERNAL_API
6 #include <fs/emu.h>
7 #include <fs/emu/input.h>
8 #include <fs/emu/options.h>
9 #include <fs/lazyness.h>
10 #include "input.h"
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <fs/base.h>
15 #include <fs/i18n.h>
16 #include <fs/inifile.h>
17 #include <fs/glib.h>
18 #include <fs/thread.h>
19 #include <fs/emu/actions.h>
20 #include "hud.h"
21 #include "menu.h"
22 #include "netplay.h"
23 #include "libfsemu.h"
24 #include "video.h"
25 
26 static char *g_controllers_dir = NULL;
27 
fs_emu_set_controllers_dir(const char * path)28 void fs_emu_set_controllers_dir(const char *path)
29 {
30     if (g_controllers_dir) {
31         free(g_controllers_dir);
32     }
33     if (path) {
34         g_controllers_dir = g_strdup(path);
35     }
36 }
37 
38 static GHashTable *configure_input_device(const char *name,
39         const char *platform);
40 
41 #define MAX_ACTIONS 1024
42 #define MAX_ACTIONS_WITH_LIBFSEMU_INTERNAL 1200
43 static fs_emu_action g_actions[MAX_ACTIONS_WITH_LIBFSEMU_INTERNAL] = {};
44 
45 /*
46 input mapping
47 then comes all joysticks in order
48 every device has 512 "slots"
49 joysticks are device index 0 .. num joysticks - 1
50 keyboard is MAX_DEVICES - 1
51 - for keyboard, every index corresponds to a keysym
52 - for joystick: axis, buttons and hats are mapped to an index between
53 - 0 and 512 (see button_index)
54 */
55 
56 #define MAX_DEVICES 64
57 #define KEYBOARD 0
58 #define MOUSE 1
59 #define SLOTS 512
60 
61 /* KEYBOARD occupies 16 "devices" (15 extra) at the beginning, to account
62  * for all modifier combinations */
63 #define RESERVED_DEVICES 15
64 
65 #define CTRL_BIT          1
66 #define ALT_BIT           2
67 #define SHIFT_BIT         4
68 #define SPECIAL_BIT       8
69 
70 #define INPUT_ACTION_TABLE_SIZE_BYTES (MAX_DEVICES * SLOTS * sizeof(int))
71 
72 static int g_input_action_table[MAX_DEVICES * SLOTS];
73 static int g_menu_action_table[MAX_DEVICES * SLOTS];
74 static unsigned char g_input_state[MAX_DEVICES * SLOTS];
75 static int g_key_modifiers_at_pressed_state[FS_ML_KEY_LAST] = {};
76 static int g_modifier_key;
77 static bool g_modifier_key_pressed;
78 bool g_fs_emu_grab_input_on_mod_release = false;
79 
80 // used to look up start index from select index and vice-versa for menu
81 // button emulation (you can simultaneously press start and select instead
82 // of pressing menu button)
83 static int g_menu_action_corresponding[MAX_DEVICES * SLOTS];
84 
85 #define MAX_JOYSTICKS 63
86 #define MAX_BUTTONS 63
87 #define MAX_AXIS 63
88 
key_index(int key,int mod,int offset)89 static int key_index(int key, int mod, int offset)
90 {
91     if (key == 0)
92         return 0;
93 
94     int slots_offset = offset;
95     if (mod & FS_ML_KEY_MOD_CTRL)
96         slots_offset |= CTRL_BIT;
97     if (mod & FS_ML_KEY_MOD_ALT)
98         slots_offset |= ALT_BIT;
99     if (mod & FS_ML_KEY_MOD_SHIFT)
100         slots_offset |= SHIFT_BIT;
101     if (mod & FS_ML_KEY_MOD_SPECIAL)
102         slots_offset |= SPECIAL_BIT;
103 
104     return slots_offset * SLOTS + key;
105 }
106 
event_mod(fs_ml_event * event)107 static int event_mod(fs_ml_event *event)
108 {
109     if (g_modifier_key_pressed && !fs_emu_full_keyboard_emulation())
110         return FS_ML_KEY_MOD_SPECIAL;
111     else if (event->key.keysym.mod == FS_ML_KEY_MOD_F11)
112         return FS_ML_KEY_MOD_SPECIAL;
113     else if (event->key.keysym.mod == FS_ML_KEY_MOD_F12)
114         return FS_ML_KEY_MOD_SPECIAL;
115     return event->key.keysym.mod;
116 }
117 
mouse_index(int device_index,int horiz,int vert,int button)118 static int mouse_index(int device_index, int horiz, int vert, int button)
119 {
120     int index = 0;
121     if (horiz)
122         index = 1;
123     else if (vert)
124         index = 2;
125     else if (button == FS_ML_BUTTON_LEFT)
126         index = 3;
127     else if (button == FS_ML_BUTTON_MIDDLE)
128         index = 4;
129     else if (button == FS_ML_BUTTON_RIGHT)
130         index = 5;
131     return (RESERVED_DEVICES + device_index) * SLOTS + index;
132 }
133 
map_keyboard_key(int key,int mod,int action,int offset)134 static void map_keyboard_key(int key, int mod, int action, int offset)
135 {
136     if (mod == -1) {
137         /* On purpose we do not map for SPECIAL_BIT, so key events are
138          * not sent to emulator when special modifier is pressed. */
139         for (int i = 0; i < (CTRL_BIT | SHIFT_BIT | ALT_BIT); i++) {
140             map_keyboard_key(key, 0, action, i);
141         }
142         return;
143     }
144     int index = key_index(key, mod, offset);
145     if (index > 0) {
146         g_input_action_table[index] = action;
147 
148         for (int i = 0; g_actions[i].input_event != FS_EMU_ACTION_LAST; i++) {
149             /* Not very elegant, but ok for now since there is only a few fs
150              * emu actions. */
151             if (g_actions[i].input_event == action) {
152                 if ((g_actions[i].flags & FS_EMU_ACTION_FLAG_MENU)) {
153                     // fs_log("MENU ACTION index %d -> action %d\n", index, action);
154                     g_menu_action_table[index] = action;
155                 }
156                 break;
157             }
158         }
159     }
160 }
161 
fs_emu_set_keyboard_translation(fs_emu_key_translation * keymap)162 void fs_emu_set_keyboard_translation(fs_emu_key_translation *keymap)
163 {
164     for (; keymap->system_key; keymap++) {
165         int key = keymap->system_key;
166         int mod = keymap->system_mod;
167         int input_event = keymap->input_event;
168         if (key == -1) {
169             continue;
170         }
171         map_keyboard_key(key, mod, input_event, 0);
172     }
173 }
174 
fs_emu_configure_mouse(const char * name,int horiz,int vert,int left,int middle,int right,int wheel_axis)175 void fs_emu_configure_mouse(const char* name, int horiz, int vert, int left,
176         int middle, int right, int wheel_axis)
177 {
178     fs_log("fs_emu_configure_mouse (device: %s)\n", name);
179 
180     fs_ml_input_device device;
181     for (int i = 0; i < FS_ML_INPUT_DEVICES_MAX; i++) {
182         if (!fs_ml_input_device_get(i, &device)) {
183             continue;
184         }
185         if (device.name == NULL || (
186                 (g_ascii_strcasecmp(device.name, name) != 0) &&
187                 (g_ascii_strcasecmp(device.alias, name) != 0))) {
188             fs_log("did not match device #%d (%s)\n", i, device.name);
189             continue;
190         }
191         fs_log("matched device #%d\n", i);
192         // if (out_name) {
193         //     strncpy(out_name, device.name, out_name_len);
194         // }
195 
196         g_input_action_table[mouse_index(
197                 device.index, 1, 0, 0)] = horiz;
198         g_input_action_table[mouse_index(
199                 device.index, 0, 1, 0)] = vert;
200         g_input_action_table[mouse_index(
201                 device.index, 0, 0, FS_ML_BUTTON_LEFT)] = left;
202         g_input_action_table[mouse_index(
203                 device.index, 0, 0, FS_ML_BUTTON_MIDDLE)] = middle;
204         g_input_action_table[mouse_index(
205                 device.index, 0, 0, FS_ML_BUTTON_RIGHT)] = right;
206         g_input_action_table[mouse_index(
207                 device.index, 0, 0, FS_ML_BUTTON_WHEELUP)] = wheel_axis;
208         g_input_action_table[mouse_index(
209                 device.index, 0, 0, FS_ML_BUTTON_WHEELDOWN)] = wheel_axis;
210         break;
211     }
212 }
213 
214 typedef struct input_config_item {
215     char *config_key;
216     char *config_value;
217     int key;
218     int axis;
219     int hat;
220     int button;
221     int value;
222 } input_config_item;
223 
free_input_config_item_list(input_config_item * items)224 static void free_input_config_item_list(input_config_item *items)
225 {
226     for (input_config_item *item = items; item->config_key; item++) {
227         g_free(item->config_key);
228         g_free(item->config_value);
229     }
230     g_free(items);
231 }
232 
map_input_config_item(const char * desc,int * out_key,int * out_axis,int * out_hat,int * out_button,int * out_value)233 static void map_input_config_item(
234         const char* desc, int *out_key, int *out_axis, int *out_hat,
235         int *out_button, int *out_value)
236 {
237     /* Make parts always at least three items -this way we do not have to
238      * bounds check parts. */
239     char *tmp = g_strconcat(desc, "_x_x_x_x", NULL);
240     char** parts = g_strsplit(tmp, "_", 4);
241 
242     if (g_ascii_strcasecmp(parts[0], "key") == 0) {
243         for (int i = 0; g_fs_emu_key_names[i]; i++) {
244             if (g_ascii_strcasecmp(parts[1], g_fs_emu_key_names[i]) == 0) {
245                 if (out_key) {
246                     *out_key = i;
247                 }
248                 break;
249             }
250         }
251     } else if (g_ascii_strcasecmp(parts[0], "button") == 0) {
252         if (out_button) {
253             *out_button = atoi(parts[1]);
254         }
255     } else if (g_ascii_strcasecmp(parts[0], "axis") == 0) {
256         int axis = atoi(parts[1]);
257         int direction = -1;
258         if (g_ascii_strcasecmp(parts[2], "pos") == 0) {
259             direction = 1;
260         } else if (g_ascii_strcasecmp(parts[2], "neg") == 0) {
261             direction = 0;
262         } else {
263             fs_log("[INPUT] Error parsing \"%s\"\n", desc);
264             g_free(tmp);
265             g_strfreev(parts);
266             return;
267         }
268         if (out_axis) {
269             *out_axis = axis;
270         }
271         if (out_value) {
272             *out_value = direction;
273         }
274     } else if (g_ascii_strcasecmp(parts[0], "hat") == 0) {
275         int hat = atoi(parts[1]);
276         int direction = -1;
277         if (g_ascii_strcasecmp(parts[2], "up") == 0) {
278             direction = FS_ML_HAT_UP;
279         } else if (g_ascii_strcasecmp(parts[2], "down") == 0) {
280             direction = FS_ML_HAT_DOWN;
281         } else if (g_ascii_strcasecmp(parts[2], "left") == 0) {
282             direction = FS_ML_HAT_LEFT;
283         } else if (g_ascii_strcasecmp(parts[2], "right") == 0) {
284             direction = FS_ML_HAT_RIGHT;
285         } else {
286             fs_log("[INPUT] Error parsing \"%s\"\n", desc);
287             g_free(tmp);
288             g_strfreev(parts);
289             return;
290         }
291         if (out_hat) {
292             *out_hat = hat;
293         }
294         if (out_value) {
295             *out_value = direction;
296         }
297     }
298     g_free(tmp);
299     g_strfreev(parts);
300 
301 }
302 
get_system_config_for_device(const char * device,const char * platform)303 static input_config_item *get_system_config_for_device(
304         const char *device, const char *platform)
305 {
306     fs_log("get system config for device: %s\n", device);
307     GHashTable *config = configure_input_device(device, platform);
308     if (config == NULL) {
309         return NULL;
310     }
311     int num_keys = g_hash_table_size(config);
312     input_config_item *result = g_malloc0((num_keys + 1) *
313             sizeof(input_config_item));
314     input_config_item *p = result;
315     GList *keys = g_hash_table_get_keys(config);
316     GList *key_item = keys;
317     while (key_item) {
318         char* value = g_hash_table_lookup(config, key_item->data);
319         // both key and value is owned by hash table, must not be freed
320         //*(p++) = fs_strdup(key_item->data);
321         //*(p++) = fs_strdup(value);
322         //*p = (input_config_item*) g_malloc0(sizeof(input_config_item));
323         p->config_key = g_strdup(key_item->data);
324         p->config_value = g_strdup(value);
325         p->key = -1;
326         p->axis = -1;
327         p->hat = -1;
328         p->button = -1;
329         p->value = 0;
330         // fill out key, axis, hat button and value fields based on
331         // config_key
332         map_input_config_item(p->config_key, &(p->key), &(p->axis),
333                 &(p->hat), &(p->button), &(p->value));
334         p++;
335         key_item = key_item->next;
336     }
337     g_list_free(keys);
338     g_hash_table_destroy(config);
339     // terminate result with NULL pointer and return
340     //*(p++) = NULL;
341     return result;
342 }
343 
get_config_for_device(const char * device,const char * platform)344 static input_config_item *get_config_for_device(
345         const char *device, const char *platform)
346 {
347     return get_system_config_for_device(device, platform);
348 }
349 
fs_emu_input_action_from_string(const char * value)350 int fs_emu_input_action_from_string(const char *value)
351 {
352     char *value_l = g_ascii_strdown(value, -1);
353     fs_emu_action *action = g_actions;
354     while (action->name) {
355         //fs_log(" %s vs %s\n", value_l, action->name);
356         if (strcmp(value_l, action->name) == 0) {
357             //fs_log(" ** found %s %d** \n", action->name, action->input_event);
358             g_free(value_l);
359             return action->input_event;
360         }
361         action++;
362     }
363     g_free(value_l);
364     return -1;
365 }
366 
map_custom_key_action(const char * key_name,int key_val,const char * mod_name,int mod_val)367 static void map_custom_key_action(
368         const char *key_name, int key_val, const char *mod_name, int mod_val)
369 {
370     char *config_key = g_strdup_printf("keyboard_key_%s%s", mod_name,
371             key_name);
372     const char *config_value = fs_config_get_const_string(config_key);
373     if (!config_value) {
374         g_free(config_key);
375         return;
376     }
377     int action = fs_emu_input_action_from_string(config_value);
378     if (action >= 0) {
379         map_keyboard_key(key_val, mod_val, action, 0);
380     }
381     g_free(config_key);
382 }
383 
map_custom_keyboard_actions(void)384 static void map_custom_keyboard_actions(void)
385 {
386     fs_log("map_custom_keyboard_actions\n");
387     const char **key = g_fs_emu_key_names;
388     int k = 0;
389     while (*key) {
390         if (**key == 0) {
391             key++;
392             k++;
393             continue;
394         }
395         char *keyl = g_ascii_strdown(*key, -1);
396         map_custom_key_action(keyl, k, "", -1);
397         map_custom_key_action(keyl, k, "ctrl_", FS_ML_KEY_MOD_CTRL);
398         map_custom_key_action(keyl, k, "ctrl_shift_",
399                 FS_ML_KEY_MOD_CTRL | FS_ML_KEY_MOD_SHIFT);
400         map_custom_key_action(keyl, k, "ctrl_shift_alt_",
401                 FS_ML_KEY_MOD_CTRL | FS_ML_KEY_MOD_SHIFT | FS_ML_KEY_MOD_ALT);
402         map_custom_key_action(keyl, k, "ctrl_alt_", FS_ML_KEY_MOD_CTRL |
403                 FS_ML_KEY_MOD_ALT);
404         map_custom_key_action(keyl, k, "shift_", FS_ML_KEY_MOD_SHIFT);
405         map_custom_key_action(keyl, k, "shift_alt_", FS_ML_KEY_MOD_SHIFT |
406                 FS_ML_KEY_MOD_ALT);
407         map_custom_key_action(keyl, k, "alt_", FS_ML_KEY_MOD_ALT);
408         map_custom_key_action(keyl, k, "mod_", FS_ML_KEY_MOD_SPECIAL);
409         free(keyl);
410         key++;
411         k++;
412     }
413 }
414 
button_index(int key,int joystick,int axis,int hat,int button,int value)415 static int button_index(
416         int key, int joystick, int axis, int hat, int button, int value)
417 {
418     if (key >= 0) {
419         return key_index(key, 0, 0);
420     }
421     // base index for this device
422     //int index = (joystick + 1) * SLOTS;
423 
424     // first valid index is 1
425     int index = (RESERVED_DEVICES + joystick) * SLOTS + 1;
426     if (axis >= 0) {
427         index += axis * 2;
428         if (value == 1) {
429             index += 1;
430         }
431     }
432     else if (hat >= 0) {
433         index += 128;
434         index += hat * 16 + value;
435     }
436     else if (button >= 0) {
437         index += 384;
438         index += button;
439     }
440     else {
441         // no match
442         index = (RESERVED_DEVICES + joystick) * SLOTS;
443     }
444     return index;
445 }
446 
map_custom_joystick_action(int joy,const char * name,int axis,int hat,int button,int value,const char * n1,int n2,const char * n3)447 static void map_custom_joystick_action(
448         int joy, const char *name, int axis, int hat, int button, int value,
449         const char *n1, int n2, const char *n3)
450 {
451     char *config_key = g_strdup_printf("%s%s%d%s", name, n1, n2, n3);
452     if (g_fs_log_input) {
453         fs_log("[INPUT] %s\n", config_key);
454     }
455     const char *config_value = fs_config_get_const_string(config_key);
456     if (!config_value) {
457         free(config_key);
458         return;
459     }
460     int index = button_index(-1, joy, axis, hat, button, value);
461     int action = fs_emu_input_action_from_string(config_value);
462     if (action >= 0) {
463         g_input_action_table[index] = action;
464     }
465     free(config_key);
466 }
467 
468 // 0-based or 1-based configuuration
469 #define CONFIG_OFFSET 0
470 
map_custom_axis_actions(int joy,const char * name,int axis)471 static void map_custom_axis_actions(int joy, const char *name, int axis)
472 {
473     map_custom_joystick_action(joy, name, axis, -1, -1, 0,
474             "_axis_", axis + CONFIG_OFFSET, "_neg");
475     map_custom_joystick_action(joy, name, axis, -1, -1, 1,
476             "_axis_", axis + CONFIG_OFFSET, "_pos");
477 }
478 
map_custom_hat_actions(int joy,const char * name,int hat)479 static void map_custom_hat_actions(int joy, const char *name, int hat)
480 {
481     map_custom_joystick_action(joy, name, -1, hat, -1, FS_ML_HAT_UP,
482             "_hat_", hat + CONFIG_OFFSET, "_up");
483     map_custom_joystick_action(joy, name, -1, hat, -1, FS_ML_HAT_DOWN,
484             "_hat_", hat + CONFIG_OFFSET, "_down");
485     map_custom_joystick_action(joy, name, -1, hat, -1, FS_ML_HAT_LEFT,
486             "_hat_", hat + CONFIG_OFFSET, "_left");
487     map_custom_joystick_action(joy, name, -1, hat, -1, FS_ML_HAT_RIGHT,
488             "_hat_", hat + CONFIG_OFFSET, "_right");
489 }
490 
map_custom_button_actions(int joy,const char * name,int button)491 static void map_custom_button_actions(int joy, const char *name, int button)
492 {
493     map_custom_joystick_action(joy, name, -1, -1, button, 0,
494             "_button_", button + CONFIG_OFFSET, "");
495 }
496 
map_custom_joystick_actions_2(int joy,const char * name,int axis_count,int hat_count,int button_count)497 static void map_custom_joystick_actions_2(
498         int joy, const char *name, int axis_count, int hat_count,
499         int button_count)
500 {
501     for (int i = 0; i < axis_count; i++) {
502         map_custom_axis_actions(joy, name, i);
503     }
504     for (int i = 0; i < hat_count; i++) {
505         map_custom_hat_actions(joy, name, i);
506     }
507     for (int i = 0; i < button_count; i++) {
508         map_custom_button_actions(joy, name, i);
509     }
510 }
511 
joystick_long_config_name(const fs_ml_input_device * device)512 static char *joystick_long_config_name(const fs_ml_input_device *device)
513 {
514     const char *in = device->name;
515     char *result = g_malloc(strlen(device->name) + 1);
516     char *out = result;
517     int other = 0;
518     while (*in) {
519 #if 0
520         if (!with_number) {
521 #endif
522             if (*in == '#') {
523                 // remove #2, #3 from name
524                 break;
525             }
526 #if 0
527         }
528 #endif
529         char c = g_ascii_tolower(*in);
530         if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) {
531             if (other) {
532                 *(out++) = '_';
533             }
534             *(out++) = c;
535             other = 0;
536         }
537         else {
538             other = 1;
539         }
540         in++;
541     }
542     *out = '\0';
543     if (g_str_has_suffix(result, "_")) {
544         result[strlen(result) - 1] = '\0';
545     }
546 
547     char *result2 = g_strdup_printf("%s_%d_%d_%d_%d_%s", result,
548             device->buttons, device->axes, device->hats, device->balls,
549             OS_NAME);
550     g_free(result);
551     return result2;
552 }
553 
joystick_config_name(const char * name,int with_number)554 static char *joystick_config_name(const char* name, int with_number)
555 {
556     const char *in = name;
557     char *result = g_malloc(strlen(name) + 1);
558     char *out = result;
559     int other = 0;
560     while (*in) {
561         if (!with_number) {
562             if (*in == '#') {
563                 // remove #2, #3 from name
564                 break;
565             }
566         }
567         char c = g_ascii_tolower(*in);
568         if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) {
569             if (other) {
570                 *(out++) = '_';
571             }
572             *(out++) = c;
573             other = 0;
574         }
575         else {
576             other = 1;
577         }
578         in++;
579     }
580     *out = '\0';
581     if (g_str_has_suffix(result, "_")) {
582         result[strlen(result) - 1] = '\0';
583     }
584     return result;
585 }
586 
map_custom_gamepad_actions(int joy,const char * name,fs_ml_input_device * device)587 static void map_custom_gamepad_actions(
588         int joy, const char *name, fs_ml_input_device *device)
589 {
590     char* config_name = joystick_long_config_name(device);
591     fs_log("[INPUT] Config name \"%s\"\n", config_name);
592     input_config_item *config = get_config_for_device(config_name,
593             "universal");
594     if (config == NULL) {
595         fs_log("[INPUT] Did not find generic gamepad config for device "
596                "\"%s\"\n", config_name);
597         free(config_name);
598         config_name = joystick_config_name(device->name, 0);
599         fs_log("config name \"%s\"\n", config_name);
600         config = get_config_for_device(config_name, "universal");
601         if (config == NULL) {
602             fs_log("[INPUT] Did not find generic gamepad config for device"
603                    "\"%s\"\n", config_name);
604             free(config_name);
605             return;
606         }
607     }
608     for (int j = 0; config[j].config_key != NULL; j++) {
609         char *config_key = g_strdup_printf("%s_%s", name,
610                 config[j].config_value);
611         if (g_fs_log_input) {
612             fs_log("[INPUT] %s\n", config_key);
613         }
614         const char *config_value = fs_config_get_const_string(config_key);
615         if (!config_value) {
616             free(config_key);
617             continue;
618         }
619         int index = button_index(-1, joy, config[j].axis, config[j].hat,
620                 config[j].button, config[j].value);
621         int action = fs_emu_input_action_from_string(config_value);
622         if (action >= 0) {
623             g_input_action_table[index] = action;
624         }
625     }
626     free_input_config_item_list(config);
627     free(config_name);
628 }
629 
map_custom_joystick_actions()630 static void map_custom_joystick_actions()
631 {
632     fs_log("map_custom_joystick_actions\n");
633     fs_ml_input_device device;
634     int joystick_index = 0;
635     for (int i = 0; i < FS_ML_INPUT_DEVICES_MAX; i++) {
636         if (!fs_ml_input_device_get(i, &device)) {
637             continue;
638         }
639         if (device.name == NULL) {
640             continue;
641         }
642         char *name, *config_name;
643 
644         name = g_ascii_strdown(device.name, -1);
645         config_name = joystick_config_name(name, 1);
646         fs_log("[INPUT] Map custom joystick actions for %s\n", config_name);
647         g_free(name);
648         map_custom_joystick_actions_2(i, config_name, device.axes,
649                 device.hats, device.buttons);
650         map_custom_gamepad_actions(i, config_name, &device);
651         g_free(config_name);
652 
653         if (device.type == FS_ML_JOYSTICK) {
654             config_name = g_strdup_printf("joystick_%d", joystick_index);
655             fs_log("[INPUT] Map custom joystick actions for %s\n",
656                    config_name);
657             map_custom_joystick_actions_2(i, config_name, device.axes,
658                     device.hats, device.buttons);
659             map_custom_gamepad_actions(i, config_name, &device);
660             g_free(config_name);
661             joystick_index += 1;
662         }
663     }
664 }
665 
fs_emu_map_custom_actions()666 void fs_emu_map_custom_actions() {
667     map_custom_keyboard_actions();
668     map_custom_joystick_actions();
669 }
670 
fs_emu_set_actions(fs_emu_action * actions)671 void fs_emu_set_actions(fs_emu_action *actions)
672 {
673     int k = 0;
674 
675     g_actions[k].name = "action_full_keyboard";
676     g_actions[k].flags = 0;
677     g_actions[k++].input_event = FS_EMU_ACTION_FULL_KEYBOARD;
678 
679     g_actions[k].name = "action_fullscreen";
680     g_actions[k].flags = FS_EMU_ACTION_FLAG_MENU;
681     g_actions[k++].input_event = FS_EMU_ACTION_FULLSCREEN;
682 
683     g_actions[k].name = "action_grab_input";
684     g_actions[k].flags = 0;
685     g_actions[k++].input_event = FS_EMU_ACTION_GRAB_INPUT;
686 
687     g_actions[k].name = "action_menu";
688     g_actions[k].flags = FS_EMU_ACTION_FLAG_MENU;
689     g_actions[k++].input_event = FS_EMU_ACTION_MENU_ALT;
690 
691     g_actions[k].name = "action_pause";
692     g_actions[k].flags = FS_EMU_ACTION_FLAG_MENU;
693     g_actions[k++].input_event = FS_EMU_ACTION_PAUSE;
694 
695     g_actions[k].name = "action_quit";
696     g_actions[k].flags = FS_EMU_ACTION_FLAG_MENU;
697     g_actions[k++].input_event = FS_EMU_ACTION_QUIT;
698 
699     g_actions[k].name = "action_screenshot";
700     g_actions[k].flags = FS_EMU_ACTION_FLAG_MENU;
701     g_actions[k++].input_event = FS_EMU_ACTION_SCREENSHOT;
702 
703     g_actions[k].name = "action_special";
704     g_actions[k].flags = 0;
705     g_actions[k++].input_event = FS_EMU_ACTION_SPECIAL;
706 
707     g_actions[k].name = "action_taunt";
708     g_actions[k].flags = 0;
709     g_actions[k++].input_event = FS_EMU_ACTION_TAUNT;
710 
711     g_actions[k].name = "action_volume_down";
712     g_actions[k].flags = FS_EMU_ACTION_FLAG_MENU;
713     g_actions[k++].input_event = FS_EMU_ACTION_VOLUME_DOWN;
714 
715     g_actions[k].name = "action_volume_mute";
716     g_actions[k].flags = FS_EMU_ACTION_FLAG_MENU;
717     g_actions[k++].input_event = FS_EMU_ACTION_VOLUME_MUTE;
718 
719     g_actions[k].name = "action_volume_up";
720     g_actions[k].flags = FS_EMU_ACTION_FLAG_MENU;
721     g_actions[k++].input_event = FS_EMU_ACTION_VOLUME_UP;
722 
723     g_actions[k].name = "action_warp";
724     g_actions[k].flags = 0;
725     g_actions[k++].input_event = FS_EMU_ACTION_WARP;
726 
727     g_actions[k].name = "action_zoom";
728     g_actions[k].flags = 0;
729     g_actions[k++].input_event = FS_EMU_ACTION_ZOOM;
730 
731     g_actions[k].name = "action_zoom_border";
732     g_actions[k].flags = 0;
733     g_actions[k++].input_event = FS_EMU_ACTION_ZOOM_BORDER;
734 
735     g_actions[k].name = "action_cycle_stretch_mode";
736     g_actions[k].flags = 0;
737     g_actions[k++].input_event = FSE_ACTION_CYCLE_STRETCH_MODE;
738 
739     g_actions[k].name = "";
740     g_actions[k].flags = 0;
741     g_actions[k++].input_event = FS_EMU_ACTION_LAST;
742 
743     while (actions->name) {
744         if (k == MAX_ACTIONS) {
745             fs_log("MAX_ACTIONS reached\n");
746             break;
747         }
748         g_actions[k].name = g_ascii_strdown(actions->name, -1);
749         g_actions[k].input_event = actions->input_event;
750         g_actions[k].flags = actions->flags;
751         k++;
752         actions++;
753     }
754 }
755 
fs_emu_reset_input_mapping()756 void fs_emu_reset_input_mapping()
757 {
758     memset(g_input_action_table, 0, INPUT_ACTION_TABLE_SIZE_BYTES);
759     int count;
760     fs_ml_input_device *devices = fs_ml_get_input_devices(&count);
761     for (int i = 0; i < count; i++) {
762         devices[i].usage = 0;
763     }
764 }
765 
766 static fs_mutex* g_input_event_mutex;
767 static GQueue* g_input_event_queue;
768 
fs_emu_get_input_event()769 int fs_emu_get_input_event()
770 {
771     fs_mutex_lock(g_input_event_mutex);
772     int input_event = FS_POINTER_TO_INT(g_queue_pop_tail(
773             g_input_event_queue));
774     fs_mutex_unlock(g_input_event_mutex);
775     return input_event;
776 }
777 
fs_emu_queue_input_event_internal(int input_event)778 void fs_emu_queue_input_event_internal(int input_event)
779 {
780     if (input_event == 0) {
781         fs_log("WARNING: tried to queue input event 0\n");
782         return;
783     }
784     fs_mutex_lock(g_input_event_mutex);
785     g_queue_push_head(g_input_event_queue, FS_INT_TO_POINTER(input_event));
786     fs_mutex_unlock(g_input_event_mutex);
787 }
788 
fs_emu_queue_action(int action,int state)789 void fs_emu_queue_action(int action, int state)
790 {
791     int input_event = action | (state << 16);
792     fs_emu_queue_input_event(input_event);
793 }
794 
795 static fs_emu_hotkey_function g_hotkey_function = NULL;
fs_emu_set_hotkey_function(fs_emu_hotkey_function function)796 void fs_emu_set_hotkey_function(fs_emu_hotkey_function function)
797 {
798     g_hotkey_function = function;
799 }
800 
fs_emu_handle_local_action(int action,int state)801 bool fs_emu_handle_local_action(int action, int state)
802 {
803     if (action & FS_EMU_ACTION_LOCAL) {
804         /* Local action */
805         if (action >= FS_EMU_ACTION_LOCAL_LIBFSEMU) {
806             /* This is a libfsemu-internal action */
807             fs_emu_handle_libfsemu_action(action, state);
808         } else {
809             /* Local application action */
810             if (g_hotkey_function != NULL) {
811                 g_hotkey_function(action, state);
812             }
813         }
814         return true;
815     }
816     return false;
817 }
818 
fs_emu_handle_local_input_event(int input_event)819 static bool fs_emu_handle_local_input_event(int input_event)
820 {
821     if (input_event & FS_EMU_ACTION_LOCAL) {
822         int action = input_event & 0xffff;
823         int state = (input_event & 0xff0000) >> 16;
824         return fs_emu_handle_local_action(action, state);
825     }
826     return false;
827 }
828 
fs_emu_queue_input_event(int input_event)829 void fs_emu_queue_input_event(int input_event)
830 {
831     if (fs_emu_handle_local_input_event(input_event))
832         return;
833 #ifdef WITH_NETPLAY
834     if (!fs_emu_netplay_send_input_event(input_event)) {
835 #endif
836         fs_emu_queue_input_event_internal(input_event);
837 #ifdef WITH_NETPLAY
838     }
839 #endif
840 }
841 
fs_emu_get_input_devices(int * count)842 fs_emu_input_device *fs_emu_get_input_devices(int* count)
843 {
844     return fs_ml_get_input_devices(count);
845 }
846 
queue_input_event_with_state(int input_event,int state)847 static void queue_input_event_with_state(int input_event, int state)
848 {
849     //printf("----------------------------- %d\n", state);
850     //printf("action_function => input event %d (state %d)\n", input_event, state);
851     if (input_event > 0) {
852         input_event = input_event | (state << 16);
853         fs_emu_queue_input_event(input_event);
854     }
855 }
856 
857 static int g_cursor_visible = 1;
858 static int64_t g_cursor_visible_to = 0;
859 
fs_emu_mouse_integration(void)860 bool fs_emu_mouse_integration(void)
861 {
862     return fs_ml_mouse_integration();
863 }
864 
fs_emu_cursor_allowed(void)865 bool fs_emu_cursor_allowed(void)
866 {
867     if (fs_emu_menu_mode())
868         return true;
869     return fs_ml_cursor_allowed();
870 }
871 
fs_emu_show_cursor(int show)872 void fs_emu_show_cursor(int show)
873 {
874     fs_ml_show_cursor(0, 0);
875     g_cursor_visible = (show != 0);
876     g_cursor_visible_to = 0;
877 }
878 
fs_emu_show_cursor_msec(int duration)879 void fs_emu_show_cursor_msec(int duration)
880 {
881     fs_ml_show_cursor(duration > 0, 0);
882     g_cursor_visible = 1;
883     g_cursor_visible_to = fs_emu_monotonic_time() + \
884                           (int64_t) duration * 1000;
885 }
886 
fs_emu_is_cursor_visible(void)887 int fs_emu_is_cursor_visible(void)
888 {
889     return g_cursor_visible;
890 }
891 
fs_emu_cursor_is_visible_to(void)892 int64_t fs_emu_cursor_is_visible_to(void)
893 {
894     return g_cursor_visible_to;
895 }
896 
fs_emu_input_grab(void)897 bool fs_emu_input_grab(void)
898 {
899     return fs_ml_input_grab();
900 }
901 
902 static int g_ignore_next_motion = 0;
903 
fs_emu_set_input_grab(bool grab)904 void fs_emu_set_input_grab(bool grab)
905 {
906     fs_emu_set_input_grab_and_visibility(grab, FS_EMU_MOUSE_DEFAULT_DURATION);
907     g_fs_emu_grab_input_on_mod_release = false;
908 }
909 
fs_emu_set_input_grab_and_visibility(bool grab,int duration)910 void fs_emu_set_input_grab_and_visibility(bool grab, int duration)
911 {
912     if (grab == fs_emu_input_grab())
913         return;
914 
915     fs_log("EMU: %s input\n", grab ? "Grab" : "Ungrab");
916     if (grab) {
917         fs_ml_set_input_grab(true);
918         fs_emu_show_cursor(0);
919     } else {
920         fs_ml_set_input_grab(false);
921         if (fs_emu_cursor_allowed()) {
922            fs_emu_show_cursor_msec(duration);
923         }
924     }
925     g_ignore_next_motion = 1;
926 }
927 
fs_emu_clear_menu_input_states(int key)928 void fs_emu_clear_menu_input_states(int key) {
929     // FIXME: quick hack for fixing the state of the key used to exit
930     // menu mode
931     int index = button_index(key, -1, -1, -1, -1, -1);
932     g_input_state[index] = 0;
933 }
934 
map_joystick(int joystick,input_config_item * config,fs_emu_input_mapping * mapping,int * action_table,int * out_action,int * out_index)935 static int map_joystick(int joystick, input_config_item *config,
936         fs_emu_input_mapping *mapping, int *action_table, int *out_action,
937         int *out_index) {
938     const char* action_name = config->config_value;
939     int action = 0;
940     // mapping must be terminated with an entry with name set to NULL
941     for (int i = 0;; i++) {
942         if (mapping[i].name == NULL) {
943             fs_log("did not find action for \"%s\"\n", action_name);
944             return 0;
945         }
946         //fs_log("checking %s %s\n", mapping[i].name, action_name);
947         if (strcmp(mapping[i].name, action_name) == 0) {
948             action = mapping[i].action;
949             break;
950         }
951     }
952     int index = button_index(config->key, joystick, config->axis,
953             config->hat, config->button, config->value);
954     if (index > 0) {
955         action_table[index] = action;
956         if (config->key >= 0) {
957             // also map for modifier combinations
958             for (int i = 1; i < 8; i++) {
959                 action_table[index + SLOTS * i] = action;
960             }
961         }
962 
963         fs_log("%s (%d) => action \"%s\" (%d)\n", config->config_key,
964                 index, action_name, action);
965         if (out_action) {
966             *out_action = action;
967         }
968         if (out_index) {
969             *out_index = index;
970         }
971         return 1;
972     }
973     else {
974         fs_log("no mapping for %s => action \"%s\" (%d)\n",
975                 config->config_key, action_name, action);
976         if (out_action) {
977             *out_action = 0;
978         }
979         if (out_index) {
980             *out_index = 0;
981         }
982         return 0;
983     }
984 }
985 
986 static GHashTable *g_input_config_paths = NULL;
987 
read_input_config(const char * config_name,GHashTable * config,const char * platform)988 static int read_input_config(
989         const char *config_name, GHashTable *config, const char *platform)
990 {
991     const char *path = g_hash_table_lookup(g_input_config_paths, config_name);
992     char *data = NULL;
993     int data_size = 0;
994     if (path == NULL) {
995         int error;
996         gchar *data_name = g_strdup_printf("input/%s.conf", config_name);
997         error = fs_get_program_data(data_name, &data, &data_size);
998         fs_log("checked data \"%s\" = %d\n", data_name, error);
999         g_free(data_name);
1000         if (error != 0) {
1001             fs_log("config file for %s was not found\n", config_name);
1002             return 0;
1003         }
1004     }
1005 
1006     fs_ini_file *ini_file;
1007     if (path) {
1008         fs_log("read config for %s for %s (from %s)\n",
1009                config_name, platform, path);
1010         ini_file = fs_ini_file_open(path);
1011     } else if (data) {
1012         fs_log("read config for %s for %s (from data)\n",
1013                config_name, platform);
1014         ini_file = fs_ini_file_open_data(data, data_size);
1015         free(data);
1016         data = NULL;
1017         data_size = 0;
1018     }
1019     if (ini_file == NULL) {
1020         fs_log("error loading config file\n");
1021         return 0;
1022     }
1023 
1024     char *value;
1025     //value = fs_ini_file_get_string(ini_file, "device", "type");
1026 #if 0
1027     if cp.has_option('device', 'type'):
1028         self.type = cp.get('device', 'type')
1029     if cp.has_option('device', 'name'):
1030         self.name = cp.get('device', 'name')
1031         self.decorate_name_with_number()
1032 #endif
1033 
1034     const char *section = "default";
1035     if (fs_ini_file_has_group(ini_file, platform)) {
1036         section = platform;
1037     }
1038     else if (fs_ini_file_has_group(ini_file, "default")) {
1039 
1040     }
1041     else {
1042         fs_log("no config for platform %s\n", platform);
1043         return 0;
1044     }
1045 
1046     value = fs_ini_file_get_string(ini_file, section, "include");
1047     if (value) {
1048         //fs_log("has section/include\n");
1049         int len = strlen(value);
1050         for (int i = 0; i < len; i++) {
1051             if (value[i] == '/') {
1052                 value[i] = '_';
1053             }
1054         }
1055         int result = read_input_config(value, config, platform);
1056         g_free(value);
1057         if (!result) {
1058             return 0;
1059         }
1060     }
1061 
1062     char **keys = fs_ini_file_get_keys(ini_file, section, NULL);
1063     if (keys) {
1064         for (char **k = keys; *k; k++) {
1065             char *key = *k;
1066             value = fs_ini_file_get_string(ini_file, section, key);
1067             if (value == NULL) {
1068                 continue;
1069             }
1070             char *temp = g_hash_table_lookup(config, value);
1071             if (temp) {
1072                 g_hash_table_insert(config, g_strdup(key), g_strdup(temp));
1073                 g_hash_table_remove(config, value);
1074             }
1075             else {
1076                 g_hash_table_insert(config, g_strdup(key), g_strdup(value));
1077             }
1078             g_free(value);
1079         }
1080         g_strfreev(keys);
1081         keys = NULL;
1082     }
1083     // indicate success
1084     return 1;
1085 }
1086 
configure_input_device(const char * name,const char * platform)1087 static GHashTable *configure_input_device(
1088         const char *name, const char *platform)
1089 {
1090     GHashTable *config = g_hash_table_new(g_str_hash, g_str_equal);
1091     int result = read_input_config(name, config, platform);
1092     if (result) {
1093         return config;
1094     } else {
1095         g_hash_table_destroy(config);
1096         return NULL;
1097     }
1098 }
1099 
get_config(fs_ml_input_device * device,const char * type)1100 static input_config_item *get_config(
1101         fs_ml_input_device *device, const char *type)
1102 {
1103     input_config_item *config = NULL;
1104     char *config_name = NULL;
1105 
1106     if (config == NULL) {
1107         fs_log("config name \"%s\"\n", device->name);
1108         config = get_config_for_device(device->name, type);
1109         if (config == NULL) {
1110             fs_log("did not find config for device \"%s\"\n", device->name);
1111         }
1112     }
1113     if (config == NULL) {
1114         config_name = joystick_long_config_name(device);
1115         fs_log("config name \"%s\"\n", config_name);
1116         config = get_config_for_device(config_name, type);
1117         if (config == NULL) {
1118             fs_log("did not find config for device \"%s\"\n", config_name);
1119         }
1120         free(config_name);
1121     }
1122     if (config == NULL) {
1123         config_name = joystick_config_name(device->name, 0);
1124         fs_log("config name \"%s\"\n", config_name);
1125         config = get_config_for_device(config_name, type);
1126         if (config == NULL) {
1127             fs_log("did not find config for device \"%s\"\n", config_name);
1128         }
1129         free(config_name);
1130     }
1131     if (config == NULL) {
1132         config_name = g_strdup("unknown");
1133         fs_log("config name \"%s\"\n", config_name);
1134         config = get_config_for_device(config_name, type);
1135         if (config == NULL) {
1136             fs_log("did not find config for device \"%s\"\n", config_name);
1137         }
1138         free(config_name);
1139     }
1140     return config;
1141 }
1142 
fs_emu_configure_joystick(const char * name,const char * type,fs_emu_input_mapping * mapping,int usage,char * out_name,int out_name_len,bool reuse)1143 int fs_emu_configure_joystick(
1144         const char *name, const char *type, fs_emu_input_mapping *mapping,
1145         int usage, char *out_name, int out_name_len, bool reuse)
1146 {
1147     fs_log("configure joystick \"%s\" for \"%s\"\n", name, type);
1148     if (name == NULL || name[0] == '\0') {
1149         return 0;
1150     }
1151 
1152     // FIXME: replace use of fs_ml_input_device_get, use a function returning
1153     // a pointer instead, we we can use the usage flag
1154     fs_ml_input_device device;
1155     for (int i = 0; i < FS_ML_INPUT_DEVICES_MAX; i++) {
1156         if (!fs_ml_input_device_get(i, &device)) {
1157             continue;
1158         }
1159         if (device.name == NULL || (
1160                 (g_ascii_strcasecmp(device.name, name) != 0) &&
1161                 (g_ascii_strcasecmp(device.alias, name) != 0))) {
1162             fs_log("did not match device #%d (%s)\n", i, device.name);
1163             continue;
1164         }
1165         fs_log("matched device #%d\n", i);
1166         if (device.usage && !reuse) {
1167             fs_log("existing usage (%d) - cannot reuse\n", device.usage);
1168             return 0;
1169         }
1170         if (out_name) {
1171             strncpy(out_name, device.name, out_name_len);
1172         }
1173 
1174         input_config_item *config = get_config(&device, type);
1175         if (config == NULL) {
1176             fse_notify(0, _("Device needs config for %s: %s"),
1177                     type, name);
1178             break;
1179         }
1180         for (int j = 0; config[j].config_key != NULL; j++) {
1181             map_joystick(i, config + j, mapping, g_input_action_table,
1182                     NULL, NULL);
1183         }
1184 
1185         fs_ml_input_device *devices = fs_ml_get_input_devices(NULL);
1186         devices[i].usage = usage;
1187         free_input_config_item_list(config);
1188         return 1;
1189     }
1190     return 0;
1191 }
1192 
1193 //                printf("index %d action %d\n", index, action);
1194 //printf("index %d state = %d g_input_state[index] = %d\n", index, state, g_input_state[index]);
1195 //if (!g_fs_emu_menu_mode) {
1196 
1197 #define PROCESS_STATE \
1198         index = button_index(key, joystick, axis, hat, button, value); \
1199         if (g_input_state[index] != state) { \
1200             g_input_state[index] = state; \
1201             int menu_action = g_menu_action_table[index]; \
1202             int corresp_index = g_menu_action_corresponding[index]; \
1203             if (state && (menu_action == ACTION_MENU_START \
1204                     || menu_action == ACTION_MENU_SELECT \
1205                     || menu_action == ACTION_MENU_MENU) && \
1206                     (!corresp_index || g_input_state[corresp_index])) { \
1207                 fs_emu_menu_toggle(); \
1208             } \
1209             else if (fs_emu_menu_or_dialog_is_active()) {\
1210                 handled = 1; \
1211                 int action = g_menu_action_table[index]; \
1212                 if (action) {\
1213                     fs_emu_menu_function(action, state); \
1214                 } \
1215             } \
1216             else {\
1217                 int action = g_input_action_table[index]; \
1218                 if (action) {\
1219                     handled = 1; \
1220                     queue_input_event_with_state(action, state); \
1221                 } \
1222             } \
1223         }
1224 
process_input_event(fs_ml_event * event)1225 static int process_input_event(fs_ml_event *event)
1226 {
1227     int handled = 0;
1228 
1229     //fs_log("process_input_event type %d (%d)\n", event->type, FS_ML_JOYBUTTONDOWN);
1230     int joystick = event->jbutton.which;
1231 
1232     int state = 0;
1233     int key = -1;
1234     int axis = -1;
1235     int hat = -1;
1236     int button = -1;
1237     int value = 0;
1238     int index = 0;
1239 
1240     switch(event->type) {
1241         case FS_ML_KEYDOWN:
1242         case FS_ML_KEYUP:
1243             state = (event->type == FS_ML_KEYDOWN);
1244             key = event->key.keysym.sym;
1245             PROCESS_STATE;
1246             break;
1247         case FS_ML_JOYBUTTONDOWN:
1248         case FS_ML_JOYBUTTONUP:
1249             button = event->jbutton.button;
1250             state = event->jbutton.state;
1251             PROCESS_STATE;
1252             break;
1253         case FS_ML_JOYAXISMOTION:
1254             axis = event->jaxis.axis;
1255             state = event->jaxis.value < -20000;
1256             value = 0; // negative axis
1257             PROCESS_STATE;
1258             state = event->jaxis.value > 20000;
1259             value = 1; // positive axis
1260             PROCESS_STATE;
1261             break;
1262         case FS_ML_JOYHATMOTION:
1263             hat = event->jhat.hat;
1264             state = (event->jhat.value & FS_ML_HAT_LEFT) != 0;
1265             value = FS_ML_HAT_LEFT;
1266             PROCESS_STATE;
1267             state = (event->jhat.value & FS_ML_HAT_RIGHT) != 0;
1268             value = FS_ML_HAT_RIGHT;
1269             PROCESS_STATE;
1270             state = (event->jhat.value & FS_ML_HAT_UP) != 0;
1271             value = FS_ML_HAT_UP;
1272             PROCESS_STATE;
1273             state = (event->jhat.value & FS_ML_HAT_DOWN) != 0;
1274             value = FS_ML_HAT_DOWN;
1275             PROCESS_STATE;
1276             break;
1277     }
1278     return handled;
1279 }
1280 
1281 #define NOTIFICATION_FULL_KEYBOARD 0x30a91db6
1282 
1283 static bool g_full_keyboard;
1284 
fs_emu_full_keyboard_emulation(void)1285 bool fs_emu_full_keyboard_emulation(void)
1286 {
1287     return g_full_keyboard;
1288 }
1289 
fs_emu_set_full_keyboard_emulation(bool full,bool notification)1290 void fs_emu_set_full_keyboard_emulation(bool full, bool notification)
1291 {
1292     g_full_keyboard = full;
1293     if (notification) {
1294         const char *msg;
1295         if (g_full_keyboard) {
1296             msg = gettext("Full keyboard emulation enabled");
1297         } else {
1298             msg = gettext("Full keyboard emulation disabled");
1299         }
1300         fse_notify(NOTIFICATION_FULL_KEYBOARD, msg);
1301     }
1302 }
1303 
initialize_modifier_key(void)1304 static void initialize_modifier_key(void)
1305 {
1306     const char *value = fs_config_get_const_string(OPTION_MODIFIER_KEY);
1307     if (!value) {
1308 #ifdef MACOSX
1309         fs_log("[INPUT] Using default modifier key LSUPER\n");
1310         g_modifier_key = FS_ML_KEY_LSUPER;
1311 #else
1312         fs_log("[INPUT] Using default modifier key LALT\n");
1313         g_modifier_key = FS_ML_KEY_LALT;
1314 #endif
1315         return;
1316     } else if (strcmp(value, "0") == 0) {
1317         fs_log("[INPUT] Modifier key disabled\n");
1318         g_modifier_key = -1;
1319         return;
1320     }
1321 
1322     int key = 0;
1323     map_input_config_item(value, &key, NULL, NULL, NULL, NULL);
1324     if (key) {
1325         fs_log("[INPUT] Using modifier key 0x%d (%s)\n", key, value);
1326         g_modifier_key = key;
1327     } else {
1328         fs_log("[INPUT] Error parsing modifier key (%s)\n", value);
1329     }
1330 }
1331 
handle_modifier_key(int key_code,int state)1332 static bool handle_modifier_key(int key_code, int state)
1333 {
1334     if (key_code == g_modifier_key) {
1335         g_modifier_key_pressed = state ? true : false;
1336         if (state) {
1337             if (!fs_emu_full_keyboard_emulation()) {
1338                 if (fs_emu_input_grab()) {
1339                     fs_emu_set_input_grab_and_visibility(false, 0);
1340                     g_fs_emu_grab_input_on_mod_release = true;
1341                 }
1342             }
1343         } else {
1344             if (g_fs_emu_grab_input_on_mod_release) {
1345                 if (!fs_emu_input_grab())
1346                     fs_emu_set_input_grab(true);
1347                 g_fs_emu_grab_input_on_mod_release = false;
1348             }
1349         }
1350         if (!fs_emu_full_keyboard_emulation()) {
1351             /* Signal that we want to swallow this key event. */
1352             return true;
1353         }
1354     }
1355     /* Continue processing the key event. */
1356     return false;
1357 }
1358 
1359 #define F11_F12_SPECIAL_STATE -1
1360 
fs_emu_process_key_event(int key_code,int key_mod,int state)1361 int fs_emu_process_key_event(int key_code, int key_mod, int state)
1362 {
1363 #if 0
1364     fs_log("fs_emu_process_key_event %d %d %d\n", key_code, key_mod, state);
1365 #endif
1366 
1367     if (key_code == FS_ML_KEY_F11 || key_code == FS_ML_KEY_F12) {
1368         /* Special handling because we only want to process F11/F12 if
1369          * it hasn't been used as a modifier key. */
1370         if (state == F11_F12_SPECIAL_STATE)
1371             state = 1;
1372         else
1373             return 1;
1374     }
1375 
1376     int index = key_index(key_code, key_mod, 0);
1377 
1378     if (fs_emu_menu_or_dialog_is_active()) {
1379 #if 0
1380         //printf("in menu mode\n");
1381         // for now
1382         return 0;
1383 #endif
1384         int action = g_menu_action_table[index];
1385         fs_emu_menu_function(action, state);
1386         return 1;
1387     }
1388 
1389     int input_event = g_input_action_table[index];
1390 
1391     if (state == 0) {
1392         /* The key was released - we must now send a "release" event for
1393          * the key that was originally pressed (with the original
1394          * modifiers). */
1395         key_mod = g_key_modifiers_at_pressed_state[key_code];
1396     } else {
1397         g_key_modifiers_at_pressed_state[key_code] = key_mod;
1398     }
1399 
1400     if (g_fs_log_input) {
1401         fs_log("--> key_code %d key_mod %d state %d: \"%s\"\n",
1402                 key_code, key_mod, state, g_fs_emu_key_names[key_code]);
1403     }
1404     // 65536 is also used as null event
1405     if (input_event > 0 && input_event < 65536) {
1406         if (g_fs_log_input) {
1407             fs_log("  = press (index %d) => "
1408                     "input event %d\n", index, input_event);
1409         }
1410         // encode both state and input event in input_event
1411         input_event = input_event | (state << 16);
1412         fs_emu_queue_input_event(input_event);
1413     }
1414     else if (g_fs_log_input) {
1415         fs_log("  = press (index %d) => NO INPUT EVENT\n", index);
1416     }
1417     return 1;
1418 }
1419 
fs_emu_process_event(fs_emu_event * event)1420 int fs_emu_process_event(fs_emu_event *event)
1421 {
1422     return 0;
1423 }
1424 
1425 static fs_emu_input_mapping g_menu_mapping[] = {
1426     { "left", ACTION_MENU_LEFT },
1427     { "right", ACTION_MENU_RIGHT },
1428     { "up", ACTION_MENU_UP },
1429     { "down", ACTION_MENU_DOWN },
1430     { "primary", ACTION_MENU_PRIMARY },
1431     { "back", ACTION_MENU_BACK },
1432     { "menu", ACTION_MENU_MENU },
1433     { "escape", ACTION_MENU_ESCAPE },
1434     { "start", ACTION_MENU_START },
1435     { "select", ACTION_MENU_SELECT },
1436     { NULL, ACTION_MENU_NONE },
1437 };
1438 
read_input_configs_from_dir(const char * dir_name)1439 static void read_input_configs_from_dir(const char *dir_name)
1440 {
1441     fs_log("reading input device configs from %s\n", dir_name);
1442     GDir *dir = g_dir_open(dir_name, 0, NULL);
1443     if (dir == NULL) {
1444         fs_log("could not read directory %s\n", dir_name);
1445         return;
1446     }
1447     const char *name;
1448     while ((name = g_dir_read_name(dir)) != NULL) {
1449         //fs_log("name: %s\n", name);
1450         char *dir2_name = g_build_filename(dir_name, name, NULL);
1451         GDir *dir2 = g_dir_open(dir2_name, 0, NULL);
1452         if (dir2 == NULL) {
1453             if (g_str_has_suffix(name, ".ini")) {
1454                 // remove .ini suffix
1455                 char* name3 = g_strdup(name);
1456                 name3[strlen(name3) - 4] = '\0';
1457                 g_hash_table_insert(g_input_config_paths, g_strdup(name3),
1458                                     g_strdup(dir2_name));
1459                 ////fs_log("[*] %s\n", name3);
1460                 g_free(name3);
1461             } else if (g_str_has_suffix(name, ".conf")) {
1462                 // remove .conf suffix
1463                 char* name3 = g_strdup(name);
1464                 name3[strlen(name3) - 5] = '\0';
1465                 g_hash_table_insert(g_input_config_paths, g_strdup(name3),
1466                                     g_strdup(dir2_name));
1467                 //fs_log("[*] %s\n", name3);
1468                 g_free(name3);
1469             }
1470             g_free(dir2_name);
1471             continue;
1472         }
1473         const char *name2;
1474         while ((name2 = g_dir_read_name(dir2)) != NULL) {
1475             //fs_log("name2: %s\n", name2);
1476             if (!g_str_has_suffix(name2, ".ini")) {
1477                 continue;
1478             }
1479             // remove .ini suffix
1480             char* name3 = g_strdup(name2);
1481             name3[strlen(name3) - 4] = '\0';
1482             char *path = g_build_filename(dir2_name, name2, NULL);
1483             char* full_name = g_strconcat(name, "_", name3, NULL);
1484             //register_input_config(full_name, path);
1485             //register_input_config(name2, path);
1486             g_hash_table_insert(g_input_config_paths, g_strdup(full_name),
1487                                 g_strdup(path));
1488             g_hash_table_insert(g_input_config_paths, g_strconcat(
1489                                     full_name, "_usb", NULL), g_strdup(path));
1490             ////fs_log("[*] %s\n", full_name);
1491             g_hash_table_insert(g_input_config_paths, g_strdup(name3),
1492                                 g_strdup(path));
1493             g_hash_table_insert(g_input_config_paths, g_strconcat(
1494                     name3, "_usb", NULL), g_strdup(path));
1495             ////fs_log("[*] %s\n", name3);
1496             g_free(full_name);
1497             g_free(path);
1498             g_free(name3);
1499         }
1500 
1501         g_dir_close(dir2);
1502         g_free(dir2_name);
1503     }
1504 
1505     g_dir_close(dir);
1506 }
1507 
init_input_configs()1508 static void init_input_configs()
1509 {
1510     fs_log("init_input_configs\n");
1511     g_input_config_paths = g_hash_table_new_full(g_str_hash, g_str_equal,
1512                                                  g_free, g_free);
1513     char *dir_name = fs_get_program_data_file("input");
1514     if (dir_name != NULL) {
1515         read_input_configs_from_dir(dir_name);
1516         free(dir_name);
1517     }
1518     // read override configurations
1519     if (g_controllers_dir) {
1520         read_input_configs_from_dir(g_controllers_dir);
1521     }
1522     // read override configurations
1523     gchar *devs_dir = g_build_filename(fs_data_dir(), "Devs", "Keyboards", NULL);
1524     read_input_configs_from_dir(devs_dir);
1525     g_free(devs_dir);
1526     if (g_controllers_dir) {
1527         read_input_configs_from_dir(g_controllers_dir);
1528     }
1529 }
1530 
handle_shortcut(fs_ml_event * event)1531 static int handle_shortcut(fs_ml_event *event)
1532 {
1533     //int sym = event->key.keysym.sym;
1534     int key_code = event->key.keysym.sym;
1535     int key_mod = event->key.keysym.mod;
1536     int state = (event->type == FS_ML_KEYDOWN);
1537     int special = key_mod & (FS_ML_KEY_MOD_F11 | FS_ML_KEY_MOD_F12);
1538 
1539     /* Keep track of whether F11/F12 has been used alone or not. This code
1540      * will get a little confused if you use F11 and F12 keys
1541      * simultaneously. */
1542     static int special_pressed = 0;
1543     static int special_combo = 0;
1544 
1545     if (key_code == FS_ML_KEY_F11 || key_code == FS_ML_KEY_F12) {
1546         if (state) {
1547             special_pressed = 1;
1548         }
1549         // we must check key codes here, not modifiers, since the modifier will
1550         // be reset now that the keys are unpressed
1551         if (!state) {
1552             // we check special pressed here, because we get an bogus
1553             // release event after switching fullscreen / window mode
1554             if (special_pressed && !special_combo) {
1555                 if (key_code == FS_ML_KEY_F12) {
1556                     fs_emu_process_key_event(
1557                         FS_ML_KEY_F12, 0, F11_F12_SPECIAL_STATE);
1558                 }
1559                 else {
1560                     fs_emu_process_key_event(
1561                         FS_ML_KEY_F11, 0, F11_F12_SPECIAL_STATE);
1562                 }
1563             }
1564             special_combo = 0;
1565             special_pressed = 0;
1566         }
1567     }
1568     else if (special) {
1569         if (state) {
1570             // F11/F12 has been used in combination with another key
1571             special_combo = 1;
1572             /* FIXME: can this be removed? */
1573         }
1574     }
1575 
1576     if (special || key_code == FS_ML_KEY_F11 || key_code == FS_ML_KEY_F12) {
1577         return 0;
1578     }
1579 
1580     if (key_code == FS_ML_KEY_TAB && !fs_emu_hud_in_chat_mode() &&
1581             !fs_emu_menu_or_dialog_is_active()) {
1582         if (key_mod == 0 && fs_emu_netplay_enabled()) {
1583             if (state) {
1584                 fs_emu_hud_enable_chat_mode();
1585             }
1586             return 1;
1587         }
1588     }
1589     if (key_code == FS_ML_KEY_F10) {
1590         if (key_mod & FS_ML_KEY_MOD_CTRL) {
1591             if (state) {
1592                 g_fs_emu_video_debug = !g_fs_emu_video_debug;
1593             }
1594             return 1;
1595         }
1596     }
1597     else if (key_code == FS_ML_KEY_F9) {
1598         if (key_mod & FS_ML_KEY_MOD_CTRL) {
1599             if (state) {
1600                 if (g_fs_emu_benchmark_start_time == 0) {
1601                     g_fs_emu_benchmark_start_time = fs_emu_monotonic_time();
1602                 }
1603             }
1604             return 1;
1605         }
1606     }
1607     else if (fs_emu_hud_in_chat_mode() && !fs_emu_menu_or_dialog_is_active()) {
1608         if (state) {
1609             fs_emu_hud_handle_chat_input(event);
1610         }
1611         return 1;
1612     }
1613     return 0;
1614 }
1615 
1616 static int g_middle_click_ungrab = 1;
1617 static int g_swap_ctrl_keys = 0;
1618 static int g_fs_emu_mouse_speed = 100;
1619 
1620 #define MAX_MICE 2
1621 #define MAX_MICE_AXES 2
1622 
adjust_mouse_movement(int mouse,int axis,int * movement)1623 static void adjust_mouse_movement(int mouse, int axis, int *movement) {
1624     static double fract[MAX_MICE][MAX_MICE_AXES];
1625     double d = *movement * g_fs_emu_mouse_speed / 100.0;
1626     int v = (int)d;
1627     fract[mouse][axis] += d - v;
1628     int diff = (int) fract[mouse][axis];
1629     v += diff;
1630     fract[mouse][axis] -= diff;
1631     *movement = v;
1632 }
1633 
1634 #include <fs/emu/hacks.h>
1635 
1636 int fs_emu_mouse_absolute_x = 0;
1637 int fs_emu_mouse_absolute_y = 0;
1638 
input_function(fs_ml_event * event)1639 static int input_function(fs_ml_event *event)
1640 {
1641     if (event->type == FS_ML_MOUSEMOTION) {
1642         if (g_ignore_next_motion) {
1643             g_ignore_next_motion = 0;
1644             return 1;
1645         }
1646         // if (event->motion.device > 1) {
1647         //     printf("motion (device %d) %d %d\n", event->motion.device,
1648         //             event->motion.xrel, event->motion.yrel);
1649         // }
1650 
1651         if (fs_emu_input_grab() == FALSE) {
1652             if (fs_emu_cursor_allowed()) {
1653                 fs_emu_show_cursor_msec(FS_EMU_MOUSE_DEFAULT_DURATION);
1654             }
1655         }
1656 
1657         if (event->motion.x != FS_ML_NO_ABSOLUTE_MOUSE_POS &&
1658                 event->motion.y != FS_ML_NO_ABSOLUTE_MOUSE_POS) {
1659             fs_emu_mouse_absolute_x = event->motion.x;
1660             fs_emu_mouse_absolute_y = event->motion.y;
1661             //printf("ABS: %d, %d\n",
1662             //       fs_emu_mouse_absolute_x, fs_emu_mouse_absolute_y);
1663         }
1664 
1665         if (event->motion.xrel) {
1666             //printf("xrel %d x %d\n", event->motion.xrel, event->motion.x);
1667             int input_event = g_input_action_table[mouse_index(
1668                     event->motion.device, 1, 0, 0)];
1669             // printf("x input_event %d\n", input_event);
1670             int movement = event->motion.xrel;
1671             adjust_mouse_movement(0, 0, &movement);
1672 
1673             if (input_event > 0) {
1674                 int state = MAX(-128, MIN(127, movement));
1675                 input_event = input_event | (state << 16);
1676                 input_event = input_event & 0x00ffffff;
1677                 fs_emu_queue_input_event(input_event);
1678             }
1679         }
1680         if (event->motion.yrel) {
1681             int input_event = g_input_action_table[mouse_index(
1682                     event->motion.device, 0, 1, 0)];
1683             int movement = event->motion.yrel;
1684             adjust_mouse_movement(0, 1, &movement);
1685             if (input_event > 0) {
1686                 int state = MAX(-128, MIN(127, movement));
1687                 input_event = input_event | (state << 16);
1688                 input_event = input_event & 0x00ffffff;
1689                 fs_emu_queue_input_event(input_event);
1690             }
1691         }
1692     }
1693     else if (event->type == FS_ML_KEYDOWN || event->type == FS_ML_KEYUP) {
1694         if (g_swap_ctrl_keys) {
1695             if (event->key.keysym.sym == FS_ML_KEY_LCTRL) {
1696                 event->key.keysym.sym = FS_ML_KEY_RCTRL;
1697             }
1698             else if (event->key.keysym.sym == FS_ML_KEY_RCTRL) {
1699                 event->key.keysym.sym = FS_ML_KEY_LCTRL;
1700             }
1701         }
1702         if (handle_modifier_key(
1703                 event->key.keysym.sym, event->type == FS_ML_KEYDOWN)) {
1704             return 1;
1705         }
1706         if (handle_shortcut(event)) {
1707             /* Mostly just net play chat and a few special shortcuts. */
1708             return 1;
1709         }
1710         if (fs_emu_process_key_event(event->key.keysym.sym,
1711                 event_mod(event), event->type == FS_ML_KEYDOWN)) {
1712             return 1;
1713         }
1714     }
1715     else if (event->type == FS_ML_TEXTINPUT) {
1716         //printf("text: %s\n", event->text.text);
1717         if (fs_emu_hud_in_chat_mode() && !fs_emu_menu_or_dialog_is_active()) {
1718             fs_emu_hud_handle_chat_input(event);
1719             return 1;
1720         }
1721     }
1722     /*
1723     else if (event->type == FS_ML_KEYUP) {
1724 
1725         // FIXME: key depress is sent to Amiga for key presses which
1726         // are processed by chat...
1727 
1728         if (fs_emu_process_key_event(event->key.keysym.sym,
1729                 event_mod(event), event->type == FS_ML_KEYDOWN)) {
1730             return 1;
1731         }
1732     }
1733     */
1734     else if (event->type == FS_ML_MOUSEBUTTONDOWN
1735              || event->type == FS_ML_MOUSEBUTTONUP) {
1736         if (event->type == FS_ML_MOUSEBUTTONDOWN
1737                 && event->button.device == fs_ml_first_mouse_index()) {
1738             /* We only check this for device 1 (system mouse), since otherwise
1739              * we would process double events due to specific mouse input
1740              * events too (ManyMouse). */
1741             if (fs_emu_input_grab()) {
1742                 if (g_middle_click_ungrab
1743                         && event->button.button == FS_ML_BUTTON_MIDDLE) {
1744                     fs_emu_set_input_grab(false);
1745                 }
1746             } else if (fs_emu_menu_mode()) {
1747                     /* Mouse is always ungrabbed in menu mode. */
1748             } else {
1749                 if (g_middle_click_ungrab
1750                         && event->button.button == FS_ML_BUTTON_MIDDLE) {
1751                     fs_emu_set_input_grab(true);
1752                 } else if (fs_ml_automatic_input_grab()) {
1753                     fs_emu_set_input_grab(true);
1754                 }
1755             }
1756         }
1757 
1758         int state = event->button.state;
1759         if (g_fs_log_input) {
1760             fs_log(" => mouse button %d, %d\n", event->button.button, state);
1761         }
1762         if (event->button.button == FS_ML_BUTTON_WHEELUP) {
1763             state = state * 1;
1764         }
1765         else if (event->button.button == FS_ML_BUTTON_WHEELDOWN) {
1766             state = state * -1;
1767         }
1768         int input_event = g_input_action_table[mouse_index(
1769                 event->button.device, 0, 0, event->button.button)];
1770         if (input_event > 0) {
1771             if (g_fs_log_input) {
1772                 fs_log(" => button input_event %d state %d\n",
1773                        input_event, state);
1774             }
1775             input_event = input_event | (state << 16);
1776             input_event = input_event & 0x00ffffff;
1777             fs_emu_queue_input_event(input_event);
1778         }
1779     }
1780     //printf("calling process_input_event\n");
1781     return process_input_event(event);
1782 }
1783 
initialize_devices_for_menu(void)1784 static void initialize_devices_for_menu(void)
1785 {
1786     fs_log("[INPUT] Initializing devices for \"menu\"\n");
1787     fs_ml_input_device device;
1788     for (int i = 0; i < FS_ML_INPUT_DEVICES_MAX; i++) {
1789         if (!fs_ml_input_device_get(i, &device)) {
1790             continue;
1791         }
1792         fs_log("%i %s\n", i, device.name);
1793         input_config_item *config = NULL;
1794         if (config == NULL) {
1795             fs_log("[INPUT] Config name \"%s\"\n", device.name);
1796             config = get_config_for_device(device.name, "menu");
1797             if (config == NULL) {
1798                 fs_log("[INPUT] Did not find config for device "
1799                        "\"%s\"\n", device.name);
1800             }
1801         }
1802         if (config == NULL) {
1803             char *config_name = joystick_long_config_name(&device);
1804             config = get_config_for_device(config_name, "menu");
1805             if (config == NULL) {
1806                 fs_log("[INPUT] Did not find menu config for device "
1807                        "\"%s\"\n", config_name);
1808             }
1809             g_free(config_name);
1810         }
1811         if (config == NULL) {
1812             char *config_name = joystick_config_name(device.name, 0);
1813             config = get_config_for_device(config_name, "menu");
1814             if (config == NULL) {
1815                 fs_log("[INPUT] Did not find menu config for device"
1816                        "\"%s\"\n", config_name);
1817             }
1818             g_free(config_name);
1819         }
1820         if (config != NULL) {
1821             int start_index = 0;
1822             int select_index = 0;
1823             int action, index;
1824             for (int j = 0; config[j].config_key != NULL; j++) {
1825                 if (map_joystick(i, config + j, g_menu_mapping,
1826                         g_menu_action_table, &action, &index)) {
1827                     if (action == ACTION_MENU_START) {
1828                         start_index = index;
1829                     } else if (action == ACTION_MENU_SELECT) {
1830                         select_index = index;
1831                     }
1832                 }
1833             }
1834             if (start_index && select_index) {
1835                 /* Register menu button emulation. */
1836                 g_menu_action_corresponding[start_index] = select_index;
1837                 g_menu_action_corresponding[select_index] = start_index;
1838             }
1839             free_input_config_item_list(config);
1840         }
1841     }
1842 }
1843 
fs_emu_input_init_2(void)1844 void fs_emu_input_init_2(void)
1845 {
1846     fs_log("[INPUT] fs_emu_input_init\n");
1847 
1848     g_input_event_mutex = fs_mutex_create();
1849     g_input_event_queue = g_queue_new();
1850 
1851     init_input_configs();
1852 
1853     // reset all input mappings
1854     for (int i = 0; i < (MAX_DEVICES * SLOTS); i++) {
1855         g_input_action_table[i] = 0;
1856         g_menu_action_table[i] = 0;
1857     }
1858 
1859     if (fs_config_get_boolean("middle_click_ungrab") == 0) {
1860         g_middle_click_ungrab = 0;
1861     }
1862 
1863     g_fs_emu_mouse_speed = fs_config_get_int("mouse_speed");
1864     if (g_fs_emu_mouse_speed <= 0 || g_fs_emu_mouse_speed > 500) {
1865         g_fs_emu_mouse_speed = 100;
1866     }
1867 
1868     if (g_fs_emu_mouse_speed <= 0 || g_fs_emu_mouse_speed > 500) {
1869         g_fs_emu_mouse_speed = 100;
1870     }
1871 
1872     g_swap_ctrl_keys = fs_config_get_boolean("swap_ctrl_keys");
1873     if (g_swap_ctrl_keys == FS_CONFIG_NONE) {
1874         g_swap_ctrl_keys = 0;
1875     }
1876 
1877     if (fs_config_true(OPTION_FULL_KEYBOARD)) {
1878         fs_emu_set_full_keyboard_emulation(true, false);
1879     }
1880 
1881     initialize_modifier_key();
1882     initialize_devices_for_menu();
1883     fs_ml_set_input_function(input_function);
1884 }
1885