Mercurial > repos > blastem
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) |