blob: 179391feffd1a76322d4f506b2095fe09439c1bd [file] [log] [blame]
#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);
}