diff --git a/src/emu/emulator.c b/src/emu/emulator.c index cde1d0b9..b124ab15 100644 --- a/src/emu/emulator.c +++ b/src/emu/emulator.c @@ -140,6 +140,18 @@ static void emu_keydown(void *data, int device_index, enum keycode code, dc_keydown(emu->dc, device_index, code, value); } +static void emu_joy_add(void *data, int joystick_index) { + struct emu *emu = data; + + dc_joy_add(emu->dc, joystick_index); +} + +static void emu_joy_remove(void *data, int joystick_index) { + struct emu *emu = data; + + dc_joy_remove(emu->dc, joystick_index); +} + static void emu_close(void *data) { struct emu *emu = data; @@ -223,9 +235,16 @@ struct emu *emu_create(struct window *window) { struct emu *emu = calloc(1, sizeof(struct emu)); emu->window = window; - emu->listener = - (struct window_listener){emu, &emu_paint, &emu_debug_menu, &emu_keydown, - NULL, NULL, &emu_close, {0}}; + emu->listener = (struct window_listener){emu, + &emu_paint, + &emu_debug_menu, + &emu_joy_add, + &emu_joy_remove, + &emu_keydown, + NULL, + NULL, + &emu_close, + {0}}; win_add_listener(emu->window, &emu->listener); return emu; diff --git a/src/emu/tracer.c b/src/emu/tracer.c index b53c9907..61393dbb 100644 --- a/src/emu/tracer.c +++ b/src/emu/tracer.c @@ -864,8 +864,8 @@ struct tracer *tracer_create(struct window *window) { tracer->window = window; tracer->listener = (struct window_listener){ - tracer, &tracer_paint, NULL, &tracer_keydown, - NULL, NULL, &tracer_close, {0}}; + tracer, &tracer_paint, NULL, NULL, NULL, + &tracer_keydown, NULL, NULL, &tracer_close, {0}}; tracer->provider = (struct texture_provider){tracer, &tracer_texture_provider_find_texture}; tracer->rb = window->rb; diff --git a/src/hw/dreamcast.c b/src/hw/dreamcast.c index a07e09cf..9f9b593c 100644 --- a/src/hw/dreamcast.c +++ b/src/hw/dreamcast.c @@ -17,6 +17,22 @@ DEFINE_OPTION_BOOL(gdb, false, "Run gdb debug server"); +void dc_joy_remove(struct dreamcast *dc, int joystick_index) { + list_for_each_entry(dev, &dc->devices, struct device, it) { + if (dev->window_if && dev->window_if->joy_remove) { + dev->window_if->joy_remove(dev, joystick_index); + } + } +} + +void dc_joy_add(struct dreamcast *dc, int joystick_index) { + list_for_each_entry(dev, &dc->devices, struct device, it) { + if (dev->window_if && dev->window_if->joy_add) { + dev->window_if->joy_add(dev, joystick_index); + } + } +} + void dc_keydown(struct dreamcast *dc, int device_index, enum keycode code, int16_t value) { list_for_each_entry(dev, &dc->devices, struct device, it) { @@ -95,10 +111,13 @@ void dc_destroy_window_interface(struct window_interface *window) { } struct window_interface *dc_create_window_interface( - device_debug_menu_cb debug_menu, device_keydown_cb keydown) { + device_debug_menu_cb debug_menu, device_keydown_cb keydown, + device_joy_add_cb joy_add, device_joy_remove_cb joy_remove) { struct window_interface *window = calloc(1, sizeof(struct window_interface)); window->debug_menu = debug_menu; window->keydown = keydown; + window->joy_add = joy_add; + window->joy_remove = joy_remove; return window; } @@ -140,7 +159,6 @@ struct device *dc_get_device(struct dreamcast *dc, const char *name) { return dev; } } - return NULL; } diff --git a/src/hw/dreamcast.h b/src/hw/dreamcast.h index a5c33424..97061493 100644 --- a/src/hw/dreamcast.h +++ b/src/hw/dreamcast.h @@ -88,10 +88,14 @@ struct memory_interface { /* window interface */ typedef void (*device_debug_menu_cb)(struct device *, struct nk_context *); typedef void (*device_keydown_cb)(struct device *, int, enum keycode, int16_t); +typedef void (*device_joy_add_cb)(struct device *, int); +typedef void (*device_joy_remove_cb)(struct device *, int); struct window_interface { device_debug_menu_cb debug_menu; device_keydown_cb keydown; + device_joy_add_cb joy_add; + device_joy_remove_cb joy_remove; }; /* @@ -164,7 +168,8 @@ struct memory_interface *dc_create_memory_interface(struct dreamcast *dc, void dc_destroy_memory_interface(struct memory_interface *memory); struct window_interface *dc_create_window_interface( - device_debug_menu_cb debug_menu, device_keydown_cb keydown); + device_debug_menu_cb debug_menu, device_keydown_cb keydown, + device_joy_add_cb joy_add, device_joy_remove_cb joy_remove); void dc_destroy_window_interface(struct window_interface *window); bool dc_init(struct dreamcast *dc); @@ -174,5 +179,7 @@ void dc_tick(struct dreamcast *dc, int64_t ns); void dc_debug_menu(struct dreamcast *dc, struct nk_context *ctx); void dc_keydown(struct dreamcast *dc, int device_index, enum keycode code, int16_t value); +void dc_joy_add(struct dreamcast *dc, int joystick_index); +void dc_joy_remove(struct dreamcast *dc, int joystick_index); #endif diff --git a/src/hw/maple/maple.c b/src/hw/maple/maple.c index 29157c47..c20949da 100644 --- a/src/hw/maple/maple.c +++ b/src/hw/maple/maple.c @@ -11,6 +11,20 @@ struct maple { struct maple_device *devices[MAPLE_NUM_PORTS][MAPLE_MAX_UNITS]; }; +static void maple_unregister_device(struct maple *mp, int port, int unit) { + struct maple_device **dev = &mp->devices[port][unit]; + + if (!*dev) { + return; + } + + if ((*dev)->destroy) { + (*dev)->destroy(*dev); + } + + *dev = NULL; +} + static void maple_register_device(struct maple *mp, const char *device_type, int port, int unit) { CHECK(!mp->devices[port][unit], @@ -26,6 +40,34 @@ static void maple_register_device(struct maple *mp, const char *device_type, } } +void maple_joy_add(struct device *data, int joystick_index) { + struct maple *mp = (struct maple *)data; + + /* ignore out of range events or events for the default controller which is + always connected */ + if (joystick_index <= 0 || joystick_index >= MAPLE_NUM_PORTS) { + return; + } + + /* attach joystick to the corresponding maple port */ + maple_register_device(mp, "controller", joystick_index, 0); +} + +void maple_joy_remove(struct device *data, int joystick_index) { + struct maple *mp = (struct maple *)data; + + /* ignore out of range events or events for the default controller which is + always connected */ + if (joystick_index <= 0 || joystick_index >= MAPLE_NUM_PORTS) { + return; + } + + /* remove all units from the corresponding maple port */ + for (int i = 0; i < MAPLE_MAX_UNITS; i++) { + maple_unregister_device(mp, joystick_index, i); + } +} + static void maple_keydown(struct device *d, int device_index, enum keycode key, int16_t value) { if (device_index >= MAPLE_NUM_PORTS) { @@ -34,11 +76,6 @@ static void maple_keydown(struct device *d, int device_index, enum keycode key, struct maple *mp = (struct maple *)d; - /* create a controller if getting data from a new device */ - if (!mp->devices[device_index][0]) { - maple_register_device(mp, "controller", device_index, 0); - } - for (int i = 0; i < MAPLE_MAX_UNITS; i++) { struct maple_device *dev = mp->devices[device_index][i]; @@ -127,11 +164,7 @@ static bool maple_init(struct device *dev) { void maple_destroy(struct maple *mp) { for (int i = 0; i < MAPLE_NUM_PORTS; i++) { for (int j = 0; j < MAPLE_MAX_UNITS; j++) { - struct maple_device *dev = mp->devices[i][j]; - - if (dev && dev->destroy) { - dev->destroy(dev); - } + maple_unregister_device(mp, i, j); } } @@ -142,7 +175,8 @@ void maple_destroy(struct maple *mp) { struct maple *maple_create(struct dreamcast *dc) { struct maple *mp = dc_create_device(dc, sizeof(struct maple), "maple", &maple_init); - mp->window_if = dc_create_window_interface(NULL, &maple_keydown); + mp->window_if = dc_create_window_interface(NULL, &maple_keydown, + &maple_joy_add, &maple_joy_remove); /* add one controller and vmu by default */ maple_register_device(mp, "controller", 0, 0); diff --git a/src/hw/pvr/ta.c b/src/hw/pvr/ta.c index 11290f84..2a3991a2 100644 --- a/src/hw/pvr/ta.c +++ b/src/hw/pvr/ta.c @@ -962,7 +962,7 @@ struct ta *ta_create(struct dreamcast *dc) { ta_build_tables(); struct ta *ta = dc_create_device(dc, sizeof(struct ta), "ta", &ta_init); - ta->window_if = dc_create_window_interface(&ta_debug_menu, NULL); + ta->window_if = dc_create_window_interface(&ta_debug_menu, NULL, NULL, NULL); ta->provider = (struct texture_provider){ta, &ta_texture_provider_find_texture}; ta->pending_mutex = mutex_create(); diff --git a/src/hw/sh4/sh4.c b/src/hw/sh4/sh4.c index bec1dc73..99892f1c 100644 --- a/src/hw/sh4/sh4.c +++ b/src/hw/sh4/sh4.c @@ -346,7 +346,8 @@ struct sh4 *sh4_create(struct dreamcast *dc) { struct sh4 *sh4 = dc_create_device(dc, sizeof(struct sh4), "sh", &sh4_init); sh4->execute_if = dc_create_execute_interface(&sh4_run, 0); sh4->memory_if = dc_create_memory_interface(dc, &sh4_data_map); - sh4->window_if = dc_create_window_interface(&sh4_debug_menu, NULL); + sh4->window_if = + dc_create_window_interface(&sh4_debug_menu, NULL, NULL, NULL); return sh4; } diff --git a/src/ui/microprofile.cc b/src/ui/microprofile.cc index 5f02eec0..c9bb8a5f 100644 --- a/src/ui/microprofile.cc +++ b/src/ui/microprofile.cc @@ -271,7 +271,8 @@ struct microprofile *mp_create(struct window *window) { calloc(1, sizeof(struct microprofile))); mp->window = window; - mp->listener = {mp, NULL, NULL, &mp_keydown, NULL, &mp_mousemove, NULL, {}}; + mp->listener = {mp, NULL, NULL, NULL, NULL, + &mp_keydown, NULL, &mp_mousemove, NULL, {}}; win_add_listener(mp->window, &mp->listener); diff --git a/src/ui/nuklear.c b/src/ui/nuklear.c index cad7efde..56b78c38 100644 --- a/src/ui/nuklear.c +++ b/src/ui/nuklear.c @@ -160,7 +160,8 @@ struct nuklear *nk_create(struct window *window) { struct nuklear *nk = calloc(1, sizeof(struct nuklear)); nk->window = window; nk->listener = (struct window_listener){ - nk, NULL, NULL, &nk_keydown, &nk_textinput, &nk_mousemove, NULL, {0}}; + nk, NULL, NULL, NULL, NULL, + &nk_keydown, &nk_textinput, &nk_mousemove, NULL, {0}}; win_add_listener(nk->window, &nk->listener); diff --git a/src/ui/window.c b/src/ui/window.c index fe5c52ba..ccedadaa 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -15,10 +15,23 @@ static void win_destroy_joystick(struct window *win, SDL_Joystick *del) { for (int i = 0; i < MAX_JOYSTICKS; i++) { SDL_Joystick **joy = &win->joysticks[i]; - if (*joy == del) { - SDL_JoystickClose(*joy); - *joy = NULL; + if (*joy != del) { + continue; } + + LOG_INFO("Closing joystick %d: %s", i, SDL_JoystickName(*joy)); + + SDL_JoystickClose(*joy); + *joy = NULL; + + /* inform listeners */ + list_for_each_entry(listener, &win->listeners, struct window_listener, it) { + if (listener->joy_remove) { + listener->joy_remove(listener->data, i); + } + } + + break; } } @@ -36,11 +49,18 @@ static void win_create_joystick(struct window *win, int joystick_index) { break; } - LOG_INFO("Opened joystick %d: %s", i, SDL_JoystickName(win->joysticks[i])); + LOG_INFO("Opened joystick %d: %s", i, SDL_JoystickName(*joy)); /* reset state */ memset(win->hat_state[i], 0, sizeof(win->hat_state[i])); + /* inform listeners */ + list_for_each_entry(listener, &win->listeners, struct window_listener, it) { + if (listener->joy_add) { + listener->joy_add(listener->data, joystick_index); + } + } + break; } } @@ -927,6 +947,7 @@ void win_destroy(struct window *win) { if (win->handle) { SDL_DestroyWindow(win->handle); } + for (int i = 0; i < MAX_JOYSTICKS; i++) { if (win->joysticks[i]) { win_destroy_joystick(win, win->joysticks[i]); diff --git a/src/ui/window.h b/src/ui/window.h index 821b0812..87ea6328 100644 --- a/src/ui/window.h +++ b/src/ui/window.h @@ -32,6 +32,8 @@ struct window_listener { void *data; void (*paint)(void *data); void (*debug_menu)(void *data, struct nk_context *ctx); + void (*joy_add)(void *data, int joystick_index); + void (*joy_remove)(void *data, int joystick_index); void (*keydown)(void *data, int device_index, enum keycode code, int16_t value); void (*textinput)(void *data, const char *text); diff --git a/src/video/gl_backend.c b/src/video/gl_backend.c index f7da2e4b..ac8bc9dd 100644 --- a/src/video/gl_backend.c +++ b/src/video/gl_backend.c @@ -713,8 +713,8 @@ void rb_destroy(struct render_backend *rb) { struct render_backend *rb_create(struct window *window) { struct render_backend *rb = calloc(1, sizeof(struct render_backend)); rb->window = window; - rb->listener = (struct window_listener){rb, NULL, &rb_debug_menu, NULL, - NULL, NULL, NULL, {0}}; + rb->listener = (struct window_listener){ + rb, NULL, &rb_debug_menu, NULL, NULL, NULL, NULL, NULL, NULL, {0}}; win_add_listener(rb->window, &rb->listener);