voxelcore/src/window/Events.cpp
2024-06-02 22:10:39 +03:00

225 lines
6.3 KiB
C++

#include "Events.hpp"
#include "Window.hpp"
#include "../debug/Logger.hpp"
#include "../util/stringutil.hpp"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <string.h>
static debug::Logger logger("events");
inline constexpr short _MOUSE_KEYS_OFFSET = 1024;
bool Events::keys[KEYS_BUFFER_SIZE] = {};
uint Events::frames[KEYS_BUFFER_SIZE] = {};
uint Events::currentFrame = 0;
int Events::scroll = 0;
glm::vec2 Events::delta = {};
glm::vec2 Events::cursor = {};
bool Events::cursor_drag = false;
bool Events::_cursor_locked = false;
std::vector<uint> Events::codepoints;
std::vector<keycode> Events::pressedKeys;
std::unordered_map<std::string, Binding> Events::bindings;
bool Events::pressed(keycode keycode) {
return pressed(static_cast<int>(keycode));
}
bool Events::pressed(int keycode) {
if (keycode < 0 || keycode >= KEYS_BUFFER_SIZE) {
return false;
}
return keys[keycode];
}
bool Events::jpressed(keycode keycode) {
return jpressed(static_cast<int>(keycode));
}
bool Events::jpressed(int keycode) {
return Events::pressed(keycode) && frames[keycode] == currentFrame;
}
bool Events::clicked(mousecode button) {
return clicked(static_cast<int>(button));
}
bool Events::clicked(int button) {
return Events::pressed(_MOUSE_KEYS_OFFSET + button);
}
bool Events::jclicked(mousecode button) {
return jclicked(static_cast<int>(button));
}
bool Events::jclicked(int button) {
return Events::jpressed(_MOUSE_KEYS_OFFSET + button);
}
void Events::toggleCursor() {
cursor_drag = false;
_cursor_locked = !_cursor_locked;
Window::setCursorMode(_cursor_locked ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_NORMAL);
}
void Events::pollEvents() {
currentFrame++;
delta.x = 0.f;
delta.y = 0.f;
scroll = 0;
codepoints.clear();
pressedKeys.clear();
glfwPollEvents();
for (auto& entry : bindings) {
auto& binding = entry.second;
binding.justChange = false;
bool newstate = false;
switch (binding.type) {
case inputtype::keyboard: newstate = pressed(binding.code); break;
case inputtype::mouse: newstate = clicked(binding.code); break;
}
if (newstate) {
if (!binding.state) {
binding.state = true;
binding.justChange = true;
binding.onactived.notify();
}
} else {
if (binding.state) {
binding.state = false;
binding.justChange = true;
}
}
}
}
void Events::bind(const std::string& name, inputtype type, keycode code) {
bind(name, type, static_cast<int>(code));
}
void Events::bind(const std::string& name, inputtype type, mousecode code) {
bind(name, type, static_cast<int>(code));
}
void Events::bind(const std::string& name, inputtype type, int code) {
bindings.emplace(name, Binding(type, code));
}
void Events::rebind(const std::string& name, inputtype type, int code) {
bindings[name] = Binding(type, code);
}
bool Events::active(const std::string& name) {
const auto& found = bindings.find(name);
if (found == bindings.end()) {
return false;
}
return found->second.active();
}
bool Events::jactive(const std::string& name) {
const auto& found = bindings.find(name);
if (found == bindings.end()) {
return false;
}
return found->second.jactive();
}
void Events::setKey(int key, bool b) {
Events::keys[key] = b;
Events::frames[key] = currentFrame;
}
void Events::setButton(int button, bool b) {
setKey(_MOUSE_KEYS_OFFSET + button, b);
}
void Events::setPosition(float xpos, float ypos) {
if (Events::cursor_drag) {
Events::delta.x += xpos - Events::cursor.x;
Events::delta.y += ypos - Events::cursor.y;
}
else {
Events::cursor_drag = true;
}
Events::cursor.x = xpos;
Events::cursor.y = ypos;
}
#include "../data/dynamic.hpp"
#include "../coders/json.hpp"
#include "../coders/toml.hpp"
std::string Events::writeBindings() {
dynamic::Map obj;
for (auto& entry : Events::bindings) {
const auto& binding = entry.second;
std::string value;
switch (binding.type) {
case inputtype::keyboard:
value = "key:"+input_util::get_name(static_cast<keycode>(binding.code));
break;
case inputtype::mouse:
value = "mouse:"+input_util::get_name(static_cast<mousecode>(binding.code));
break;
default: throw std::runtime_error("unsupported control type");
}
obj.put(entry.first, value);
}
return toml::stringify(obj);
}
void Events::loadBindingsOld(const std::string& filename, const std::string& source) {
auto obj = json::parse(filename, source);
for (auto& entry : Events::bindings) {
auto& binding = entry.second;
auto jentry = obj->map(entry.first);
if (jentry == nullptr)
continue;
inputtype type;
std::string typestr;
jentry->str("type", typestr);
if (typestr == "keyboard") {
type = inputtype::keyboard;
} else if (typestr == "mouse") {
type = inputtype::mouse;
} else {
logger.error() << "unknown input type '" << typestr << "'";
continue;
}
binding.type = type;
jentry->num("code", binding.code);
}
}
void Events::loadBindings(const std::string& filename, const std::string& source) {
auto map = toml::parse(filename, source);
for (auto& entry : map->values) {
if (auto value = std::get_if<std::string>(&entry.second)) {
auto [prefix, codename] = util::split_at(*value, ':');
inputtype type;
int code;
if (prefix == "key") {
type = inputtype::keyboard;
code = static_cast<int>(input_util::keycode_from(codename));
} else if (prefix == "mouse") {
type = inputtype::mouse;
code = static_cast<int>(input_util::mousecode_from(codename));
} else {
logger.error() << "unknown input type: " << prefix
<< " (binding " << util::quote(entry.first) << ")";
continue;
}
Events::bind(entry.first, type, code);
} else {
logger.error() << "invalid binding entry: " << entry.first;
}
}
}