| #include "SDL.h" |
| |
| #include "Input.hpp" |
| #include "engine/input.hpp" |
| #include "System.hpp" |
| |
| std::map<int, int> Input::keys = { |
| // arrow keys |
| {SDLK_DOWN, blit::Button::DPAD_DOWN}, |
| {SDLK_UP, blit::Button::DPAD_UP}, |
| {SDLK_LEFT, blit::Button::DPAD_LEFT}, |
| {SDLK_RIGHT, blit::Button::DPAD_RIGHT}, |
| |
| // wasd |
| {SDLK_w, blit::Button::DPAD_UP}, |
| {SDLK_a, blit::Button::DPAD_LEFT}, |
| {SDLK_s, blit::Button::DPAD_DOWN}, |
| {SDLK_d, blit::Button::DPAD_RIGHT}, |
| |
| // action buttons |
| {SDLK_z, blit::Button::A}, |
| {SDLK_x, blit::Button::B}, |
| {SDLK_c, blit::Button::X}, |
| {SDLK_v, blit::Button::Y}, |
| |
| {SDLK_u, blit::Button::A}, |
| {SDLK_i, blit::Button::B}, |
| {SDLK_o, blit::Button::X}, |
| {SDLK_p, blit::Button::Y}, |
| |
| // system buttons |
| {SDLK_1, blit::Button::HOME}, |
| {SDLK_2, blit::Button::MENU}, |
| {SDLK_3, blit::Button::JOYSTICK}, |
| |
| {SDLK_ESCAPE, blit::Button::MENU}, |
| }; |
| |
| std::map<int, int> Input::buttons = { |
| // dpad |
| {SDL_CONTROLLER_BUTTON_DPAD_DOWN, blit::Button::DPAD_DOWN}, |
| {SDL_CONTROLLER_BUTTON_DPAD_UP, blit::Button::DPAD_UP}, |
| {SDL_CONTROLLER_BUTTON_DPAD_LEFT, blit::Button::DPAD_LEFT}, |
| {SDL_CONTROLLER_BUTTON_DPAD_RIGHT, blit::Button::DPAD_RIGHT}, |
| |
| // action buttons |
| {SDL_CONTROLLER_BUTTON_A, blit::Button::A}, |
| {SDL_CONTROLLER_BUTTON_B, blit::Button::B}, |
| {SDL_CONTROLLER_BUTTON_X, blit::Button::X}, |
| {SDL_CONTROLLER_BUTTON_Y, blit::Button::Y}, |
| |
| // system buttons |
| {SDL_CONTROLLER_BUTTON_BACK, blit::Button::HOME}, |
| {SDL_CONTROLLER_BUTTON_START, blit::Button::MENU}, |
| {SDL_CONTROLLER_BUTTON_LEFTSTICK, blit::Button::JOYSTICK}, |
| }; |
| |
| int Input::find_key(int key) { |
| auto iter = keys.find(key); |
| if (iter == keys.end()) return 0; |
| else return iter->second; |
| } |
| |
| int Input::find_button(int button) { |
| auto iter = buttons.find(button); |
| if (iter == buttons.end()) return 0; |
| else return iter->second; |
| } |
| |
| Input::Input(System *target) : target(target) { |
| // Open all joysticks as game controllers |
| for(int n = 0; n < SDL_NumJoysticks(); n++) { |
| |
| if(SDL_IsGameController(n)) { |
| |
| auto gc = SDL_GameControllerOpen(n); |
| if(gc != nullptr) { |
| _add_controller(gc); |
| } |
| } |
| } |
| } |
| |
| Input::~Input() { |
| for (auto gc : game_controllers) |
| { |
| _remove_controller(gc.gc_id); |
| } |
| game_controllers.clear(); |
| } |
| |
| bool Input::handle_mouse(int button, bool state, int x, int y) { |
| |
| int half_w = target->mode() ? target->width / 2 : target->width / 4; |
| int half_h = target->mode() ? target->height / 2 : target->height / 4; |
| |
| if (button == SDL_BUTTON_LEFT) { |
| if (state) { |
| if(left_ctrl){ |
| _virtual_tilt(x, y, half_w, half_h); |
| } else { |
| x = x - half_w; |
| y = y - half_h; |
| _virtual_analog(x, y, half_w, half_h); |
| } |
| } else { |
| _virtual_analog(0, 0, half_w, half_h); |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| bool Input::handle_keyboard(int key, bool state) { |
| if (int blit_button = find_key(key)) { |
| target->set_button(blit_button, state); |
| return true; |
| } else if (key == SDLK_LCTRL) { |
| left_ctrl = state; |
| return true; |
| } |
| return false; |
| } |
| |
| bool Input::handle_controller_button(int button, bool state) { |
| if (int blit_button = find_button(button)) { |
| target->set_button(blit_button, state); |
| return true; |
| } |
| return false; |
| } |
| |
| bool Input::handle_controller_motion(int axis, int value) { |
| float fvalue = value / 32768.0f; |
| switch(axis) { |
| case SDL_CONTROLLER_AXIS_LEFTX: |
| target->set_joystick(0, fvalue); |
| return true; |
| case SDL_CONTROLLER_AXIS_LEFTY: |
| target->set_joystick(1, fvalue); |
| return true; |
| case SDL_CONTROLLER_AXIS_RIGHTX: |
| target->set_tilt(0, fvalue); |
| return true; |
| case SDL_CONTROLLER_AXIS_RIGHTY: |
| target->set_tilt(1, fvalue); |
| return true; |
| default: |
| break; |
| } |
| return false; |
| } |
| |
| bool Input::handle_controller_accel(float data[3]) { |
| target->set_tilt(0, -data[0]); |
| target->set_tilt(1, -data[2]); |
| target->set_tilt(2, data[1]); |
| return true; |
| } |
| |
| void Input::handle_controller_added(Sint32 joystick_index) { |
| |
| SDL_GameController* gc = SDL_GameControllerOpen(joystick_index); |
| if (gc != nullptr) { |
| _add_controller(gc); |
| } |
| } |
| |
| void Input::handle_controller_removed(Sint32 joystick_index) { |
| |
| auto gc_removed = SDL_GameControllerFromInstanceID(joystick_index); |
| if(gc_removed != nullptr) { |
| _remove_controller(gc_removed); |
| } |
| } |
| |
| void Input::rumble_controllers(const float& volume) { |
| |
| if(volume > 0) { |
| for (auto gc : game_controllers) { |
| if(gc.can_rumble) { |
| auto frequency = volume * 0xFFFF; |
| SDL_GameControllerRumble(gc.gc_id, frequency, frequency, 50); |
| } |
| } |
| } |
| } |
| |
| void Input::_virtual_tilt(int x, int y, int half_w, int half_h) { |
| float z = 80.0f; |
| x = x - half_w; |
| y = y - half_h; |
| blit::Vec3 shadow_tilt(x, y, z); |
| shadow_tilt.normalize(); |
| target->set_tilt(0, shadow_tilt.x); |
| target->set_tilt(1, shadow_tilt.y); |
| target->set_tilt(2, shadow_tilt.z); |
| } |
| |
| void Input::_virtual_analog(int x, int y, int half_w, int half_h) { |
| float jx = (float)x / half_w; |
| float jy = (float)y / half_h; |
| target->set_joystick(0, jx); |
| target->set_joystick(1, jy); |
| } |
| |
| void Input::_add_controller(SDL_GameController* gc) { |
| // welcome rumble to test if it can rumble |
| auto can_rumble = SDL_GameControllerRumble(gc, 0xFFFF, 0xFFFF, 200); |
| |
| #if SDL_VERSION_ATLEAST(2, 0, 14) |
| // enable accelerometer if present |
| SDL_GameControllerSetSensorEnabled(gc, SDL_SENSOR_ACCEL, SDL_TRUE); |
| #endif |
| |
| GameController gcs = {gc, can_rumble == 0}; |
| game_controllers.push_back(gcs); |
| } |
| |
| void Input::_remove_controller(SDL_GameController* gc) { |
| game_controllers.erase( |
| std::remove_if(game_controllers.begin(), game_controllers.end(), [&](GameController const & controller) { |
| return controller.gc_id == gc; |
| }), |
| game_controllers.end()); |
| |
| SDL_GameControllerClose(gc); |
| } |