433 lines
12 KiB
C++
433 lines
12 KiB
C++
#include "sdl2_input.h"
|
|
#include <extra2d/utils/logger.h>
|
|
#include <cmath>
|
|
|
|
namespace extra2d {
|
|
|
|
SDL2Input::SDL2Input()
|
|
: initialized_(false) {
|
|
keyCurrent_.fill(false);
|
|
keyPrevious_.fill(false);
|
|
mouseCurrent_.fill(false);
|
|
mousePrevious_.fill(false);
|
|
gamepadCurrent_.fill(false);
|
|
gamepadPrevious_.fill(false);
|
|
}
|
|
|
|
SDL2Input::~SDL2Input() {
|
|
shutdown();
|
|
}
|
|
|
|
void SDL2Input::init() {
|
|
if (initialized_) return;
|
|
|
|
E2D_LOG_INFO("SDL2Input initialized");
|
|
|
|
if (SDL_Init(SDL_INIT_GAMECONTROLLER) != 0) {
|
|
E2D_LOG_WARN("Failed to init gamecontroller subsystem: {}", SDL_GetError());
|
|
}
|
|
|
|
openGamepad();
|
|
initialized_ = true;
|
|
}
|
|
|
|
void SDL2Input::shutdown() {
|
|
if (!initialized_) return;
|
|
|
|
closeGamepad();
|
|
initialized_ = false;
|
|
E2D_LOG_INFO("SDL2Input shutdown");
|
|
}
|
|
|
|
void SDL2Input::update() {
|
|
keyPrevious_ = keyCurrent_;
|
|
mousePrevious_ = mouseCurrent_;
|
|
gamepadPrevious_ = gamepadCurrent_;
|
|
|
|
scrollDelta_ = 0.0f;
|
|
mouseDelta_ = Vec2{0.0f, 0.0f};
|
|
|
|
updateGamepad();
|
|
}
|
|
|
|
void SDL2Input::setEventCallback(EventCallback callback) {
|
|
eventCallback_ = std::move(callback);
|
|
}
|
|
|
|
void SDL2Input::handleSDLEvent(const SDL_Event& event) {
|
|
switch (event.type) {
|
|
case SDL_KEYDOWN: {
|
|
int key = event.key.keysym.scancode;
|
|
if (key >= 0 && key < static_cast<int>(Key::Count)) {
|
|
if (!keyCurrent_[key]) {
|
|
keyCurrent_[key] = true;
|
|
|
|
Event e = Event::createKeyPress(
|
|
event.key.keysym.sym,
|
|
event.key.keysym.scancode,
|
|
event.key.keysym.mod
|
|
);
|
|
dispatchEvent(e);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SDL_KEYUP: {
|
|
int key = event.key.keysym.scancode;
|
|
if (key >= 0 && key < static_cast<int>(Key::Count)) {
|
|
keyCurrent_[key] = false;
|
|
|
|
Event e = Event::createKeyRelease(
|
|
event.key.keysym.sym,
|
|
event.key.keysym.scancode,
|
|
event.key.keysym.mod
|
|
);
|
|
dispatchEvent(e);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SDL_MOUSEBUTTONDOWN: {
|
|
int btn = event.button.button;
|
|
int idx = btn - 1;
|
|
if (idx >= 0 && idx < static_cast<int>(Mouse::Count)) {
|
|
mouseCurrent_[idx] = true;
|
|
|
|
Vec2 pos{static_cast<float>(event.button.x),
|
|
static_cast<float>(event.button.y)};
|
|
Event e = Event::createMousePress(btn, 0, pos);
|
|
dispatchEvent(e);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SDL_MOUSEBUTTONUP: {
|
|
int btn = event.button.button;
|
|
int idx = btn - 1;
|
|
if (idx >= 0 && idx < static_cast<int>(Mouse::Count)) {
|
|
mouseCurrent_[idx] = false;
|
|
|
|
Vec2 pos{static_cast<float>(event.button.x),
|
|
static_cast<float>(event.button.y)};
|
|
Event e = Event::createMouseRelease(btn, 0, pos);
|
|
dispatchEvent(e);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SDL_MOUSEMOTION: {
|
|
Vec2 newPos{static_cast<float>(event.motion.x),
|
|
static_cast<float>(event.motion.y)};
|
|
Vec2 delta{static_cast<float>(event.motion.xrel),
|
|
static_cast<float>(event.motion.yrel)};
|
|
|
|
mouseDelta_ = mouseDelta_ + delta;
|
|
mousePos_ = newPos;
|
|
|
|
Event e = Event::createMouseMove(newPos, delta);
|
|
dispatchEvent(e);
|
|
break;
|
|
}
|
|
|
|
case SDL_MOUSEWHEEL: {
|
|
Vec2 offset{static_cast<float>(event.wheel.x),
|
|
static_cast<float>(event.wheel.y)};
|
|
Vec2 pos = mousePos_;
|
|
|
|
scroll_ += event.wheel.y;
|
|
scrollDelta_ += event.wheel.y;
|
|
|
|
Event e = Event::createMouseScroll(offset, pos);
|
|
dispatchEvent(e);
|
|
break;
|
|
}
|
|
|
|
case SDL_CONTROLLERDEVICEADDED:
|
|
E2D_LOG_INFO("Gamepad connected: index {}", event.cdevice.which);
|
|
openGamepad();
|
|
break;
|
|
|
|
case SDL_CONTROLLERDEVICEREMOVED:
|
|
if (gamepad_ && event.cdevice.which == SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(gamepad_))) {
|
|
E2D_LOG_INFO("Gamepad disconnected");
|
|
closeGamepad();
|
|
}
|
|
break;
|
|
|
|
case SDL_CONTROLLERBUTTONDOWN:
|
|
if (gamepad_) {
|
|
int btn = event.cbutton.button;
|
|
if (btn >= 0 && btn < static_cast<int>(Gamepad::Count)) {
|
|
gamepadCurrent_[btn] = true;
|
|
|
|
GamepadEvent btnEvent;
|
|
btnEvent.gamepadId = gamepadIndex_;
|
|
btnEvent.button = btn;
|
|
|
|
Event e;
|
|
e.type = EventType::GamepadPress;
|
|
e.data = btnEvent;
|
|
dispatchEvent(e);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SDL_CONTROLLERBUTTONUP:
|
|
if (gamepad_) {
|
|
int btn = event.cbutton.button;
|
|
if (btn >= 0 && btn < static_cast<int>(Gamepad::Count)) {
|
|
gamepadCurrent_[btn] = false;
|
|
|
|
GamepadEvent btnEvent;
|
|
btnEvent.gamepadId = gamepadIndex_;
|
|
btnEvent.button = btn;
|
|
|
|
Event e;
|
|
e.type = EventType::GamepadRelease;
|
|
e.data = btnEvent;
|
|
dispatchEvent(e);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void SDL2Input::dispatchEvent(const Event& event) {
|
|
if (eventCallback_) {
|
|
eventCallback_(event);
|
|
}
|
|
}
|
|
|
|
bool SDL2Input::down(Key key) const {
|
|
int idx = static_cast<int>(key);
|
|
if (idx >= 0 && idx < static_cast<int>(Key::Count)) {
|
|
return keyCurrent_[idx];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SDL2Input::pressed(Key key) const {
|
|
int idx = static_cast<int>(key);
|
|
if (idx >= 0 && idx < static_cast<int>(Key::Count)) {
|
|
return keyCurrent_[idx] && !keyPrevious_[idx];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SDL2Input::released(Key key) const {
|
|
int idx = static_cast<int>(key);
|
|
if (idx >= 0 && idx < static_cast<int>(Key::Count)) {
|
|
return !keyCurrent_[idx] && keyPrevious_[idx];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SDL2Input::down(Mouse btn) const {
|
|
int sdlBtn = static_cast<int>(btn);
|
|
int idx = sdlBtn - 1;
|
|
if (idx >= 0 && idx < static_cast<int>(Mouse::Count)) {
|
|
return mouseCurrent_[idx];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SDL2Input::pressed(Mouse btn) const {
|
|
int sdlBtn = static_cast<int>(btn);
|
|
int idx = sdlBtn - 1;
|
|
if (idx >= 0 && idx < static_cast<int>(Mouse::Count)) {
|
|
return mouseCurrent_[idx] && !mousePrevious_[idx];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SDL2Input::released(Mouse btn) const {
|
|
int sdlBtn = static_cast<int>(btn);
|
|
int idx = sdlBtn - 1;
|
|
if (idx >= 0 && idx < static_cast<int>(Mouse::Count)) {
|
|
return !mouseCurrent_[idx] && mousePrevious_[idx];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Vec2 SDL2Input::mouse() const {
|
|
return mousePos_;
|
|
}
|
|
|
|
Vec2 SDL2Input::mouseDelta() const {
|
|
return mouseDelta_;
|
|
}
|
|
|
|
float SDL2Input::scroll() const {
|
|
return scroll_;
|
|
}
|
|
|
|
float SDL2Input::scrollDelta() const {
|
|
return scrollDelta_;
|
|
}
|
|
|
|
void SDL2Input::setMouse(const Vec2& pos) {
|
|
SDL_WarpMouseInWindow(nullptr, static_cast<int>(pos.x), static_cast<int>(pos.y));
|
|
}
|
|
|
|
bool SDL2Input::gamepad() const {
|
|
return gamepad_ != nullptr;
|
|
}
|
|
|
|
bool SDL2Input::down(Gamepad btn) const {
|
|
int idx = static_cast<int>(btn);
|
|
if (idx >= 0 && idx < static_cast<int>(Gamepad::Count)) {
|
|
return gamepadCurrent_[idx];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SDL2Input::pressed(Gamepad btn) const {
|
|
int idx = static_cast<int>(btn);
|
|
if (idx >= 0 && idx < static_cast<int>(Gamepad::Count)) {
|
|
return gamepadCurrent_[idx] && !gamepadPrevious_[idx];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SDL2Input::released(Gamepad btn) const {
|
|
int idx = static_cast<int>(btn);
|
|
if (idx >= 0 && idx < static_cast<int>(Gamepad::Count)) {
|
|
return !gamepadCurrent_[idx] && gamepadPrevious_[idx];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Vec2 SDL2Input::leftStick() const {
|
|
return leftStick_;
|
|
}
|
|
|
|
Vec2 SDL2Input::rightStick() const {
|
|
return rightStick_;
|
|
}
|
|
|
|
float SDL2Input::leftTrigger() const {
|
|
return leftTrigger_;
|
|
}
|
|
|
|
float SDL2Input::rightTrigger() const {
|
|
return rightTrigger_;
|
|
}
|
|
|
|
void SDL2Input::vibrate(float left, float right) {
|
|
if (gamepad_) {
|
|
Uint16 lowFreq = static_cast<Uint16>(left * 65535.0f);
|
|
Uint16 highFreq = static_cast<Uint16>(right * 65535.0f);
|
|
SDL_GameControllerRumble(gamepad_, lowFreq, highFreq, 500);
|
|
}
|
|
}
|
|
|
|
bool SDL2Input::touching() const {
|
|
return false;
|
|
}
|
|
|
|
int SDL2Input::touchCount() const {
|
|
return 0;
|
|
}
|
|
|
|
Vec2 SDL2Input::touch(int index) const {
|
|
(void)index;
|
|
return Vec2{0.0f, 0.0f};
|
|
}
|
|
|
|
TouchPoint SDL2Input::touchPoint(int index) const {
|
|
(void)index;
|
|
return TouchPoint{};
|
|
}
|
|
|
|
void SDL2Input::updateKeyboard() {
|
|
}
|
|
|
|
void SDL2Input::updateMouse() {
|
|
int x = 0, y = 0;
|
|
SDL_GetMouseState(&x, &y);
|
|
mousePos_ = Vec2{static_cast<float>(x), static_cast<float>(y)};
|
|
}
|
|
|
|
void SDL2Input::updateGamepad() {
|
|
if (!gamepad_) {
|
|
return;
|
|
}
|
|
|
|
auto applyDeadzone = [this](float value) -> float {
|
|
if (std::abs(value) < deadzone_) {
|
|
return 0.0f;
|
|
}
|
|
float sign = value >= 0.0f ? 1.0f : -1.0f;
|
|
return sign * (std::abs(value) - deadzone_) / (1.0f - deadzone_);
|
|
};
|
|
|
|
int lx = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_LEFTX);
|
|
int ly = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_LEFTY);
|
|
int rx = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_RIGHTX);
|
|
int ry = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_RIGHTY);
|
|
|
|
leftStick_.x = applyDeadzone(lx / 32767.0f);
|
|
leftStick_.y = applyDeadzone(ly / 32767.0f);
|
|
rightStick_.x = applyDeadzone(rx / 32767.0f);
|
|
rightStick_.y = applyDeadzone(ry / 32767.0f);
|
|
|
|
int lt = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_TRIGGERLEFT);
|
|
int rt = SDL_GameControllerGetAxis(gamepad_, SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
|
|
|
|
leftTrigger_ = lt / 32767.0f;
|
|
rightTrigger_ = rt / 32767.0f;
|
|
}
|
|
|
|
void SDL2Input::openGamepad() {
|
|
int numJoysticks = SDL_NumJoysticks();
|
|
for (int i = 0; i < numJoysticks; ++i) {
|
|
if (SDL_IsGameController(i)) {
|
|
gamepad_ = SDL_GameControllerOpen(i);
|
|
if (gamepad_) {
|
|
gamepadIndex_ = i;
|
|
E2D_LOG_INFO("Gamepad opened: {}", SDL_GameControllerName(gamepad_));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SDL2Input::closeGamepad() {
|
|
if (gamepad_) {
|
|
SDL_GameControllerClose(gamepad_);
|
|
gamepad_ = nullptr;
|
|
gamepadIndex_ = -1;
|
|
gamepadCurrent_.fill(false);
|
|
gamepadPrevious_.fill(false);
|
|
}
|
|
}
|
|
|
|
int SDL2Input::keyToSDL(Key key) {
|
|
return static_cast<int>(key);
|
|
}
|
|
|
|
int SDL2Input::mouseToSDL(Mouse btn) {
|
|
return static_cast<int>(btn);
|
|
}
|
|
|
|
int SDL2Input::gamepadToSDL(Gamepad btn) {
|
|
return static_cast<int>(btn);
|
|
}
|
|
|
|
Key SDL2Input::sdlToKey(int sdlKey) {
|
|
if (sdlKey >= 0 && sdlKey < static_cast<int>(Key::Count)) {
|
|
return static_cast<Key>(sdlKey);
|
|
}
|
|
return Key::None;
|
|
}
|
|
|
|
Mouse SDL2Input::sdlToMouse(int sdlButton) {
|
|
return static_cast<Mouse>(sdlButton);
|
|
}
|
|
|
|
}
|