diff --git a/test/testcontroller.c b/test/testcontroller.c index 4cf35c9d9a590..da87c72778301 100644 --- a/test/testcontroller.c +++ b/test/testcontroller.c @@ -12,6 +12,7 @@ /* Simple program to test the SDL controller routines */ +#define SDL_MAIN_USE_CALLBACKS #include #include #include @@ -64,6 +65,7 @@ typedef struct int trigger_effect; } Controller; +static SDLTest_CommonState *state; static SDL_Window *window = NULL; static SDL_Renderer *screen = NULL; static ControllerDisplayMode display_mode = CONTROLLER_MODE_TESTING; @@ -194,47 +196,47 @@ typedef struct static void CyclePS5AudioRoute(Controller *device) { - DS5EffectsState_t state; + DS5EffectsState_t effects; device->audio_route = (device->audio_route + 1) % 4; - SDL_zero(state); + SDL_zero(effects); switch (device->audio_route) { case 0: /* Audio disabled */ - state.ucEnableBits1 |= (0x80 | 0x20 | 0x10); /* Modify audio route and speaker / headphone volume */ - state.ucSpeakerVolume = 0; /* Minimum volume */ - state.ucHeadphoneVolume = 0; /* Minimum volume */ - state.ucAudioEnableBits = 0x00; /* Output to headphones */ + effects.ucEnableBits1 |= (0x80 | 0x20 | 0x10); /* Modify audio route and speaker / headphone volume */ + effects.ucSpeakerVolume = 0; /* Minimum volume */ + effects.ucHeadphoneVolume = 0; /* Minimum volume */ + effects.ucAudioEnableBits = 0x00; /* Output to headphones */ break; case 1: /* Headphones */ - state.ucEnableBits1 |= (0x80 | 0x10); /* Modify audio route and headphone volume */ - state.ucHeadphoneVolume = 50; /* 50% volume - don't blast into the ears */ - state.ucAudioEnableBits = 0x00; /* Output to headphones */ + effects.ucEnableBits1 |= (0x80 | 0x10); /* Modify audio route and headphone volume */ + effects.ucHeadphoneVolume = 50; /* 50% volume - don't blast into the ears */ + effects.ucAudioEnableBits = 0x00; /* Output to headphones */ break; case 2: /* Speaker */ - state.ucEnableBits1 |= (0x80 | 0x20); /* Modify audio route and speaker volume */ - state.ucSpeakerVolume = 100; /* Maximum volume */ - state.ucAudioEnableBits = 0x30; /* Output to speaker */ + effects.ucEnableBits1 |= (0x80 | 0x20); /* Modify audio route and speaker volume */ + effects.ucSpeakerVolume = 100; /* Maximum volume */ + effects.ucAudioEnableBits = 0x30; /* Output to speaker */ break; case 3: /* Both */ - state.ucEnableBits1 |= (0x80 | 0x20 | 0x10); /* Modify audio route and speaker / headphone volume */ - state.ucSpeakerVolume = 100; /* Maximum volume */ - state.ucHeadphoneVolume = 50; /* 50% volume - don't blast into the ears */ - state.ucAudioEnableBits = 0x20; /* Output to both speaker and headphones */ + effects.ucEnableBits1 |= (0x80 | 0x20 | 0x10); /* Modify audio route and speaker / headphone volume */ + effects.ucSpeakerVolume = 100; /* Maximum volume */ + effects.ucHeadphoneVolume = 50; /* 50% volume - don't blast into the ears */ + effects.ucAudioEnableBits = 0x20; /* Output to both speaker and headphones */ break; } - SDL_SendGamepadEffect(device->gamepad, &state, sizeof(state)); + SDL_SendGamepadEffect(device->gamepad, &effects, sizeof(effects)); } static void CyclePS5TriggerEffect(Controller *device) { - DS5EffectsState_t state; + DS5EffectsState_t effects; - Uint8 effects[3][11] = { + Uint8 trigger_effects[3][11] = { /* Clear trigger effect */ { 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* Constant resistance across entire trigger pull */ @@ -243,13 +245,13 @@ static void CyclePS5TriggerEffect(Controller *device) { 0x06, 15, 63, 128, 0, 0, 0, 0, 0, 0, 0 }, }; - device->trigger_effect = (device->trigger_effect + 1) % SDL_arraysize(effects); + device->trigger_effect = (device->trigger_effect + 1) % SDL_arraysize(trigger_effects); - SDL_zero(state); - state.ucEnableBits1 |= (0x04 | 0x08); /* Modify right and left trigger effect respectively */ - SDL_memcpy(state.rgucRightTriggerEffect, effects[device->trigger_effect], sizeof(effects[0])); - SDL_memcpy(state.rgucLeftTriggerEffect, effects[device->trigger_effect], sizeof(effects[0])); - SDL_SendGamepadEffect(device->gamepad, &state, sizeof(state)); + SDL_zero(effects); + effects.ucEnableBits1 |= (0x04 | 0x08); /* Modify right and left trigger effect respectively */ + SDL_memcpy(effects.rgucRightTriggerEffect, trigger_effects[device->trigger_effect], sizeof(trigger_effects[0])); + SDL_memcpy(effects.rgucLeftTriggerEffect, trigger_effects[device->trigger_effect], sizeof(trigger_effects[0])); + SDL_SendGamepadEffect(device->gamepad, &effects, sizeof(effects)); } static void ClearButtonHighlights(void) @@ -1573,358 +1575,359 @@ static void UpdateGamepadEffects(void) } } -static void loop(void *arg) +SDL_AppResult SDLCALL SDL_AppEvent(void *appstate, SDL_Event *event) { - SDL_Event event; + SDL_ConvertEventToRenderCoordinates(screen, event); - /* If we have a virtual controller, send a virtual accelerometer sensor reading */ - if (virtual_joystick) { - float data[3] = { 0.0f, SDL_STANDARD_GRAVITY, 0.0f }; - SDL_SendJoystickVirtualSensorData(virtual_joystick, SDL_SENSOR_ACCEL, SDL_GetTicksNS(), data, SDL_arraysize(data)); - } - - /* Update to get the current event state */ - SDL_PumpEvents(); - - /* Process all currently pending events */ - while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST) == 1) { - SDL_ConvertEventToRenderCoordinates(screen, &event); - - switch (event.type) { - case SDL_EVENT_JOYSTICK_ADDED: - AddController(event.jdevice.which, true); - break; + switch (event->type) { + case SDL_EVENT_JOYSTICK_ADDED: + AddController(event->jdevice.which, true); + break; - case SDL_EVENT_JOYSTICK_REMOVED: - DelController(event.jdevice.which); - break; + case SDL_EVENT_JOYSTICK_REMOVED: + DelController(event->jdevice.which); + break; - case SDL_EVENT_JOYSTICK_AXIS_MOTION: - if (display_mode == CONTROLLER_MODE_TESTING) { - if (event.jaxis.value <= (-SDL_JOYSTICK_AXIS_MAX / 2) || event.jaxis.value >= (SDL_JOYSTICK_AXIS_MAX / 2)) { - SetController(event.jaxis.which); - } - } else if (display_mode == CONTROLLER_MODE_BINDING && - event.jaxis.which == controller->id && - event.jaxis.axis < controller->num_axes && - binding_element != SDL_GAMEPAD_ELEMENT_INVALID) { - const int MAX_ALLOWED_JITTER = SDL_JOYSTICK_AXIS_MAX / 80; /* ShanWan PS3 gamepad needed 96 */ - AxisState *pAxisState = &controller->axis_state[event.jaxis.axis]; - int nValue = event.jaxis.value; - int nCurrentDistance, nFarthestDistance; - if (!pAxisState->m_bMoving) { - Sint16 nInitialValue; - pAxisState->m_bMoving = SDL_GetJoystickAxisInitialState(controller->joystick, event.jaxis.axis, &nInitialValue); - pAxisState->m_nLastValue = nValue; - pAxisState->m_nStartingValue = nInitialValue; - pAxisState->m_nFarthestValue = nInitialValue; - } else if (SDL_abs(nValue - pAxisState->m_nLastValue) <= MAX_ALLOWED_JITTER) { - break; - } else { - pAxisState->m_nLastValue = nValue; - } - nCurrentDistance = SDL_abs(nValue - pAxisState->m_nStartingValue); + case SDL_EVENT_JOYSTICK_AXIS_MOTION: + if (display_mode == CONTROLLER_MODE_TESTING) { + if (event->jaxis.value <= (-SDL_JOYSTICK_AXIS_MAX / 2) || event->jaxis.value >= (SDL_JOYSTICK_AXIS_MAX / 2)) { + SetController(event->jaxis.which); + } + } else if (display_mode == CONTROLLER_MODE_BINDING && + event->jaxis.which == controller->id && + event->jaxis.axis < controller->num_axes && + binding_element != SDL_GAMEPAD_ELEMENT_INVALID) { + const int MAX_ALLOWED_JITTER = SDL_JOYSTICK_AXIS_MAX / 80; /* ShanWan PS3 gamepad needed 96 */ + AxisState *pAxisState = &controller->axis_state[event->jaxis.axis]; + int nValue = event->jaxis.value; + int nCurrentDistance, nFarthestDistance; + if (!pAxisState->m_bMoving) { + Sint16 nInitialValue; + pAxisState->m_bMoving = SDL_GetJoystickAxisInitialState(controller->joystick, event->jaxis.axis, &nInitialValue); + pAxisState->m_nLastValue = nValue; + pAxisState->m_nStartingValue = nInitialValue; + pAxisState->m_nFarthestValue = nInitialValue; + } else if (SDL_abs(nValue - pAxisState->m_nLastValue) <= MAX_ALLOWED_JITTER) { + break; + } else { + pAxisState->m_nLastValue = nValue; + } + nCurrentDistance = SDL_abs(nValue - pAxisState->m_nStartingValue); + nFarthestDistance = SDL_abs(pAxisState->m_nFarthestValue - pAxisState->m_nStartingValue); + if (nCurrentDistance > nFarthestDistance) { + pAxisState->m_nFarthestValue = nValue; nFarthestDistance = SDL_abs(pAxisState->m_nFarthestValue - pAxisState->m_nStartingValue); - if (nCurrentDistance > nFarthestDistance) { - pAxisState->m_nFarthestValue = nValue; - nFarthestDistance = SDL_abs(pAxisState->m_nFarthestValue - pAxisState->m_nStartingValue); - } + } #ifdef DEBUG_AXIS_MAPPING - SDL_Log("AXIS %d nValue %d nCurrentDistance %d nFarthestDistance %d\n", event.jaxis.axis, nValue, nCurrentDistance, nFarthestDistance); + SDL_Log("AXIS %d nValue %d nCurrentDistance %d nFarthestDistance %d\n", event->jaxis.axis, nValue, nCurrentDistance, nFarthestDistance); #endif - /* If we've gone out far enough and started to come back, let's bind this axis */ - if (nFarthestDistance >= 16000 && nCurrentDistance <= 10000) { - char binding[12]; - int axis_min = StandardizeAxisValue(pAxisState->m_nStartingValue); - int axis_max = StandardizeAxisValue(pAxisState->m_nFarthestValue); - - if (axis_min == 0 && axis_max == SDL_JOYSTICK_AXIS_MIN) { - /* The negative half axis */ - (void)SDL_snprintf(binding, sizeof(binding), "-a%d", event.jaxis.axis); - } else if (axis_min == 0 && axis_max == SDL_JOYSTICK_AXIS_MAX) { - /* The positive half axis */ - (void)SDL_snprintf(binding, sizeof(binding), "+a%d", event.jaxis.axis); - } else { - (void)SDL_snprintf(binding, sizeof(binding), "a%d", event.jaxis.axis); - if (axis_min > axis_max) { - /* Invert the axis */ - SDL_strlcat(binding, "~", SDL_arraysize(binding)); - } + /* If we've gone out far enough and started to come back, let's bind this axis */ + if (nFarthestDistance >= 16000 && nCurrentDistance <= 10000) { + char binding[12]; + int axis_min = StandardizeAxisValue(pAxisState->m_nStartingValue); + int axis_max = StandardizeAxisValue(pAxisState->m_nFarthestValue); + + if (axis_min == 0 && axis_max == SDL_JOYSTICK_AXIS_MIN) { + /* The negative half axis */ + (void)SDL_snprintf(binding, sizeof(binding), "-a%d", event->jaxis.axis); + } else if (axis_min == 0 && axis_max == SDL_JOYSTICK_AXIS_MAX) { + /* The positive half axis */ + (void)SDL_snprintf(binding, sizeof(binding), "+a%d", event->jaxis.axis); + } else { + (void)SDL_snprintf(binding, sizeof(binding), "a%d", event->jaxis.axis); + if (axis_min > axis_max) { + /* Invert the axis */ + SDL_strlcat(binding, "~", SDL_arraysize(binding)); } + } #ifdef DEBUG_AXIS_MAPPING - SDL_Log("AXIS %d axis_min = %d, axis_max = %d, binding = %s\n", event.jaxis.axis, axis_min, axis_max, binding); + SDL_Log("AXIS %d axis_min = %d, axis_max = %d, binding = %s\n", event->jaxis.axis, axis_min, axis_max, binding); #endif - CommitBindingElement(binding, false); - } + CommitBindingElement(binding, false); } - break; + } + break; - case SDL_EVENT_JOYSTICK_BUTTON_DOWN: - if (display_mode == CONTROLLER_MODE_TESTING) { - SetController(event.jbutton.which); - } - break; + case SDL_EVENT_JOYSTICK_BUTTON_DOWN: + if (display_mode == CONTROLLER_MODE_TESTING) { + SetController(event->jbutton.which); + } + break; - case SDL_EVENT_JOYSTICK_BUTTON_UP: - if (display_mode == CONTROLLER_MODE_BINDING && - event.jbutton.which == controller->id && - binding_element != SDL_GAMEPAD_ELEMENT_INVALID) { - char binding[12]; + case SDL_EVENT_JOYSTICK_BUTTON_UP: + if (display_mode == CONTROLLER_MODE_BINDING && + event->jbutton.which == controller->id && + binding_element != SDL_GAMEPAD_ELEMENT_INVALID) { + char binding[12]; - SDL_snprintf(binding, sizeof(binding), "b%d", event.jbutton.button); - CommitBindingElement(binding, false); - } - break; + SDL_snprintf(binding, sizeof(binding), "b%d", event->jbutton.button); + CommitBindingElement(binding, false); + } + break; - case SDL_EVENT_JOYSTICK_HAT_MOTION: - if (display_mode == CONTROLLER_MODE_BINDING && - event.jhat.which == controller->id && - event.jhat.value != SDL_HAT_CENTERED && - binding_element != SDL_GAMEPAD_ELEMENT_INVALID) { - char binding[12]; + case SDL_EVENT_JOYSTICK_HAT_MOTION: + if (display_mode == CONTROLLER_MODE_BINDING && + event->jhat.which == controller->id && + event->jhat.value != SDL_HAT_CENTERED && + binding_element != SDL_GAMEPAD_ELEMENT_INVALID) { + char binding[12]; - SDL_snprintf(binding, sizeof(binding), "h%d.%d", event.jhat.hat, event.jhat.value); - CommitBindingElement(binding, false); - } - break; + SDL_snprintf(binding, sizeof(binding), "h%d.%d", event->jhat.hat, event->jhat.value); + CommitBindingElement(binding, false); + } + break; - case SDL_EVENT_GAMEPAD_ADDED: - HandleGamepadAdded(event.gdevice.which, true); - break; + case SDL_EVENT_GAMEPAD_ADDED: + HandleGamepadAdded(event->gdevice.which, true); + break; - case SDL_EVENT_GAMEPAD_REMOVED: - HandleGamepadRemoved(event.gdevice.which); - break; + case SDL_EVENT_GAMEPAD_REMOVED: + HandleGamepadRemoved(event->gdevice.which); + break; - case SDL_EVENT_GAMEPAD_REMAPPED: - HandleGamepadRemapped(event.gdevice.which); - break; + case SDL_EVENT_GAMEPAD_REMAPPED: + HandleGamepadRemapped(event->gdevice.which); + break; - case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED: - RefreshControllerName(); - break; + case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED: + RefreshControllerName(); + break; #ifdef VERBOSE_TOUCHPAD - case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN: - case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION: - case SDL_EVENT_GAMEPAD_TOUCHPAD_UP: - SDL_Log("Gamepad %" SDL_PRIu32 " touchpad %" SDL_PRIs32 " finger %" SDL_PRIs32 " %s %.2f, %.2f, %.2f\n", - event.gtouchpad.which, - event.gtouchpad.touchpad, - event.gtouchpad.finger, - (event.type == SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN ? "pressed at" : (event.type == SDL_EVENT_GAMEPAD_TOUCHPAD_UP ? "released at" : "moved to")), - event.gtouchpad.x, - event.gtouchpad.y, - event.gtouchpad.pressure); - break; + case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN: + case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION: + case SDL_EVENT_GAMEPAD_TOUCHPAD_UP: + SDL_Log("Gamepad %" SDL_PRIu32 " touchpad %" SDL_PRIs32 " finger %" SDL_PRIs32 " %s %.2f, %.2f, %.2f\n", + event->gtouchpad.which, + event->gtouchpad.touchpad, + event->gtouchpad.finger, + (event->type == SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN ? "pressed at" : (event->type == SDL_EVENT_GAMEPAD_TOUCHPAD_UP ? "released at" : "moved to")), + event->gtouchpad.x, + event->gtouchpad.y, + event->gtouchpad.pressure); + break; #endif /* VERBOSE_TOUCHPAD */ #ifdef VERBOSE_SENSORS - case SDL_EVENT_GAMEPAD_SENSOR_UPDATE: - SDL_Log("Gamepad %" SDL_PRIu32 " sensor %s: %.2f, %.2f, %.2f (%" SDL_PRIu64 ")\n", - event.gsensor.which, - GetSensorName((SDL_SensorType) event.gsensor.sensor), - event.gsensor.data[0], - event.gsensor.data[1], - event.gsensor.data[2], - event.gsensor.sensor_timestamp); - break; + case SDL_EVENT_GAMEPAD_SENSOR_UPDATE: + SDL_Log("Gamepad %" SDL_PRIu32 " sensor %s: %.2f, %.2f, %.2f (%" SDL_PRIu64 ")\n", + event->gsensor.which, + GetSensorName((SDL_SensorType) event->gsensor.sensor), + event->gsensor.data[0], + event->gsensor.data[1], + event->gsensor.data[2], + event->gsensor.sensor_timestamp); + break; #endif /* VERBOSE_SENSORS */ #ifdef VERBOSE_AXES - case SDL_EVENT_GAMEPAD_AXIS_MOTION: - if (display_mode == CONTROLLER_MODE_TESTING) { - if (event.gaxis.value <= (-SDL_JOYSTICK_AXIS_MAX / 2) || event.gaxis.value >= (SDL_JOYSTICK_AXIS_MAX / 2)) { - SetController(event.gaxis.which); - } + case SDL_EVENT_GAMEPAD_AXIS_MOTION: + if (display_mode == CONTROLLER_MODE_TESTING) { + if (event->gaxis.value <= (-SDL_JOYSTICK_AXIS_MAX / 2) || event->gaxis.value >= (SDL_JOYSTICK_AXIS_MAX / 2)) { + SetController(event->gaxis.which); } - SDL_Log("Gamepad %" SDL_PRIu32 " axis %s changed to %d\n", - event.gaxis.which, - SDL_GetGamepadStringForAxis((SDL_GamepadAxis) event.gaxis.axis), - event.gaxis.value); - break; + } + SDL_Log("Gamepad %" SDL_PRIu32 " axis %s changed to %d\n", + event->gaxis.which, + SDL_GetGamepadStringForAxis((SDL_GamepadAxis) event->gaxis.axis), + event->gaxis.value); + break; #endif /* VERBOSE_AXES */ - case SDL_EVENT_GAMEPAD_BUTTON_DOWN: - case SDL_EVENT_GAMEPAD_BUTTON_UP: - if (display_mode == CONTROLLER_MODE_TESTING) { - if (event.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) { - SetController(event.gbutton.which); - } + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + case SDL_EVENT_GAMEPAD_BUTTON_UP: + if (display_mode == CONTROLLER_MODE_TESTING) { + if (event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) { + SetController(event->gbutton.which); } + } #ifdef VERBOSE_BUTTONS - SDL_Log("Gamepad %" SDL_PRIu32 " button %s %s\n", - event.gbutton.which, - SDL_GetGamepadStringForButton((SDL_GamepadButton) event.gbutton.button), - event.gbutton.state ? "pressed" : "released"); + SDL_Log("Gamepad %" SDL_PRIu32 " button %s %s\n", + event->gbutton.which, + SDL_GetGamepadStringForButton((SDL_GamepadButton) event->gbutton.button), + event->gbutton.state ? "pressed" : "released"); #endif /* VERBOSE_BUTTONS */ - if (display_mode == CONTROLLER_MODE_TESTING) { - if (event.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN && - controller && SDL_GetGamepadType(controller->gamepad) == SDL_GAMEPAD_TYPE_PS5) { - /* Cycle PS5 audio routing when the microphone button is pressed */ - if (event.gbutton.button == SDL_GAMEPAD_BUTTON_MISC1) { - CyclePS5AudioRoute(controller); - } + if (display_mode == CONTROLLER_MODE_TESTING) { + if (event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN && + controller && SDL_GetGamepadType(controller->gamepad) == SDL_GAMEPAD_TYPE_PS5) { + /* Cycle PS5 audio routing when the microphone button is pressed */ + if (event->gbutton.button == SDL_GAMEPAD_BUTTON_MISC1) { + CyclePS5AudioRoute(controller); + } - /* Cycle PS5 trigger effects when the triangle button is pressed */ - if (event.gbutton.button == SDL_GAMEPAD_BUTTON_NORTH) { - CyclePS5TriggerEffect(controller); - } + /* Cycle PS5 trigger effects when the triangle button is pressed */ + if (event->gbutton.button == SDL_GAMEPAD_BUTTON_NORTH) { + CyclePS5TriggerEffect(controller); } } - break; + } + break; - case SDL_EVENT_MOUSE_BUTTON_DOWN: - if (virtual_joystick && controller && controller->joystick == virtual_joystick) { - VirtualGamepadMouseDown(event.button.x, event.button.y); - } - UpdateButtonHighlights(event.button.x, event.button.y, event.button.down); - break; + case SDL_EVENT_MOUSE_BUTTON_DOWN: + if (virtual_joystick && controller && controller->joystick == virtual_joystick) { + VirtualGamepadMouseDown(event->button.x, event->button.y); + } + UpdateButtonHighlights(event->button.x, event->button.y, event->button.down); + break; - case SDL_EVENT_MOUSE_BUTTON_UP: - if (virtual_joystick && controller && controller->joystick == virtual_joystick) { - VirtualGamepadMouseUp(event.button.x, event.button.y); - } + case SDL_EVENT_MOUSE_BUTTON_UP: + if (virtual_joystick && controller && controller->joystick == virtual_joystick) { + VirtualGamepadMouseUp(event->button.x, event->button.y); + } - if (display_mode == CONTROLLER_MODE_TESTING) { - if (GamepadButtonContains(setup_mapping_button, event.button.x, event.button.y)) { - SetDisplayMode(CONTROLLER_MODE_BINDING); + if (display_mode == CONTROLLER_MODE_TESTING) { + if (GamepadButtonContains(setup_mapping_button, event->button.x, event->button.y)) { + SetDisplayMode(CONTROLLER_MODE_BINDING); + } + } else if (display_mode == CONTROLLER_MODE_BINDING) { + if (GamepadButtonContains(done_mapping_button, event->button.x, event->button.y)) { + if (controller->mapping) { + SDL_Log("Mapping complete:\n"); + SDL_Log("%s\n", controller->mapping); } - } else if (display_mode == CONTROLLER_MODE_BINDING) { - if (GamepadButtonContains(done_mapping_button, event.button.x, event.button.y)) { - if (controller->mapping) { - SDL_Log("Mapping complete:\n"); - SDL_Log("%s\n", controller->mapping); - } - SetDisplayMode(CONTROLLER_MODE_TESTING); - } else if (GamepadButtonContains(cancel_button, event.button.x, event.button.y)) { - CancelMapping(); - } else if (GamepadButtonContains(clear_button, event.button.x, event.button.y)) { - ClearMapping(); - } else if (controller->has_bindings && - GamepadButtonContains(copy_button, event.button.x, event.button.y)) { - CopyMapping(); - } else if (GamepadButtonContains(paste_button, event.button.x, event.button.y)) { - PasteMapping(); - } else if (title_pressed) { - SetCurrentBindingElement(SDL_GAMEPAD_ELEMENT_NAME, false); - } else if (type_pressed) { - SetCurrentBindingElement(SDL_GAMEPAD_ELEMENT_TYPE, false); - } else if (binding_element == SDL_GAMEPAD_ELEMENT_TYPE) { - int type = GetGamepadTypeDisplayAt(gamepad_type, event.button.x, event.button.y); - if (type != SDL_GAMEPAD_TYPE_UNSELECTED) { - CommitGamepadType((SDL_GamepadType)type); - StopBinding(); - } - } else { - int gamepad_element = SDL_GAMEPAD_ELEMENT_INVALID; - char *joystick_element; + SetDisplayMode(CONTROLLER_MODE_TESTING); + } else if (GamepadButtonContains(cancel_button, event->button.x, event->button.y)) { + CancelMapping(); + } else if (GamepadButtonContains(clear_button, event->button.x, event->button.y)) { + ClearMapping(); + } else if (controller->has_bindings && + GamepadButtonContains(copy_button, event->button.x, event->button.y)) { + CopyMapping(); + } else if (GamepadButtonContains(paste_button, event->button.x, event->button.y)) { + PasteMapping(); + } else if (title_pressed) { + SetCurrentBindingElement(SDL_GAMEPAD_ELEMENT_NAME, false); + } else if (type_pressed) { + SetCurrentBindingElement(SDL_GAMEPAD_ELEMENT_TYPE, false); + } else if (binding_element == SDL_GAMEPAD_ELEMENT_TYPE) { + int type = GetGamepadTypeDisplayAt(gamepad_type, event->button.x, event->button.y); + if (type != SDL_GAMEPAD_TYPE_UNSELECTED) { + CommitGamepadType((SDL_GamepadType)type); + StopBinding(); + } + } else { + int gamepad_element = SDL_GAMEPAD_ELEMENT_INVALID; + char *joystick_element; - if (controller->joystick != virtual_joystick) { - gamepad_element = GetGamepadImageElementAt(image, event.button.x, event.button.y); - } - if (gamepad_element == SDL_GAMEPAD_ELEMENT_INVALID) { - gamepad_element = GetGamepadDisplayElementAt(gamepad_elements, controller->gamepad, event.button.x, event.button.y); - } - if (gamepad_element != SDL_GAMEPAD_ELEMENT_INVALID) { - /* Set this to false if you don't want to start the binding flow at this point */ - const bool should_start_flow = true; - SetCurrentBindingElement(gamepad_element, should_start_flow); - } + if (controller->joystick != virtual_joystick) { + gamepad_element = GetGamepadImageElementAt(image, event->button.x, event->button.y); + } + if (gamepad_element == SDL_GAMEPAD_ELEMENT_INVALID) { + gamepad_element = GetGamepadDisplayElementAt(gamepad_elements, controller->gamepad, event->button.x, event->button.y); + } + if (gamepad_element != SDL_GAMEPAD_ELEMENT_INVALID) { + /* Set this to false if you don't want to start the binding flow at this point */ + const bool should_start_flow = true; + SetCurrentBindingElement(gamepad_element, should_start_flow); + } - joystick_element = GetJoystickDisplayElementAt(joystick_elements, controller->joystick, event.button.x, event.button.y); - if (joystick_element) { - CommitBindingElement(joystick_element, true); - SDL_free(joystick_element); - } + joystick_element = GetJoystickDisplayElementAt(joystick_elements, controller->joystick, event->button.x, event->button.y); + if (joystick_element) { + CommitBindingElement(joystick_element, true); + SDL_free(joystick_element); } } - UpdateButtonHighlights(event.button.x, event.button.y, event.button.down); - break; + } + UpdateButtonHighlights(event->button.x, event->button.y, event->button.down); + break; - case SDL_EVENT_MOUSE_MOTION: - if (virtual_joystick && controller && controller->joystick == virtual_joystick) { - VirtualGamepadMouseMotion(event.motion.x, event.motion.y); - } - UpdateButtonHighlights(event.motion.x, event.motion.y, event.motion.state ? true : false); - break; + case SDL_EVENT_MOUSE_MOTION: + if (virtual_joystick && controller && controller->joystick == virtual_joystick) { + VirtualGamepadMouseMotion(event->motion.x, event->motion.y); + } + UpdateButtonHighlights(event->motion.x, event->motion.y, event->motion.state ? true : false); + break; - case SDL_EVENT_KEY_DOWN: - if (display_mode == CONTROLLER_MODE_TESTING) { - if (event.key.key >= SDLK_0 && event.key.key <= SDLK_9) { - if (controller && controller->gamepad) { - int player_index = (event.key.key - SDLK_0); + case SDL_EVENT_KEY_DOWN: + if (display_mode == CONTROLLER_MODE_TESTING) { + if (event->key.key >= SDLK_0 && event->key.key <= SDLK_9) { + if (controller && controller->gamepad) { + int player_index = (event->key.key - SDLK_0); - SDL_SetGamepadPlayerIndex(controller->gamepad, player_index); - } - break; - } else if (event.key.key == SDLK_A) { - OpenVirtualGamepad(); - } else if (event.key.key == SDLK_D) { - CloseVirtualGamepad(); - } else if (event.key.key == SDLK_R && (event.key.mod & SDL_KMOD_CTRL)) { - SDL_ReloadGamepadMappings(); - } else if (event.key.key == SDLK_ESCAPE) { - done = true; - } - } else if (display_mode == CONTROLLER_MODE_BINDING) { - if (event.key.key == SDLK_C && (event.key.mod & SDL_KMOD_CTRL)) { - if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) { - CopyControllerName(); - } else { - CopyMapping(); - } - } else if (event.key.key == SDLK_V && (event.key.mod & SDL_KMOD_CTRL)) { - if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) { - ClearControllerName(); - PasteControllerName(); - } else { - PasteMapping(); - } - } else if (event.key.key == SDLK_X && (event.key.mod & SDL_KMOD_CTRL)) { - if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) { - CopyControllerName(); - ClearControllerName(); - } else { - CopyMapping(); - ClearMapping(); - } - } else if (event.key.key == SDLK_SPACE) { - if (binding_element != SDL_GAMEPAD_ELEMENT_NAME) { - ClearBinding(); - } - } else if (event.key.key == SDLK_BACKSPACE) { - if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) { - BackspaceControllerName(); - } - } else if (event.key.key == SDLK_RETURN) { - if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) { - StopBinding(); - } - } else if (event.key.key == SDLK_ESCAPE) { - if (binding_element != SDL_GAMEPAD_ELEMENT_INVALID) { - StopBinding(); - } else { - CancelMapping(); - } + SDL_SetGamepadPlayerIndex(controller->gamepad, player_index); } + break; + } else if (event->key.key == SDLK_A) { + OpenVirtualGamepad(); + } else if (event->key.key == SDLK_D) { + CloseVirtualGamepad(); + } else if (event->key.key == SDLK_R && (event->key.mod & SDL_KMOD_CTRL)) { + SDL_ReloadGamepadMappings(); + } else if (event->key.key == SDLK_ESCAPE) { + done = true; } - break; - case SDL_EVENT_TEXT_INPUT: - if (display_mode == CONTROLLER_MODE_BINDING) { + } else if (display_mode == CONTROLLER_MODE_BINDING) { + if (event->key.key == SDLK_C && (event->key.mod & SDL_KMOD_CTRL)) { + if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) { + CopyControllerName(); + } else { + CopyMapping(); + } + } else if (event->key.key == SDLK_V && (event->key.mod & SDL_KMOD_CTRL)) { + if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) { + ClearControllerName(); + PasteControllerName(); + } else { + PasteMapping(); + } + } else if (event->key.key == SDLK_X && (event->key.mod & SDL_KMOD_CTRL)) { + if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) { + CopyControllerName(); + ClearControllerName(); + } else { + CopyMapping(); + ClearMapping(); + } + } else if (event->key.key == SDLK_SPACE) { + if (binding_element != SDL_GAMEPAD_ELEMENT_NAME) { + ClearBinding(); + } + } else if (event->key.key == SDLK_BACKSPACE) { + if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) { + BackspaceControllerName(); + } + } else if (event->key.key == SDLK_RETURN) { if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) { - AddControllerNameText(event.text.text); + StopBinding(); + } + } else if (event->key.key == SDLK_ESCAPE) { + if (binding_element != SDL_GAMEPAD_ELEMENT_INVALID) { + StopBinding(); + } else { + CancelMapping(); } } - break; - case SDL_EVENT_QUIT: - done = true; - break; - default: - break; } + break; + case SDL_EVENT_TEXT_INPUT: + if (display_mode == CONTROLLER_MODE_BINDING) { + if (binding_element == SDL_GAMEPAD_ELEMENT_NAME) { + AddControllerNameText(event->text.text); + } + } + break; + case SDL_EVENT_QUIT: + done = true; + break; + default: + break; + } + + if (done) { + return SDL_APP_SUCCESS; + } else { + return SDL_APP_CONTINUE; + } +} + +SDL_AppResult SDLCALL SDL_AppIterate(void *appstate) +{ + /* If we have a virtual controller, send a virtual accelerometer sensor reading */ + if (virtual_joystick) { + float data[3] = { 0.0f, SDL_STANDARD_GRAVITY, 0.0f }; + SDL_SendJoystickVirtualSensorData(virtual_joystick, SDL_SENSOR_ACCEL, SDL_GetTicksNS(), data, SDL_arraysize(data)); } /* Wait 30 ms for joystick events to stop coming in, @@ -1982,14 +1985,10 @@ static void loop(void *arg) SDL_Delay(16); SDL_RenderPresent(screen); -#ifdef SDL_PLATFORM_EMSCRIPTEN - if (done) { - emscripten_cancel_main_loop(); - } -#endif + return SDL_APP_CONTINUE; } -int main(int argc, char *argv[]) +SDL_AppResult SDLCALL SDL_AppInit(void **appstate, int argc, char *argv[]) { bool show_mappings = false; int i; @@ -1997,12 +1996,11 @@ int main(int argc, char *argv[]) int screen_width, screen_height; SDL_FRect area; int gamepad_index = -1; - SDLTest_CommonState *state; /* Initialize test framework */ state = SDLTest_CommonCreateState(argv, 0); if (!state) { - return 1; + return SDL_APP_FAILURE; } SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI, "1"); @@ -2038,7 +2036,7 @@ int main(int argc, char *argv[]) if (consumed <= 0) { static const char *options[] = { "[--mappings]", "[--virtual]", "[index]", NULL }; SDLTest_CommonLogUsage(state, argv[0], options); - return 1; + return SDL_APP_FAILURE; } i += consumed; @@ -2050,7 +2048,7 @@ int main(int argc, char *argv[]) /* Initialize SDL (Note: video is required to start event loop) */ if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); - return 1; + return SDL_APP_FAILURE; } SDL_AddGamepadMappingsFromFile("gamecontrollerdb.txt"); @@ -2077,14 +2075,14 @@ int main(int argc, char *argv[]) window = SDL_CreateWindow("SDL Controller Test", screen_width, screen_height, 0); if (!window) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError()); - return 2; + return SDL_APP_FAILURE; } screen = SDL_CreateRenderer(window, NULL); if (!screen) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError()); SDL_DestroyWindow(window); - return 2; + return SDL_APP_FAILURE; } SDL_SetRenderDrawColor(screen, 0x00, 0x00, 0x00, SDL_ALPHA_OPAQUE); @@ -2110,7 +2108,7 @@ int main(int argc, char *argv[]) if (!image) { SDL_DestroyRenderer(screen); SDL_DestroyWindow(window); - return 2; + return SDL_APP_FAILURE; } SetGamepadImagePosition(image, PANEL_WIDTH + PANEL_SPACING, TITLE_HEIGHT); @@ -2178,7 +2176,7 @@ int main(int argc, char *argv[]) SetGamepadButtonArea(done_mapping_button, &area); /* Process the initial gamepad list */ - loop(NULL); + SDL_AppIterate(NULL); if (gamepad_index < num_controllers) { SetController(controllers[gamepad_index].id); @@ -2186,15 +2184,11 @@ int main(int argc, char *argv[]) SetController(controllers[0].id); } - /* Loop, getting gamepad events! */ -#ifdef SDL_PLATFORM_EMSCRIPTEN - emscripten_set_main_loop_arg(loop, NULL, 0, 1); -#else - while (!done) { - loop(NULL); - } -#endif + return SDL_APP_CONTINUE; +} +void SDLCALL SDL_AppQuit(void *appstate, SDL_AppResult result) +{ CloseVirtualGamepad(); while (num_controllers > 0) { HandleGamepadRemoved(controllers[0].id); @@ -2217,5 +2211,4 @@ int main(int argc, char *argv[]) SDL_DestroyWindow(window); SDL_Quit(); SDLTest_CommonDestroyState(state); - return 0; }