From e8849a4b49f289c90cd27687645aadea381f26f4 Mon Sep 17 00:00:00 2001 From: OmniaX Date: Fri, 12 Jan 2024 17:28:45 +0100 Subject: [PATCH] [0.1.1818] - Added KeyboardController --- CMakeLists.txt | 1 + build.nr | 2 +- changelog.txt | 6 ++ src/ostd/Console.hpp | 100 ++++++++++++++++++++++ src/ostd/Keyboard.cpp | 189 ++++++++++++++++++++++++++++++++++++++++++ src/ostd/Signals.cpp | 12 +++ src/ostd/Signals.hpp | 4 + src/ostd/String.cpp | 68 +++++++-------- src/ostd/String.hpp | 47 +++++++---- src/ostd/Utils.hpp | 19 +++++ src/test.cpp | 28 +++++++ 11 files changed, 423 insertions(+), 53 deletions(-) create mode 100644 changelog.txt create mode 100644 src/ostd/Keyboard.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e8a363..0b31dfc 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ list(APPEND OSTD_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/src/ostd/File.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ostd/FileSystem.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ostd/Geometry.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/ostd/Keyboard.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ostd/Logger.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ostd/Logic.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ostd/OutputHandlers.cpp diff --git a/build.nr b/build.nr index baa45fb..20aaf66 100644 --- a/build.nr +++ b/build.nr @@ -1 +1 @@ -1808 +1819 diff --git a/changelog.txt b/changelog.txt new file mode 100644 index 0000000..f443be1 --- /dev/null +++ b/changelog.txt @@ -0,0 +1,6 @@ +[0.1.1818] +Added ostd::String::fixedLength(...) method, with corresponding 'new_fixedLength' version. +Added "KeyboardController" class to (implemented in ) to handle + keypresses in the console in a cross-platform way +Added helper functions in ostd::Utils for dealing with raw arrays +Added more Builtin signals \ No newline at end of file diff --git a/src/ostd/Console.hpp b/src/ostd/Console.hpp index 2ed4326..1af6712 100644 --- a/src/ostd/Console.hpp +++ b/src/ostd/Console.hpp @@ -4,6 +4,17 @@ #include #include +#include "Defines.hpp" +#include "String.hpp" + +#ifndef WINDOWS_OS + #include +#else + #include +#endif +#include +#include + namespace ostd { class InteractiveConsole : public OutputHandlerBase @@ -89,4 +100,93 @@ namespace ostd }; }; + + enum class eKeys + { + NoKeyPressed = 0, + Backspace = 127, + Enter = 10, + Tab = 9, + Up = 0x5B41, + Down = 0x5B42, + Left = 0x5B44, + Right = 0x5B43, + Escape = 27, + Space = ' ', + symExclamation = '!', + symDoubleQuote = '\"', + symPound = '#', + symDollar = '$', + symPercent = '%', + symAmpersand = '&', + symSingeQuote = '\'', + symLeftParenthesis = '(', + symRightParenthesis = ')', + symAsterisk = '*', + symPlus = '+', + symComma = ',', + symMinus = '-', + symPeriod = '.', + symSlash = '/', + Num0 = '0', Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, + symColon = ':', + symSemicolon = ';', + symLessThan = '<', + symEquals = '=', + symGreaterThan = '>', + symQuestionMark = '?', + symAtSign = '@', + A = 'A',B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z, + symLeftSquareBracket = '[', + symBackslash = '\\', + symRightSquareBracket = ']', + symCaret = '^', + symUnderscore = '_', + symGraveAccent = 96, + a = 'a',b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z, + symLeftCurlyBracket = '{', + symVerticalBar = '|', + symRightCurlyBracket = '}', + symTilde = '~' + }; + + class KeyboardController + { + public: + KeyboardController(void); + ~KeyboardController(void); + + eKeys getPressedKey(void); + eKeys waitForKeyPress(void); + + inline String getInputString(void) { return m_cmd; } + + inline bool isOutputEnabled(void) { return m_output_enabled; } + inline void enableOutput(bool __oe = true) { m_output_enabled = __oe; } + inline void disableOutput(void) { enableOutput(false); } + + inline bool isCommandBufferEnabled(void) { return m_cmd_buffer_enabled; } + inline void enableCommandBuffer(bool __cbe = true) { m_cmd_buffer_enabled = __cbe; } + inline void disableCommandBuffer(void) { enableCommandBuffer(false); } + + private: + String getKeyBuffer(void); + String flushKeyBuffer(void); + +#ifndef WINDOWS_OS + int kbhit(void); + int getch(void); +#endif + + + private: +#ifndef WINDOWS_OS + struct termios initial_settings, new_settings; + int peek_character; +#endif + std::vector m_key_buff; + String m_cmd; + bool m_output_enabled; + bool m_cmd_buffer_enabled; + }; } \ No newline at end of file diff --git a/src/ostd/Keyboard.cpp b/src/ostd/Keyboard.cpp new file mode 100644 index 0000000..7db15df --- /dev/null +++ b/src/ostd/Keyboard.cpp @@ -0,0 +1,189 @@ +#include "Console.hpp" + +#include + +namespace ostd +{ + KeyboardController::KeyboardController(void) + { +#ifndef WINDOWS_OS + tcgetattr(0, &initial_settings); + new_settings = initial_settings; + new_settings.c_lflag &= ~ICANON; + new_settings.c_lflag &= ~ECHO; + new_settings.c_lflag &= ~ISIG; + new_settings.c_cc[VMIN] = 1; + new_settings.c_cc[VTIME] = 0; + tcsetattr(0, TCSANOW, &new_settings); + peek_character = -1; +#endif + + m_cmd = ""; + m_output_enabled = true; + m_cmd_buffer_enabled = true; + } + + KeyboardController::~KeyboardController(void) + { +#ifndef WINDOWS_OS + tcsetattr(0, TCSANOW, &initial_settings); +#endif + } + +#ifndef WINDOWS_OS + int KeyboardController::kbhit(void) + { + unsigned char ch; + int nread; + if (peek_character != -1) return 1; + new_settings.c_cc[VMIN] = 0; + tcsetattr(0, TCSANOW, &new_settings); + nread = read(0, &ch, 1); + new_settings.c_cc[VMIN] = 1; + tcsetattr(0, TCSANOW, &new_settings); + + if (nread == 1) + { + peek_character = ch; + return 1; + } + return 0; + } + + int KeyboardController::getch(void) + { + char ch; + + if (peek_character != -1) + { + ch = peek_character; + peek_character = -1; + } + else + read(0, &ch, 1); + return ch; + } +#endif + + String KeyboardController::getKeyBuffer(void) + { + std::string __str = ""; + for (auto& key : m_key_buff) + { + switch (key) + { + case eKeys::Backspace: + case eKeys::Enter: + case eKeys::Up: + case eKeys::Down: + case eKeys::Left: + case eKeys::Right: + case eKeys::Escape: + case eKeys::NoKeyPressed: + break; + case eKeys::Tab: + __str += '\t'; + break; + default: + __str += (char)(key); + break; + } + } + return String(__str); + } + + String KeyboardController::flushKeyBuffer(void) + { + String __str = getKeyBuffer(); + m_key_buff.clear(); + return __str; + } + + eKeys KeyboardController::waitForKeyPress(void) //TODO: Add sleep to this method + { + eKeys key = eKeys::NoKeyPressed; + while (key == eKeys::NoKeyPressed) + key = getPressedKey(); + return key; + } + + eKeys KeyboardController::getPressedKey(void) + { + int k1 = 0, k2 = 0, k3 = 0; + eKeys key; + if(kbhit()) + { + k1 = getch(); + + if (k1 == 127 || k1 == 8) + { + key = eKeys::Backspace; + if (isOutputEnabled()) + std::cout << "\b \b" << std::flush; + if (m_key_buff.size() > 0 && isCommandBufferEnabled()) + m_key_buff.pop_back(); + } + else if (k1 == 10 || k1 == 13) + { + key = eKeys::Enter; + if (isOutputEnabled()) + std::cout << "\n" << std::flush; + if (isCommandBufferEnabled()) + m_cmd = flushKeyBuffer(); + } + else if (k1 == 9) + { + if (isOutputEnabled()) + std::cout << "\t" << std::flush; + if (isCommandBufferEnabled()) + m_key_buff.push_back(key); + key = eKeys::Tab; + } + else if (k1 >= ' ' && k1 <= '~') + { + key = (eKeys)(k1); + if (isCommandBufferEnabled()) + m_key_buff.push_back(key); + if (isOutputEnabled()) + std::cout << (char)(key) << std::flush; + } +#ifndef WINDOWS_OS + else if (k1 == 27) + { + if (!kbhit()) + { + key = eKeys::Escape; + return key; + } + k2 = getch(); + if (k2 == 91) + { + k3 = getch(); + if (k3 == 65) key = eKeys::Up; + else if (k3 == 66) key = eKeys::Down; + else if (k3 == 67) key = eKeys::Right; + else if (k3 == 68) key = eKeys::Left; + } + } +#else + else if (k1 == 0xE0) + { + k2 = getch(); + if (k2 == 0x48) key = eKeys::Up; + else if (k2 == 0x50) key = eKeys::Down; + else if (k2 == 0x4D) key = eKeys::Right; + else if (k2 == 0x4B) key = eKeys::Left; + else key = eKeys::NoKeyPressed; + } + else if (k1 == 27) + { + key = eKeys::Escape; + } +#endif + + } + else key = eKeys::NoKeyPressed; + return key; + } +} + diff --git a/src/ostd/Signals.cpp b/src/ostd/Signals.cpp index 267dbdc..2b10675 100755 --- a/src/ostd/Signals.cpp +++ b/src/ostd/Signals.cpp @@ -18,8 +18,12 @@ namespace ostd SignalHandler::m_keyReleasedRecievers.reserve(SignalHandler::__SIGNAL_BUFFER_START_SIZE); SignalHandler::m_mouseMovedRecievers.clear(); SignalHandler::m_mouseMovedRecievers.reserve(SignalHandler::__SIGNAL_BUFFER_START_SIZE); + SignalHandler::m_mouseDraggedRecievers.clear(); + SignalHandler::m_mouseDraggedRecievers.reserve(SignalHandler::__SIGNAL_BUFFER_START_SIZE); SignalHandler::m_windowResizedRecievers.clear(); SignalHandler::m_windowResizedRecievers.reserve(SignalHandler::__SIGNAL_BUFFER_START_SIZE); + SignalHandler::m_windowClosedRecievers.clear(); + SignalHandler::m_windowClosedRecievers.reserve(SignalHandler::__SIGNAL_BUFFER_START_SIZE); SignalHandler::m_delegatedSignals.clear(); SignalHandler::m_delegatedSignals.reserve(SignalHandler::__DELEGATED_SIGNALS_BUFFER_START_SIZE); SignalHandler::m_onGuiEventRecievers.clear(); @@ -53,8 +57,12 @@ namespace ostd sig_list = &m_keyReleasedRecievers; else if (signal_id == tBuiltinSignals::MouseMoved) sig_list = &m_mouseMovedRecievers; + else if (signal_id == tBuiltinSignals::MouseDragged) + sig_list = &m_mouseDraggedRecievers; else if (signal_id == tBuiltinSignals::WindowResized) sig_list = &m_windowResizedRecievers; + else if (signal_id == tBuiltinSignals::WindowClosed) + sig_list = &m_windowClosedRecievers; else if (signal_id == tBuiltinSignals::OnGuiEvent) sig_list = &m_onGuiEventRecievers; @@ -87,8 +95,12 @@ namespace ostd m_keyReleasedRecievers.push_back({ &object, signal_id }); else if (signal_id == tBuiltinSignals::MouseMoved) m_mouseMovedRecievers.push_back({ &object, signal_id }); + else if (signal_id == tBuiltinSignals::MouseDragged) + m_mouseDraggedRecievers.push_back({ &object, signal_id }); else if (signal_id == tBuiltinSignals::WindowResized) m_windowResizedRecievers.push_back({ &object, signal_id }); + else if (signal_id == tBuiltinSignals::WindowClosed) + m_windowClosedRecievers.push_back({ &object, signal_id }); else if (signal_id == tBuiltinSignals::OnGuiEvent) m_onGuiEventRecievers.push_back({ &object, signal_id }); else if (signal_id > tBuiltinSignals::CustomSignalBase) diff --git a/src/ostd/Signals.hpp b/src/ostd/Signals.hpp index 4913890..9828761 100755 --- a/src/ostd/Signals.hpp +++ b/src/ostd/Signals.hpp @@ -22,10 +22,12 @@ namespace ostd inline static constexpr uint32_t MousePressed = 0x0003; inline static constexpr uint32_t MouseReleased = 0x0004; inline static constexpr uint32_t MouseMoved = 0x0005; + inline static constexpr uint32_t MouseDragged = 0x0006; inline static constexpr uint32_t OnGuiEvent = 0x2001; inline static constexpr uint32_t WindowResized = 0x1001; + inline static constexpr uint32_t WindowClosed = 0x1002; /*********************/ inline static constexpr uint32_t CustomSignalBase = 0xFF0000; @@ -80,7 +82,9 @@ namespace ostd inline static std::vector m_keyPressedRecievers; inline static std::vector m_keyReleasedRecievers; inline static std::vector m_mouseMovedRecievers; + inline static std::vector m_mouseDraggedRecievers; inline static std::vector m_windowResizedRecievers; + inline static std::vector m_windowClosedRecievers; inline static std::vector m_onGuiEventRecievers; /************************************/ diff --git a/src/ostd/String.cpp b/src/ostd/String.cpp index c6fa6bd..29763e7 100644 --- a/src/ostd/String.cpp +++ b/src/ostd/String.cpp @@ -8,13 +8,13 @@ namespace ostd { String String::Tokens::next(void) { - if (!hasNext()) return Tokens::END; + if (!hasNext()) return ""; //TODO: Error return m_tokens[m_current_index++]; } String String::Tokens::previous(void) { - if (!hasPrevious()) return Tokens::END; + if (!hasPrevious()) return ""; //TODO: Error return m_tokens[--m_current_index]; } @@ -162,6 +162,20 @@ namespace ostd return *this; } + String& String::fixedLength(uint32_t length, char fill_character, const String& truncate_indicator) + { + if (length < truncate_indicator.len()) return *this; + if (len() > length) + { + int32_t tr_len = truncate_indicator.len(); + substr(0, length - tr_len); + return add(truncate_indicator); + } + else if (len() < length) + return addRightPadding(length, fill_character); + return *this; + } + String& String::addChar(char c) { @@ -326,74 +340,80 @@ namespace ostd return __str.substr(start, end); } + String String::new_fixedLength(uint32_t length, char fill_character, const String& truncate_indicator) const + { + String __str = m_data; + return __str.fixedLength(length, fill_character, truncate_indicator); + } - String String::new_addChar(char c) + + String String::new_addChar(char c) const { String __str = m_data; return __str.addChar(c); } - String String::new_add(const String& se) + String String::new_add(const String& se) const { String __str = m_data; return __str.add(se); } - String String::new_add(uint8_t i) + String String::new_add(uint8_t i) const { String __str = m_data; return __str.add(i); } - String String::new_add(int8_t i) + String String::new_add(int8_t i) const { String __str = m_data; return __str.add(i); } - String String::new_add(uint16_t i) + String String::new_add(uint16_t i) const { String __str = m_data; return __str.add(i); } - String String::new_add(int16_t i) + String String::new_add(int16_t i) const { String __str = m_data; return __str.add(i); } - String String::new_add(uint32_t i) + String String::new_add(uint32_t i) const { String __str = m_data; return __str.add(i); } - String String::new_add(int32_t i) + String String::new_add(int32_t i) const { String __str = m_data; return __str.add(i); } - String String::new_add(uint64_t i) + String String::new_add(uint64_t i) const { String __str = m_data; return __str.add(i); } - String String::new_add(int64_t i) + String String::new_add(int64_t i) const { String __str = m_data; return __str.add(i); } - String String::new_add(float f, uint8_t precision) + String String::new_add(float f, uint8_t precision) const { String __str = m_data; return __str.add(f, precision); } - String String::new_add(double f, uint8_t precision) + String String::new_add(double f, uint8_t precision) const { String __str = m_data; return __str.add(f, precision); @@ -542,26 +562,6 @@ namespace ostd return String(str1) + str; } - // bool operator== (const String& str1, const char* str2) - // { - // return std::strcmp(str1.c_str(), str2) == 0; - // } - - // bool operator!= (const String& str1, const char* str2) - // { - // return std::strcmp(str1.c_str(), str2) != 0; - // } - - // bool operator== (const char* str1, const String& str2) - // { - // return std::strcmp(str1, str2.c_str()) == 0; - // } - - // bool operator!= (const char* str1, const String& str2) - // { - // return std::strcmp(str1, str2.c_str()) != 0; - // } - std::ostream& operator<<(std::ostream& out, const String& val) { out << val.cpp_str(); diff --git a/src/ostd/String.hpp b/src/ostd/String.hpp index 2ee9871..2db159f 100644 --- a/src/ostd/String.hpp +++ b/src/ostd/String.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace ostd { @@ -33,9 +34,6 @@ namespace ostd std::vector m_tokens; uint32_t m_current_index; - public: - inline static const cpp_string END = "%END%"; - friend class String; }; public: enum class ePaddingBehavior { ForceEvenPositive = 1, ForceEvenNegative, AllowOddExtraLeft, AllowOddExtraRight }; @@ -52,14 +50,13 @@ namespace ostd inline char operator[](uint32_t index) const { return m_data[index]; } inline bool operator== (const char* str2) const { return std::strcmp(c_str(), str2) == 0; } inline bool operator!= (const char* str2) const { return std::strcmp(c_str(), str2) != 0; } - // friend bool operator== (const char* str1, const String& str2); - // friend bool operator!= (const char* str1, const String& str2); inline String operator+(const String& str2) const { return m_data + str2.cpp_str(); } friend String operator+(const cpp_string& str1, const String& str); inline String& operator+=(const String& str2) { m_data += str2.cpp_str(); return *this; } inline String& operator+=(const char& c) { m_data += c; return *this; } inline operator std::string() const { return m_data; } inline operator const char*() const { return c_str(); } + inline operator std::filesystem::path() const { return cpp_str(); } inline String& clr(void) { m_data = ""; return *this; } inline String& set(const cpp_string& str) { m_data = str; return *this; } @@ -85,6 +82,7 @@ namespace ostd String& regexReplace(const String& regex_pattern, const String& replace_with, bool case_insensitive = false); String& put(uint32_t index, char c); String& substr(uint32_t start, int32_t end = -1); + String& fixedLength(uint32_t length, char fill_character = ' ', const String& truncate_indicator = "... "); String& addChar(char c); String& add(const String& se); @@ -114,19 +112,20 @@ namespace ostd String new_regexReplace(const String& regex_pattern, const String& replace_with, bool case_insensitive = false) const; String new_put(uint32_t index, char c) const; String new_substr(uint32_t start, int32_t end = -1) const; + String new_fixedLength(uint32_t length, char fill_character = ' ', const String& truncate_indicator = "... ") const; - String new_addChar(char c); - String new_add(const String& se); - String new_add(uint8_t i); - String new_add(int8_t i); - String new_add(uint16_t i); - String new_add(int16_t i); - String new_add(uint32_t i); - String new_add(int32_t i); - String new_add(uint64_t i); - String new_add(int64_t i); - String new_add(float f, uint8_t precision = 0); - String new_add(double f, uint8_t precision = 0); + String new_addChar(char c) const; + String new_add(const String& se) const; + String new_add(uint8_t i) const; + String new_add(int8_t i) const; + String new_add(uint16_t i) const; + String new_add(int16_t i) const; + String new_add(uint32_t i) const; + String new_add(int32_t i) const; + String new_add(uint64_t i) const; + String new_add(int64_t i) const; + String new_add(float f, uint8_t precision = 0) const; + String new_add(double f, uint8_t precision = 0) const; //Utility int64_t toInt(void) const; @@ -258,4 +257,16 @@ namespace ostd }; } -} \ No newline at end of file +} + + + +template <> +struct std::hash +{ + std::size_t operator()(const ostd::String& str) const + { + hash hasher; + return hasher(str.cpp_str()); + } +}; \ No newline at end of file diff --git a/src/ostd/Utils.hpp b/src/ostd/Utils.hpp index cf7a657..c80b674 100755 --- a/src/ostd/Utils.hpp +++ b/src/ostd/Utils.hpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -165,6 +166,24 @@ namespace ostd static int32_t getConsoleWidth(void); static int32_t getConsoleHeight(void); + //Array helpers + template + static inline T* createArray(size_t size) + { + T* array = (T*)malloc(size * sizeof(T)); + return array; + } + template + static inline T* resizeArray(T* array, size_t new_size) + { + T* new_array = (T*)realloc(array, new_size * sizeof(T)); + return new_array; + } + static inline void destroyArray(void* array) + { + free(array); + } + private: inline static uint64_t s_startTime_ms; }; diff --git a/src/test.cpp b/src/test.cpp index 4a64bae..1c48cd9 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -1,6 +1,7 @@ #include #include #include +#include ostd::ConsoleOutputHandler out; @@ -42,5 +43,32 @@ int main(int argc, char** argv) rgxrstr.fg("Hello", "Blue"); std::cout << rgxrstr << "\n"; + out.nl().nl(); + ostd::String test_str = "Hello World, my love"; + ostd::String test_str_2 = "HEELO"; + ostd::String test_str_3 = "0123456789"; + out.p("==========\n"); + test_str.fixedLength(10, ' ', ".........."); + test_str_2.fixedLength(10); + test_str_3.fixedLength(10); + out.p(test_str).p("|").nl(); + out.p(test_str_2).p("|").nl(); + out.p(test_str_3).p("|").nl(); + + ostd::KeyboardController keyboard; + keyboard.disableCommandBuffer(); + + out.p("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"); + out.p("HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH"); + out.p("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + out.p(" "); + out.p("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + + ostd::eKeys k = ostd::eKeys::NoKeyPressed; + do + { + k = keyboard.waitForKeyPress(); + } while (k != ostd::eKeys::Escape); + return 0; } \ No newline at end of file