From 650dcf411eca90969d3a86bc89ceb855015c04c4 Mon Sep 17 00:00:00 2001 From: Borin Ouch Date: Sun, 7 Apr 2024 23:27:53 -0700 Subject: [PATCH] Implement keyboard --- CMakeLists.txt | 2 ++ src/interface.cpp | 42 +++--------------------- src/interface.h | 2 ++ src/interpreter.cpp | 16 +++++++-- src/interpreter.h | 3 ++ src/keyboard.cpp | 80 +++++++++++++++++++++++++++++++++++++++++++++ src/keyboard.h | 24 ++++++++++++++ 7 files changed, 130 insertions(+), 39 deletions(-) create mode 100644 src/keyboard.cpp create mode 100644 src/keyboard.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ef6eb8..d918d38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,8 @@ set(SOURCE_FILES src/applog.cpp src/screen.cpp src/assembly.cpp + src/keyboard.cpp + src/keyboard.h ) set(EXPECTED_BUILD_TESTS OFF) diff --git a/src/interface.cpp b/src/interface.cpp index d6889d9..1572ce5 100644 --- a/src/interface.cpp +++ b/src/interface.cpp @@ -123,6 +123,8 @@ void Interface::initialize() { screen.initialize(kScreenWidth, kScreenHeight, kDefaultScreenPixelSize, regs->screen.data()); assembly.initialize(regs.get()); + + keyboard.initialize(regs); } bool Interface::update() { @@ -151,6 +153,8 @@ bool Interface::update() { UnloadDroppedFiles(droppedFiles); } + keyboard.update(); + play_sound = regs->st > 0; screen.update(); @@ -440,43 +444,7 @@ bool Interface::update() { if (show_keyboard) { if (ImGui::Begin("Keyboard", &show_keyboard)) { - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(24, 18)); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 2)); - - ImGui::Button("1"); - ImGui::SameLine(); - ImGui::Button("2"); - ImGui::SameLine(); - ImGui::Button("3"); - ImGui::SameLine(); - ImGui::Button("C"); - - ImGui::Button("4"); - ImGui::SameLine(); - ImGui::Button("5"); - ImGui::SameLine(); - ImGui::Button("6"); - ImGui::SameLine(); - ImGui::Button("D"); - - ImGui::Button("7"); - ImGui::SameLine(); - ImGui::Button("8"); - ImGui::SameLine(); - ImGui::Button("9"); - ImGui::SameLine(); - ImGui::Button("E"); - - ImGui::Button("A"); - ImGui::SameLine(); - ImGui::Button("0"); - ImGui::SameLine(); - ImGui::Button("B"); - ImGui::SameLine(); - ImGui::Button("F"); - - ImGui::PopStyleVar(3); + keyboard.draw(); } ImGui::End(); } diff --git a/src/interface.h b/src/interface.h index 934bf7d..b295532 100644 --- a/src/interface.h +++ b/src/interface.h @@ -4,6 +4,7 @@ #include "applog.h" #include "screen.h" #include "assembly.h" +#include "keyboard.h" #include #include @@ -32,6 +33,7 @@ class Interface { AppLog app_log; Screen screen; AssemblyViewer assembly; + Keyboard keyboard; std::vector rom; diff --git a/src/interpreter.cpp b/src/interpreter.cpp index db64c90..d3ca11a 100644 --- a/src/interpreter.cpp +++ b/src/interpreter.cpp @@ -18,6 +18,8 @@ void Interpreter::initialize() { } void Interpreter::update() { + update_keyboard(); + double update_frequency = 1.0 / static_cast(update_play_rate); double dt = timer.duration(); @@ -319,9 +321,19 @@ uint16_t Interpreter::stack_pop() { return stack[--(*sp)]; } -std::optional Interpreter::get_pressed_key() { +void Interpreter::update_keyboard() { for (int key = 0; key < regs->kbd.size(); key += 1) { - if (regs->kbd[key]) { + if (key_down[key] && !regs->kbd[key]) { + key_released[key] = true; + spdlog::debug("Key pressed: 0x{:02x}", key); + } + } + key_down = regs->kbd; +} + +std::optional Interpreter::get_pressed_key() { + for (int key = 0; key < key_released.size(); key += 1) { + if (key_released[key]) { return key; } } diff --git a/src/interpreter.h b/src/interpreter.h index ed9f108..c8bd9bd 100644 --- a/src/interpreter.h +++ b/src/interpreter.h @@ -30,6 +30,7 @@ class Interpreter { bool is_playing() const; private: + void update_keyboard(); void update_timers(double dt); void stack_push(uint16_t val); uint16_t stack_pop(); @@ -47,4 +48,6 @@ class Interpreter { bool playing = false; std::shared_ptr regs; + std::array key_down; + std::array key_released; }; diff --git a/src/keyboard.cpp b/src/keyboard.cpp new file mode 100644 index 0000000..47473a6 --- /dev/null +++ b/src/keyboard.cpp @@ -0,0 +1,80 @@ +#include "keyboard.h" + +#include +#include +#include +#include +#include + +Keyboard::Keyboard() { + mapping.push_back({"1", KEY_ONE, 0x1}); + mapping.push_back({"2", KEY_TWO, 0x2}); + mapping.push_back({"3", KEY_THREE, 0x3}); + mapping.push_back({"C", KEY_FOUR, 0xc}); + + mapping.push_back({"4", KEY_Q, 0x4}); + mapping.push_back({"5", KEY_W, 0x5}); + mapping.push_back({"6", KEY_E, 0x6}); + mapping.push_back({"D", KEY_R, 0xd}); + + mapping.push_back({"7", KEY_A, 0x7}); + mapping.push_back({"8", KEY_S, 0x8}); + mapping.push_back({"9", KEY_D, 0x9}); + mapping.push_back({"E", KEY_F, 0xe}); + + mapping.push_back({"A", KEY_Z, 0xa}); + mapping.push_back({"0", KEY_X, 0x0}); + mapping.push_back({"B", KEY_C, 0xb}); + mapping.push_back({"F", KEY_V, 0xf}); +} + +void Keyboard::initialize(std::shared_ptr regs_) { + regs = std::move(regs_); +} + +void Keyboard::update() { + for (auto &m : mapping) { + regs->kbd[m.key] = IsKeyDown(m.keycode); + } +} + +void Keyboard::draw() { + auto push_disabled_flags = [] () { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + }; + + auto pop_disabled_flags = [] () { + ImGui::PopItemFlag(); + ImGui::PopStyleVar(); + }; + + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(24, 18)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 2)); + + int n = 0; + for (auto &m : mapping) { + if (n % 4 != 0) { + ImGui::SameLine(); + } + + bool is_disabled = regs->kbd[m.key]; + + if (is_disabled) { + push_disabled_flags(); + } + + if (ImGui::Button(m.label.c_str())) { + regs->kbd[m.key]; + } + + if (is_disabled) { + pop_disabled_flags(); + } + + n += 1; + } + + ImGui::PopStyleVar(3); +} diff --git a/src/keyboard.h b/src/keyboard.h new file mode 100644 index 0000000..1628414 --- /dev/null +++ b/src/keyboard.h @@ -0,0 +1,24 @@ +#pragma once + +#include "registers.h" +#include +#include + +struct key_mapping { + std::string label; + int keycode; + uint8_t key; +}; + +class Keyboard { +public: + Keyboard(); + + void initialize(std::shared_ptr regs); + void update(); + void draw(); + +private: + std::vector mapping; + std::shared_ptr regs; +};