Add initial keyboard_input parser and tests

The current implementation SEGFAULTs when F characters are followed by
end of string.
This commit is contained in:
Vasily
2019-05-25 18:49:42 +02:00
committed by username223
parent 49b16ebc8f
commit d6c7b52a47
5 changed files with 383 additions and 2 deletions
+4 -2
View File
@@ -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 \
+103
View File
@@ -0,0 +1,103 @@
#include "input_parser.h"
std::optional<Token> 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<Token> getNumberOrLetter( const char& character )
{
if ( islower( character ) || isdigit( character ) )
{
return static_cast<Token>( character );
}
return std::nullopt;
}
std::optional<Token> 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<Token> ParseKeyboardInputsToTokens( const std::string inputs )
{
std::vector<Token> 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;
}
+91
View File
@@ -0,0 +1,91 @@
#pragma once
#include <string>
#include <vector>
#include <cctype>
#include <optional>
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<Token> ParseKeyboardInputsToTokens( std::string inputs );
+16
View File
@@ -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
+169
View File
@@ -0,0 +1,169 @@
#include <QtTest>
#include <QDebug>
#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<Token>( { static_cast<Token>( letter ) } );
QCOMPARE( ParseKeyboardInputsToTokens( l ), t );
}
}
void ParserTest::singleCharactersShouldFail()
{
for ( const auto letter : alphabet )
{
const auto l = std::string( &letter );
const auto t
= std::vector<Token>( { static_cast<Token>( letter + 1 ) } );
QVERIFY( ParseKeyboardInputsToTokens( l ) != t );
}
}
void ParserTest::severalCharacters()
{
const auto tokens = ParseKeyboardInputsToTokens( "mad" );
const auto e
= std::vector<Token>( { 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>( { 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<Token>( { static_cast<Token>( n ) } );
QCOMPARE( ParseKeyboardInputsToTokens( l ), t );
}
}
void ParserTest::singleDigitShouldFail()
{
for ( const auto n : digits )
{
const auto l = std::string( &n );
const auto t = std::vector<Token>( { static_cast<Token>( n + 1 ) } );
QVERIFY( ParseKeyboardInputsToTokens( l ) != t );
}
}
void ParserTest::severalDigits()
{
const auto t = ParseKeyboardInputsToTokens( "123" );
const auto e
= std::vector<Token>( { 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>( { Token::KEY_1, Token::KEY_3, Token::KEY_2 } );
QVERIFY( t != e );
}
void ParserTest::Modifiers()
{
auto t = ParseKeyboardInputsToTokens( "^" );
auto e = std::vector<Token>( { Token::MODIFIER_CTRL } );
QVERIFY( t == e );
t = ParseKeyboardInputsToTokens( "*" );
e = std::vector<Token>( { Token::MODIFIER_ALT } );
QVERIFY( t == e );
t = ParseKeyboardInputsToTokens( ">" );
e = std::vector<Token>( { Token::MODIFIER_SHIFT } );
QVERIFY( t == e );
t = ParseKeyboardInputsToTokens( "/" );
e = std::vector<Token>( { Token::MODIFIER_ALTGR } );
QVERIFY( t == e );
t = ParseKeyboardInputsToTokens( "#" );
e = std::vector<Token>( { Token::MODIFIER_SUPER } );
QVERIFY( t == e );
}
void ParserTest::functionKeys()
{
auto t = ParseKeyboardInputsToTokens( "F1" );
auto e = std::vector<Token>( { Token::KEY_F1 } );
QVERIFY( t == e );
t = ParseKeyboardInputsToTokens( "F2" );
e = std::vector<Token>( { Token::KEY_F2 } );
QVERIFY( t == e );
t = ParseKeyboardInputsToTokens( "F3" );
e = std::vector<Token>( { Token::KEY_F3 } );
QVERIFY( t == e );
t = ParseKeyboardInputsToTokens( "F4" );
e = std::vector<Token>( { Token::KEY_F4 } );
QVERIFY( t == e );
t = ParseKeyboardInputsToTokens( "F5" );
e = std::vector<Token>( { Token::KEY_F5 } );
QVERIFY( t == e );
t = ParseKeyboardInputsToTokens( "F6" );
e = std::vector<Token>( { Token::KEY_F6 } );
QVERIFY( t == e );
t = ParseKeyboardInputsToTokens( "F7" );
e = std::vector<Token>( { Token::KEY_F7 } );
QVERIFY( t == e );
t = ParseKeyboardInputsToTokens( "F8" );
e = std::vector<Token>( { Token::KEY_F8 } );
QVERIFY( t == e );
t = ParseKeyboardInputsToTokens( "F9" );
e = std::vector<Token>( { Token::KEY_F9 } );
QVERIFY( t == e );
}
QTEST_APPLESS_MAIN( ParserTest )
#include "tst_parsertest.moc"