|
- #include <SDL.h>
-
- #include "input.h"
- #include "state.h"
-
-
- #define DBG_LOG(...) printf(__VA_ARGS__)
- #define ERR_LOG(...) DBG_LOG(__VA_ARGS__)
-
- #ifdef DEBUG_INPUT
- #define INPUT_DBG DBG_LOG
- #define INPUT_INFO DBG_LOG
- #else
- #define INPUT_DBG(...)
- #define INPUT_INFO(...)
- #endif
- #define INPUT_ERR ERR_LOG
-
-
- #define axis_threshold (8192L)
-
- typedef struct {
- int16_t last_x_axis;
- int16_t last_y_axis;
- SDL_GameController* gamepad;
- } sdl_input_data;
-
- static sdl_input_data the_input_data = {0};
-
-
- static SDL_GameController* sdl_find_gamepad() {
- int i = SDL_NumJoysticks() - 1;
- INPUT_INFO("Found %d joysticks\n", i + 1);
- for ( ; i >= 0 && !SDL_IsGameController(i); --i);
- if (i >= 0) INPUT_INFO("Joystick %d is a gamepad\n", i);
- return (i < 0 ? NULL : SDL_GameControllerOpen(i));
- }
-
- static void sdl_lose_gamepad(SDL_GameController* gamepad) {
- if (NULL != gamepad) {
- SDL_GameControllerClose(gamepad);
- }
- }
-
- static int sdl_match_gamepad(SDL_JoystickID id,
- SDL_GameController* gamepad) {
- return ( id == SDL_JoystickInstanceID(
- SDL_GameControllerGetJoystick(gamepad)));
- }
- /*
- static int sdl_event_filter(void*, SDL_Event* event) {
- return ( SDL_QUIT == event->type ||
- SDL_KEYDOWN == event->type ||
- SDL_KEYUP == event->type ||
- SDL_CONTROLLERBUTTONDOWN == event->type ||
- SDL_CONTROLLERBUTTONUP == event->type ||
- SDL_CONTROLLERDEVICEADDED == event->type ||
- SDL_CONTROLLERDEVICEREMOVED == event->type
- );
- }
- */
- static int sdl_input_init(nes_Input_Reader* reader) {
- reader->data = &the_input_data;
- sdl_input_data* data = (sdl_input_data*)reader->data;
-
- int status = SDL_Init(SDL_INIT_EVENTS |
- SDL_INIT_GAMECONTROLLER);
-
- if (status == 0) {
- data->gamepad = sdl_find_gamepad();
- // SDL_SetEventFilter(sdl_event_filter, NULL);
- if (NULL != data->gamepad) {
- INPUT_INFO("Gamepad found\n");
- }
- }
-
- return status;
- }
-
- static void sdl_input_done(nes_Input_Reader* reader) {
- sdl_input_data* data = (sdl_input_data*)reader->data;
- sdl_lose_gamepad(data->gamepad);
- }
-
- static const int sdl_menu_key = SDLK_ESCAPE;
- static const int sdl_save_key = SDLK_F1;
- static const int sdl_load_key = SDLK_F2;
- static const int sdl_alt_start_key = SDLK_RETURN;
-
- static const int sdl_keycodes[nes_controller_num_buttons] = {
- SDLK_a,
- SDLK_s,
- SDLK_q,
- SDLK_w,
- SDLK_UP,
- SDLK_DOWN,
- SDLK_LEFT,
- SDLK_RIGHT,
- };
-
- static const int sdl_menu_button = SDL_CONTROLLER_BUTTON_X;
- static const int sdl_save_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
- static const int sdl_load_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
-
- static const int sdl_buttons[nes_controller_num_buttons] = {
- SDL_CONTROLLER_BUTTON_A,
- SDL_CONTROLLER_BUTTON_B,
- SDL_CONTROLLER_BUTTON_BACK,
- SDL_CONTROLLER_BUTTON_START,
- SDL_CONTROLLER_BUTTON_DPAD_UP,
- SDL_CONTROLLER_BUTTON_DPAD_DOWN,
- SDL_CONTROLLER_BUTTON_DPAD_LEFT,
- SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
- };
-
- static int button_index(int keycode, const int* codes) {
- int index = nes_controller_num_buttons - 1;
- for ( ; index >= 0 && keycode != codes[index]; --index);
- return index;
- }
-
-
- #define input_debug(o, ...) INPUT_DBG(__VA_ARGS__)
- /*
- static void input_debug(Overlay* overlay,
- const char* fmt, ...) {
- char msg[100] = {0};
- va_list args;
- va_start(args, fmt);
- vsnprintf(msg, sizeof(msg) - 1, fmt, args);
- va_end(args);
-
- overlay_add_message(overlay, msg, 60);
- }
- */
-
- static int sdl_input_update(nes_Input_Reader* reader,
- nese_Components* comp) {
- int status = input_Result_OK;
-
- sdl_input_data* data = (sdl_input_data*)reader->data;
-
- if (reader->menu_timer > 0 && --reader->menu_timer == 0) {
- status = input_Result_Menu;
- }
-
- SDL_Event event = {0};
- while (0 == status && 0 != SDL_PollEvent(&event)) {
- if (SDL_QUIT == event.type) {
- status = input_Result_Quit;
-
- } else if (SDL_WINDOWEVENT == event.type) {
- if ( SDL_WINDOWEVENT_EXPOSED ==
- event.window.event) {
- nes_render_refresh(comp->rend);
- status = input_Result_Refresh;
- }
-
- } else if ( ( SDL_KEYDOWN == event.type ||
- SDL_KEYUP == event.type) &&
- 0 == event.key.repeat
- ) {
- input_debug(&comp->rend->overlay,
- "Input: K %d S %d\n",
- SDL_KEYDOWN == event.type ? 1 : 0,
- event.key.keysym.sym);
-
- int index = ( sdl_alt_start_key ==
- event.key.keysym.sym) ?
- Button_Start : button_index(
- event.key.keysym.sym,
- sdl_keycodes);
- if (index >= 0) {
- uint8_t mask = (1 << index);
- if (SDL_KEYDOWN == event.type) {
- comp->sys->input.controllers[0].buttons |= mask;
- } else {
- comp->sys->input.controllers[0].buttons &= ~mask;
- }
- /*
- input_debug(
- &comp->rend->overlay,
- "Input: Key: %s %02x\n",
- (SDL_KEYDOWN == event.type) ?
- "Set" : "Clear",
- mask
- );
- */
-
- } else if ( sdl_menu_key == event.key.keysym.sym &&
- SDL_KEYDOWN == event.type) {
- status = input_Result_Menu;
-
- } else if (sdl_save_key == event.key.keysym.sym) {
- if (SDL_KEYDOWN == event.type) {
- status = input_Result_Save;
- } else {
- status = input_Result_Cancel;
- }
-
- } else if (sdl_load_key == event.key.keysym.sym) {
- if (SDL_KEYDOWN == event.type) {
- status = input_Result_Load;
- } else {
- status = input_Result_Cancel;
- }
- }
-
- } else if ( SDL_CONTROLLERBUTTONDOWN == event.type ||
- SDL_CONTROLLERBUTTONUP == event.type) {
- input_debug(&comp->rend->overlay,
- "Input: B %d B %d\n",
- SDL_CONTROLLERBUTTONDOWN == event.type ?
- 1 : 0,
- event.cbutton.button);
-
- int index = button_index(event.cbutton.button,
- sdl_buttons);
- if (index >= 0) {
- uint8_t mask = (1 << index);
- if (SDL_CONTROLLERBUTTONDOWN == event.type) {
- comp->sys->input.controllers[0].buttons |= mask;
- } else {
- comp->sys->input.controllers[0].buttons &= ~mask;
- }
- /*
- input_debug(
- &comp->rend->overlay,
- "Input: Button: %s %02x\n",
- (SDL_CONTROLLERBUTTONDOWN == event.type) ?
- "Set" : "Clear",
- mask
- );
- */
-
- if (Button_Start == index) {
- if (SDL_CONTROLLERBUTTONDOWN == event.type) {
- reader->menu_timer = 60;
- } else {
- reader->menu_timer = 0;
- }
- }
-
- } else if (sdl_menu_button == event.cbutton.button) {
- if (SDL_CONTROLLERBUTTONDOWN == event.type) {
- status = input_Result_Menu;
- }
-
- } else if (sdl_save_button == event.cbutton.button) {
- if (SDL_CONTROLLERBUTTONDOWN == event.type) {
- status = input_Result_Save;
- } else {
- status = input_Result_Cancel;
- }
-
- } else if (sdl_load_button == event.cbutton.button) {
- if (SDL_CONTROLLERBUTTONDOWN == event.type) {
- status = input_Result_Load;
- } else {
- status = input_Result_Cancel;
- }
- }
-
- } else if (SDL_CONTROLLERAXISMOTION == event.type) {
- const uint8_t axis = event.caxis.axis;
- const int16_t value = event.caxis.value;
- uint8_t mask_set = 0;
- uint8_t mask_clear = 0;
-
- int dir = 0;
- if (value <= -axis_threshold) dir = -1;
- else if (value >= axis_threshold) dir = 1;
-
- if (SDL_CONTROLLER_AXIS_LEFTX == axis) {
- if (dir != data->last_x_axis) {
- mask_clear = (1 << Button_Left) |
- (1 << Button_Right);
- if (dir < 0) {
- mask_set = (1 << Button_Left);
- } else if (dir > 0) {
- mask_set = (1 << Button_Right);
- }
- }
- data->last_x_axis = dir;
-
- } else if (SDL_CONTROLLER_AXIS_LEFTY == axis) {
- if (dir != data->last_y_axis) {
- mask_clear = (1 << Button_Down) |
- (1 << Button_Up);
- if (dir < 0) {
- mask_set = (1 << Button_Up);
- } else if (dir > 0) {
- mask_set = (1 << Button_Down);
- }
- }
- data->last_y_axis = dir;
- }
-
- uint32_t old_buttons = comp->sys->input.controllers[0].buttons;
- uint32_t new_buttons = ((old_buttons & ~mask_clear) | mask_set);
- comp->sys->input.controllers[0].buttons = new_buttons;
- /*
- if (old_buttons != new_buttons) {
- input_debug(&comp->rend->overlay,
- "Input: Axis: S %02x C %02x V %d\n",
- mask_set, mask_clear, value);
- }
- */
-
- } else if (SDL_CONTROLLERDEVICEADDED == event.type) {
- if (NULL == data->gamepad) {
- INPUT_INFO("New gamepad connected\n");
- data->gamepad = sdl_find_gamepad();
- if (data->gamepad) INPUT_INFO("Using new gamepad\n");
- } else {
- INPUT_INFO("Redundant gamepad connected\n");
- }
-
- } else if (SDL_CONTROLLERDEVICEREMOVED == event.type) {
- if (sdl_match_gamepad(event.cdevice.which,
- data->gamepad)) {
- INPUT_INFO("Gamepad disconnected\n");
- sdl_lose_gamepad(reader->data);
- data->gamepad = sdl_find_gamepad();
- if (data->gamepad) INPUT_INFO("Using another gamepad\n");
- } else {
- INPUT_INFO("Redundant gamepad disconnected\n");
- }
- }
- }
-
- if (0 != status) {
- input_debug(&comp->rend->overlay,
- "Input: Returning %d\n", status);
- }
-
- return status;
- }
-
-
- nes_Input_Reader sdl_input = {
- .init = sdl_input_init,
- .done = sdl_input_done,
- .update = sdl_input_update,
- };
|