comparison io.c @ 903:0e5f9d6135be

Make nexus player remote useable as a controller for games that only require a dpad + start + c. Use warning() instead of fprintf(stder,...) in io.c
author Michael Pavone <pavone@retrodev.com>
date Sat, 28 Nov 2015 14:30:30 -0800
parents b9564fb88a5a
children b5d35222047e
comparison
equal deleted inserted replaced
902:6011409ded0d 903:0e5f9d6135be
16 #include <stdlib.h> 16 #include <stdlib.h>
17 17
18 #include "io.h" 18 #include "io.h"
19 #include "blastem.h" 19 #include "blastem.h"
20 #include "render.h" 20 #include "render.h"
21 #include "util.h"
21 22
22 const char * device_type_names[] = { 23 const char * device_type_names[] = {
23 "3-button gamepad", 24 "3-button gamepad",
24 "6-button gamepad", 25 "6-button gamepad",
25 "Mega Mouse", 26 "Mega Mouse",
73 typedef struct { 74 typedef struct {
74 io_port *port; 75 io_port *port;
75 uint8_t mode; 76 uint8_t mode;
76 } mousebinding; 77 } mousebinding;
77 78
78 keybinding * bindings[256]; 79 keybinding * bindings[0x10000];
79 keybinding * joybindings[MAX_JOYSTICKS]; 80 keybinding * joybindings[MAX_JOYSTICKS];
80 joydpad * joydpads[MAX_JOYSTICKS]; 81 joydpad * joydpads[MAX_JOYSTICKS];
81 mousebinding *mice[MAX_MICE]; 82 mousebinding *mice[MAX_MICE];
82 const uint8_t dpadbits[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT}; 83 const uint8_t dpadbits[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT};
83 84
84 void bind_key(int keycode, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value) 85 void bind_key(int keycode, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value)
85 { 86 {
86 int bucket = keycode >> 8 & 0xFF; 87 int bucket = keycode >> 15 & 0xFFFF;
87 if (!bindings[bucket]) { 88 if (!bindings[bucket]) {
88 bindings[bucket] = malloc(sizeof(keybinding) * 256); 89 bindings[bucket] = malloc(sizeof(keybinding) * 0x8000);
89 memset(bindings[bucket], 0, sizeof(keybinding) * 256); 90 memset(bindings[bucket], 0, sizeof(keybinding) * 0x8000);
90 } 91 }
91 int idx = keycode & 0xFF; 92 int idx = keycode & 0x7FFF;
92 bindings[bucket][idx].bind_type = bind_type; 93 bindings[bucket][idx].bind_type = bind_type;
93 bindings[bucket][idx].subtype_a = subtype_a; 94 bindings[bucket][idx].subtype_a = subtype_a;
94 bindings[bucket][idx].subtype_b = subtype_b; 95 bindings[bucket][idx].subtype_b = subtype_b;
95 bindings[bucket][idx].value = value; 96 bindings[bucket][idx].value = value;
96 } 97 }
209 } 210 }
210 } 211 }
211 212
212 void handle_keydown(int keycode) 213 void handle_keydown(int keycode)
213 { 214 {
214 int bucket = keycode >> 8 & 0xFF; 215 int bucket = keycode >> 15 & 0xFFFF;
215 if (!bindings[bucket]) { 216 if (!bindings[bucket]) {
216 return; 217 return;
217 } 218 }
218 int idx = keycode & 0xFF; 219 int idx = keycode & 0x7FFF;
219 keybinding * binding = bindings[bucket] + idx; 220 keybinding * binding = bindings[bucket] + idx;
220 handle_binding_down(binding); 221 handle_binding_down(binding);
221 } 222 }
222 223
223 void handle_joydown(int joystick, int button) 224 void handle_joydown(int joystick, int button)
305 } 306 }
306 } 307 }
307 308
308 void handle_keyup(int keycode) 309 void handle_keyup(int keycode)
309 { 310 {
310 int bucket = keycode >> 8 & 0xFF; 311 int bucket = keycode >> 15 & 0xFFFF;
311 if (!bindings[bucket]) { 312 if (!bindings[bucket]) {
312 return; 313 return;
313 } 314 }
314 int idx = keycode & 0xFF; 315 int idx = keycode & 0x7FFF;
315 keybinding * binding = bindings[bucket] + idx; 316 keybinding * binding = bindings[bucket] + idx;
316 handle_binding_up(binding); 317 handle_binding_up(binding);
317 } 318 }
318 319
319 void handle_joyup(int joystick, int button) 320 void handle_joyup(int joystick, int button)
363 *padnum_out = padnum; 364 *padnum_out = padnum;
364 *padbutton_out = button; 365 *padbutton_out = button;
365 return 1; 366 return 1;
366 } else { 367 } else {
367 if (target[gpadslen+1]) { 368 if (target[gpadslen+1]) {
368 fprintf(stderr, "Gamepad mapping string '%s' refers to an invalid button '%s'\n", target, target + gpadslen + 1); 369 warning("Gamepad mapping string '%s' refers to an invalid button '%s'\n", target, target + gpadslen + 1);
369 } else { 370 } else {
370 fprintf(stderr, "Gamepad mapping string '%s' has no button component\n", target); 371 warning("Gamepad mapping string '%s' has no button component\n", target);
371 } 372 }
372 } 373 }
373 } else { 374 } else {
374 fprintf(stderr, "Gamepad mapping string '%s' refers to an invalid gamepad number %c\n", target, target[gpadslen]); 375 warning("Gamepad mapping string '%s' refers to an invalid gamepad number %c\n", target, target[gpadslen]);
375 } 376 }
376 } else if(!strncmp(target, "ui.", strlen("ui."))) { 377 } else if(!strncmp(target, "ui.", strlen("ui."))) {
377 *padbutton_out = 0; 378 *padbutton_out = 0;
378 if (!strcmp(target + 3, "vdp_debug_mode")) { 379 if (!strcmp(target + 3, "vdp_debug_mode")) {
379 *ui_out = UI_DEBUG_MODE_INC; 380 *ui_out = UI_DEBUG_MODE_INC;
391 } else if(!strcmp(target + 3, "prev_speed")) { 392 } else if(!strcmp(target + 3, "prev_speed")) {
392 *ui_out = UI_PREV_SPEED; 393 *ui_out = UI_PREV_SPEED;
393 } else if(!strcmp(target + 3, "exit")) { 394 } else if(!strcmp(target + 3, "exit")) {
394 *ui_out = UI_EXIT; 395 *ui_out = UI_EXIT;
395 } else { 396 } else {
396 fprintf(stderr, "Unreconized UI binding type %s\n", target); 397 warning("Unreconized UI binding type %s\n", target);
397 return 0; 398 return 0;
398 } 399 }
399 return 2; 400 return 2;
400 } else { 401 } else {
401 fprintf(stderr, "Unrecognized binding type %s\n", target); 402 warning("Unrecognized binding type %s\n", target);
402 } 403 }
403 return 0; 404 return 0;
404 } 405 }
405 406
406 void process_keys(tern_node * cur, tern_node * special, tern_node * padbuttons, char * prefix) 407 void process_keys(tern_node * cur, tern_node * special, tern_node * padbuttons, char * prefix)
426 } else { 427 } else {
427 int keycode = tern_find_int(special, curstr, 0); 428 int keycode = tern_find_int(special, curstr, 0);
428 if (!keycode) { 429 if (!keycode) {
429 keycode = curstr[0]; 430 keycode = curstr[0];
430 if (curstr[1] != 0) { 431 if (curstr[1] != 0) {
431 fprintf(stderr, "%s is not recognized as a key identifier, truncating to %c\n", curstr, curstr[0]); 432 warning("%s is not recognized as a key identifier, truncating to %c\n", curstr, curstr[0]);
432 } 433 }
433 } 434 }
434 char * target = cur->straight.value.ptrval; 435 char * target = cur->straight.value.ptrval;
435 int ui_func, padnum, button; 436 int ui_func, padnum, button;
436 int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); 437 int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button);
469 process_speeds(cur->straight.next, curstr); 470 process_speeds(cur->straight.next, curstr);
470 } else { 471 } else {
471 int speed_index = atoi(curstr); 472 int speed_index = atoi(curstr);
472 if (speed_index < 1) { 473 if (speed_index < 1) {
473 if (!strcmp(curstr, "0")) { 474 if (!strcmp(curstr, "0")) {
474 fputs("Speed index 0 cannot be set to a custom value\n", stderr); 475 warning("Speed index 0 cannot be set to a custom value\n");
475 } else { 476 } else {
476 fprintf(stderr, "%s is not a valid speed index", curstr); 477 warning("%s is not a valid speed index", curstr);
477 } 478 }
478 } else { 479 } else {
479 if (speed_index >= num_speeds) { 480 if (speed_index >= num_speeds) {
480 speeds = realloc(speeds, sizeof(uint32_t) * (speed_index+1)); 481 speeds = realloc(speeds, sizeof(uint32_t) * (speed_index+1));
481 for(; num_speeds < speed_index + 1; num_speeds++) { 482 for(; num_speeds < speed_index + 1; num_speeds++) {
508 (device_type[gamepad_len] != '3' && device_type[gamepad_len] != '6') 509 (device_type[gamepad_len] != '3' && device_type[gamepad_len] != '6')
509 || device_type[gamepad_len+1] != '.' || device_type[gamepad_len+2] < '1' 510 || device_type[gamepad_len+1] != '.' || device_type[gamepad_len+2] < '1'
510 || device_type[gamepad_len+2] > '8' || device_type[gamepad_len+3] != 0 511 || device_type[gamepad_len+2] > '8' || device_type[gamepad_len+3] != 0
511 ) 512 )
512 { 513 {
513 fprintf(stderr, "%s is not a valid gamepad type\n", device_type); 514 warning("%s is not a valid gamepad type\n", device_type);
514 } else if (device_type[gamepad_len] == '3') 515 } else if (device_type[gamepad_len] == '3')
515 { 516 {
516 port->device_type = IO_GAMEPAD3; 517 port->device_type = IO_GAMEPAD3;
517 } else { 518 } else {
518 port->device_type = IO_GAMEPAD6; 519 port->device_type = IO_GAMEPAD6;
570 if (ports[i].device_type == IO_SEGA_PARALLEL) 571 if (ports[i].device_type == IO_SEGA_PARALLEL)
571 { 572 {
572 char *pipe_name = tern_find_path(config, "io\0parallel_pipe\0").ptrval; 573 char *pipe_name = tern_find_path(config, "io\0parallel_pipe\0").ptrval;
573 if (!pipe_name) 574 if (!pipe_name)
574 { 575 {
575 fprintf(stderr, "IO port %s is configured to use the sega parallel board, but no paralell_pipe is set!\n", io_name(i)); 576 warning("IO port %s is configured to use the sega parallel board, but no paralell_pipe is set!\n", io_name(i));
576 ports[i].device_type = IO_NONE; 577 ports[i].device_type = IO_NONE;
577 } else { 578 } else {
578 printf("IO port: %s connected to device '%s' with pipe name: %s\n", io_name(i), device_type_names[ports[i].device_type], pipe_name); 579 printf("IO port: %s connected to device '%s' with pipe name: %s\n", io_name(i), device_type_names[ports[i].device_type], pipe_name);
579 if (!strcmp("stdin", pipe_name)) 580 if (!strcmp("stdin", pipe_name))
580 { 581 {
581 ports[i].device.stream.data_fd = STDIN_FILENO; 582 ports[i].device.stream.data_fd = STDIN_FILENO;
582 } else { 583 } else {
583 if (mkfifo(pipe_name, 0666) && errno != EEXIST) 584 if (mkfifo(pipe_name, 0666) && errno != EEXIST)
584 { 585 {
585 fprintf(stderr, "Failed to create fifo %s for Sega parallel board emulation: %d %s\n", pipe_name, errno, strerror(errno)); 586 warning("Failed to create fifo %s for Sega parallel board emulation: %d %s\n", pipe_name, errno, strerror(errno));
586 ports[i].device_type = IO_NONE; 587 ports[i].device_type = IO_NONE;
587 } else { 588 } else {
588 ports[i].device.stream.data_fd = open(pipe_name, O_NONBLOCK | O_RDONLY); 589 ports[i].device.stream.data_fd = open(pipe_name, O_NONBLOCK | O_RDONLY);
589 if (ports[i].device.stream.data_fd == -1) 590 if (ports[i].device.stream.data_fd == -1)
590 { 591 {
591 fprintf(stderr, "Failed to open fifo %s for Sega parallel board emulation: %d %s\n", pipe_name, errno, strerror(errno)); 592 warning("Failed to open fifo %s for Sega parallel board emulation: %d %s\n", pipe_name, errno, strerror(errno));
592 ports[i].device_type = IO_NONE; 593 ports[i].device_type = IO_NONE;
593 } 594 }
594 } 595 }
595 } 596 }
596 } 597 }
597 } else if (ports[i].device_type == IO_GENERIC) { 598 } else if (ports[i].device_type == IO_GENERIC) {
598 char *sock_name = tern_find_path(config, "io\0socket\0").ptrval; 599 char *sock_name = tern_find_path(config, "io\0socket\0").ptrval;
599 if (!sock_name) 600 if (!sock_name)
600 { 601 {
601 fprintf(stderr, "IO port %s is configured to use generic IO, but no socket is set!\n", io_name(i)); 602 warning("IO port %s is configured to use generic IO, but no socket is set!\n", io_name(i));
602 ports[i].device_type = IO_NONE; 603 ports[i].device_type = IO_NONE;
603 } else { 604 } else {
604 printf("IO port: %s connected to device '%s' with socket name: %s\n", io_name(i), device_type_names[ports[i].device_type], sock_name); 605 printf("IO port: %s connected to device '%s' with socket name: %s\n", io_name(i), device_type_names[ports[i].device_type], sock_name);
605 ports[i].device.stream.data_fd = -1; 606 ports[i].device.stream.data_fd = -1;
606 ports[i].device.stream.listen_fd = socket(AF_UNIX, SOCK_STREAM, 0); 607 ports[i].device.stream.listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
609 struct sockaddr_un *saddr = malloc(addrlen); 610 struct sockaddr_un *saddr = malloc(addrlen);
610 saddr->sun_family = AF_UNIX; 611 saddr->sun_family = AF_UNIX;
611 memcpy(saddr->sun_path, sock_name, pathlen+1); 612 memcpy(saddr->sun_path, sock_name, pathlen+1);
612 if (bind(ports[i].device.stream.listen_fd, (struct sockaddr *)saddr, addrlen)) 613 if (bind(ports[i].device.stream.listen_fd, (struct sockaddr *)saddr, addrlen))
613 { 614 {
614 fprintf(stderr, "Failed to bind socket for IO Port %s to path %s: %d %s\n", io_name(i), sock_name, errno, strerror(errno)); 615 warning("Failed to bind socket for IO Port %s to path %s: %d %s\n", io_name(i), sock_name, errno, strerror(errno));
615 goto cleanup_sock; 616 goto cleanup_sock;
616 } 617 }
617 if (listen(ports[i].device.stream.listen_fd, 1)) 618 if (listen(ports[i].device.stream.listen_fd, 1))
618 { 619 {
619 fprintf(stderr, "Failed to listen on socket for IO Port %s: %d %s\n", io_name(i), errno, strerror(errno)); 620 warning("Failed to listen on socket for IO Port %s: %d %s\n", io_name(i), errno, strerror(errno));
620 goto cleanup_sockfile; 621 goto cleanup_sockfile;
621 } 622 }
622 sockfile_name = sock_name; 623 sockfile_name = sock_name;
623 atexit(cleanup_sockfile); 624 atexit(cleanup_sockfile);
624 continue; 625 continue;
669 special = tern_insert_int(special, "right", RENDERKEY_RIGHT); 670 special = tern_insert_int(special, "right", RENDERKEY_RIGHT);
670 special = tern_insert_int(special, "enter", '\r'); 671 special = tern_insert_int(special, "enter", '\r');
671 special = tern_insert_int(special, "esc", RENDERKEY_ESC); 672 special = tern_insert_int(special, "esc", RENDERKEY_ESC);
672 special = tern_insert_int(special, "lshift", RENDERKEY_LSHIFT); 673 special = tern_insert_int(special, "lshift", RENDERKEY_LSHIFT);
673 special = tern_insert_int(special, "rshift", RENDERKEY_RSHIFT); 674 special = tern_insert_int(special, "rshift", RENDERKEY_RSHIFT);
675 special = tern_insert_int(special, "select", RENDERKEY_SELECT);
676 special = tern_insert_int(special, "play", RENDERKEY_PLAY);
677 special = tern_insert_int(special, "search", RENDERKEY_SEARCH);
678 special = tern_insert_int(special, "back", RENDERKEY_BACK);
674 679
675 tern_node * padbuttons = tern_insert_int(NULL, ".up", DPAD_UP); 680 tern_node * padbuttons = tern_insert_int(NULL, ".up", DPAD_UP);
676 padbuttons = tern_insert_int(padbuttons, ".down", DPAD_DOWN); 681 padbuttons = tern_insert_int(padbuttons, ".down", DPAD_DOWN);
677 padbuttons = tern_insert_int(padbuttons, ".left", DPAD_LEFT); 682 padbuttons = tern_insert_int(padbuttons, ".left", DPAD_LEFT);
678 padbuttons = tern_insert_int(padbuttons, ".right", DPAD_RIGHT); 683 padbuttons = tern_insert_int(padbuttons, ".right", DPAD_RIGHT);
756 speeds[0] = 100; 761 speeds[0] = 100;
757 process_speeds(speed_nodes, NULL); 762 process_speeds(speed_nodes, NULL);
758 for (int i = 0; i < num_speeds; i++) 763 for (int i = 0; i < num_speeds; i++)
759 { 764 {
760 if (!speeds[i]) { 765 if (!speeds[i]) {
761 fprintf(stderr, "Speed index %d was not set to a valid percentage!", i); 766 warning("Speed index %d was not set to a valid percentage!", i);
762 speeds[i] = 100; 767 speeds[i] = 100;
763 } 768 }
764 } 769 }
765 map_all_bindings(ports); 770 map_all_bindings(ports);
766 } 771 }
767 772
768 void map_all_bindings(io_port *ports) 773 void map_all_bindings(io_port *ports)
769 { 774 {
770 for (int bucket = 0; bucket < 256; bucket++) 775 for (int bucket = 0; bucket < 0x10000; bucket++)
771 { 776 {
772 if (bindings[bucket]) 777 if (bindings[bucket])
773 { 778 {
774 map_bindings(ports, bindings[bucket], 256); 779 map_bindings(ports, bindings[bucket], 0x8000);
775 } 780 }
776 } 781 }
777 for (int stick = 0; stick < MAX_JOYSTICKS; stick++) 782 for (int stick = 0; stick < MAX_JOYSTICKS; stick++)
778 { 783 {
779 if (joybindings[stick]) 784 if (joybindings[stick])
828 if (numRead > 0) 833 if (numRead > 0)
829 { 834 {
830 port->input[IO_TH0] = (value & 0xF) | 0x10; 835 port->input[IO_TH0] = (value & 0xF) | 0x10;
831 port->input[IO_TH1] = (value >> 4) | 0x10; 836 port->input[IO_TH1] = (value >> 4) | 0x10;
832 } else if(numRead == -1 && errno != EAGAIN && errno != EWOULDBLOCK) { 837 } else if(numRead == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
833 fprintf(stderr, "Error reading pipe for IO port: %d %s\n", errno, strerror(errno)); 838 warning("Error reading pipe for IO port: %d %s\n", errno, strerror(errno));
834 } 839 }
835 } 840 }
836 841
837 static void service_socket(io_port *port) 842 static void service_socket(io_port *port)
838 { 843 {
858 } 863 }
859 } else if (numRead == 0) { 864 } else if (numRead == 0) {
860 port->device.stream.data_fd = -1; 865 port->device.stream.data_fd = -1;
861 wait_for_connection(port); 866 wait_for_connection(port);
862 } else if (errno != EAGAIN && errno != EWOULDBLOCK) { 867 } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
863 fprintf(stderr, "Error reading from socket for IO port: %d %s\n", errno, strerror(errno)); 868 warning("Error reading from socket for IO port: %d %s\n", errno, strerror(errno));
864 close(port->device.stream.data_fd); 869 close(port->device.stream.data_fd);
865 wait_for_connection(port); 870 wait_for_connection(port);
866 } else if (port->input[IO_STATE] == IO_READ_PENDING) { 871 } else if (port->input[IO_STATE] == IO_READ_PENDING) {
867 //clear the nonblocking flag so the next read will block 872 //clear the nonblocking flag so the next read will block
868 if (!blocking) 873 if (!blocking)
894 } 899 }
895 } else if (written == 0) { 900 } else if (written == 0) {
896 port->device.stream.data_fd = -1; 901 port->device.stream.data_fd = -1;
897 wait_for_connection(port); 902 wait_for_connection(port);
898 } else if (errno != EAGAIN && errno != EWOULDBLOCK) { 903 } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
899 fprintf(stderr, "Error writing to socket for IO port: %d %s\n", errno, strerror(errno)); 904 warning("Error writing to socket for IO port: %d %s\n", errno, strerror(errno));
900 close(port->device.stream.data_fd); 905 close(port->device.stream.data_fd);
901 wait_for_connection(port); 906 wait_for_connection(port);
902 } else { 907 } else {
903 //clear the nonblocking flag so the next write will block 908 //clear the nonblocking flag so the next write will block
904 if (!blocking) 909 if (!blocking)