# HG changeset patch # User Michael Pavone # Date 1456291076 28800 # Node ID 9364dad5561aa278a834ba50800f032ebcf0bba4 # Parent f1a8124ad881bdf1c0b37b849087222b58718aa0 Added reasonable handling of joystick hotplug diff -r f1a8124ad881 -r 9364dad5561a io.c --- a/io.c Sat Feb 20 01:11:18 2016 -0800 +++ b/io.c Tue Feb 23 21:17:56 2016 -0800 @@ -90,18 +90,26 @@ } joydpad; typedef struct { + keybinding *buttons; + joydpad *dpads; + uint32_t num_buttons; //number of entries in the buttons array, not necessarily the number of buttons on the device + uint32_t num_dpads; //number of entries in the dpads array, not necessarily the number of dpads on the device +} joystick; + +typedef struct { io_port *motion_port; keybinding buttons[MAX_MOUSE_BUTTONS]; uint8_t bind_type; } mousebinding; -keybinding * bindings[0x10000]; -keybinding * joybindings[MAX_JOYSTICKS]; -joydpad * joydpads[MAX_JOYSTICKS]; -mousebinding mice[MAX_MICE]; +#define DEFAULT_JOYBUTTON_ALLOC 12 + +static keybinding * bindings[0x10000]; +static joystick joysticks[MAX_JOYSTICKS]; +static mousebinding mice[MAX_MICE]; const uint8_t dpadbits[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT}; -mouse_modes mouse_mode; -char mouse_captured; +static mouse_modes mouse_mode; +static char mouse_captured; void bind_key(int keycode, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value) { @@ -122,18 +130,19 @@ if (joystick >= MAX_JOYSTICKS) { return; } - if (!joybindings[joystick]) { - int num = render_joystick_num_buttons(joystick); - if (!num) { - return; - } - joybindings[joystick] = malloc(sizeof(keybinding)*num); - memset(joybindings[joystick], 0, sizeof(keybinding)*num); + if (!joysticks[joystick].buttons) { + joysticks[joystick].num_buttons = button < DEFAULT_JOYBUTTON_ALLOC ? DEFAULT_JOYBUTTON_ALLOC : button + 1; + joysticks[joystick].buttons = calloc(joysticks[joystick].num_buttons, sizeof(keybinding)); + } else if (joysticks[joystick].num_buttons <= button) { + uint32_t old_capacity = joysticks[joystick].num_buttons; + joysticks[joystick].num_buttons *= 2; + joysticks[joystick].buttons = realloc(joysticks[joystick].buttons, sizeof(keybinding) * joysticks[joystick].num_buttons); + memset(joysticks[joystick].buttons + old_capacity, 0, joysticks[joystick].num_buttons - old_capacity); } - joybindings[joystick][button].bind_type = bind_type; - joybindings[joystick][button].subtype_a = subtype_a; - joybindings[joystick][button].subtype_b = subtype_b; - joybindings[joystick][button].value = value; + joysticks[joystick].buttons[button].bind_type = bind_type; + joysticks[joystick].buttons[button].subtype_a = subtype_a; + joysticks[joystick].buttons[button].subtype_b = subtype_b; + joysticks[joystick].buttons[button].value = value; } void bind_dpad(int joystick, int dpad, int direction, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value) @@ -141,20 +150,22 @@ if (joystick >= MAX_JOYSTICKS) { return; } - if (!joydpads[joystick]) { - int num = render_joystick_num_hats(joystick); - if (!num) { - return; - } - joydpads[joystick] = malloc(sizeof(joydpad)*num); - memset(joydpads[joystick], 0, sizeof(joydpad)*num); + if (!joysticks[joystick].dpads) { + //multiple D-pads hats are not common, so don't allocate any extra space + joysticks[joystick].dpads = calloc(dpad+1, sizeof(joydpad)); + joysticks[joystick].num_dpads = dpad+1; + } else if (joysticks[joystick].num_dpads <= dpad) { + uint32_t old_capacity = joysticks[joystick].num_dpads; + joysticks[joystick].num_dpads *= 2; + joysticks[joystick].dpads = realloc(joysticks[joystick].dpads, sizeof(joydpad) * joysticks[joystick].num_dpads); + memset(joysticks[joystick].dpads + old_capacity, 0, joysticks[joystick].num_dpads - old_capacity); } for (int i = 0; i < 4; i ++) { if (dpadbits[i] & direction) { - joydpads[joystick][dpad].bindings[i].bind_type = bind_type; - joydpads[joystick][dpad].bindings[i].subtype_a = subtype_a; - joydpads[joystick][dpad].bindings[i].subtype_b = subtype_b; - joydpads[joystick][dpad].bindings[i].value = value; + joysticks[joystick].dpads[dpad].bindings[i].bind_type = bind_type; + joysticks[joystick].dpads[dpad].bindings[i].subtype_a = subtype_a; + joysticks[joystick].dpads[dpad].bindings[i].subtype_b = subtype_b; + joysticks[joystick].dpads[dpad].bindings[i].value = value; break; } } @@ -258,10 +269,10 @@ void handle_joydown(int joystick, int button) { - if (!joybindings[joystick]) { + if (joystick >= MAX_JOYSTICKS || button >= joysticks[joystick].num_buttons) { return; } - keybinding * binding = joybindings[joystick] + button; + keybinding * binding = joysticks[joystick].buttons + button; handle_binding_down(binding); } @@ -392,19 +403,19 @@ void handle_joyup(int joystick, int button) { - if (!joybindings[joystick]) { + if (joystick >= MAX_JOYSTICKS || button >= joysticks[joystick].num_buttons) { return; } - keybinding * binding = joybindings[joystick] + button; + keybinding * binding = joysticks[joystick].buttons + button; handle_binding_up(binding); } void handle_joy_dpad(int joystick, int dpadnum, uint8_t value) { - if (!joydpads[joystick]) { + if (joystick >= MAX_JOYSTICKS || dpadnum >= joysticks[joystick].num_dpads) { return; } - joydpad * dpad = joydpads[joystick] + dpadnum; + joydpad * dpad = joysticks[joystick].dpads + dpadnum; uint8_t newdown = (value ^ dpad->state) & value; uint8_t newup = ((~value) ^ (~dpad->state)) & (~value); dpad->state = value; @@ -931,7 +942,7 @@ char numstr[] = "00"; tern_node * pads = tern_get_node(tern_find_path(config, "bindings\0pads\0")); if (pads) { - for (int i = 0; i < 100 && i < render_num_joysticks(); i++) + for (int i = 0; i < MAX_JOYSTICKS; i++) { if (i < 10) { @@ -945,7 +956,7 @@ if (pad) { tern_node * dpad_node = tern_find_ptr(pad, "dpads"); if (dpad_node) { - for (int dpad = 0; dpad < 10 && dpad < render_joystick_num_hats(i); dpad++) + for (int dpad = 0; dpad < 10; dpad++) { numstr[0] = dpad + '0'; numstr[1] = 0; @@ -968,7 +979,7 @@ } tern_node *button_node = tern_find_ptr(pad, "buttons"); if (button_node) { - for (int but = 0; but < 100 && but < render_joystick_num_buttons(i); but++) + for (int but = 0; but < 30; but++) { if (but < 10) { numstr[0] = but + '0'; @@ -1023,14 +1034,14 @@ } for (int stick = 0; stick < MAX_JOYSTICKS; stick++) { - if (joybindings[stick]) + if (joysticks[stick].buttons) { + map_bindings(ports, joysticks[stick].buttons, joysticks[stick].num_buttons); + } + if (joysticks[stick].dpads) { - int numbuttons = render_joystick_num_buttons(stick); - map_bindings(ports, joybindings[stick], render_joystick_num_buttons(stick)); - } - if (joydpads[stick]) - { - map_bindings(ports, joydpads[stick]->bindings, 4); + for (uint32_t i = 0; i < joysticks[stick].num_dpads; i++) { + map_bindings(ports, joysticks[stick].dpads[i].bindings, 4); + } } } for (int mouse = 0; mouse < MAX_MICE; mouse++) diff -r f1a8124ad881 -r 9364dad5561a render.h --- a/render.h Sat Feb 20 01:11:18 2016 -0800 +++ b/render.h Tue Feb 23 21:17:56 2016 -0800 @@ -55,9 +55,6 @@ void render_debug_mode(uint8_t mode); void render_debug_pal(uint8_t pal); void process_events(); -int render_joystick_num_buttons(int joystick); -int render_joystick_num_hats(int joystick); -int render_num_joysticks(); int render_width(); int render_height(); int render_fullscreen(); diff -r f1a8124ad881 -r 9364dad5561a render_sdl.c --- a/render_sdl.c Sat Feb 20 01:11:18 2016 -0800 +++ b/render_sdl.c Tue Feb 23 21:17:56 2016 -0800 @@ -90,13 +90,7 @@ SDL_CloseAudio(); } -SDL_Joystick * joysticks[MAX_JOYSTICKS]; -int num_joysticks; - -int render_num_joysticks() -{ - return num_joysticks; -} +static SDL_Joystick * joysticks[MAX_JOYSTICKS]; int render_width() { @@ -389,17 +383,6 @@ sample_rate = actual.freq; printf("Initialized audio at frequency %d with a %d sample buffer\n", actual.freq, actual.samples); SDL_PauseAudio(0); - num_joysticks = SDL_NumJoysticks(); - if (num_joysticks > MAX_JOYSTICKS) { - num_joysticks = MAX_JOYSTICKS; - } - for (int i = 0; i < num_joysticks; i++) { - SDL_Joystick * joy = joysticks[i] = SDL_JoystickOpen(i); - printf("Joystick %d: %s\n", i, SDL_JoystickName(joy)); - if (joy) { - printf("\tNum Axes: %d\n\tNum Buttons: %d\n\tNum Hats: %d\n", SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy), SDL_JoystickNumHats(joy)); - } - } SDL_JoystickEventState(SDL_ENABLE); atexit(render_quit); @@ -491,22 +474,6 @@ } } -int render_joystick_num_buttons(int joystick) -{ - if (joystick >= num_joysticks) { - return 0; - } - return SDL_JoystickNumButtons(joysticks[joystick]); -} - -int render_joystick_num_hats(int joystick) -{ - if (joystick >= num_joysticks) { - return 0; - } - return SDL_JoystickNumHats(joysticks[joystick]); -} - void render_wait_quit(vdp_context * context) { SDL_Event event; @@ -546,6 +513,26 @@ } } +int find_joystick_index(SDL_JoystickID instanceID) +{ + for (int i = 0; i < MAX_JOYSTICKS; i++) { + if (joysticks[i] && SDL_JoystickInstanceID(joysticks[i]) == instanceID) { + return i; + } + } + return -1; +} + +int lowest_unused_joystick_index() +{ + for (int i = 0; i < MAX_JOYSTICKS; i++) { + if (!joysticks[i]) { + return i; + } + } + return -1; +} + int32_t handle_event(SDL_Event *event) { switch (event->type) { @@ -556,14 +543,37 @@ handle_keyup(event->key.keysym.sym); break; case SDL_JOYBUTTONDOWN: - handle_joydown(event->jbutton.which, event->jbutton.button); + handle_joydown(find_joystick_index(event->jbutton.which), event->jbutton.button); break; case SDL_JOYBUTTONUP: - handle_joyup(event->jbutton.which, event->jbutton.button); + handle_joyup(find_joystick_index(event->jbutton.which), event->jbutton.button); break; case SDL_JOYHATMOTION: - handle_joy_dpad(event->jbutton.which, event->jhat.hat, event->jhat.value); + handle_joy_dpad(find_joystick_index(event->jbutton.which), event->jhat.hat, event->jhat.value); break; + case SDL_JOYDEVICEADDED: + if (event->jdevice.which < MAX_JOYSTICKS) { + int index = lowest_unused_joystick_index(); + if (index >= 0) { + SDL_Joystick * joy = joysticks[index] = SDL_JoystickOpen(event->jdevice.which); + if (joy) { + printf("Joystick %d added: %s\n", index, SDL_JoystickName(joy)); + printf("\tNum Axes: %d\n\tNum Buttons: %d\n\tNum Hats: %d\n", SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy), SDL_JoystickNumHats(joy)); + } + } + } + break; + case SDL_JOYDEVICEREMOVED: { + int index = find_joystick_index(event->jdevice.which); + if (index >= 0) { + SDL_JoystickClose(joysticks[index]); + joysticks[index] = NULL; + printf("Joystick %d removed\n", index); + } else { + printf("Failed to find removed joystick with instance ID: %d\n", index); + } + break; + } case SDL_MOUSEMOTION: handle_mouse_moved(event->motion.which, event->motion.x, event->motion.y, event->motion.xrel, event->motion.yrel); break;