From b0a1b45489b8495ea71921d8e9ac1e5c9efadae5 Mon Sep 17 00:00:00 2001 From: Alberto Mardegan Date: Sat, 13 Jun 2026 14:58:59 +0300 Subject: [PATCH] ogc: use embedded-game-controller as input backend This greatly simplify handling of different controllers, since EGC input reports are designed after SDL's GameController API. Unfortunately, due to the need to support applications using the older SDL joystick API, we map the D-pad buttons to a joystick hat, and this makes the code not as linear as it could be. For more information about this issue, see https://github.com/libsdl-org/SDL/issues/8754 The switch to EGC brings some other changes: - Removed support for the split-controller feature, which has not been used in any applications yet; it might come back, but then it would be most likely implemented in EGC itself. - Added support for USB and Bluetooth controllers (see EGC's `hid-drivers` folder for a list of supported devices). - If the SDL_WII_JOYSTICK_SIDEWAYS environment variable is set, now not only the D-pad is rotated, but the accelerometer too. - Support for the Wiimote+ gyroscope. --- CMakeLists.txt | 8 +- src/joystick/ogc/SDL_sysjoystick.c | 1412 ++++++++-------------------- src/main/wii/SDL_wii_main.c | 5 - src/video/ogc/SDL_ogcevents.c | 126 ++- src/video/ogc/SDL_ogcevents_c.h | 32 + src/video/ogc/SDL_ogcmouse.c | 19 +- src/video/ogc/SDL_ogcvideo.c | 8 + 7 files changed, 555 insertions(+), 1055 deletions(-) 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);