// Copyright (c) 2025 Dominic Masters // // This software is released under the MIT License. // https://opensource.org/licenses/MIT #include "Input.hpp" #include "assert/Assert.hpp" #include "engine/Engine.hpp" using namespace Dawn; Input::Input(Engine &engine) : engine(engine), states({}), buttons({}) { engine.console.registerCommand("bind", [this](auto console, auto args) { if(args.size() == 0) { this->engine.console.print("Usage: bind [command]"); return; } // Find input by name. auto itButton = this->buttons.begin(); while(itButton != this->buttons.end()) { if(itButton->getName() == args[0]) break; ++itButton; } if(itButton == this->buttons.end()) { this->engine.console.print("No such input: %s", args[0].c_str()); return; } // Is there a second arg? if(args.size() == 1) { auto bind = itButton->getBind(); if(bind) { console.print(bind->getName()); } else { console.print(itButton->getCommand()); } return; } // Is there a bind for the arg? auto itBind = InputBind::ALL_BINDS.begin(); while(itBind != InputBind::ALL_BINDS.end()) { if(strcasecmp((*itBind)->getName().c_str(),args[1].c_str()) == 0) break; ++itBind; } // This is a bind? if(itBind != InputBind::ALL_BINDS.end()) { itButton->setBind(const_cast(*itBind)); return; } // This is a command then. itButton->setCommand(args[1]); }); #if DAWN_SDL2 buttons.push_back(InputButton("esc", InputButtonType::KEY, { .scancode = SDL_SCANCODE_ESCAPE })); buttons.push_back(InputButton("1", InputButtonType::KEY, { .scancode = SDL_SCANCODE_1 })); buttons.push_back(InputButton("2", InputButtonType::KEY, { .scancode = SDL_SCANCODE_2 })); buttons.push_back(InputButton("3", InputButtonType::KEY, { .scancode = SDL_SCANCODE_3 })); buttons.push_back(InputButton("4", InputButtonType::KEY, { .scancode = SDL_SCANCODE_4 })); buttons.push_back(InputButton("5", InputButtonType::KEY, { .scancode = SDL_SCANCODE_5 })); buttons.push_back(InputButton("6", InputButtonType::KEY, { .scancode = SDL_SCANCODE_6 })); buttons.push_back(InputButton("7", InputButtonType::KEY, { .scancode = SDL_SCANCODE_7 })); buttons.push_back(InputButton("8", InputButtonType::KEY, { .scancode = SDL_SCANCODE_8 })); buttons.push_back(InputButton("9", InputButtonType::KEY, { .scancode = SDL_SCANCODE_9 })); buttons.push_back(InputButton("0", InputButtonType::KEY, { .scancode = SDL_SCANCODE_0 })); buttons.push_back(InputButton("-", InputButtonType::KEY, { .scancode = SDL_SCANCODE_MINUS })); buttons.push_back(InputButton("backspace", InputButtonType::KEY, { .scancode = SDL_SCANCODE_BACKSPACE })); buttons.push_back(InputButton("tab", InputButtonType::KEY, { .scancode = SDL_SCANCODE_TAB })); buttons.push_back(InputButton("q", InputButtonType::KEY, { .scancode = SDL_SCANCODE_Q })); buttons.push_back(InputButton("w", InputButtonType::KEY, { .scancode = SDL_SCANCODE_W })); buttons.push_back(InputButton("e", InputButtonType::KEY, { .scancode = SDL_SCANCODE_E })); buttons.push_back(InputButton("r", InputButtonType::KEY, { .scancode = SDL_SCANCODE_R })); buttons.push_back(InputButton("t", InputButtonType::KEY, { .scancode = SDL_SCANCODE_T })); buttons.push_back(InputButton("y", InputButtonType::KEY, { .scancode = SDL_SCANCODE_Y })); buttons.push_back(InputButton("u", InputButtonType::KEY, { .scancode = SDL_SCANCODE_U })); buttons.push_back(InputButton("i", InputButtonType::KEY, { .scancode = SDL_SCANCODE_I })); buttons.push_back(InputButton("o", InputButtonType::KEY, { .scancode = SDL_SCANCODE_O })); buttons.push_back(InputButton("p", InputButtonType::KEY, { .scancode = SDL_SCANCODE_P })); buttons.push_back(InputButton("[", InputButtonType::KEY, { .scancode = SDL_SCANCODE_LEFTBRACKET })); buttons.push_back(InputButton("]", InputButtonType::KEY, { .scancode = SDL_SCANCODE_RIGHTBRACKET })); buttons.push_back(InputButton("enter", InputButtonType::KEY, { .scancode = SDL_SCANCODE_RETURN })); buttons.push_back(InputButton("a", InputButtonType::KEY, { .scancode = SDL_SCANCODE_A })); buttons.push_back(InputButton("s", InputButtonType::KEY, { .scancode = SDL_SCANCODE_S })); buttons.push_back(InputButton("d", InputButtonType::KEY, { .scancode = SDL_SCANCODE_D })); buttons.push_back(InputButton("f", InputButtonType:: KEY, { .scancode = SDL_SCANCODE_F })); buttons.push_back(InputButton("g", InputButtonType::KEY, { .scancode = SDL_SCANCODE_G })); buttons.push_back(InputButton("h", InputButtonType::KEY, { .scancode = SDL_SCANCODE_H })); buttons.push_back(InputButton("j", InputButtonType::KEY, { .scancode = SDL_SCANCODE_J })); buttons.push_back(InputButton("k", InputButtonType::KEY, { .scancode = SDL_SCANCODE_K })); buttons.push_back(InputButton("l", InputButtonType::KEY, { .scancode = SDL_SCANCODE_L })); buttons.push_back(InputButton(";", InputButtonType::KEY, { .scancode = SDL_SCANCODE_SEMICOLON })); buttons.push_back(InputButton("'", InputButtonType::KEY, { .scancode = SDL_SCANCODE_APOSTROPHE })); buttons.push_back(InputButton("`", InputButtonType::KEY, { .scancode = SDL_SCANCODE_GRAVE })); buttons.push_back(InputButton("\\", InputButtonType::KEY, { .scancode = SDL_SCANCODE_BACKSLASH })); buttons.push_back(InputButton("z", InputButtonType::KEY, { .scancode = SDL_SCANCODE_Z })); buttons.push_back(InputButton("x", InputButtonType::KEY, { .scancode = SDL_SCANCODE_X })); buttons.push_back(InputButton("c", InputButtonType::KEY, { .scancode = SDL_SCANCODE_C })); buttons.push_back(InputButton("v", InputButtonType::KEY, { .scancode = SDL_SCANCODE_V })); buttons.push_back(InputButton("b", InputButtonType::KEY, { .scancode = SDL_SCANCODE_B })); buttons.push_back(InputButton("n", InputButtonType::KEY, { .scancode = SDL_SCANCODE_N })); buttons.push_back(InputButton("m", InputButtonType::KEY, { .scancode = SDL_SCANCODE_M })); buttons.push_back(InputButton(",", InputButtonType::KEY, { .scancode = SDL_SCANCODE_COMMA })); buttons.push_back(InputButton(".", InputButtonType::KEY, { .scancode = SDL_SCANCODE_PERIOD })); buttons.push_back(InputButton("/", InputButtonType::KEY, { .scancode = SDL_SCANCODE_SLASH })); buttons.push_back(InputButton("space", InputButtonType::KEY, { .scancode = SDL_SCANCODE_SPACE })); buttons.push_back(InputButton("capslock", InputButtonType::KEY, { .scancode = SDL_SCANCODE_CAPSLOCK })); buttons.push_back(InputButton("f1", InputButtonType::KEY, { .scancode = SDL_SCANCODE_F1 })); buttons.push_back(InputButton("f2", InputButtonType::KEY, { .scancode = SDL_SCANCODE_F2 })); buttons.push_back(InputButton("f3", InputButtonType::KEY, { .scancode = SDL_SCANCODE_F3 })); buttons.push_back(InputButton("f4", InputButtonType::KEY, { .scancode = SDL_SCANCODE_F4 })); buttons.push_back(InputButton("f5", InputButtonType::KEY, { .scancode = SDL_SCANCODE_F5 })); buttons.push_back(InputButton("f6", InputButtonType::KEY, { .scancode = SDL_SCANCODE_F6 })); buttons.push_back(InputButton("f7", InputButtonType::KEY, { .scancode = SDL_SCANCODE_F7 })); buttons.push_back(InputButton("f8", InputButtonType::KEY, { .scancode = SDL_SCANCODE_F8 })); buttons.push_back(InputButton("f9", InputButtonType::KEY, { .scancode = SDL_SCANCODE_F9 })); buttons.push_back(InputButton("f10", InputButtonType::KEY, { .scancode = SDL_SCANCODE_F10 })); buttons.push_back(InputButton("f11", InputButtonType::KEY, { .scancode = SDL_SCANCODE_F11 })); buttons.push_back(InputButton("f12", InputButtonType::KEY, { .scancode = SDL_SCANCODE_F12 })); buttons.push_back(InputButton("printscreen", InputButtonType::KEY, { .scancode = SDL_SCANCODE_PRINTSCREEN })); buttons.push_back(InputButton("scrolllock", InputButtonType::KEY, { .scancode = SDL_SCANCODE_SCROLLLOCK })); buttons.push_back(InputButton("pause", InputButtonType::KEY, { .scancode = SDL_SCANCODE_PAUSE })); buttons.push_back(InputButton("insert", InputButtonType::KEY, { .scancode = SDL_SCANCODE_INSERT })); buttons.push_back(InputButton("home", InputButtonType::KEY, { .scancode = SDL_SCANCODE_HOME })); buttons.push_back(InputButton("end", InputButtonType::KEY, { .scancode = SDL_SCANCODE_END })); buttons.push_back(InputButton("pageup", InputButtonType::KEY, { .scancode = SDL_SCANCODE_PAGEUP })); buttons.push_back(InputButton("pagedown", InputButtonType::KEY, { .scancode = SDL_SCANCODE_PAGEDOWN })); buttons.push_back(InputButton("delete", InputButtonType::KEY, { .scancode = SDL_SCANCODE_DELETE })); buttons.push_back(InputButton("right", InputButtonType::KEY, { .scancode = SDL_SCANCODE_RIGHT })); buttons.push_back(InputButton("left", InputButtonType::KEY, { .scancode = SDL_SCANCODE_LEFT })); buttons.push_back(InputButton("down", InputButtonType::KEY, { .scancode = SDL_SCANCODE_DOWN })); buttons.push_back(InputButton("up", InputButtonType::KEY, { .scancode = SDL_SCANCODE_UP })); buttons.push_back(InputButton("numlock", InputButtonType::KEY, { .scancode = SDL_SCANCODE_NUMLOCKCLEAR })); buttons.push_back(InputButton("kp_divide", InputButtonType::KEY, { .scancode = SDL_SCANCODE_KP_DIVIDE })); buttons.push_back(InputButton("kp_multiply", InputButtonType::KEY, { .scancode = SDL_SCANCODE_KP_MULTIPLY })); buttons.push_back(InputButton("kp_minus", InputButtonType::KEY, { .scancode = SDL_SCANCODE_KP_MINUS })); buttons.push_back(InputButton("kp_plus", InputButtonType::KEY, { .scancode = SDL_SCANCODE_KP_PLUS })); buttons.push_back(InputButton("kp_enter", InputButtonType::KEY, { .scancode = SDL_SCANCODE_KP_ENTER })); buttons.push_back(InputButton("kp_1", InputButtonType::KEY, { .scancode = SDL_SCANCODE_KP_1 })); buttons.push_back(InputButton("kp_2", InputButtonType::KEY, { .scancode = SDL_SCANCODE_KP_2 })); buttons.push_back(InputButton("kp_3", InputButtonType::KEY, { .scancode = SDL_SCANCODE_KP_3 })); buttons.push_back(InputButton("kp_4", InputButtonType::KEY, { .scancode = SDL_SCANCODE_KP_4 })); buttons.push_back(InputButton("kp_5", InputButtonType::KEY, { .scancode = SDL_SCANCODE_KP_5 })); buttons.push_back(InputButton("kp_6", InputButtonType::KEY, { .scancode = SDL_SCANCODE_KP_6 })); buttons.push_back(InputButton("kp_7", InputButtonType::KEY, { .scancode = SDL_SCANCODE_KP_7 })); buttons.push_back(InputButton("kp_8", InputButtonType::KEY, { .scancode = SDL_SCANCODE_KP_8 })); buttons.push_back(InputButton("kp_9", InputButtonType::KEY, { .scancode = SDL_SCANCODE_KP_9 })); buttons.push_back(InputButton("kp_0", InputButtonType::KEY, { .scancode = SDL_SCANCODE_KP_0 })); buttons.push_back(InputButton("kp_period", InputButtonType::KEY, { .scancode = SDL_SCANCODE_KP_PERIOD })); buttons.push_back(InputButton("ctrl", InputButtonType::KEY, { .scancode = SDL_SCANCODE_LCTRL })); buttons.push_back(InputButton("shift", InputButtonType::KEY, { .scancode = SDL_SCANCODE_LSHIFT })); buttons.push_back(InputButton("alt", InputButtonType::KEY, { .scancode = SDL_SCANCODE_LALT })); buttons.push_back(InputButton("rctrl", InputButtonType::KEY, { .scancode = SDL_SCANCODE_RCTRL })); buttons.push_back(InputButton("rshift", InputButtonType::KEY, { .scancode = SDL_SCANCODE_RSHIFT })); buttons.push_back(InputButton("ralt", InputButtonType::KEY, { .scancode = SDL_SCANCODE_RALT })); #endif } float_t Input::getCurrent(const InputBind *bind) const { assertNotNull(bind, "Input bind cannot be NULL"); auto it = states.find(bind); if(it != states.end()) return it->second.current; return 0.0f; } float_t Input::getPrevious(const InputBind* bind) const { assertNotNull(bind, "Input bind cannot be NULL"); auto it = states.find(bind); if(it != states.end()) return it->second.previous; return 0.0f; } float_t Input::getWhen(const InputBind *bind) const { auto it = states.find(bind); if(it != states.end()) return it->second.when; return 0.0f; } bool_t Input::isDown(const InputBind* bind) const { assertNotNull(bind, "Input bind cannot be NULL"); return this->getCurrent(bind) != 0.0f; } bool_t Input::isUp(const InputBind* bind) const { assertNotNull(bind, "Input bind cannot be NULL"); return this->getCurrent(bind) == 0.0f; } bool_t Input::wasPressed(const InputBind* bind) const { assertNotNull(bind, "Input bind cannot be NULL"); return this->getPrevious(bind) == 0.0f && this->getCurrent(bind) != 0.0f; } bool_t Input::wasReleased(const InputBind* bind) const { assertNotNull(bind, "Input bind cannot be NULL"); return this->getPrevious(bind) != 0.0f && this->getCurrent(bind) == 0.0f; } void Input::update(void) { // Reset all input bind states for(auto &state : this->states) { state.second.previous = state.second.current; state.second.current = 0.0f; } // Update button states. auto itButton = this->buttons.begin(); while(itButton != this->buttons.end()) { itButton->update(); if(itButton->getCurrent() != 0.0f) { // Exec command if actuated this tick. auto cmd = itButton->getCommand(); if(itButton->getPrevious() == 0.0f && cmd.length() > 0) { engine.console.exec(cmd); } else { // If bound to an input, update the bind state. auto bind = itButton->getBind(); if(bind != nullptr) { states[bind].when = engine.time.time; states[bind].current = fmaxf( states[bind].current, itButton->getCurrent() ); } } } ++itButton; } } Input::~Input(void) { }