#include #include "input.h" static SDL_GameController* sdl_find_gamepad() { int i = SDL_NumJoysticks() - 1; printf("Found %d joysticks\n", i + 1); for ( ; i >= 0 && !SDL_IsGameController(i); --i); if (i >= 0) printf("Joystick %d is a gamepad\n", i); return (i < 0 ? NULL : SDL_GameControllerOpen(i)); } static void sdl_lose_gamepad(void* data) { SDL_GameController* gamepad = (SDL_GameController*)data; if (NULL != gamepad) SDL_GameControllerClose(gamepad); } static int sdl_match_gamepad(SDL_JoystickID id, void* data) { SDL_GameController* gamepad = (SDL_GameController*)data; return ( SDL_JoystickInstanceID( SDL_GameControllerGetJoystick(gamepad)) == id); } /* 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) { int status = SDL_Init(SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER); if (status == 0) { reader->data = sdl_find_gamepad(); // SDL_SetEventFilter(sdl_event_filter, NULL); if (NULL != reader->data) { printf("Gamepad found\n"); } } return status; } static void sdl_input_done(nes_Input_Reader* input) { sdl_lose_gamepad(input->data); } static const int sdl_reset_key = SDLK_ESCAPE; static const int sdl_save_key = SDLK_F1; static const int sdl_load_key = SDLK_F2; 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_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; } static int sdl_input_update(nes_Input_Reader* reader, nes_input* input) { int status = input_Result_OK; SDL_Event event = {0}; while (0 == status && 0 != SDL_PollEvent(&event)) { if (SDL_QUIT == event.type) { status = input_Result_Quit; } else if ( ( SDL_KEYDOWN == event.type || SDL_KEYUP == event.type) && 0 == event.key.repeat ) { int index = button_index(event.key.keysym.sym, sdl_keycodes); if (index >= 0) { uint8_t mask = (1 << index); if (SDL_KEYDOWN == event.type) { input->controllers[0].buttons |= mask; } else { input->controllers[0].buttons &= ~mask; } } else if ( sdl_reset_key == event.key.keysym.sym && SDL_KEYDOWN == event.type) { status = input_Result_Reset; } 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) { int index = button_index(event.cbutton.button, sdl_buttons); if (index >= 0) { uint8_t mask = (1 << index); if (SDL_CONTROLLERBUTTONDOWN == event.type) { input->controllers[0].buttons |= mask; } else { input->controllers[0].buttons &= ~mask; } } 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; if (SDL_CONTROLLER_AXIS_LEFTX == axis) { mask_clear = (1 << Button_Left) | (1 << Button_Right); if (value <= -8192) { mask_set = (1 << Button_Left); } else if (value >= 8192) { mask_set = (1 << Button_Right); } } else if (SDL_CONTROLLER_AXIS_LEFTY == axis) { mask_clear = (1 << Button_Down) | (1 << Button_Up); if (value <= -8192) { mask_set = (1 << Button_Up); } else if (value >= 8192) { mask_set = (1 << Button_Down); } } input->controllers[0].buttons &= ~mask_clear; input->controllers[0].buttons |= mask_set; } else if (SDL_CONTROLLERDEVICEADDED == event.type) { if (NULL == reader->data) { printf("New gamepad connected\n"); reader->data = sdl_find_gamepad(); if (reader->data) printf("Using new gamepad\n"); } else { printf("Redundant gamepad connected\n"); } } else if (SDL_CONTROLLERDEVICEREMOVED == event.type) { if (sdl_match_gamepad(event.cdevice.which, reader->data)) { printf("Gamepad disconnected\n"); sdl_lose_gamepad(reader->data); reader->data = sdl_find_gamepad(); if (reader->data) printf("Using another gamepad\n"); } else { printf("Redundant gamepad disconnected\n"); } } } return status; } nes_Input_Reader sdl_input = { .init = sdl_input_init, .done = sdl_input_done, .update = sdl_input_update, };