Files
OpenVR-AdvancedSettings-frame/src/keyboard_input/input_parser.cpp
T
ykearaandRTUnreal ca0ec3e07d Qt6 (#669)
* update qt6 upgrade progress

* add flawed addition for QRenderTarget and link needed libs

* update to better logging format

* move many assets and qml files into qrc

* get rid of deprecation messages

* remove additional deprecation notices

* make Qt6 finally render on desktop with some progress on vr

* initialize QRhi with QQuickRenderControl

* use default values to stop SegFaults

* fix compilation on windows

* add windows files for aiding in running exe

* fix formatting of testing qt.conf

* first attempt on using textures instead of files in AudioTabController

* Fix public/private access issue

---------

Co-authored-by: RTUnreal <unreal@rtinf.net>
2024-04-03 22:49:24 -05:00

561 lines
12 KiB
C++

#include "input_parser.h"
#include <QtLogging>
#include <QtDebug>
std::optional<Token> getModifier( const char& character ) noexcept
{
switch ( character )
{
case '^':
return Token::MODIFIER_CTRL;
case '*':
return Token::MODIFIER_ALT;
case '>':
return Token::MODIFIER_SHIFT;
case '#':
return Token::MODIFIER_SUPER;
default:
return std::nullopt;
}
}
std::optional<Token> getNumberOrLetter( const char& character ) noexcept
{
if ( islower( character ) || isdigit( character ) )
{
return static_cast<Token>( character );
}
return std::nullopt;
}
std::optional<Token> getFunctionNumber( const char& character ) noexcept
{
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:
qInfo() << "Unknown function key number: " << character;
return std::nullopt;
}
}
std::optional<Token> getFunctionNumberExtended( const char& character ) noexcept
{
switch ( character )
{
case '0':
return Token::KEY_F10;
case '1':
return Token::KEY_F11;
case '2':
return Token::KEY_F12;
case '3':
return Token::KEY_F13;
case '4':
return Token::KEY_F14;
case '5':
return Token::KEY_F15;
case '6':
return Token::KEY_F16;
case '7':
return Token::KEY_F17;
case '8':
return Token::KEY_F18;
case '9':
return Token::KEY_F19;
default:
qInfo() << "Unknown function key number: " << character;
return std::nullopt;
}
}
std::optional<Token> checkIfLegalCapitalLiteral( std::string input ) noexcept
{
// C++ can't do string comparisons in switches. :(
if ( input == "BACKSPACE" )
{
return Token::KEY_BACKSPACE;
}
if ( input == "SPACE" )
{
return Token::KEY_SPACE;
}
if ( input == "TAB" )
{
return Token::KEY_TAB;
}
if ( input == "ESC" )
{
return Token::KEY_ESC;
}
if ( input == "INS" )
{
return Token::KEY_INS;
}
if ( input == "DEL" )
{
return Token::KEY_DEL;
}
if ( input == "END" )
{
return Token::KEY_END;
}
if ( input == "PGDN" )
{
return Token::KEY_PGDN;
}
if ( input == "PGUP" )
{
return Token::KEY_PGUP;
}
if ( input == "CAPS" )
{
return Token::KEY_CAPS;
}
if ( input == "PRNSCRN" )
{
return Token::KEY_PRNSCRN;
}
if ( input == "PAUSE" )
{
return Token::KEY_PAUSE;
}
if ( input == "SCRLOCK" )
{
return Token::KEY_SCRLOCK;
}
if ( input == "LEFTARROW" )
{
return Token::KEY_LEFTARROW;
}
if ( input == "RIGHTARROW" )
{
return Token::KEY_RIGHTARROW;
}
if ( input == "UPARROW" )
{
return Token::KEY_UPARROW;
}
if ( input == "DOWNARROW" )
{
return Token::KEY_DOWNARROW;
}
if ( input == "KPSLASH" )
{
return Token::KEY_KPSLASH;
}
if ( input == "KPSTAR" )
{
return Token::KEY_KPSTAR;
}
if ( input == "KPMINUS" )
{
return Token::KEY_KPMINUS;
}
if ( input == "KPPLUS" )
{
return Token::KEY_KPPLUS;
}
if ( input == "ENTER" )
{
return Token::KEY_ENTER;
}
if ( input == "BACKSLASH" )
{
return Token::KEY_BACKSLASH;
}
return std::nullopt;
}
std::vector<Token>
ParseKeyboardInputsToTokens( const std::string inputs ) noexcept
{
std::vector<Token> tokens{};
for ( auto ch = inputs.begin(), end = inputs.end(); ch != 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( Token::TOKEN_NO_KEYUP_NEXT );
tokens.push_back( *c );
continue;
}
if ( isspace( *ch ) )
{
tokens.push_back( Token::TOKEN_NEW_SEQUENCE );
}
if ( !isupper( *ch ) || isspace( *ch ) )
{
qInfo() << "Unknown character found in sequence: " << *ch;
continue;
}
// Everything below is upper case
if ( *ch == 'F' )
{
++ch;
if ( ch == end )
{
break;
}
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;
}
}
else if ( *ch == 'G' )
{
++ch;
if ( ch == end )
{
break;
}
const auto token = getFunctionNumberExtended( *ch );
if ( token.has_value() )
{
tokens.push_back( *token );
continue;
}
else
{
// Spec says to abort on errors and submit correct values before
// error.
break;
}
}
std::string characters;
characters.push_back( *ch );
while ( ch + 1 != end )
{
++ch;
characters.push_back( *ch );
if ( auto c = checkIfLegalCapitalLiteral( characters );
c.has_value() )
{
tokens.push_back( *c );
characters.clear();
// break out of the while
break;
}
}
if ( ch == end )
{
break;
}
}
return tokens;
}
std::vector<Token>
removeDuplicateNewSequences( const std::vector<Token>& tokens ) noexcept
{
std::vector<Token> approvedTokens = {};
bool previouslyNewSequenceToken = false;
for ( const auto& token : tokens )
{
if ( token != Token::TOKEN_NEW_SEQUENCE )
{
previouslyNewSequenceToken = false;
}
if ( previouslyNewSequenceToken )
{
continue;
}
if ( token == Token::TOKEN_NEW_SEQUENCE )
{
previouslyNewSequenceToken = true;
}
approvedTokens.push_back( token );
}
return approvedTokens;
}
std::vector<Token>
removeTokenInSameSequence( const std::vector<Token>& tokens,
const Token tokenToRemove ) noexcept
{
std::vector<Token> approvedTokens = {};
bool tokenInSequence = false;
for ( const auto& token : tokens )
{
if ( token == Token::TOKEN_NEW_SEQUENCE )
{
tokenInSequence = false;
}
if ( tokenInSequence && ( token == tokenToRemove ) )
{
continue;
}
if ( token == tokenToRemove )
{
tokenInSequence = true;
}
approvedTokens.push_back( token );
}
return approvedTokens;
}
std::vector<Token>
removeIncorrectTokens( const std::vector<Token>& tokens ) noexcept
{
const auto spacesRemoved = removeDuplicateNewSequences( tokens );
const auto ctrlRemoved
= removeTokenInSameSequence( spacesRemoved, Token::MODIFIER_CTRL );
const auto altRemoved
= removeTokenInSameSequence( ctrlRemoved, Token::MODIFIER_ALT );
const auto shiftRemoved
= removeTokenInSameSequence( altRemoved, Token::MODIFIER_SHIFT );
const auto superRemoved
= removeTokenInSameSequence( shiftRemoved, Token::MODIFIER_SUPER );
return superRemoved;
}
bool isModifier( const Token token ) noexcept
{
switch ( token )
{
case Token::MODIFIER_CTRL:
[[fallthrough]];
case Token::MODIFIER_ALT:
[[fallthrough]];
case Token::MODIFIER_SHIFT:
[[fallthrough]];
case Token::MODIFIER_RSHIFT:
[[fallthrough]];
case Token::MODIFIER_SUPER:
[[fallthrough]];
case Token::MODIFIER_TILDE:
return true;
default:
return false;
}
}
bool isLiteralKey( const Token token ) noexcept
{
switch ( token )
{
case Token::KEY_a:
return true;
case Token::KEY_b:
return true;
case Token::KEY_c:
return true;
case Token::KEY_d:
return true;
case Token::KEY_e:
return true;
case Token::KEY_f:
return true;
case Token::KEY_g:
return true;
case Token::KEY_h:
return true;
case Token::KEY_i:
return true;
case Token::KEY_j:
return true;
case Token::KEY_k:
return true;
case Token::KEY_l:
return true;
case Token::KEY_m:
return true;
case Token::KEY_n:
return true;
case Token::KEY_o:
return true;
case Token::KEY_p:
return true;
case Token::KEY_q:
return true;
case Token::KEY_r:
return true;
case Token::KEY_s:
return true;
case Token::KEY_t:
return true;
case Token::KEY_u:
return true;
case Token::KEY_v:
return true;
case Token::KEY_w:
return true;
case Token::KEY_x:
return true;
case Token::KEY_y:
return true;
case Token::KEY_z:
return true;
case Token::KEY_0:
return true;
case Token::KEY_1:
return true;
case Token::KEY_2:
return true;
case Token::KEY_3:
return true;
case Token::KEY_4:
return true;
case Token::KEY_5:
return true;
case Token::KEY_6:
return true;
case Token::KEY_7:
return true;
case Token::KEY_8:
return true;
case Token::KEY_9:
return true;
default:
return false;
}
}
bool isLiteral( const Token token ) noexcept
{
if ( isLiteralKey( token ) )
{
return true;
}
switch ( token )
{
case Token::KEY_F1:
return true;
case Token::KEY_F2:
return true;
case Token::KEY_F3:
return true;
case Token::KEY_F4:
return true;
case Token::KEY_F5:
return true;
case Token::KEY_F6:
return true;
case Token::KEY_F7:
return true;
case Token::KEY_F8:
return true;
case Token::KEY_F9:
return true;
case Token::KEY_F10:
return true;
case Token::KEY_F11:
return true;
case Token::KEY_F12:
return true;
case Token::KEY_F13:
return true;
case Token::KEY_F14:
return true;
case Token::KEY_F15:
return true;
case Token::KEY_F16:
return true;
case Token::KEY_F17:
return true;
case Token::KEY_F18:
return true;
case Token::KEY_F19:
return true;
case Token::KEY_BACKSPACE:
return true;
case Token::KEY_SPACE:
return true;
case Token::KEY_TAB:
return true;
case Token::KEY_ESC:
return true;
case Token::KEY_INS:
return true;
case Token::KEY_DEL:
return true;
case Token::KEY_END:
return true;
case Token::KEY_PGDN:
return true;
case Token::KEY_PGUP:
return true;
case Token::KEY_CAPS:
return true;
case Token::KEY_PRNSCRN:
return true;
case Token::KEY_PAUSE:
return true;
case Token::KEY_SCRLOCK:
return true;
case Token::KEY_LEFTARROW:
return true;
case Token::KEY_RIGHTARROW:
return true;
case Token::KEY_UPARROW:
return true;
case Token::KEY_DOWNARROW:
return true;
case Token::KEY_KPSLASH:
return true;
case Token::KEY_KPSTAR:
return true;
case Token::KEY_KPMINUS:
return true;
case Token::KEY_KPPLUS:
return true;
case Token::KEY_ENTER:
return true;
case Token::KEY_BACKSLASH:
return true;
default:
return false;
}
}