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