diff --git a/build_scripts/qt/sources.pri b/build_scripts/qt/sources.pri index bed2abb..7866f56 100644 --- a/build_scripts/qt/sources.pri +++ b/build_scripts/qt/sources.pri @@ -17,7 +17,8 @@ SOURCES += src/main.cpp\ src/openvr/ivrinput.cpp \ src/utils/setup.cpp \ src/utils/paths.cpp \ - src/openvr/overlay_utils.cpp + src/openvr/overlay_utils.cpp \ + src/keyboard_input/input_parser.cpp HEADERS += src/overlaycontroller.h \ src/tabcontrollers/AudioTabController.h \ @@ -45,7 +46,8 @@ HEADERS += src/overlaycontroller.h \ src/openvr/ivrinput.h \ src/utils/setup.h \ src/utils/paths.h \ - src/openvr/overlay_utils.h + src/openvr/overlay_utils.h \ + src/keyboard_input/input_parser.h win32 { SOURCES += src/tabcontrollers/audiomanager/AudioManagerWindows.cpp \ diff --git a/src/keyboard_input/input_parser.cpp b/src/keyboard_input/input_parser.cpp new file mode 100644 index 0000000..da4692f --- /dev/null +++ b/src/keyboard_input/input_parser.cpp @@ -0,0 +1,103 @@ +#include "input_parser.h" + +std::optional getModifier( const char& character ) +{ + switch ( character ) + { + case '^': + return Token::MODIFIER_CTRL; + case '*': + return Token::MODIFIER_ALT; + case '>': + return Token::MODIFIER_SHIFT; + case '/': + return Token::MODIFIER_ALTGR; + case '#': + return Token::MODIFIER_SUPER; + default: + return std::nullopt; + } +} + +std::optional getNumberOrLetter( const char& character ) +{ + if ( islower( character ) || isdigit( character ) ) + { + return static_cast( character ); + } + return std::nullopt; +} + +std::optional getFunctionNumber( const char& character ) +{ + switch ( character ) + { + case '1': + return Token::KEY_F1; + case '2': + return Token::KEY_F2; + case '3': + return Token::KEY_F3; + case '4': + return Token::KEY_F4; + case '5': + return Token::KEY_F5; + case '6': + return Token::KEY_F6; + case '7': + return Token::KEY_F7; + case '8': + return Token::KEY_F8; + case '9': + return Token::KEY_F9; + + default: + // LOG incorrect character + return std::nullopt; + } +} + +std::vector ParseKeyboardInputsToTokens( const std::string inputs ) +{ + std::vector tokens{}; + + for ( auto ch = inputs.begin(); ch != inputs.end(); ++ch ) + { + if ( const auto c = getNumberOrLetter( *ch ); c.has_value() ) + { + tokens.push_back( *c ); + continue; + } + if ( const auto c = getModifier( *ch ); c.has_value() ) + { + tokens.push_back( *c ); + continue; + } + + if ( !isupper( *ch ) ) + { + // LOG incorrect character + continue; + } + // Everything below is upper case + + if ( *ch == 'F' ) + { + ++ch; + const auto token = getFunctionNumber( *ch ); + if ( token.has_value() ) + { + tokens.push_back( *token ); + continue; + } + else + { + // Spec says to abort on errors and submit correct values before + // error. + break; + } + } + } + + return tokens; +} diff --git a/src/keyboard_input/input_parser.h b/src/keyboard_input/input_parser.h new file mode 100644 index 0000000..01b39e0 --- /dev/null +++ b/src/keyboard_input/input_parser.h @@ -0,0 +1,91 @@ +#pragma once +#include +#include +#include +#include + +enum class Token +{ + // Literals + KEY_a = 'a', + KEY_b = 'b', + KEY_c = 'c', + KEY_d = 'd', + KEY_e = 'e', + KEY_f = 'f', + KEY_g = 'g', + KEY_h = 'h', + KEY_i = 'i', + KEY_j = 'j', + KEY_k = 'k', + KEY_l = 'l', + KEY_m = 'm', + KEY_n = 'n', + KEY_o = 'o', + KEY_p = 'p', + KEY_q = 'q', + KEY_r = 'r', + KEY_s = 's', + KEY_t = 't', + KEY_u = 'u', + KEY_v = 'v', + KEY_w = 'w', + KEY_x = 'x', + KEY_y = 'y', + KEY_z = 'z', + + KEY_0 = '0', + KEY_1 = '1', + KEY_2 = '2', + KEY_3 = '3', + KEY_4 = '4', + KEY_5 = '5', + KEY_6 = '6', + KEY_7 = '7', + KEY_8 = '8', + KEY_9 = '9', + + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + + KEY_BACKSPACE, + KEY_SPACE, + KEY_TAB, + KEY_ESC, + KEY_INS, + KEY_DEL, + KEY_END, + KEY_PGDN, + KEY_PGUP, + KEY_CAPS, + KEY_PRNSCRN, + KEY_PAUSE, + KEY_SCRLOCK, + KEY_LEFTARROW, + KEY_RIGHTARROW, + KEY_UPARROW, + KEY_DOWNARROW, + KEY_KPSLASH, + KEY_KPSTAR, + KEY_KPMINUS, + KEY_KPPLUS, + + // Misc tokens + TOKEN_NEW_SEQUENCE, + + // Modifiers + MODIFIER_CTRL, + MODIFIER_ALT, + MODIFIER_SHIFT, + MODIFIER_ALTGR, + MODIFIER_SUPER, +}; + +std::vector ParseKeyboardInputsToTokens( std::string inputs ); diff --git a/test/keyboard_input/keyboard_input.pro b/test/keyboard_input/keyboard_input.pro new file mode 100644 index 0000000..e3adecb --- /dev/null +++ b/test/keyboard_input/keyboard_input.pro @@ -0,0 +1,16 @@ +QT += testlib +QT -= gui +CONFIG += c++1z + +CONFIG += qt console warn_on depend_includepath testcase +CONFIG -= app_bundle + +TEMPLATE = app + +INCLUDEPATH += ../../src/keyboard_input + +SOURCES += tst_parsertest.cpp \ + ../../src/keyboard_input/input_parser.cpp + +HEADERS += \ + ../../src/keyboard_input/input_parser.h diff --git a/test/keyboard_input/tst_parsertest.cpp b/test/keyboard_input/tst_parsertest.cpp new file mode 100644 index 0000000..7c73dce --- /dev/null +++ b/test/keyboard_input/tst_parsertest.cpp @@ -0,0 +1,169 @@ +#include +#include +#include "input_parser.h" + +// add necessary includes here + +class ParserTest : public QObject +{ + Q_OBJECT + +private slots: + void singleCharacters(); + void singleCharactersShouldFail(); + + void severalCharacters(); + void severalCharactersShouldFail(); + + void singleDigit(); + void singleDigitShouldFail(); + + void severalDigits(); + void severalDigitsShouldFail(); + + void Modifiers(); + + void functionKeys(); +}; + +const std::string alphabet = "abcdefghijklmnopqrstuvxyz"; +const std::string digits = "0123456789"; + +void ParserTest::singleCharacters() +{ + for ( const auto letter : alphabet ) + { + const auto l = std::string( &letter ); + const auto t = std::vector( { static_cast( letter ) } ); + QCOMPARE( ParseKeyboardInputsToTokens( l ), t ); + } +} + +void ParserTest::singleCharactersShouldFail() +{ + for ( const auto letter : alphabet ) + { + const auto l = std::string( &letter ); + const auto t + = std::vector( { static_cast( letter + 1 ) } ); + QVERIFY( ParseKeyboardInputsToTokens( l ) != t ); + } +} + +void ParserTest::severalCharacters() +{ + const auto tokens = ParseKeyboardInputsToTokens( "mad" ); + const auto e + = std::vector( { Token::KEY_m, Token::KEY_a, Token::KEY_d } ); + QCOMPARE( tokens, e ); +} + +void ParserTest::severalCharactersShouldFail() +{ + const auto tokens = ParseKeyboardInputsToTokens( "mad" ); + const auto e + = std::vector( { Token::KEY_m, Token::KEY_e, Token::KEY_d } ); + QVERIFY( tokens != e ); +} + +void ParserTest::singleDigit() +{ + for ( const auto n : digits ) + { + const auto l = std::string( &n ); + const auto t = std::vector( { static_cast( n ) } ); + QCOMPARE( ParseKeyboardInputsToTokens( l ), t ); + } +} + +void ParserTest::singleDigitShouldFail() +{ + for ( const auto n : digits ) + { + const auto l = std::string( &n ); + const auto t = std::vector( { static_cast( n + 1 ) } ); + QVERIFY( ParseKeyboardInputsToTokens( l ) != t ); + } +} + +void ParserTest::severalDigits() +{ + const auto t = ParseKeyboardInputsToTokens( "123" ); + const auto e + = std::vector( { Token::KEY_1, Token::KEY_2, Token::KEY_3 } ); + QVERIFY( t == e ); +} + +void ParserTest::severalDigitsShouldFail() +{ + const auto t = ParseKeyboardInputsToTokens( "123" ); + const auto e + = std::vector( { Token::KEY_1, Token::KEY_3, Token::KEY_2 } ); + QVERIFY( t != e ); +} + +void ParserTest::Modifiers() +{ + auto t = ParseKeyboardInputsToTokens( "^" ); + auto e = std::vector( { Token::MODIFIER_CTRL } ); + QVERIFY( t == e ); + + t = ParseKeyboardInputsToTokens( "*" ); + e = std::vector( { Token::MODIFIER_ALT } ); + QVERIFY( t == e ); + + t = ParseKeyboardInputsToTokens( ">" ); + e = std::vector( { Token::MODIFIER_SHIFT } ); + QVERIFY( t == e ); + + t = ParseKeyboardInputsToTokens( "/" ); + e = std::vector( { Token::MODIFIER_ALTGR } ); + QVERIFY( t == e ); + + t = ParseKeyboardInputsToTokens( "#" ); + e = std::vector( { Token::MODIFIER_SUPER } ); + QVERIFY( t == e ); +} + +void ParserTest::functionKeys() +{ + auto t = ParseKeyboardInputsToTokens( "F1" ); + auto e = std::vector( { Token::KEY_F1 } ); + QVERIFY( t == e ); + + t = ParseKeyboardInputsToTokens( "F2" ); + e = std::vector( { Token::KEY_F2 } ); + QVERIFY( t == e ); + + t = ParseKeyboardInputsToTokens( "F3" ); + e = std::vector( { Token::KEY_F3 } ); + QVERIFY( t == e ); + + t = ParseKeyboardInputsToTokens( "F4" ); + e = std::vector( { Token::KEY_F4 } ); + QVERIFY( t == e ); + + t = ParseKeyboardInputsToTokens( "F5" ); + e = std::vector( { Token::KEY_F5 } ); + QVERIFY( t == e ); + + t = ParseKeyboardInputsToTokens( "F6" ); + e = std::vector( { Token::KEY_F6 } ); + QVERIFY( t == e ); + + t = ParseKeyboardInputsToTokens( "F7" ); + e = std::vector( { Token::KEY_F7 } ); + QVERIFY( t == e ); + + t = ParseKeyboardInputsToTokens( "F8" ); + e = std::vector( { Token::KEY_F8 } ); + QVERIFY( t == e ); + + t = ParseKeyboardInputsToTokens( "F9" ); + e = std::vector( { Token::KEY_F9 } ); + QVERIFY( t == e ); +} + +QTEST_APPLESS_MAIN( ParserTest ) + +#include "tst_parsertest.moc"