diff --git a/src/kekengine/cpp/defaults.cpp b/src/kekengine/cpp/defaults.cpp index 9efab40..68e7fe1 100644 --- a/src/kekengine/cpp/defaults.cpp +++ b/src/kekengine/cpp/defaults.cpp @@ -13,11 +13,14 @@ static KeyBinding keyUp, keyDown, keyOptions, - keyToggleCursorMode; + keyToggleCursorMode, + keyExit; static ButtonElement *options; static void defaultInput(GLFWwindow *window, void *data) { + if(Input::isKeyboardCaptured()) return; + if(Input::getKeyState(keyForward) == GLFW_PRESS) { kekData.activeCamera->translate(kekData.activeCamera->direction * KEK_NOCLIP_SPEED * kekData.lastFrameTime); } @@ -46,6 +49,10 @@ static void defaultInput(GLFWwindow *window, void *data) { } static void defaultKeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods, void *data) { + if(key == Input::getKeyBinding(keyExit).key && action == GLFW_PRESS) { + glfwSetWindowShouldClose(window, true); + } + if(key == Input::getKeyBinding(keyOptions).key && action == GLFW_PRESS) { options->visible = !options->visible; } @@ -128,6 +135,7 @@ void init() { keyDown = Input::createKeyBinding("Down", GLFW_KEY_LEFT_CONTROL); keyOptions = Input::createKeyBinding("Options", GLFW_KEY_Q); keyToggleCursorMode = Input::createKeyBinding("Toggle Cursor Mode", GLFW_KEY_TAB); + keyExit = Input::createKeyBinding("Exit", GLFW_KEY_ESCAPE); Input::addPeriodicCallback(PeriodicCallback(defaultInput, nullptr)); Input::addKeyListener(KeyCallback(defaultKeyCallback, nullptr)); diff --git a/src/kekengine/cpp/engine.cpp b/src/kekengine/cpp/engine.cpp index b728684..3af4b72 100644 --- a/src/kekengine/cpp/engine.cpp +++ b/src/kekengine/cpp/engine.cpp @@ -50,11 +50,27 @@ static void onCursorPosCallback(GLFWwindow *window, double x, double y) { } static void onKeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) { + if(Input::isKeyboardCaptured()) { + if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) Input::uncaptureKeyboardInput(kekData.activeKeyboardCapture.id); + return; + } + for(auto cb : kekData.keyCallbacks) { cb.second(window, key, scancode, action, mods); } } +static void onKeyCharCallback(GLFWwindow *window, unsigned int codepoint) { + if(Input::isKeyboardCaptured()) { + kekData.activeKeyboardCapture.callback(window, codepoint); + return; + } + + for(auto cb : kekData.keyCharCallbacks) { + cb.second(window, codepoint); + } +} + void onMouseButtonCallback(GLFWwindow* window, int button, int action, int mods) { for(auto cb : kekData.mouseButtonCallbacks) { cb.second(window, button, action, mods); @@ -159,6 +175,7 @@ int init() { glfwSetCursorPosCallback(kekData.window, onCursorPosCallback); Input::setCursorMode(GLFWCursorMode::CAPTURE); glfwSetKeyCallback(kekData.window, onKeyCallback); + glfwSetCharCallback(kekData.window, onKeyCharCallback); glfwSetMouseButtonCallback(kekData.window, onMouseButtonCallback); glClearColor(0.1f, 0.3f, 0.1f, 0.0f); @@ -195,10 +212,6 @@ int start() { cb.second(kekData.window); } - if(glfwGetKey(kekData.window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { - break; - } - kekData.shader->use(); glm::mat4 view = kekData.activeCamera->transformationMatrix(); diff --git a/src/kekengine/cpp/input.cpp b/src/kekengine/cpp/input.cpp index 5e76b2f..bc6ebaa 100644 --- a/src/kekengine/cpp/input.cpp +++ b/src/kekengine/cpp/input.cpp @@ -29,6 +29,16 @@ void removeKeyListener(InputListener listener) { kekData.keyCallbacks.erase(listener); } +InputListener addKeyCharListener(KeyCharCallback callback) { + InputListener id = nextID++; + kekData.keyCharCallbacks.emplace(id, callback); + return id; +} + +void removeKeyCharListener(InputListener listener) { + kekData.keyCharCallbacks.erase(listener); +} + InputListener addMouseListener(MouseCallback callback) { InputListener id = nextID++; kekData.mouseCallbacks.emplace(id, callback); @@ -50,7 +60,7 @@ void removeMouseButtonListener(InputListener listener) { } KeyBinding createKeyBinding(std::string name, GLFWKey defaultKey) { - if(name == KEK_INVALID_KEY_BINDING_NAME) return KEK_INVALID_KEY_BINDING; + if(name == KEK_INVALID_KEY_BINDING_NAME) return KEK_INVALID_ID; KeyBinding id = nextID++; KeyBindingData d; d.name = name; @@ -60,7 +70,7 @@ KeyBinding createKeyBinding(std::string name, GLFWKey defaultKey) { } void reassignKeyBinding(KeyBinding binding, GLFWKey key) { - if(binding == KEK_INVALID_KEY_BINDING) return; + if(binding == KEK_INVALID_ID) return; auto it = kekData.keyBindings.find(binding); if(it == kekData.keyBindings.end()) return; KeyBindingData d = it->second; @@ -89,4 +99,24 @@ GLFWCursorMode getCursorMode() { return kekData.uiCursorMode; } +KeyboardCapture captureKeyboardInput(KeyCharCallback callback, Callable uncaptureCallback) { + KeyboardCapture id = nextID++; + kekData.activeKeyboardCapture.id = id; + kekData.activeKeyboardCapture.callback = callback; + kekData.activeKeyboardCapture.uncaptureCallback = uncaptureCallback; + return id; +} + +bool uncaptureKeyboardInput(KeyboardCapture capture) { + if(capture == KEK_INVALID_ID || capture != kekData.activeKeyboardCapture.id) return false; + kekData.activeKeyboardCapture.id = KEK_INVALID_ID; + kekData.activeKeyboardCapture.callback = KeyCharCallback(); + kekData.activeKeyboardCapture.uncaptureCallback = Callable(); + return true; +} + +bool isKeyboardCaptured() { + return kekData.activeKeyboardCapture.id != KEK_INVALID_ID; +} + } diff --git a/src/kekengine/cpp/uielements.cpp b/src/kekengine/cpp/uielements.cpp index 3931de3..29d3109 100644 --- a/src/kekengine/cpp/uielements.cpp +++ b/src/kekengine/cpp/uielements.cpp @@ -55,6 +55,10 @@ void TextElement::setText(std::string text) { this->text->setText(text); } +std::string TextElement::getText() { + return text->getText(); +} + void TextElement::draw(UIPoint screenPos, glm::mat4 projection) { UIBounds offset = getBounds(); diff --git a/src/kekengine/cpp/unicode.cpp b/src/kekengine/cpp/unicode.cpp new file mode 100644 index 0000000..dbde47d --- /dev/null +++ b/src/kekengine/cpp/unicode.cpp @@ -0,0 +1,17 @@ +#include "unicode.h" + +#include + +namespace kek::Unicode { + +static std::wstring_convert, char32_t> utf32cvt; + +std::u32string convertStdToU32(std::string string) { + return utf32cvt.from_bytes(string); +} + +std::string convertU32ToStd(std::u32string string) { + return utf32cvt.to_bytes(string); +} + +} diff --git a/src/kekengine/include/constants.h b/src/kekengine/include/constants.h index 4794a55..df6623f 100644 --- a/src/kekengine/include/constants.h +++ b/src/kekengine/include/constants.h @@ -27,14 +27,14 @@ #define KEK_LIGHT_MAX_DISTANCE_SQUARED (KEK_LIGHT_MAX_DISTANCE * KEK_LIGHT_MAX_DISTANCE) #define KEK_INVALID_KEY_BINDING_NAME "INVALID" -#define KEK_INVALID_KEY_BINDING -1u +#define KEK_INVALID_ID -1u #define KEK_FONT_RESOLUTION 64 #define KEK_FONT_BITMAP_WIDTH_BLOCKS 16 #define KEK_FONT_BITMAP_HEIGHT_BLOCKS 16 #define KEK_FONT_BITMAP_WIDTH (KEK_FONT_BITMAP_WIDTH_BLOCKS * KEK_FONT_RESOLUTION) #define KEK_FONT_BITMAP_HEIGHT (KEK_FONT_BITMAP_HEIGHT_BLOCKS * KEK_FONT_RESOLUTION) -#define KEK_FONT_BITMAP_CHAR_BITS 8 // = log2(KEK_FONT_BITMAP_WIDTH_BLOCKS * KEK_FONT_BITMAP_HEIGHT_BLOCKS) +#define KEK_FONT_BITMAP_CHAR_BITS 8 // = ceil(log2(KEK_FONT_BITMAP_WIDTH_BLOCKS * KEK_FONT_BITMAP_HEIGHT_BLOCKS)) #define KEK_FONT_BITMAP_CHAR_MASK 0xFF // = KEK_FONT_BITMAP_CHAR_BITS 1s in binary #define KEK_TEXT_BLOCK_SIZE 8 diff --git a/src/kekengine/include/input.h b/src/kekengine/include/input.h index 02e5c4f..a78e07b 100644 --- a/src/kekengine/include/input.h +++ b/src/kekengine/include/input.h @@ -9,6 +9,7 @@ namespace kek { typedef GenericCallable PeriodicCallback; // periodicCallback(GLFWwindow *window) typedef GenericCallable KeyCallback; // keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) +typedef GenericCallable KeyCharCallback; // keyCharCallback(GLFWwindow *window, unsigned int codepoint) typedef GenericCallable MouseCallback; // mouseCallback(GLFWwindow *window, double x, double y) typedef GenericCallable MouseButtonCallback; // void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) @@ -16,6 +17,7 @@ typedef unsigned int InputListener; typedef int GLFWKey; typedef int GLFWKeyState; typedef unsigned int KeyBinding; +typedef unsigned int KeyboardCapture; struct KeyBindingData { std::string name; @@ -44,6 +46,9 @@ void removePeriodicCallback(InputListener listener); InputListener addKeyListener(KeyCallback callback); void removeKeyListener(InputListener listener); +InputListener addKeyCharListener(KeyCharCallback callback); +void removeKeyCharListener(InputListener listener); + InputListener addMouseListener(MouseCallback callback); void removeMouseListener(InputListener listener); @@ -58,4 +63,8 @@ GLFWKeyState getKeyState(KeyBinding mapping); void setCursorMode(GLFWCursorMode mode); GLFWCursorMode getCursorMode(); +KeyboardCapture captureKeyboardInput(KeyCharCallback callback, Callable uncaptureCallback); +bool uncaptureKeyboardInput(KeyboardCapture capture); +bool isKeyboardCaptured(); + } diff --git a/src/kekengine/include/internal.h b/src/kekengine/include/internal.h index 37e782a..9bd861b 100644 --- a/src/kekengine/include/internal.h +++ b/src/kekengine/include/internal.h @@ -13,9 +13,16 @@ namespace kek { +struct ActiveKeyboardCapture { + KeyboardCapture id = KEK_INVALID_ID; + KeyCharCallback callback; + Callable uncaptureCallback; +}; + struct KekData { std::map periodicCallbacks; std::map keyCallbacks; + std::map keyCharCallbacks; std::map mouseCallbacks; std::map mouseButtonCallbacks; std::map keyBindings; @@ -39,6 +46,7 @@ struct KekData { Font *uiDefaultFont; Shader *uiRectangleShader; GLFWCursorMode uiCursorMode; + ActiveKeyboardCapture activeKeyboardCapture; }; extern KekData kekData; diff --git a/src/kekengine/include/kekengine.h b/src/kekengine/include/kekengine.h index 4081c97..12a5dc8 100644 --- a/src/kekengine/include/kekengine.h +++ b/src/kekengine/include/kekengine.h @@ -13,6 +13,7 @@ #include "scene.h" #include "shader.h" #include "types.h" -#include "utils.h" #include "ui.h" +#include "unicode.h" #include "uielements.h" +#include "utils.h" diff --git a/src/kekengine/include/uielements.h b/src/kekengine/include/uielements.h index f3ad222..cdefe0b 100644 --- a/src/kekengine/include/uielements.h +++ b/src/kekengine/include/uielements.h @@ -51,6 +51,8 @@ public: void setText(std::string text); + std::string getText(); + virtual void draw(UIPoint screenPos, glm::mat4 projection); }; diff --git a/src/kekengine/include/unicode.h b/src/kekengine/include/unicode.h new file mode 100644 index 0000000..53db12c --- /dev/null +++ b/src/kekengine/include/unicode.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace kek::Unicode { + +std::u32string convertStdToU32(std::string string); +std::string convertU32ToStd(std::u32string string); + +} diff --git a/src/kekgame/cpp/kekgame.cpp b/src/kekgame/cpp/kekgame.cpp index 6ebbf55..05cfa77 100644 --- a/src/kekgame/cpp/kekgame.cpp +++ b/src/kekgame/cpp/kekgame.cpp @@ -6,6 +6,8 @@ using namespace kek; +static ButtonElement *button; + void periodicCallback(GLFWwindow *window, void *data){ } @@ -19,7 +21,11 @@ void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods, v } void onButtonClick(void *data) { - std::cout << "Clicked!" << std::endl; + Input::captureKeyboardInput(KeyCharCallback([](GLFWwindow *window, unsigned int codepoint, void *data) { + std::u32string str = Unicode::convertStdToU32(button->text->getText()); + str.push_back(codepoint); + button->text->setText(Unicode::convertU32ToStd(str)); + }, nullptr), Callable()); } int main(int argc, char **argv) { @@ -58,13 +64,13 @@ int main(int argc, char **argv) { Input::addKeyListener(KeyCallback(keyCallback, nullptr)); Input::addMouseButtonListener(MouseButtonCallback(mouseButtonCallback, nullptr)); - ButtonElement *btn = new ButtonElement(px(10), px(100), px(200), px(50)); - btn->text->color = Colors::BLACK; - btn->color = Colors::WHITE; - btn->hoverColor = Colors::GRAY; - btn->text->setText("Hello There!"); - btn->onClick = Callable(onButtonClick, nullptr); - UI::addElement(btn); + button = new ButtonElement(px(10), px(100), px(200), px(50)); + button->text->color = Colors::BLACK; + button->color = Colors::WHITE; + button->hoverColor = Colors::GRAY; + button->text->setText("Hello There!"); + button->onClick = Callable(onButtonClick, nullptr); + UI::addElement(button); Engine::start(); }