diff --git a/CMakeLists.txt b/CMakeLists.txt index b127adb242fbf..e95157a9c7617 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2949,8 +2949,11 @@ elseif(OGC) list(APPEND EXTRA_LIBS "fat") endif() list(APPEND EXTRA_LDFLAGS "${OGC_ARCH_SETTINGS} ${OGC_LINKER_FLAGS}") + pkg_search_module(EGC embedded-game-controller REQUIRED IMPORTED_TARGET) + list(APPEND EXTRA_LIBS "${EGC_LIBRARIES}") + target_include_directories(sdl-build-options INTERFACE ${EGC_INCLUDE_DIRS}) if(NINTENDO_WII) - list(APPEND EXTRA_LIBS "wiiuse;bte;wiikeyboard") + list(APPEND EXTRA_LIBS "wiikeyboard") endif() list(APPEND EXTRA_LIBS "ogc;m") endif() @@ -3398,6 +3401,9 @@ if(NOT WINDOWS_STORE AND NOT SDL2_DISABLE_SDL2MAIN) if (NOT ANDROID) set_target_properties(SDL2main PROPERTIES DEBUG_POSTFIX "${SDL_CMAKE_DEBUG_POSTFIX}") endif() + if(OGC) + target_include_directories(SDL2main PRIVATE ${EGC_INCLUDE_DIRS}) + endif() set_property(TARGET SDL2main APPEND PROPERTY COMPATIBLE_INTERFACE_STRING "SDL_VERSION") set_property(TARGET SDL2main PROPERTY INTERFACE_SDL_VERSION "SDL2") endif() diff --git a/src/joystick/ogc/SDL_sysjoystick.c b/src/joystick/ogc/SDL_sysjoystick.c index 56d5beccc4da6..3429495f88870 100644 --- a/src/joystick/ogc/SDL_sysjoystick.c +++ b/src/joystick/ogc/SDL_sysjoystick.c @@ -29,169 +29,44 @@ #include "SDL_events.h" #include "SDL_hints.h" #include "../../SDL_hints_c.h" +#include "../../video/ogc/SDL_ogcevents_c.h" #include "SDL_joystick.h" +#include #include +#include #include #include -#include - -#define PI 3.14159265f - -#define MAX_GC_JOYSTICKS 4 -#define MAX_WII_JOYSTICKS 4 - -#define GC_JOYSTICKS_START 0 -#define GC_JOYSTICKS_END MAX_GC_JOYSTICKS -#define WII_JOYSTICKS_START GC_JOYSTICKS_END -#define WII_WIIMOTES_START WII_JOYSTICKS_START -#define WII_WIIMOTES_END (WII_WIIMOTES_START + MAX_WII_JOYSTICKS) -#define WII_EXP_START WII_WIIMOTES_END -#define WII_EXP_END (WII_EXP_START + MAX_WII_JOYSTICKS) -#define WII_JOYSTICKS_END WII_EXP_END - -#define MAX_JOYSTICKS WII_EXP_END - -#define MAX_GC_AXES 6 -#define MAX_GC_BUTTONS 8 -#define MAX_GC_HATS 1 - -#define MAX_WII_AXES 9 -#define MAX_WII_BUTTONS 15 -#define MAX_WII_HATS 1 - -#define JOYNAMELEN 10 - -#define AXIS_MIN -32767 /* minimum value for axis coordinate */ -#define AXIS_MAX 32767 /* maximum value for axis coordinate */ #define MAX_RUMBLE 8 -typedef struct joystick_paddata_t -{ - u16 prev_buttons; - s8 stickX; - s8 stickY; - s8 substickX; - s8 substickY; - u8 triggerL; - u8 triggerR; -} joystick_paddata; - -typedef struct joystick_wpaddata_t -{ - u32 prev_buttons; - u32 exp; - s16 nunchuk_stickX; - s16 nunchuk_stickY; - s16 classicL_stickX; - s16 classicL_stickY; - s16 classicR_stickX; - s16 classicR_stickY; - u8 classic_triggerL; - u8 classic_triggerR; - u8 classic_calibrated; - s8 wiimote_pitch; - s8 wiimote_roll; - s8 wiimote_yaw; - s16 classic_cal[4][3]; // 4x axes, min/center/max -} joystick_wpaddata; - /* The private structure used to keep track of a joystick */ typedef struct joystick_hwdata { - int index; + _OGC_Controller *controller; +#ifdef __wii__ + bool rotated; /* Wiimote rotated sideways */ + EgcWiimoteExpType expansion; +#endif char sensors_disabled; /* This must be big enough for MAX_RUMBLE */ char rumble_intensity; u16 rumble_loop; - union - { - joystick_paddata gamecube; - joystick_wpaddata wiimote; - }; + u32 prev_buttons; } joystick_hwdata; -#ifdef __wii__ -static const u32 sdl_buttons_wii[] = { - WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, - WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B, - WPAD_BUTTON_1, - WPAD_BUTTON_2, - WPAD_BUTTON_MINUS | WPAD_CLASSIC_BUTTON_MINUS, - WPAD_BUTTON_PLUS | WPAD_CLASSIC_BUTTON_PLUS, - WPAD_BUTTON_HOME | WPAD_CLASSIC_BUTTON_HOME, - WPAD_NUNCHUK_BUTTON_Z, /* 7 */ - WPAD_NUNCHUK_BUTTON_C, /* 8 */ - WPAD_CLASSIC_BUTTON_X, /* 9 */ - WPAD_CLASSIC_BUTTON_Y, - WPAD_CLASSIC_BUTTON_FULL_L, - WPAD_CLASSIC_BUTTON_FULL_R, - WPAD_CLASSIC_BUTTON_ZL, - WPAD_CLASSIC_BUTTON_ZR -}; -#define SDL_WII_NUM_BUTTONS_WII \ - (sizeof(sdl_buttons_wii) / sizeof(sdl_buttons_wii[0])) - -static const u32 sdl_buttons_wiimote[] = { - WPAD_BUTTON_A, - WPAD_BUTTON_B, - WPAD_BUTTON_1, - WPAD_BUTTON_2, - WPAD_BUTTON_MINUS, - WPAD_BUTTON_PLUS, - WPAD_BUTTON_HOME, -}; -#define SDL_WII_NUM_BUTTONS_WIIMOTE \ - (sizeof(sdl_buttons_wiimote) / sizeof(sdl_buttons_wiimote[0])) - -static const u32 sdl_buttons_nunchuck[] = { - WPAD_NUNCHUK_BUTTON_Z, - WPAD_NUNCHUK_BUTTON_C, -}; -#define SDL_WII_NUM_BUTTONS_NUNCHUCK \ - (sizeof(sdl_buttons_nunchuck) / sizeof(sdl_buttons_nunchuck[0])) - -static const u32 sdl_buttons_classic[] = { - WPAD_CLASSIC_BUTTON_A, - WPAD_CLASSIC_BUTTON_B, - WPAD_CLASSIC_BUTTON_X, - WPAD_CLASSIC_BUTTON_Y, - WPAD_CLASSIC_BUTTON_FULL_L, - WPAD_CLASSIC_BUTTON_FULL_R, - WPAD_CLASSIC_BUTTON_ZL, - WPAD_CLASSIC_BUTTON_ZR, - WPAD_CLASSIC_BUTTON_MINUS, - WPAD_CLASSIC_BUTTON_PLUS, - WPAD_CLASSIC_BUTTON_HOME, -}; -#define SDL_WII_NUM_BUTTONS_CLASSIC \ - (sizeof(sdl_buttons_classic) / sizeof(sdl_buttons_classic[0])) -#endif /* __wii__ */ - -static const u16 sdl_buttons_gc[] = { - PAD_BUTTON_A, - PAD_BUTTON_B, - PAD_BUTTON_X, - PAD_BUTTON_Y, - PAD_TRIGGER_L, - PAD_TRIGGER_R, - PAD_TRIGGER_Z, - PAD_BUTTON_START, -}; - -static int split_joysticks = 0; +static char joy_name[128]; -static SDL_JoystickID s_connected_instances[MAX_JOYSTICKS]; -/* Value is 0 if controller is not present, otherwise 1 + extension enum */ -static char s_detected_devices[MAX_JOYSTICKS]; -static char s_gc_failed_reads = 0; -static u32 s_gc_last_scanpads = 0; -static bool s_hardware_queried = false; +static int print_controller_name(char *buffer, size_t size, + _OGC_Controller *controller); +#define DPAD_MASK \ + ((1 << EGC_GAMEPAD_BUTTON_DPAD_UP) | \ + (1 << EGC_GAMEPAD_BUTTON_DPAD_DOWN) | \ + (1 << EGC_GAMEPAD_BUTTON_DPAD_LEFT) | \ + (1 << EGC_GAMEPAD_BUTTON_DPAD_RIGHT)) #ifdef __wii__ -static bool s_wii_has_new_data[MAX_WII_JOYSTICKS]; static bool s_accelerometers_as_axes = false; static bool s_wiimote_sideways = false; @@ -202,111 +77,143 @@ on_hint_accel_as_joystick_cb(void *userdata, const char *name, s_accelerometers_as_axes = SDL_GetStringBoolean(hint, SDL_FALSE); } -#endif - -/* Joypad index is 0-11: 4 GC, 4 Wiimotes and (if split_joysticks) 4 expansions - */ -static int device_index_to_joypad_index(int device_index) +static bool is_wiimote(egc_input_device_t *device) { - int count = 0; - - for (int i = 0; i < MAX_JOYSTICKS; i++) { - if (s_connected_instances[i] >= 0) { - if (count == device_index) - return i; - count++; - } - } + const egc_device_description_t *desc = device->desc; + return desc->vendor_id == USB_VENDOR_NINTENDO && + desc->product_id == USB_PRODUCT_NINTENDO_WII_REMOTE; +} - SDL_LogError(SDL_LOG_CATEGORY_INPUT, - "Cannot find device index %d", device_index); - return -1; +/* Return EGC_WIIMOTE_EXP_NONE if this is not a wiimote or if no expansion + * is connected (the Wiimote+ also count as no expansion, since it's not + * usable as a separate controller). */ +static EgcWiimoteExpType get_wiimote_expansion(egc_input_device_t *device) +{ + return is_wiimote(device) ? + egc_driver_wiimote_get_exp_type(device) : EGC_WIIMOTE_EXP_NONE; } -static int device_index_to_instance(int device_index) +static const char *expansion_name(EgcWiimoteExpType expansion) { - int index = device_index_to_joypad_index(device_index); - if (index < 0) - return -1; - return s_connected_instances[index]; + switch (expansion) { + case EGC_WIIMOTE_EXP_MOTION_PLUS: + return "Motion+"; + case EGC_WIIMOTE_EXP_NUNCHUCK: + return "Nunchuk"; + case EGC_WIIMOTE_EXP_CLASSIC: + case EGC_WIIMOTE_EXP_CLASSIC_PRO: + return "Classic"; + case EGC_WIIMOTE_EXP_GUITAR_HERO_3: + return "Guitar Hero 3"; + case EGC_WIIMOTE_EXP_BALANCE_BOARD: + return "Balance board"; + default: + return "Unknown"; + } } -static void scan_hardware(void) +const char *connection_name(egc_input_device_t *device) { - /* Scan the GameCube and Wii controllers, but only if this was not done - * before during this update cycle. - * The Detect() callback, resets the s_hardware_queried variable. */ - if (!s_hardware_queried) { - s_gc_last_scanpads = PAD_ScanPads(); -#ifdef __wii__ - for (int i = 0; i < MAX_WII_JOYSTICKS; i++) { - s_wii_has_new_data[i] = WPAD_ReadPending(i, NULL); - } -#endif - s_hardware_queried = true; + switch (device->connection) { + case EGC_CONNECTION_USB: + return "Usb"; + case EGC_CONNECTION_BT: + return "Bt"; + default: + return ""; } } -static void report_joystick(int index, int connected) +static void handle_accelerometer(SDL_Joystick *joystick, + SDL_SensorType type, + int start_axis, + const egc_accelerometer_t *accel, + bool rotated) { - printf("Controller %d was %s (%d)\n", - index, connected ? "connected" : "removed", connected); - - /* First, if the joystick was connected with a different expansion, remove - * it */ - if (s_connected_instances[index] >= 0) { - SDL_PrivateJoystickRemoved(s_connected_instances[index]); - s_connected_instances[index] = -1; + egc_accelerometer_t a = *accel; + if (rotated) { + a.x = accel->z; + a.z = -accel->x; } - if (connected) { - s_connected_instances[index] = SDL_GetNextJoystickInstanceID(); - SDL_PrivateJoystickAdded(s_connected_instances[index]); + if (s_accelerometers_as_axes) { + SDL_PrivateJoystickAxis(joystick, start_axis, a.x * INT16_MAX / EGC_ACCELEROMETER_RES_PER_G); + SDL_PrivateJoystickAxis(joystick, start_axis + 1, a.z * INT16_MAX / EGC_ACCELEROMETER_RES_PER_G); + } else { + float values[3]; + values[0] = a.x * SDL_STANDARD_GRAVITY / EGC_ACCELEROMETER_RES_PER_G; + values[1] = a.y * SDL_STANDARD_GRAVITY / EGC_ACCELEROMETER_RES_PER_G; + values[2] = a.z * SDL_STANDARD_GRAVITY / EGC_ACCELEROMETER_RES_PER_G; + SDL_PrivateJoystickSensor(joystick, type, 0, values, 3); } } +#endif + +static inline int count_bits(u32 mask) +{ + return __builtin_popcount(mask); +} + +static int controller_index_by_device_index(int device_index) +{ + return device_index; +} -static inline bool enable_rumble(int index, bool enable) +static _OGC_Controller *controller_by_device_index(int device_index) { - if (index >= GC_JOYSTICKS_START && index < GC_JOYSTICKS_END) { - PAD_ControlMotor(index - GC_JOYSTICKS_START, - enable ? PAD_MOTOR_RUMBLE : PAD_MOTOR_STOP); - return true; + return OGC_get_controller(controller_index_by_device_index(device_index)); +} + +static int print_controller_name(char *buffer, size_t size, + _OGC_Controller *controller) +{ + const egc_device_description_t *desc = controller->egc_device->desc; + if (desc->vendor_id == USB_VENDOR_NINTENDO) { + /* egc's GameCube driver reports this ID for GameCube controllers */ + if (desc->product_id == USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER) + return snprintf(buffer, size, "Gamecube"); #ifdef __wii__ - } else if (index >= WII_WIIMOTES_START && index < WII_JOYSTICKS_END) { - WPAD_Rumble(index - WII_WIIMOTES_START, enable); - return true; + if (desc->product_id == USB_PRODUCT_NINTENDO_WII_REMOTE) + return snprintf(buffer, size, "Wiimote"); #endif - } else { - return false; } + +#ifdef __wii__ + return snprintf(buffer, size, "%s:%04x:%04x", + connection_name(controller->egc_device), + desc->vendor_id, desc->product_id); +#else + return 0; +#endif } -static void update_rumble(SDL_Joystick *joystick) +static inline _OGC_Controller *get_controller(SDL_Joystick *joystick) { - char intensity = joystick->hwdata->rumble_intensity; - s16 loop; - int rest_frames; - bool rumble; - if (intensity == 0 || intensity == MAX_RUMBLE - 1) return; - - loop = ++joystick->hwdata->rumble_loop; - - /* The rest_frames constant should probably be set according to the current - * framerate; or we should rework the logic to be completely time-based. - * It may also be that we need different values depending on the controller - * type. */ - rest_frames = 2; - if (loop == 1) { - rumble = false; - } else if (loop > (MAX_RUMBLE - 1 - intensity) * rest_frames) { - rumble = true; - joystick->hwdata->rumble_loop = 0; - } else { - /* Keep the engine stopped until our time comes again */ - return; - } + return joystick->hwdata ? joystick->hwdata->controller : NULL; +} + +static inline egc_input_device_t *get_egc_device(SDL_Joystick *joystick) +{ + _OGC_Controller *controller = get_controller(joystick); + return controller ? controller->egc_device : NULL; +} + +static int device_index_to_instance(int device_index) +{ + _OGC_Controller *controller = controller_by_device_index(device_index); + if (!controller) + return -1; + return controller->instance_id; +} - enable_rumble(joystick->hwdata->index, rumble); +static void joystick_added_cb(_OGC_Controller *controller) +{ + SDL_PrivateJoystickAdded(controller->instance_id); +} + +static void joystick_removed_cb(_OGC_Controller *controller) +{ + SDL_PrivateJoystickRemoved(controller->instance_id); } /* Function to scan the system for joysticks. @@ -316,13 +223,6 @@ static void update_rumble(SDL_Joystick *joystick) */ static int OGC_JoystickInit(void) { - const char *split_joystick_env = getenv("SDL_WII_JOYSTICK_SPLIT"); - split_joysticks = split_joystick_env && strcmp(split_joystick_env, "1") == 0; - - PAD_Init(); - /* We don't call WPAD_Init() here, since it's already been called by - * SDL_main for the Wii */ - #ifdef __wii__ SDL_AddHintCallback(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, on_hint_accel_as_joystick_cb, NULL); @@ -334,147 +234,45 @@ static int OGC_JoystickInit(void) } #endif - /* Initialize the needed variables */ - for (int i = 0; i < MAX_JOYSTICKS; i++) { - s_connected_instances[i] = -1; - } + OGC_register_joystick_callbacks(joystick_added_cb, joystick_removed_cb); return 0; } static int OGC_JoystickGetCount(void) { - int count = 0; - - for (int i = 0; i < MAX_JOYSTICKS; i++) { - if (s_connected_instances[i] >= 0) - count++; - } - return count; + return OGC_NumControllers; } static void OGC_JoystickDetect(void) { - scan_hardware(); - - /* Ignore individual disconnected statuses, since they might just - * happen because the controller is not ready. */ - if (s_gc_last_scanpads == 0 && s_gc_failed_reads < 4) { - s_gc_failed_reads++; - s_hardware_queried = false; - } else { - s_gc_failed_reads = 0; - for (int i = 0; i < MAX_GC_JOYSTICKS; i++) { - bool connected = s_gc_last_scanpads & (1 << i); - bool was_connected = s_detected_devices[i]; - if (connected == was_connected) - continue; - - report_joystick(i, connected); - s_detected_devices[i] = connected; - } - } - -#ifdef __wii__ - for (int i = 0; i < MAX_WII_JOYSTICKS; i++) { - int connected, was_connected, index; - WPADData *data; - - if (!s_wii_has_new_data[i]) - continue; - - data = WPAD_Data(i); - index = WII_JOYSTICKS_START + i; - connected = data->err != WPAD_ERR_NO_CONTROLLER && - data->data_present != 0; - if (split_joysticks) { - int exp_index = WII_EXP_START + i; - int exp_connected = - (connected && data->exp.type != WPAD_EXP_NONE) ? (1 + data->exp.type) : 0; - int exp_was_connected = s_detected_devices[exp_index]; - if (exp_connected != exp_was_connected) { - s_detected_devices[exp_index] = exp_connected; - report_joystick(exp_index, exp_connected); - } - } else if (connected) { - connected += data->exp.type; - } - - was_connected = s_detected_devices[index]; - if (connected != was_connected) { - s_detected_devices[index] = connected; - report_joystick(index, connected); - } - } -#endif - - /* This is to force a refresh, the next time that Update() or Detect() are - * called. This relies on the fact that SDL calls Detect() after Update(). - */ - s_hardware_queried = false; } -static char joy_name[128]; - /* Function to get the device-dependent name of a joystick */ static const char *OGC_JoystickGetDeviceName(int device_index) { - int index = device_index_to_joypad_index(device_index); - if (index < 0) + _OGC_Controller *controller; + const egc_device_description_t *desc; + int offset = 0; + + controller = OGC_get_controller(device_index); + if (!controller) return NULL; - if (index >= GC_JOYSTICKS_START && index < GC_JOYSTICKS_END) { - sprintf(joy_name, "Gamecube %d", index); + offset += print_controller_name(joy_name, sizeof(joy_name), controller); + offset += snprintf(joy_name + offset, sizeof(joy_name) - offset, + " %d", device_index); #ifdef __wii__ - } else if (index >= WII_WIIMOTES_START && index < WII_WIIMOTES_END) { - char *name_ptr = joy_name; - int expansion = s_detected_devices[index] - 1; - name_ptr += sprintf(name_ptr, "Wiimote %d", index - WII_WIIMOTES_START); - if (!split_joysticks) { - // Add expansion information - switch (expansion) { - case WPAD_EXP_NUNCHUK: - strcpy(name_ptr, " + Nunchuk"); - break; - case WPAD_EXP_CLASSIC: - strcpy(name_ptr, " + Classic"); - break; - case WPAD_EXP_GUITARHERO3: - strcpy(name_ptr, " + Guitar Hero 3"); - break; - case WPAD_EXP_WIIBOARD: - strcpy(name_ptr, " + Balance board"); - break; - } + desc = controller->egc_device->desc; + if (desc->vendor_id == USB_VENDOR_NINTENDO && + desc->product_id == USB_PRODUCT_NINTENDO_WII_REMOTE) { + EgcWiimoteExpType expansion = + egc_driver_wiimote_get_exp_type(controller->egc_device); + if (expansion != EGC_WIIMOTE_EXP_NONE) { + offset += snprintf(joy_name + offset, sizeof(joy_name) - offset, + " + %s", expansion_name(expansion)); } - } else if (split_joysticks) { - /* This is an expansion and we are using the split controllers - * option: show only the expansion name, then. */ - int expansion = s_detected_devices[index] - 1; - int idx = index - WII_EXP_START; - switch (expansion) { - case WPAD_EXP_NUNCHUK: - sprintf(joy_name, "Nunchuk %d", idx); - break; - case WPAD_EXP_CLASSIC: - sprintf(joy_name, "Classic %d", idx); - break; - case WPAD_EXP_GUITARHERO3: - sprintf(joy_name, "Guitar Hero 3 %d", idx); - break; - case WPAD_EXP_WIIBOARD: - sprintf(joy_name, "Balance board %d", idx); - break; - case WPAD_EXP_NONE: - strcpy(joy_name, "Disconnected"); - break; - default: - sprintf(joy_name, "Unknown %d", idx); - break; - } -#endif - } else { - sprintf(joy_name, "Invalid device index: %d", device_index); } +#endif return joy_name; } @@ -490,32 +288,59 @@ static int OGC_JoystickGetDevicePlayerIndex(int device_index) static void OGC_JoystickSetDevicePlayerIndex(int device_index, int player_index) { + int index = controller_index_by_device_index(device_index); + _OGC_Controller *controller = OGC_get_controller(index); + egc_input_device_t *device; + u32 num_leds, leds; + + if (!controller) return; + + device = controller->egc_device; + if (!device) return; + + num_leds = device->desc->num_leds; + if (num_leds <= 1) return; + + if (player_index < num_leds) { + leds = 1 << player_index; + } else { + /* Invert the leds; first, set all leds on: */ + leds = (1 << num_leds) - 1; + /* then remove the led */ + leds ^= (1 << (player_index - num_leds)); + } + + egc_input_device_set_leds(device, leds); } static SDL_JoystickGUID OGC_JoystickGetDeviceGUID(int device_index) { - int index = device_index_to_joypad_index(device_index); + int index = controller_index_by_device_index(device_index); + _OGC_Controller *controller = OGC_get_controller(index); + const egc_device_description_t *desc; Uint16 bus, product, version; Uint8 driver_signature, driver_data; const char *name; - /* We invent our own product IDs, to tell our joysticks apart. - * Since we want the gamepads to appear with the numeric ID in their - * name, we make them unique by assigning a different product depending on - * the port. */ - product = (index + 1) << 8; - if (index >= GC_JOYSTICKS_START && index < GC_JOYSTICKS_END) { - bus = SDL_HARDWARE_BUS_UNKNOWN; - } else { + desc = controller->egc_device->desc; + product = desc->product_id; +#ifdef __wii__ + /* Return a different product ID depending on the connected expansion */ + product += get_wiimote_expansion(controller->egc_device); +#endif + if (controller->egc_device->connection == EGC_CONNECTION_BT) { bus = SDL_HARDWARE_BUS_BLUETOOTH; - product += s_detected_devices[index]; + } else if (controller->egc_device->connection == EGC_CONNECTION_USB) { + bus = SDL_HARDWARE_BUS_USB; + } else { + bus = SDL_HARDWARE_BUS_UNKNOWN; } version = 1; driver_signature = 0; driver_data = 0; name = OGC_JoystickGetDeviceName(device_index); - return SDL_CreateJoystickGUID(bus, USB_VENDOR_NINTENDO, product, version, + return SDL_CreateJoystickGUID(bus, desc->vendor_id, product, version, name, driver_signature, driver_data); } @@ -526,7 +351,10 @@ static SDL_JoystickID OGC_JoystickGetDeviceInstanceID(int device_index) static int OGC_JoystickOpen(SDL_Joystick *joystick, int device_index) { - int index = device_index_to_joypad_index(device_index); + int index = controller_index_by_device_index(device_index); + _OGC_Controller *controller; + const egc_device_description_t *desc; + u32 dpad_buttons, buttons_excluding_dpad; printf("Open joystick %d (our index: %d)\n", device_index, index); @@ -539,49 +367,41 @@ static int OGC_JoystickOpen(SDL_Joystick *joystick, int device_index) SDL_OutOfMemory(); return -1; } - joystick->instance_id = s_connected_instances[index]; + controller = OGC_get_controller(index); + desc = controller->egc_device->desc; + joystick->instance_id = controller->instance_id; SDL_memset(joystick->hwdata, 0, sizeof(joystick_hwdata)); - joystick->hwdata->index = index; - if (index >= GC_JOYSTICKS_START && index < GC_JOYSTICKS_END) { - joystick->nbuttons = MAX_GC_BUTTONS; - joystick->naxes = MAX_GC_AXES; - joystick->nhats = MAX_GC_HATS; + joystick->hwdata->controller = controller; + /* Because of https://github.com/libsdl-org/SDL/issues/8754 (hats and axes + * being the only way to provide direction information with the SDL + * joystick API) we need to convert dpad buttons into a hat. + */ + dpad_buttons = desc->available_buttons & DPAD_MASK; + buttons_excluding_dpad = desc->available_buttons & ~DPAD_MASK; + joystick->nbuttons = count_bits(buttons_excluding_dpad); + joystick->naxes = count_bits(desc->available_axes); + joystick->nhats = dpad_buttons != 0 ? 1 : 0; #ifdef __wii__ - } else { - if (split_joysticks) { - if (index < WII_WIIMOTES_END) { - // wiimote - joystick->nbuttons = SDL_WII_NUM_BUTTONS_WIIMOTE; - joystick->naxes = 3; - joystick->nhats = 1; - SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 100.0f); - } else { - // expansion - joystick->nbuttons = SDL_max(SDL_WII_NUM_BUTTONS_NUNCHUCK, - SDL_WII_NUM_BUTTONS_CLASSIC); - joystick->naxes = 6; - joystick->nhats = 1; - if (s_detected_devices[index] == 1 + WPAD_EXP_NUNCHUK) { - SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL_L, 100.0f); - } - } - } else { - joystick->nbuttons = MAX_WII_BUTTONS; - joystick->naxes = MAX_WII_AXES; - joystick->nhats = MAX_WII_HATS; - /* Add the accelerometer only if there is no expansion connected */ - if (s_detected_devices[index] == 1) { - SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 100.0f); - } else if (s_detected_devices[index] == 1 + WPAD_EXP_NUNCHUK) { - /* Or, if the nunchuck is connected, add the wiimote, and the - * nunchuk on the left */ - SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 100.0f); - SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL_L, 100.0f); - } + if (is_wiimote(controller->egc_device)) { + EgcWiimoteExpType expansion = joystick->hwdata->expansion = + get_wiimote_expansion(controller->egc_device); + if (s_wiimote_sideways && + (expansion == EGC_WIIMOTE_EXP_NONE || + expansion == EGC_WIIMOTE_EXP_MOTION_PLUS)) { + joystick->hwdata->rotated = true; } -#endif } + + if (s_accelerometers_as_axes) { + joystick->naxes += desc->num_accelerometers * 2; + } else if (desc->num_accelerometers > 0) { + SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 100.0f); + if (desc->num_accelerometers > 1) { + SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL_L, 100.0f); + } + } +#endif /* __wii__ */ return 0; } @@ -589,31 +409,12 @@ static int OGC_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { - int index = joystick->hwdata->index; - /* The Wii and GameCube controllers do not support setting the frequency of - * the rumble, so we use a hack where we periodically stop and start the - * motors during Update(). */ - char intensity = MAX_RUMBLE * - ((low_frequency_rumble + high_frequency_rumble) / 2) / - 0xffff; - /* We don't accept MAX_RUMBLE itself */ - if (intensity >= MAX_RUMBLE) - intensity = MAX_RUMBLE - 1; - - /* If it's the same as the current value, do nothing */ - if (intensity == joystick->hwdata->rumble_intensity) { - return 0; - } - - if (!enable_rumble(index, intensity > 0)) { + egc_input_device_t *device = get_egc_device(joystick); + if (!device->desc->has_rumble) { return SDL_Unsupported(); } - /* Save the current rumble status, we need it in update_rumble() */ - joystick->hwdata->rumble_intensity = intensity; - joystick->hwdata->rumble_loop = 0; - - return 0; + return egc_input_device_set_rumble(device, low_frequency_rumble, high_frequency_rumble); } static int OGC_JoystickRumbleTriggers(SDL_Joystick *joystick, @@ -626,14 +427,13 @@ static Uint32 OGC_JoystickGetCapabilities(SDL_Joystick *joystick) { Uint32 capabilities = 0; - int index = joystick->hwdata->index; - if ((index >= GC_JOYSTICKS_START && index < GC_JOYSTICKS_END) || - /* Rumble is supported on the wiimotes, but it makes sense only if no - * expansion is attached, of if we are in split mode. */ - (index >= WII_WIIMOTES_START && index < WII_WIIMOTES_END && - (s_detected_devices[index] == 1 || split_joysticks))) { + egc_input_device_t *device = get_egc_device(joystick); + if (device->desc->has_rumble) { capabilities |= SDL_JOYCAP_RUMBLE; } + if (device->desc->num_leds > 0) { + capabilities |= SDL_JOYCAP_LED; + } return capabilities; } @@ -651,463 +451,109 @@ static int OGC_JoystickSendEffect(SDL_Joystick *joystick, static int OGC_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) { - int index = joystick->hwdata->index; - if (index >= WII_WIIMOTES_START && index < WII_WIIMOTES_END) { - joystick->hwdata->sensors_disabled = !enabled; - return 0; - } - return SDL_Unsupported(); -} - -#ifdef __wii__ - -static s16 WPAD_Orient(WPADData *data, int motion) -{ - float out; - - if (motion == 0) - out = data->orient.pitch; - else if (motion == 1) - out = data->orient.roll; - else - out = data->orient.yaw; - - return (s16)((out / 180.0) * 128.0); -} - -static s16 WPAD_Pitch(WPADData *data) -{ - return WPAD_Orient(data, 0); -} - -static s16 WPAD_Roll(WPADData *data) -{ - return WPAD_Orient(data, 1); -} - -static s16 WPAD_Yaw(WPADData *data) -{ - return WPAD_Orient(data, 2); + /* EGC at the moment does not supports disabling the sensors */ + return enabled ? 0 : SDL_Unsupported(); } -static s16 WPAD_Stick(s16 x, s16 min, s16 center, s16 max, int flip) -{ - s16 d; - int ret; - - x -= center; - - if (x < 0) - d = center - min; - else - d = max - center; - - if (center - min < 5) - return 0; - if (max - center < 5) - return 0; - - if (d) - ret = (x << 15) / d; - else - return 0; - - if (flip) - ret = -ret; - - if (ret < AXIS_MIN) - ret = AXIS_MIN; - else if (ret > AXIS_MAX) - ret = AXIS_MAX; - - return ret; -} - -static const u32 _buttons[8] = { - // wiimote - WPAD_BUTTON_UP, - WPAD_BUTTON_DOWN, - WPAD_BUTTON_LEFT, - WPAD_BUTTON_RIGHT, - // classic - WPAD_CLASSIC_BUTTON_UP, - WPAD_CLASSIC_BUTTON_DOWN, - WPAD_CLASSIC_BUTTON_LEFT, - WPAD_CLASSIC_BUTTON_RIGHT -}; - -static void HandleWiiHats(SDL_Joystick *joystick, - const u32 changed, const u32 pressed, - const u32 *buttons) -{ - if (changed & (buttons[0] | buttons[1] | buttons[2] | buttons[3])) { - int hat = SDL_HAT_CENTERED; - - if (pressed & buttons[0]) - hat |= s_wiimote_sideways ? SDL_HAT_LEFT : SDL_HAT_UP; - if (pressed & buttons[1]) - hat |= s_wiimote_sideways ? SDL_HAT_RIGHT : SDL_HAT_DOWN; - if (pressed & buttons[2]) - hat |= s_wiimote_sideways ? SDL_HAT_DOWN : SDL_HAT_LEFT; - if (pressed & buttons[3]) - hat |= s_wiimote_sideways ? SDL_HAT_UP : SDL_HAT_RIGHT; - SDL_PrivateJoystickHat(joystick, 0, hat); - } -} - -/* Helpers to separate nunchuk vs classic buttons which share the - * same scan codes. In particular, up on the classic controller is - * the same as Z on the nunchuk. The numbers refer to the sdl_buttons_wii - * list above. */ -static int wii_button_is_nunchuk(int idx) -{ - return idx == 7 || idx == 8; -} - -static int wii_button_is_classic(int idx) -{ - return idx >= 9; -} - -static void HandleWiiButtons(SDL_Joystick *joystick, - const u32 changed, - const WPADData *data, - const u32 *buttons, - size_t num_buttons) -{ - for (int i = 0; i < num_buttons; i++) { - if (changed & buttons[i]) { - if (!split_joysticks && - ((data->exp.type == WPAD_EXP_CLASSIC && wii_button_is_nunchuk(i)) || - (data->exp.type == WPAD_EXP_NUNCHUK && wii_button_is_classic(i)))) - continue; - - SDL_PrivateJoystickButton(joystick, i, - (data->btns_d & buttons[i]) ? SDL_PRESSED : SDL_RELEASED); - } - } -} - -static void HandleWiiMotion(SDL_Joystick *joystick, - joystick_hwdata *prev_state, - WPADData *data, - int start_index) -{ - int axis = WPAD_Pitch(data); - if (prev_state->wiimote.wiimote_pitch != axis) { - SDL_PrivateJoystickAxis(joystick, start_index, -(axis << 8)); - prev_state->wiimote.wiimote_pitch = axis; - } - axis = WPAD_Roll(data); - if (prev_state->wiimote.wiimote_roll != axis) { - SDL_PrivateJoystickAxis(joystick, start_index + 1, axis << 8); - prev_state->wiimote.wiimote_roll = axis; - } - axis = WPAD_Yaw(data); - if (prev_state->wiimote.wiimote_yaw != axis) { - SDL_PrivateJoystickAxis(joystick, start_index + 2, axis << 8); - prev_state->wiimote.wiimote_yaw = axis; - } -} - -static void HandleNunchuckSensors(SDL_Joystick *joystick, - const nunchuk_t *data) -{ - float values[3]; - SDL_SensorType type; - - if (joystick->hwdata->sensors_disabled) return; - - type = split_joysticks ? SDL_SENSOR_ACCEL : SDL_SENSOR_ACCEL_L; - values[0] = data->gforce.x * SDL_STANDARD_GRAVITY; - values[1] = data->gforce.z * SDL_STANDARD_GRAVITY; - values[2] = -data->gforce.y * SDL_STANDARD_GRAVITY; - SDL_PrivateJoystickSensor(joystick, type, 0, values, 3); -} - -static void HandleWiimoteSensors(SDL_Joystick *joystick, - WPADData *data) +static void OGC_JoystickUpdate(SDL_Joystick *joystick) { - float values[3]; - - if (joystick->hwdata->sensors_disabled) return; + _OGC_Controller *controller; + egc_input_device_t *device; + u32 buttons, prev_buttons, changed, available_buttons; + int i_button = 0, i_axis = 0; - values[0] = data->gforce.x * SDL_STANDARD_GRAVITY; - values[1] = data->gforce.z * SDL_STANDARD_GRAVITY; - values[2] = -data->gforce.y * SDL_STANDARD_GRAVITY; - SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_ACCEL, 0, values, 3); -} + controller = get_controller(joystick); + if (!controller) return; -static void _HandleWiiJoystickUpdate(SDL_Joystick *joystick) -{ - u32 changed, pressed; - int axis, wpad_index; - joystick_hwdata *prev_state; - WPADData *data; - bool update_wiimote, update_expansion; - - prev_state = joystick->hwdata; - if (split_joysticks) { - if (joystick->hwdata->index >= WII_EXP_START) { - wpad_index = joystick->hwdata->index - WII_EXP_START; - update_wiimote = false; - update_expansion = true; - } else { - wpad_index = joystick->hwdata->index - WII_WIIMOTES_START; - update_wiimote = true; - update_expansion = false; - } - } else { - wpad_index = joystick->hwdata->index - WII_WIIMOTES_START; - update_wiimote = true; - update_expansion = true; - } - - if (update_wiimote) { - update_rumble(joystick); - } + device = get_egc_device(joystick); + if (!device) return; - if (!s_wii_has_new_data[wpad_index]) +#ifdef __wii__ + if (get_wiimote_expansion(device) != joystick->hwdata->expansion) { + /* If the expansion changes we need setup a different mapping, and the + * simplest way to do this is to pretend that the joystick was + * disconnected and reconnected. */ + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + "Expansion changed, reconnecting joystick"); + SDL_PrivateJoystickRemoved(controller->instance_id); + SDL_PrivateJoystickAdded(controller->instance_id); return; - - data = WPAD_Data(wpad_index); - changed = data->btns_d | data->btns_u; - pressed = data->btns_d | data->btns_h; - - if (update_wiimote) { - HandleWiiHats(joystick, changed, pressed, _buttons); - } - if (update_expansion) { - if (data->exp.type == WPAD_EXP_CLASSIC) { - HandleWiiHats(joystick, changed, pressed, _buttons + 4); - } - } - - if (split_joysticks) { - if (update_wiimote) { - HandleWiiButtons(joystick, changed, data, - sdl_buttons_wiimote, SDL_WII_NUM_BUTTONS_WIIMOTE); - } - if (update_expansion) { - if (data->exp.type == WPAD_EXP_CLASSIC) { - HandleWiiButtons(joystick, changed, data, - sdl_buttons_classic, SDL_WII_NUM_BUTTONS_CLASSIC); - } else if (data->exp.type == WPAD_EXP_NUNCHUK) { - HandleWiiButtons(joystick, changed, data, - sdl_buttons_nunchuck, SDL_WII_NUM_BUTTONS_NUNCHUCK); - } - } - } else { - HandleWiiButtons(joystick, changed, data, - sdl_buttons_wii, SDL_WII_NUM_BUTTONS_WII); } +#endif /* __wii__ */ - if (update_expansion) { - if (data->exp.type == WPAD_EXP_CLASSIC) { - if (prev_state->wiimote.exp != WPAD_EXP_CLASSIC) { - prev_state->wiimote.classic_calibrated = 0; - prev_state->wiimote.classic_cal[0][0] = 5; // left x min - prev_state->wiimote.classic_cal[0][2] = 59; // left x max - prev_state->wiimote.classic_cal[1][0] = 5; // left y min - prev_state->wiimote.classic_cal[1][2] = 59; // left y max - prev_state->wiimote.classic_cal[2][0] = 5; // right x min - prev_state->wiimote.classic_cal[2][2] = 27; // right x max - prev_state->wiimote.classic_cal[3][0] = 5; // right y min - prev_state->wiimote.classic_cal[3][2] = 27; // right y max - } - - // max/min checking - // left stick x - if (data->exp.classic.ljs.pos.x < prev_state->wiimote.classic_cal[0][0]) - prev_state->wiimote.classic_cal[0][0] = data->exp.classic.ljs.pos.x; - else if (data->exp.classic.ljs.pos.x > prev_state->wiimote.classic_cal[0][2]) - prev_state->wiimote.classic_cal[0][2] = data->exp.classic.ljs.pos.x; - // left stick y - if (data->exp.classic.ljs.pos.y < prev_state->wiimote.classic_cal[1][0]) - prev_state->wiimote.classic_cal[1][0] = data->exp.classic.ljs.pos.y; - else if (data->exp.classic.ljs.pos.y > prev_state->wiimote.classic_cal[1][2]) - prev_state->wiimote.classic_cal[1][2] = data->exp.classic.ljs.pos.y; - // right stick x - if (data->exp.classic.rjs.pos.x < prev_state->wiimote.classic_cal[2][0]) - prev_state->wiimote.classic_cal[2][0] = data->exp.classic.rjs.pos.x; - else if (data->exp.classic.rjs.pos.x > prev_state->wiimote.classic_cal[2][2]) - prev_state->wiimote.classic_cal[2][2] = data->exp.classic.rjs.pos.x; - // right stick y - if (data->exp.classic.rjs.pos.y < prev_state->wiimote.classic_cal[3][0]) - prev_state->wiimote.classic_cal[3][0] = data->exp.classic.rjs.pos.y; - else if (data->exp.classic.rjs.pos.y > prev_state->wiimote.classic_cal[3][2]) - prev_state->wiimote.classic_cal[3][2] = data->exp.classic.rjs.pos.y; - - // calibrate center positions - if (prev_state->wiimote.classic_calibrated < 5) { - prev_state->wiimote.classic_cal[0][1] = data->exp.classic.ljs.pos.x; - prev_state->wiimote.classic_cal[1][1] = data->exp.classic.ljs.pos.y; - prev_state->wiimote.classic_cal[2][1] = data->exp.classic.rjs.pos.x; - prev_state->wiimote.classic_cal[3][1] = data->exp.classic.rjs.pos.y; - // this is zero if the expansion hasn't finished initializing - if (data->exp.classic.ljs.max.x) - prev_state->wiimote.classic_calibrated++; - } - } - - if (data->exp.type != prev_state->wiimote.exp) { - // Reset the expansion axes - for (int i = 0; i < 6; i++) - SDL_PrivateJoystickAxis(joystick, i, 0); - } - - if (data->exp.type == WPAD_EXP_CLASSIC) { - axis = WPAD_Stick(data->exp.classic.ljs.pos.x, prev_state->wiimote.classic_cal[0][0], - prev_state->wiimote.classic_cal[0][1], prev_state->wiimote.classic_cal[0][2], 0); - if (prev_state->wiimote.classicL_stickX != axis) { - SDL_PrivateJoystickAxis(joystick, 0, axis); - prev_state->wiimote.classicL_stickX = axis; - } - // y axes are reversed - axis = WPAD_Stick(data->exp.classic.ljs.pos.y, prev_state->wiimote.classic_cal[1][0], - prev_state->wiimote.classic_cal[1][1], prev_state->wiimote.classic_cal[1][2], 1); - if (prev_state->wiimote.classicL_stickY != axis) { - SDL_PrivateJoystickAxis(joystick, 1, axis); - prev_state->wiimote.classicL_stickY = axis; - } - axis = WPAD_Stick(data->exp.classic.rjs.pos.x, prev_state->wiimote.classic_cal[2][0], - prev_state->wiimote.classic_cal[2][1], prev_state->wiimote.classic_cal[2][2], 0); - if (prev_state->wiimote.classicR_stickX != axis) { - SDL_PrivateJoystickAxis(joystick, 2, axis); - prev_state->wiimote.classicR_stickX = axis; - } - axis = WPAD_Stick(data->exp.classic.rjs.pos.y, prev_state->wiimote.classic_cal[3][0], - prev_state->wiimote.classic_cal[3][1], prev_state->wiimote.classic_cal[3][2], 1); - if (prev_state->wiimote.classicR_stickY != axis) { - SDL_PrivateJoystickAxis(joystick, 3, axis); - prev_state->wiimote.classicR_stickY = axis; - } - axis = data->exp.classic.r_shoulder; - if (prev_state->wiimote.classic_triggerR != axis) { - SDL_PrivateJoystickAxis(joystick, 4, axis << 8); - prev_state->wiimote.classic_triggerR = axis; - } - axis = data->exp.classic.l_shoulder; - if (prev_state->wiimote.classic_triggerL != axis) { - SDL_PrivateJoystickAxis(joystick, 5, axis << 8); - prev_state->wiimote.classic_triggerL = axis; - } - } else if (data->exp.type == WPAD_EXP_NUNCHUK) { - axis = WPAD_Stick(data->exp.nunchuk.js.pos.x, data->exp.nunchuk.js.min.x, - data->exp.nunchuk.js.center.x, data->exp.nunchuk.js.max.x, 0); - if (prev_state->wiimote.nunchuk_stickX != axis) { - SDL_PrivateJoystickAxis(joystick, 0, axis); - prev_state->wiimote.nunchuk_stickX = axis; - } - axis = WPAD_Stick(data->exp.nunchuk.js.pos.y, data->exp.nunchuk.js.min.y, - data->exp.nunchuk.js.center.y, data->exp.nunchuk.js.max.y, 1); - if (prev_state->wiimote.nunchuk_stickY != axis) { - SDL_PrivateJoystickAxis(joystick, 1, axis); - prev_state->wiimote.nunchuk_stickY = axis; - } + available_buttons = device->desc->available_buttons & ~DPAD_MASK; + prev_buttons = joystick->hwdata->prev_buttons; + buttons = egc_input_device_read_buttons(device); + changed = buttons ^ prev_buttons; - HandleNunchuckSensors(joystick, &data->exp.nunchuk); + for (int i = 0; i < EGC_GAMEPAD_BUTTON_COUNT; i++) { + u32 mask = 1 << i; + if (!(available_buttons & mask)) continue; + if (changed & mask) { + SDL_PrivateJoystickButton(joystick, i_button, + (buttons & mask) ? SDL_PRESSED : SDL_RELEASED); } + i_button++; } - - prev_state->wiimote.exp = data->exp.type; - - if (update_wiimote) { - if (s_accelerometers_as_axes) { - int start_index = split_joysticks ? 0 : 6; - HandleWiiMotion(joystick, prev_state, data, start_index); + /* Handle D-Pad as a hat */ + if (changed & DPAD_MASK) { + int hat = SDL_HAT_CENTERED; + if (buttons & (1 << EGC_GAMEPAD_BUTTON_DPAD_UP)) hat |= SDL_HAT_UP; + if (buttons & (1 << EGC_GAMEPAD_BUTTON_DPAD_RIGHT)) hat |= SDL_HAT_RIGHT; + if (buttons & (1 << EGC_GAMEPAD_BUTTON_DPAD_DOWN)) hat |= SDL_HAT_DOWN; + if (buttons & (1 << EGC_GAMEPAD_BUTTON_DPAD_LEFT)) hat |= SDL_HAT_LEFT; +#ifdef __wii__ + if (joystick->hwdata->rotated) { + /* We can just rotate the bits of the hat mask */ + hat = (hat >> 1) | ((hat & 0x1) << 3); } - HandleWiimoteSensors(joystick, data); - } -} #endif /* __wii__ */ - -static void _HandleGCJoystickUpdate(SDL_Joystick *joystick) -{ - u16 buttons, prev_buttons, changed; - int i; - int axis; - joystick_hwdata *prev_state; - int index = joystick->hwdata->index - GC_JOYSTICKS_START; - - update_rumble(joystick); - - buttons = PAD_ButtonsHeld(index); - prev_state = joystick->hwdata; - prev_buttons = prev_state->gamecube.prev_buttons; - changed = buttons ^ prev_buttons; - - if (changed & (PAD_BUTTON_LEFT | PAD_BUTTON_RIGHT | PAD_BUTTON_DOWN | PAD_BUTTON_UP)) { - int hat = SDL_HAT_CENTERED; - if (buttons & PAD_BUTTON_UP) - hat |= SDL_HAT_UP; - if (buttons & PAD_BUTTON_DOWN) - hat |= SDL_HAT_DOWN; - if (buttons & PAD_BUTTON_LEFT) - hat |= SDL_HAT_LEFT; - if (buttons & PAD_BUTTON_RIGHT) - hat |= SDL_HAT_RIGHT; SDL_PrivateJoystickHat(joystick, 0, hat); } - for (i = 0; i < (sizeof(sdl_buttons_gc) / sizeof(sdl_buttons_gc[0])); i++) { - if (changed & sdl_buttons_gc[i]) - SDL_PrivateJoystickButton(joystick, i, - (buttons & sdl_buttons_gc[i]) ? SDL_PRESSED : SDL_RELEASED); - } - prev_state->gamecube.prev_buttons = buttons; - axis = PAD_StickX(index); - if (prev_state->gamecube.stickX != axis) { - SDL_PrivateJoystickAxis(joystick, 0, axis << 8); - prev_state->gamecube.stickX = axis; - } + joystick->hwdata->prev_buttons = buttons; - axis = PAD_StickY(index); - if (prev_state->gamecube.stickY != axis) { - SDL_PrivateJoystickAxis(joystick, 1, (-axis) << 8); - prev_state->gamecube.stickY = axis; - } - - axis = PAD_SubStickX(index); - if (prev_state->gamecube.substickX != axis) { - SDL_PrivateJoystickAxis(joystick, 2, axis << 8); - prev_state->gamecube.substickX = axis; - } - - axis = PAD_SubStickY(index); - if (prev_state->gamecube.substickY != axis) { - SDL_PrivateJoystickAxis(joystick, 3, (-axis) << 8); - prev_state->gamecube.substickY = axis; + for (int i = 0; i < EGC_GAMEPAD_AXIS_COUNT; i++) { + u32 mask = 1 << i; + if (device->desc->available_axes & mask) { + s16 value = egc_input_device_read_axis(device, i); + if (i == EGC_GAMEPAD_AXIS_LEFT_TRIGGER || + i == EGC_GAMEPAD_AXIS_RIGHT_TRIGGER) { + /* The SDL joystick API expects trigger values to be in the + * full range of an int16, so we need to do some scaling here. + */ + value = (value * 2) + INT16_MIN; + } + SDL_PrivateJoystickAxis(joystick, i_axis, value); + i_axis++; + } } - axis = PAD_TriggerL(index); - if (prev_state->gamecube.triggerL != axis) { - SDL_PrivateJoystickAxis(joystick, 4, axis << 7); - prev_state->gamecube.triggerL = axis; +#ifdef __wii__ + if (device->desc->num_accelerometers > 0) { + const egc_accelerometer_t *accel = + egc_input_device_read_accelerometer(device, 0); + handle_accelerometer(joystick, SDL_SENSOR_ACCEL, + i_axis, accel, + joystick->hwdata->rotated); + i_axis += 2; + if (device->desc->num_accelerometers > 1) { + accel = egc_input_device_read_accelerometer(device, 1); + handle_accelerometer(joystick, SDL_SENSOR_ACCEL_L, + i_axis, accel, false); + } } - axis = PAD_TriggerR(index); - if (prev_state->gamecube.triggerR != axis) { - SDL_PrivateJoystickAxis(joystick, 5, axis << 7); - prev_state->gamecube.triggerR = axis; + if (device->desc->num_gyroscopes) { + const egc_gyroscope_t *gyro = + egc_input_device_read_gyroscope(device, 0); + float values[3]; + values[0] = (float)gyro->x / EGC_GYROSCOPE_RES; + values[1] = (float)gyro->y / EGC_GYROSCOPE_RES; + values[2] = (float)gyro->z / EGC_GYROSCOPE_RES; + SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_GYRO, 0, values, 3); } -} - -static void OGC_JoystickUpdate(SDL_Joystick *joystick) -{ - if (!joystick || !joystick->hwdata) - return; - - scan_hardware(); - - if (joystick->hwdata->index >= GC_JOYSTICKS_START && - joystick->hwdata->index < GC_JOYSTICKS_END) { - _HandleGCJoystickUpdate(joystick); -#ifdef __wii__ - } else { - _HandleWiiJoystickUpdate(joystick); #endif - } } static void OGC_JoystickClose(SDL_Joystick *joystick) @@ -1127,177 +573,89 @@ void OGC_JoystickQuit(void) #endif } +static const SDL_InputMapping s_invalid_mapping = { EMappingKind_None, 255 }; + +static SDL_InputMapping egc_map_button(u32 available, int index, int *i_button) +{ + return (1 << index) & available ? + (SDL_InputMapping){ EMappingKind_Button, (*i_button)++ } : s_invalid_mapping; +} + +static SDL_InputMapping egc_map_hat(u32 available, int index, int i_hat) +{ + return (1 << index) & available ? + (SDL_InputMapping){ EMappingKind_Hat, i_hat } : s_invalid_mapping; +} + +static SDL_InputMapping egc_map_axis(u32 available, int index, int *i_axis) +{ + return (1 << index) & available ? + (SDL_InputMapping){ EMappingKind_Axis, (*i_axis)++ } : s_invalid_mapping; +} + static SDL_bool OGC_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) { - int index = device_index_to_joypad_index(device_index); - SDL_bool is_gamepad = SDL_FALSE; - - if (index >= GC_JOYSTICKS_START && index < GC_JOYSTICKS_END) { - *out = (SDL_GamepadMapping){ - .a = { EMappingKind_Button, 0 }, - .b = { EMappingKind_Button, 2 }, - .x = { EMappingKind_Button, 1 }, - .y = { EMappingKind_Button, 3 }, - .back = { EMappingKind_Button, 6 }, - .guide = { EMappingKind_None, 255 }, - .start = { EMappingKind_Button, 7 }, - .leftstick = { EMappingKind_None, 255 }, - .rightstick = { EMappingKind_None, 255 }, - .leftshoulder = { EMappingKind_Button, 4 }, - .rightshoulder = { EMappingKind_Button, 5 }, - .dpup = { EMappingKind_Hat, 0x01 }, - .dpdown = { EMappingKind_Hat, 0x04 }, - .dpleft = { EMappingKind_Hat, 0x08 }, - .dpright = { EMappingKind_Hat, 0x02 }, - .misc1 = { EMappingKind_None, 255 }, - .paddle1 = { EMappingKind_None, 255 }, - .paddle2 = { EMappingKind_None, 255 }, - .paddle3 = { EMappingKind_None, 255 }, - .paddle4 = { EMappingKind_None, 255 }, - .leftx = { EMappingKind_Axis, 0 }, - .lefty = { EMappingKind_Axis, 1 }, - .rightx = { EMappingKind_Axis, 2 }, - .righty = { EMappingKind_Axis, 3 }, - .lefttrigger = { EMappingKind_Axis, 4 }, - .righttrigger = { EMappingKind_Axis, 5 }, - }; - is_gamepad = SDL_TRUE; + egc_input_device_t *device; + u32 buttons, axes; + int i_button = 0, i_axis = 0; + _OGC_Controller *controller = OGC_get_controller(device_index); + if (!controller) + return SDL_FALSE; + + device = controller->egc_device; + buttons = device->desc->available_buttons; + axes = device->desc->available_axes; + + *out = (SDL_GamepadMapping){ + .b = egc_map_button(buttons, EGC_GAMEPAD_BUTTON_SOUTH, &i_button), + .a = egc_map_button(buttons, EGC_GAMEPAD_BUTTON_EAST, &i_button), + .y = egc_map_button(buttons, EGC_GAMEPAD_BUTTON_WEST, &i_button), + .x = egc_map_button(buttons, EGC_GAMEPAD_BUTTON_NORTH, &i_button), + .back = egc_map_button(buttons, EGC_GAMEPAD_BUTTON_BACK, &i_button), + .guide = egc_map_button(buttons, EGC_GAMEPAD_BUTTON_GUIDE, &i_button), + .start = egc_map_button(buttons, EGC_GAMEPAD_BUTTON_START, &i_button), + .leftstick = egc_map_button(buttons, EGC_GAMEPAD_BUTTON_LEFT_STICK, &i_button), + .rightstick = egc_map_button(buttons, EGC_GAMEPAD_BUTTON_RIGHT_STICK, &i_button), + .leftshoulder = egc_map_button(buttons, EGC_GAMEPAD_BUTTON_LEFT_SHOULDER, &i_button), + .rightshoulder = egc_map_button(buttons, EGC_GAMEPAD_BUTTON_RIGHT_SHOULDER, &i_button), + .dpup = egc_map_hat(buttons, EGC_GAMEPAD_BUTTON_DPAD_UP, SDL_HAT_UP), + .dpdown = egc_map_hat(buttons, EGC_GAMEPAD_BUTTON_DPAD_DOWN, SDL_HAT_DOWN), + .dpleft = egc_map_hat(buttons, EGC_GAMEPAD_BUTTON_DPAD_LEFT, SDL_HAT_LEFT), + .dpright = egc_map_hat(buttons, EGC_GAMEPAD_BUTTON_DPAD_RIGHT, SDL_HAT_RIGHT), + .misc1 = egc_map_button(buttons, EGC_GAMEPAD_BUTTON_MISC1, &i_button), + .paddle1 = egc_map_button(buttons, EGC_GAMEPAD_BUTTON_RIGHT_PADDLE1, &i_button), + .paddle2 = egc_map_button(buttons, EGC_GAMEPAD_BUTTON_LEFT_PADDLE1, &i_button), + .paddle3 = egc_map_button(buttons, EGC_GAMEPAD_BUTTON_RIGHT_PADDLE2, &i_button), + .paddle4 = egc_map_button(buttons, EGC_GAMEPAD_BUTTON_LEFT_PADDLE2, &i_button), + .leftx = egc_map_axis(axes, EGC_GAMEPAD_AXIS_LEFTX, &i_axis), + .lefty = egc_map_axis(axes, EGC_GAMEPAD_AXIS_LEFTY, &i_axis), + .rightx = egc_map_axis(axes, EGC_GAMEPAD_AXIS_RIGHTX, &i_axis), + .righty = egc_map_axis(axes, EGC_GAMEPAD_AXIS_RIGHTY, &i_axis), + .lefttrigger = egc_map_axis(axes, EGC_GAMEPAD_AXIS_LEFT_TRIGGER, &i_axis), + .righttrigger = egc_map_axis(axes, EGC_GAMEPAD_AXIS_RIGHT_TRIGGER, &i_axis), + }; + #ifdef __wii__ - } else if (index >= WII_WIIMOTES_START && index < WII_WIIMOTES_END) { - int expansion = s_detected_devices[index] - 1; - if (split_joysticks || expansion == 0) { - /* Wiimote alone; assume it's being held sideways */ - *out = (SDL_GamepadMapping){ - .a = { EMappingKind_Button, 2 }, - .b = { EMappingKind_Button, 3 }, - .x = { EMappingKind_Button, 0 }, - .y = { EMappingKind_Button, 1 }, - .back = { EMappingKind_Button, 6 }, - .guide = { EMappingKind_Button, 4 }, - .start = { EMappingKind_Button, 5 }, - .leftstick = { EMappingKind_None, 255 }, - .rightstick = { EMappingKind_None, 255 }, - .leftshoulder = { EMappingKind_None, 255 }, - .rightshoulder = { EMappingKind_None, 255 }, - .dpup = { EMappingKind_Hat, 0x02 }, - .dpdown = { EMappingKind_Hat, 0x08 }, - .dpleft = { EMappingKind_Hat, 0x01 }, - .dpright = { EMappingKind_Hat, 0x04 }, - .misc1 = { EMappingKind_None, 255 }, - .paddle1 = { EMappingKind_None, 255 }, - .paddle2 = { EMappingKind_None, 255 }, - .paddle3 = { EMappingKind_None, 255 }, - .paddle4 = { EMappingKind_None, 255 }, - .leftx = { EMappingKind_Axis, 0 }, - .lefty = { EMappingKind_Axis, 1 }, - .rightx = { EMappingKind_None, 255 }, - .righty = { EMappingKind_None, 255 }, - .lefttrigger = { EMappingKind_None, 255 }, - .righttrigger = { EMappingKind_None, 255 }, - }; - is_gamepad = SDL_TRUE; - } else if (expansion == WPAD_EXP_NUNCHUK) { - /* Wiimote with nunchuck; assume nunchuck on left hand, wiimote - * pointed at screen */ - *out = (SDL_GamepadMapping){ - .a = { EMappingKind_Button, 0 }, - .b = { EMappingKind_Button, 1 }, - .x = { EMappingKind_Button, 7 }, - .y = { EMappingKind_Button, 8 }, - .back = { EMappingKind_Button, 6 }, - .guide = { EMappingKind_Button, 4 }, - .start = { EMappingKind_Button, 5 }, - .leftstick = { EMappingKind_None, 255 }, - .rightstick = { EMappingKind_None, 255 }, - .leftshoulder = { EMappingKind_None, 255 }, - .rightshoulder = { EMappingKind_None, 255 }, - .dpup = { EMappingKind_Hat, 0x01 }, - .dpdown = { EMappingKind_Hat, 0x04 }, - .dpleft = { EMappingKind_Hat, 0x08 }, - .dpright = { EMappingKind_Hat, 0x02 }, - .misc1 = { EMappingKind_None, 255 }, - .paddle1 = { EMappingKind_None, 255 }, - .paddle2 = { EMappingKind_None, 255 }, - .paddle3 = { EMappingKind_None, 255 }, - .paddle4 = { EMappingKind_None, 255 }, - .leftx = { EMappingKind_Axis, 0 }, - .lefty = { EMappingKind_Axis, 1 }, - .rightx = { EMappingKind_Axis, 2 }, - .righty = { EMappingKind_Axis, 3 }, - .lefttrigger = { EMappingKind_None, 255 }, - .righttrigger = { EMappingKind_None, 255 }, - }; - is_gamepad = SDL_TRUE; - } else if (expansion == WPAD_EXP_CLASSIC) { - *out = (SDL_GamepadMapping){ - .a = { EMappingKind_Button, 1 }, - .b = { EMappingKind_Button, 0 }, - .x = { EMappingKind_Button, 10 }, - .y = { EMappingKind_Button, 9 }, - .back = { EMappingKind_Button, 6 }, - .guide = { EMappingKind_Button, 4 }, - .start = { EMappingKind_Button, 5 }, - .leftstick = { EMappingKind_None, 255 }, - .rightstick = { EMappingKind_None, 255 }, - .leftshoulder = { EMappingKind_Button, 11 }, - .rightshoulder = { EMappingKind_Button, 12 }, - .dpup = { EMappingKind_Hat, 0x01 }, - .dpdown = { EMappingKind_Hat, 0x04 }, - .dpleft = { EMappingKind_Hat, 0x08 }, - .dpright = { EMappingKind_Hat, 0x02 }, - .misc1 = { EMappingKind_None, 255 }, - .paddle1 = { EMappingKind_None, 255 }, - .paddle2 = { EMappingKind_None, 255 }, - .paddle3 = { EMappingKind_None, 255 }, - .paddle4 = { EMappingKind_None, 255 }, - .leftx = { EMappingKind_Axis, 0 }, - .lefty = { EMappingKind_Axis, 1 }, - .rightx = { EMappingKind_Axis, 2 }, - .righty = { EMappingKind_Axis, 3 }, - .lefttrigger = { EMappingKind_Button, 13 }, - .righttrigger = { EMappingKind_Button, 14 }, - }; - is_gamepad = SDL_TRUE; + if (s_accelerometers_as_axes && device->desc->num_accelerometers > 0) { + out->leftx = (SDL_InputMapping){ EMappingKind_Axis, i_axis++ }; + out->lefty = (SDL_InputMapping){ EMappingKind_Axis, i_axis++ }; + if (device->desc->num_accelerometers > 1) { + out->rightx = (SDL_InputMapping){ EMappingKind_Axis, i_axis++ }; + out->righty = (SDL_InputMapping){ EMappingKind_Axis, i_axis++ }; } - } else if (index >= WII_EXP_START && index < WII_EXP_END) { - /* Wiimote + Extension: only support the classic controller, any other - * device is useless as a gamepad. */ - int expansion = s_detected_devices[index] - 1; - if (expansion != WPAD_EXP_CLASSIC) - return SDL_FALSE; - *out = (SDL_GamepadMapping){ - .a = { EMappingKind_Button, 1 }, - .b = { EMappingKind_Button, 0 }, - .x = { EMappingKind_Button, 3 }, - .y = { EMappingKind_Button, 2 }, - .back = { EMappingKind_Button, 10 }, - .guide = { EMappingKind_Button, 8 }, - .start = { EMappingKind_Button, 9 }, - .leftstick = { EMappingKind_None, 255 }, - .rightstick = { EMappingKind_None, 255 }, - .leftshoulder = { EMappingKind_Button, 4 }, - .rightshoulder = { EMappingKind_Button, 5 }, - .dpup = { EMappingKind_Hat, 0x01 }, - .dpdown = { EMappingKind_Hat, 0x04 }, - .dpleft = { EMappingKind_Hat, 0x08 }, - .dpright = { EMappingKind_Hat, 0x02 }, - .misc1 = { EMappingKind_None, 255 }, - .paddle1 = { EMappingKind_None, 255 }, - .paddle2 = { EMappingKind_None, 255 }, - .paddle3 = { EMappingKind_None, 255 }, - .paddle4 = { EMappingKind_None, 255 }, - .leftx = { EMappingKind_Axis, 0 }, - .lefty = { EMappingKind_Axis, 1 }, - .rightx = { EMappingKind_Axis, 2 }, - .righty = { EMappingKind_Axis, 3 }, - .lefttrigger = { EMappingKind_Button, 6 }, - .righttrigger = { EMappingKind_Button, 7 }, - }; - is_gamepad = SDL_TRUE; -#endif /* __wii__ */ } - return is_gamepad; + + if (s_wiimote_sideways && is_wiimote(device)) { + /* Remap buttons so that the 1 and 2 buttons on the wiimote become the + * primary ones */ + out->a = (SDL_InputMapping){ EMappingKind_Button, EGC_GAMEPAD_BUTTON_WEST }; /* 2 */ + out->b = (SDL_InputMapping){ EMappingKind_Button, EGC_GAMEPAD_BUTTON_NORTH }; /* 1 */ + out->x = (SDL_InputMapping){ EMappingKind_Button, EGC_GAMEPAD_BUTTON_EAST }; /* B */ + out->y = (SDL_InputMapping){ EMappingKind_Button, EGC_GAMEPAD_BUTTON_SOUTH }; /* A */ + } +#endif /* __wii__ */ + return SDL_TRUE; } SDL_JoystickDriver SDL_OGC_JoystickDriver = { diff --git a/src/main/wii/SDL_wii_main.c b/src/main/wii/SDL_wii_main.c index 80bbbf54b088f..6fe6b80cf474d 100644 --- a/src/main/wii/SDL_wii_main.c +++ b/src/main/wii/SDL_wii_main.c @@ -38,7 +38,6 @@ #include #include #include -#include static void ShutdownCB() { @@ -63,13 +62,9 @@ int main(int argc, char *argv[]) IOS_ReloadIOS(preferred); // Wii Power/Reset buttons - WPAD_Init(); - WPAD_SetPowerButtonCallback((WPADShutdownCallback)ShutdownCB); SYS_SetPowerCallback(ShutdownCB); SYS_SetResetCallback(ResetCB); // TODO OGC_InitVideoSystem(); - WPAD_SetDataFormat(WPAD_CHAN_ALL, WPAD_FMT_BTNS_ACC_IR); - WPAD_SetVRes(WPAD_CHAN_ALL, 640, 480); MOUSE_Init(); fatInitDefault(); diff --git a/src/video/ogc/SDL_ogcevents.c b/src/video/ogc/SDL_ogcevents.c index 4e4440d12dffe..cfc23c11b37d1 100644 --- a/src/video/ogc/SDL_ogcevents.c +++ b/src/video/ogc/SDL_ogcevents.c @@ -32,20 +32,31 @@ #include "SDL_ogcvideo.h" #include -#include /* These variables can be set from the handlers registered in SDL_main() */ bool OGC_PowerOffRequested = false; bool OGC_ResetRequested = false; +int OGC_NumControllers = 0; + +/* This is the array of structs holding the controller data */ +static _OGC_Controller s_controllers[OGC_MAX_CONTROLLERS]; +/* This is an array of indexes to the previous array: this is done to + * avoid moving the data when a controller is removed, and to preserve the + * IDs. */ +static u8 s_controller_indices[OGC_MAX_CONTROLLERS]; +static SDL_JoystickID s_next_instance_id = 1; +static _OGC_ControllerCb s_joystick_added_cb = NULL; +static _OGC_ControllerCb s_joystick_removed_cb = NULL; + #ifdef __wii__ #define MAX_WII_MOUSE_BUTTONS 2 static const struct { int wii; int mouse; } s_mouse_button_map[MAX_WII_MOUSE_BUTTONS] = { - { WPAD_BUTTON_B, SDL_BUTTON_LEFT }, - { WPAD_BUTTON_A, SDL_BUTTON_RIGHT }, + { EGC_GAMEPAD_BUTTON_SOUTH, SDL_BUTTON_LEFT }, + { EGC_GAMEPAD_BUTTON_EAST, SDL_BUTTON_RIGHT }, }; static void pump_ir_events(_THIS) @@ -54,31 +65,29 @@ static void pump_ir_events(_THIS) if (!_this->windows) return; - if (!SDL_WasInit(SDL_INIT_JOYSTICK)) { - /* Get events from WPAD; we don't need to do this if the joystick - * system was initialized, because in that case this operation is done - * there at every event loop iteration. */ - WPAD_ReadPending(WPAD_CHAN_ALL, NULL); - } - screen_w = _this->displays[0].current_mode.w; screen_h = _this->displays[0].current_mode.h; - for (int i = 0; i < 4; i++) { - WPADData *data = WPAD_Data(i); + for (int i = 0; i < OGC_NumControllers; i++) { + _OGC_Controller *controller = OGC_get_controller(i); + egc_input_device_t *device = controller->egc_device; + egc_point_t point; + + if (device->desc->num_touch_points == 0) continue; - if (!data->ir.valid) continue; + point = egc_input_device_read_touch_point(device, 0); + if (point.x < 0) continue; SDL_SendMouseMotion(_this->windows, i, 0, - data->ir.x * screen_w / 640, - data->ir.y * screen_h / 480); + point.x * screen_w / EGC_GAMEPAD_TOUCH_RES, + point.y * screen_h / EGC_GAMEPAD_TOUCH_RES); for (int b = 0; b < MAX_WII_MOUSE_BUTTONS; b++) { - if (data->btns_d & s_mouse_button_map[b].wii) { + if (controller->btns_pressed & s_mouse_button_map[b].wii) { SDL_SendMouseButton(_this->windows, i, SDL_PRESSED, s_mouse_button_map[b].mouse); } - if (data->btns_u & s_mouse_button_map[b].wii) { + if (controller->btns_released & s_mouse_button_map[b].wii) { SDL_SendMouseButton(_this->windows, i, SDL_RELEASED, s_mouse_button_map[b].mouse); } @@ -91,6 +100,12 @@ static void pump_ir_events(_THIS) } #endif +_OGC_Controller *OGC_get_controller(int i) +{ + if (i < 0 || i >= OGC_NumControllers) return NULL; + return &s_controllers[s_controller_indices[i]]; +} + void OGC_PumpEvents(_THIS) { if (OGC_ResetRequested || OGC_PowerOffRequested) { @@ -102,12 +117,89 @@ void OGC_PumpEvents(_THIS) } } + egc_handle_events(); + for (int i = 0; i < OGC_NumControllers; i++) { + _OGC_Controller *controller = OGC_get_controller(i); + u32 buttons = egc_input_device_read_buttons(controller->egc_device); + controller->btns_held = controller->btns_prev & buttons; + controller->btns_released = controller->btns_prev & ~buttons; + controller->btns_pressed = buttons & controller->btns_prev; + controller->btns_prev = buttons; + } + #ifdef __wii__ pump_ir_events(_this); OGC_PumpKeyboardEvents(_this); #endif } +void OGC_device_added_cb(egc_input_device_t *device, void *userdata) +{ + _OGC_Controller *controller; + + int free_index = -1; + for (int i = 0; i < OGC_MAX_CONTROLLERS; i++) { + controller = &s_controllers[i]; + if (controller->egc_device == NULL) { + free_index = i; + break; + } + } + if (free_index < 0) return; + + memset(controller, 0, sizeof(*controller)); + controller->egc_device = device; + controller->instance_id = s_next_instance_id++; + s_controller_indices[OGC_NumControllers++] = free_index; + +#ifdef __wii__ + egc_bt_stop_scan(); +#endif + + if (s_joystick_added_cb) { + s_joystick_added_cb(controller); + } +} + +void OGC_device_removed_cb(egc_input_device_t *device, void *userdata) +{ + _OGC_Controller *controller = NULL; + int found_index = -1; + for (int i = 0; i < OGC_NumControllers; i++) { + controller = OGC_get_controller(i); + if (controller->egc_device == device) { + found_index = i; + controller->egc_device = NULL; + break; + } + } + if (found_index < 0) return; + + if (s_joystick_removed_cb) { + s_joystick_removed_cb(controller); + } + + OGC_NumControllers--; + /* Move back all later indices by one position */ + for (int i = found_index; i < OGC_NumControllers; i++) { + s_controller_indices[i] = s_controller_indices[i + 1]; + } + +#ifdef __wii__ + if (OGC_NumControllers == 0) { + egc_bt_start_scan(); + } +#endif + +} + +void OGC_register_joystick_callbacks(_OGC_ControllerCb added_cb, + _OGC_ControllerCb removed_cb) +{ + s_joystick_added_cb = added_cb; + s_joystick_removed_cb = removed_cb; +} + #endif /* SDL_VIDEO_DRIVER_OGC */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/ogc/SDL_ogcevents_c.h b/src/video/ogc/SDL_ogcevents_c.h index 6bc6b91e68b69..f9cc9df8d8ac2 100644 --- a/src/video/ogc/SDL_ogcevents_c.h +++ b/src/video/ogc/SDL_ogcevents_c.h @@ -25,12 +25,44 @@ #include "../../SDL_internal.h" #include "SDL_ogcvideo.h" +#include "SDL_joystick.h" + +#include + +#ifdef __wii__ +/* 4 GameCube controllers + 4 Wiimotes + possibly 4 separate expansions. In + * theory there could be even more controller, connected via USB and bluetooth, + * but let's be realistic :-) + */ +#define OGC_MAX_CONTROLLERS 12 +#else +#define OGC_MAX_CONTROLLERS 4 +#endif + +typedef struct { + egc_input_device_t *egc_device; + SDL_JoystickID instance_id; + u32 btns_prev; + u32 btns_pressed; + u32 btns_held; + u32 btns_released; +} _OGC_Controller; + +extern int OGC_NumControllers; extern bool OGC_ResetRequested; extern bool OGC_PowerOffRequested; extern void OGC_PumpEvents(_THIS); +void OGC_device_added_cb(egc_input_device_t *device, void *userdata); +void OGC_device_removed_cb(egc_input_device_t *device, void *userdata); +_OGC_Controller *OGC_get_controller(int i); + +typedef void (*_OGC_ControllerCb)(_OGC_Controller *controller); +void OGC_register_joystick_callbacks(_OGC_ControllerCb added_cb, + _OGC_ControllerCb removed_cb); + #endif /* SDL_ogcevents_c_h_ */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/ogc/SDL_ogcmouse.c b/src/video/ogc/SDL_ogcmouse.c index 6e3bda25650cc..9e4cd9c09406f 100644 --- a/src/video/ogc/SDL_ogcmouse.c +++ b/src/video/ogc/SDL_ogcmouse.c @@ -26,6 +26,7 @@ #include "SDL_hints.h" #include "SDL_ogccursors.h" +#include "SDL_ogcevents_c.h" #include "SDL_ogcgxcommon.h" #include "SDL_ogcmouse.h" #include "SDL_ogcpixels.h" @@ -39,7 +40,6 @@ #include #include #include -#include typedef struct _OGC_CursorData { @@ -243,9 +243,18 @@ void OGC_draw_cursor(_THIS) /* If this is the default cursor, rotate it, and if it's not pointed at the * screen, hide it */ if (mouse->cur_cursor == mouse->def_cursor) { - WPADData *data = WPAD_Data(mouse->mouseID); - angle = data->ir.angle; - if (!data->ir.valid) return; + egc_input_device_t *device; + egc_point_t point; + const egc_accelerometer_t *accel; + + _OGC_Controller *controller = OGC_get_controller(mouse->mouseID); + if (!controller) return; + + device = controller->egc_device; + point = egc_input_device_read_touch_point(device, 0); + if (point.x < 0) return; + accel = egc_input_device_read_accelerometer(device, 0); + angle = atan2f(accel->x, accel->y); } screen_w = _this->displays[0].current_mode.w; @@ -315,7 +324,7 @@ void OGC_draw_cursor(_THIS) guMtxScaleApply(mv, mv, screen_w / 640.0f, screen_h / 480.0f, 1.0f); if (angle != 0.0f) { Mtx rot; - guMtxRotDeg(rot, 'z', angle); + guMtxRotRad(rot, 'z', angle); guMtxConcat(mv, rot, mv); } guMtxTransApply(mv, mv, mouse->x, mouse->y, 0); diff --git a/src/video/ogc/SDL_ogcvideo.c b/src/video/ogc/SDL_ogcvideo.c index a99077beb9e48..6d94e258ee1c9 100644 --- a/src/video/ogc/SDL_ogcvideo.c +++ b/src/video/ogc/SDL_ogcvideo.c @@ -314,7 +314,15 @@ int OGC_VideoInit(_THIS) videodata->vmode = vmode; + egc_initialize(OGC_device_added_cb, OGC_device_removed_cb, NULL); + #ifdef __wii__ + /* Page mode does not slow BT down, so we keep it on all the time; but + * scanning has a noticeable effect on BT performance, so we leave it on + * only until we get the first controller connected. */ + egc_bt_enter_page_mode(); + egc_bt_start_scan(); + OGC_InitMouse(_this); /* OGC_PumpEvents reads the keyboard, so we need to initialize it here */ KEYBOARD_Init(NULL);