[0.1.1818] - Added KeyboardController

This commit is contained in:
OmniaX 2024-01-12 17:28:45 +01:00
parent e520c829ef
commit e8849a4b49
11 changed files with 423 additions and 53 deletions

View file

@ -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

View file

@ -1 +1 @@
1808
1819

6
changelog.txt Normal file
View file

@ -0,0 +1,6 @@
[0.1.1818]
Added ostd::String::fixedLength(...) method, with corresponding 'new_fixedLength' version.
Added "KeyboardController" class to <Console.hpp> (implemented in <Keyboard.cpp>) 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

View file

@ -4,6 +4,17 @@
#include <ostd/Geometry.hpp>
#include <ostd/IOHandlers.hpp>
#include "Defines.hpp"
#include "String.hpp"
#ifndef WINDOWS_OS
#include <termios.h>
#else
#include <conio.h>
#endif
#include <vector>
#include <iostream>
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<eKeys> m_key_buff;
String m_cmd;
bool m_output_enabled;
bool m_cmd_buffer_enabled;
};
}

189
src/ostd/Keyboard.cpp Normal file
View file

@ -0,0 +1,189 @@
#include "Console.hpp"
#include <unistd.h>
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;
}
}

View file

@ -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)

View file

@ -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<tSignalObjPair> m_keyPressedRecievers;
inline static std::vector<tSignalObjPair> m_keyReleasedRecievers;
inline static std::vector<tSignalObjPair> m_mouseMovedRecievers;
inline static std::vector<tSignalObjPair> m_mouseDraggedRecievers;
inline static std::vector<tSignalObjPair> m_windowResizedRecievers;
inline static std::vector<tSignalObjPair> m_windowClosedRecievers;
inline static std::vector<tSignalObjPair> m_onGuiEventRecievers;
/************************************/

View file

@ -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();

View file

@ -2,6 +2,7 @@
#include <ostd/Types.hpp>
#include <cstring>
#include <filesystem>
namespace ostd
{
@ -33,9 +34,6 @@ namespace ostd
std::vector<String> 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
};
}
}
}
template <>
struct std::hash<ostd::String>
{
std::size_t operator()(const ostd::String& str) const
{
hash<std::string> hasher;
return hasher(str.cpp_str());
}
};

View file

@ -3,6 +3,7 @@
#include <ostd/Types.hpp>
#include <ostd/TextStyleParser.hpp>
#include <ostd/Defines.hpp>
#include <filesystem>
@ -165,6 +166,24 @@ namespace ostd
static int32_t getConsoleWidth(void);
static int32_t getConsoleHeight(void);
//Array helpers
template<typename T>
static inline T* createArray(size_t size)
{
T* array = (T*)malloc(size * sizeof(T));
return array;
}
template<typename T>
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;
};

View file

@ -1,6 +1,7 @@
#include <ostd/String.hpp>
#include <ostd/IOHandlers.hpp>
#include <ostd/Logger.hpp>
#include <ostd/Console.hpp>
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;
}