diff --git a/build_scripts/qt/sources.pri b/build_scripts/qt/sources.pri index 5279620..48cf95f 100644 --- a/build_scripts/qt/sources.pri +++ b/build_scripts/qt/sources.pri @@ -12,12 +12,12 @@ SOURCES += src/main.cpp\ src/tabcontrollers/PttController.cpp \ src/tabcontrollers/VideoTabController.cpp \ src/utils/ChaperoneUtils.cpp \ - src/tabcontrollers/audiomanager/AudioManagerDummy.cpp \ src/openvr/openvr_init.cpp \ src/openvr/ivrinput.cpp \ src/utils/setup.cpp \ src/utils/paths.cpp \ src/openvr/overlay_utils.cpp \ + src/tabcontrollers/keyboardinput/KeyboardInput.cpp \ src/keyboard_input/input_parser.cpp HEADERS += src/overlaycontroller.h \ @@ -52,15 +52,13 @@ HEADERS += src/overlaycontroller.h \ win32 { SOURCES += src/tabcontrollers/audiomanager/AudioManagerWindows.cpp \ - src/tabcontrollers/keyboardinput/KeyboardInputWindows.cpp \ src/keyboard_input/input_sender_win.cpp HEADERS += src/tabcontrollers/audiomanager/AudioManagerWindows.h } unix:!macx { !noX11 { - SOURCES += src/tabcontrollers/keyboardinput/KeyboardInputX11.cpp \ - src/keyboard_input/input_sender_X11.cpp + SOURCES += src/keyboard_input/input_sender_X11.cpp CONFIG += x11 LIBS += -lXtst } @@ -70,7 +68,6 @@ unix:!macx { } macx { - SOURCES += src/tabcontrollers/keyboardinput/KeyboardInputDummy.cpp } win32-msvc { diff --git a/src/keyboard_input/input_parser.cpp b/src/keyboard_input/input_parser.cpp index 7a573d9..7f5eff8 100644 --- a/src/keyboard_input/input_parser.cpp +++ b/src/keyboard_input/input_parser.cpp @@ -316,13 +316,74 @@ bool isModifier( const Token token ) noexcept } } +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; + + default: + return false; + } +} + bool isLiteral( const Token token ) noexcept { - if ( isalnum( static_cast( token ) ) ) + if ( isLiteralKey( token ) ) { return true; } - switch ( token ) { case Token::KEY_F1: diff --git a/src/keyboard_input/input_parser.h b/src/keyboard_input/input_parser.h index 59b2cf9..037a3bb 100644 --- a/src/keyboard_input/input_parser.h +++ b/src/keyboard_input/input_parser.h @@ -95,3 +95,4 @@ std::vector bool isModifier( const Token token ) noexcept; bool isLiteral( const Token token ) noexcept; +bool isLiteralKey( const Token token ) noexcept; diff --git a/src/keyboard_input/input_sender_X11.cpp b/src/keyboard_input/input_sender_X11.cpp index 48a7bd6..a05eb01 100644 --- a/src/keyboard_input/input_sender_X11.cpp +++ b/src/keyboard_input/input_sender_X11.cpp @@ -5,7 +5,7 @@ unsigned int tokenToKeyCode( const Token token, Display* const display ) { - if ( isalnum( static_cast( token ) ) ) + if ( isLiteralKey( token ) ) { return XKeysymToKeycode( display, static_cast( token ) ); } @@ -137,6 +137,14 @@ void sendTokensAsInput( const std::vector tokens ) } } + if ( !heldInputs.empty() ) + { + for ( const auto& h : heldInputs ) + { + sendKeyPress( h, KeyStatus::Up, display ); + } + } + XSync( display, False ); XTestGrabControl( display, False ); } diff --git a/src/keyboard_input/input_sender_win.cpp b/src/keyboard_input/input_sender_win.cpp index 64bc432..5a57faf 100644 --- a/src/keyboard_input/input_sender_win.cpp +++ b/src/keyboard_input/input_sender_win.cpp @@ -5,7 +5,7 @@ WORD convertToVirtualKeycode( const Token token ) { - if ( isalnum( static_cast( token ) ) ) + if ( isLiteralKey( token ) ) { return static_cast( VkKeyScan( static_cast( token ) ) ); } @@ -178,6 +178,15 @@ void sendTokensAsInput( const std::vector tokens ) } } + if ( !heldInputs.empty() ) + { + for ( const auto& h : heldInputs ) + { + inputs.push_back( createInputStruct( convertToVirtualKeycode( h ), + KeyStatus::Up ) ); + } + } + sendKeyboardInputRaw( inputs ); // send inputs } diff --git a/src/tabcontrollers/keyboardinput/KeyboardInput.cpp b/src/tabcontrollers/keyboardinput/KeyboardInput.cpp new file mode 100644 index 0000000..3755fc0 --- /dev/null +++ b/src/tabcontrollers/keyboardinput/KeyboardInput.cpp @@ -0,0 +1,79 @@ +#include "KeyboardInput.h" +#include "src/keyboard_input/input_sender.h" + +namespace keyboardinput +{ +void sendKeyboardInput( QString input ) +{ + sendStringAsInput( input.toStdString() ); +} + +void sendKeyboardEnter() +{ + const auto tokens = std::vector{ Token::KEY_ENTER }; + + sendTokensAsInput( tokens ); +} + +void sendKeyboardBackspace( const int count ) +{ + const auto tokens = std::vector{ Token::KEY_BACKSPACE }; + for ( int i = 0; i < count; ++i ) + { + sendTokensAsInput( tokens ); + } +} + +void sendKeyboardAltTab() +{ + const auto tokens + = std::vector{ Token::MODIFIER_ALT, Token::KEY_TAB }; + + sendTokensAsInput( tokens ); +} + +void sendKeyboardAltEnter() +{ + const auto tokens + = std::vector{ Token::MODIFIER_ALT, Token::KEY_ENTER }; + + sendTokensAsInput( tokens ); +} + +void sendKeyboardCtrlC() +{ + const auto tokens + = std::vector{ Token::MODIFIER_CTRL, Token::KEY_c }; + + sendTokensAsInput( tokens ); +} + +void sendKeyboardCtrlV() +{ + const auto tokens + = std::vector{ Token::MODIFIER_CTRL, Token::KEY_v }; + + sendTokensAsInput( tokens ); +} + +void sendMediaNextSong() +{ + // noop +} + +void sendMediaPreviousSong() +{ + // noop +} + +void sendMediaPausePlay() +{ + // noop +} + +void sendMediaStopSong() +{ + // noop +} + +} // namespace keyboardinput diff --git a/src/tabcontrollers/keyboardinput/KeyboardInputDummy.cpp b/src/tabcontrollers/keyboardinput/KeyboardInputDummy.cpp deleted file mode 100644 index 010a257..0000000 --- a/src/tabcontrollers/keyboardinput/KeyboardInputDummy.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "KeyboardInput.h" - -// Used to get the compiler to shut up about C4100: unreferenced formal -// parameter. The cast is to get GCC to shut up about it. -#define UNREFERENCED_PARAMETER( P ) static_cast( ( P ) ) - -namespace keyboardinput -{ -void sendKeyboardInput( QString input ) -{ - // noop - UNREFERENCED_PARAMETER( input ); -} - -void sendKeyboardEnter() -{ - // noop -} - -void sendKeyboardBackspace( const int count ) -{ - // noop - UNREFERENCED_PARAMETER( count ); -} - -void sendKeyboardAltTab() -{ - // noop -} - -void sendKeyboardAltEnter() -{ - // noop -} - -void sendKeyboardCtrlC() -{ - // noop -} - -void sendKeyboardCtrlV() -{ - // noop -} - -void sendMediaNextSong() -{ - // noop -} - -void sendMediaPreviousSong() -{ - // noop -} - -void sendMediaPausePlay() -{ - // noop -} - -void sendMediaStopSong() -{ - // noop -} - -} // namespace keyboardinput diff --git a/src/tabcontrollers/keyboardinput/KeyboardInputWindows.cpp b/src/tabcontrollers/keyboardinput/KeyboardInputWindows.cpp deleted file mode 100644 index ad2a1ae..0000000 --- a/src/tabcontrollers/keyboardinput/KeyboardInputWindows.cpp +++ /dev/null @@ -1,344 +0,0 @@ -#include "KeyboardInput.h" -#include -#include "easylogging++.h" - -namespace keyboardinput -{ -/*! -Fills out an INPUT struct ip with scanCode and keyup status. -*/ -void fillKiStruct( INPUT& ip, WORD scanCode, bool keyup ) -{ - ip.type = INPUT_KEYBOARD; - ip.ki.wVk = scanCode; - if ( keyup ) - { - ip.ki.dwFlags = KEYEVENTF_KEYUP; - } - else - { - ip.ki.dwFlags = 0; - } - ip.ki.wScan = 0; - ip.ki.dwExtraInfo = 0; - ip.ki.time = 0; -} - -/*! -Calls SendInput on an INPUT struct and has associated error handling. - -inputCount can't be deduced from input because of implicit conversions from -arrays to pointers when passed as arguments. -*/ -void sendKeyboardInputRaw( const int inputCount, const LPINPUT input ) -{ - const auto success - = SendInput( static_cast( inputCount ), input, sizeof( INPUT ) ); - - if ( ( inputCount > 0 ) && !success ) - { - char* err; - auto errCode = GetLastError(); - if ( !FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_SYSTEM, - nullptr, - errCode, - MAKELANGID( LANG_NEUTRAL, - SUBLANG_DEFAULT ), // default language - reinterpret_cast( &err ), - 0, - nullptr ) ) - { - LOG( ERROR ) - << "Error calling SendInput(): Could not get error message (" - << errCode << ")"; - } - else - { - LOG( ERROR ) << "Error calling SendInput(): " << err; - } - } -} - -/*! -Returns an INPUT struct with the corresponding virtualKeyCode and keyStatus set. - -All fields except ki.wVk and ki.dwFlags are zero. -The INPUT struct is used with the SendInput Windows function. -Official Docs: -https://docs.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-taginput -*/ -INPUT createInputStruct( const WORD virtualKeyCode, const KeyStatus keyStatus ) -{ - // Zero init to ensure random data doesn't muck something up. - INPUT input = {}; - - input.type = INPUT_KEYBOARD; - - input.ki.wVk = virtualKeyCode; - - if ( keyStatus == KeyStatus::Up ) - { - input.ki.dwFlags = KEYEVENTF_KEYUP; - } - else if ( keyStatus == KeyStatus::Down ) - { - // Struct is already zero initialized, but this is here for clarity. - // Compiler will likely sort this out, otherwise the performance hit is - // negligible. - // There is no corresponding KEYDOWN event, you just don't - // set KEYEVENTF_KEYUP. - input.ki.dwFlags = 0; - } - - // The sizeof(INPUT) on MSVC is 28. Returning by value is a non-issue - // compared to the simplicity of not having to pass a ref to an already - // existing INPUT struct, and possibly forgetting to zero it out. - return input; -} - -/*! -Sends a key press to Windows. The virtualKeyCode is a Windows specific define -found in . - -Virtual Key Codes offical docs: -https://docs.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-codes -*/ -void sendKeyPressAndRelease( const WORD virtualKeyCode ) -{ - const auto press = createInputStruct( virtualKeyCode, KeyStatus::Down ); - const auto release = createInputStruct( virtualKeyCode, KeyStatus::Up ); - - constexpr auto numberOfActions = 2; - - INPUT actions[numberOfActions] = { press, release }; - - sendKeyboardInputRaw( numberOfActions, actions ); -} - -void sendKeyboardInput( QString input ) -{ - int len = input.length(); - if ( len > 0 ) - { - LPINPUT ips = new INPUT[static_cast( len ) * 5 + 3]; - int ii = 0; - bool shiftPressed = false; - bool ctrlPressed = false; - bool altPressed = false; - for ( int i = 0; i < len; i++ ) - { - short tmp = VkKeyScan( input.at( i ).toLatin1() ); - WORD c = tmp & 0xFF; - short shiftState = tmp >> 8; - bool isShift = shiftState & 1; - bool isCtrl = shiftState & 2; - bool isAlt = shiftState & 4; - if ( isShift && !shiftPressed ) - { - fillKiStruct( ips[ii++], VK_SHIFT, false ); - shiftPressed = true; - } - else if ( !isShift && shiftPressed ) - { - fillKiStruct( ips[ii++], VK_SHIFT, true ); - shiftPressed = false; - } - if ( isCtrl && !ctrlPressed ) - { - fillKiStruct( ips[ii++], VK_CONTROL, false ); - ctrlPressed = true; - } - else if ( !isCtrl && ctrlPressed ) - { - fillKiStruct( ips[ii++], VK_CONTROL, true ); - ctrlPressed = false; - } - if ( isAlt && !altPressed ) - { - fillKiStruct( ips[ii++], VK_MENU, false ); - altPressed = true; - } - else if ( !isAlt && altPressed ) - { - fillKiStruct( ips[ii++], VK_MENU, true ); - altPressed = false; - } - fillKiStruct( ips[ii++], c, false ); - fillKiStruct( ips[ii++], c, true ); - } - if ( shiftPressed ) - { - fillKiStruct( ips[ii++], VK_SHIFT, true ); - shiftPressed = false; - } - if ( ctrlPressed ) - { - fillKiStruct( ips[ii++], VK_CONTROL, true ); - ctrlPressed = false; - } - if ( altPressed ) - { - fillKiStruct( ips[ii++], VK_MENU, true ); - altPressed = false; - } - - sendKeyboardInputRaw( ii, ips ); - delete[] ips; - } -} - -/*! -Sends a single Enter keypress to Windows. -*/ -void sendKeyboardEnter() -{ - sendKeyPressAndRelease( VK_RETURN ); -} - -/*! -Sends count amount of backspaces to Windows. count of 0 or below will do -nothing. -*/ -void sendKeyboardBackspace( const int count ) -{ - // We can only send a positive amount of key presses. - if ( count <= 0 ) - { - return; - } - - for ( int presses = 0; presses < count; ++presses ) - { - sendKeyPressAndRelease( VK_BACK ); - } -} - -/*! -Sends an Alt + Tab combination to Windows. - -Used for tabbing out of game windows blocking other programs on desktop while in -VR. At least one use case was tabbing out of a fullscreen game to be able to use -a music player. -*/ -void sendKeyboardAltTab() -{ - constexpr auto altKey = VK_MENU; - constexpr auto tabKey = VK_TAB; - - const auto pressAlt = createInputStruct( altKey, KeyStatus::Down ); - const auto pressTab = createInputStruct( tabKey, KeyStatus::Down ); - const auto releaseAlt = createInputStruct( altKey, KeyStatus::Up ); - const auto releaseTab = createInputStruct( tabKey, KeyStatus::Up ); - - constexpr auto numberOfActions = 4; - - INPUT actions[numberOfActions] - = { pressAlt, pressTab, releaseAlt, releaseTab }; - - sendKeyboardInputRaw( numberOfActions, actions ); -} - -/*! -Sends an Alt + Tab combination to Windows. - -Used for toggling full screen on games and various applications that appear on -the desktop. -*/ -void sendKeyboardAltEnter() -{ - constexpr auto altKey = VK_MENU; - constexpr auto enterKey = VK_RETURN; - - const auto pressAlt = createInputStruct( altKey, KeyStatus::Down ); - const auto pressEnter = createInputStruct( enterKey, KeyStatus::Down ); - const auto releaseAlt = createInputStruct( altKey, KeyStatus::Up ); - const auto releaseEnter = createInputStruct( enterKey, KeyStatus::Up ); - - constexpr auto numberOfActions = 4; - - INPUT actions[numberOfActions] - = { pressAlt, pressEnter, releaseAlt, releaseEnter }; - - sendKeyboardInputRaw( numberOfActions, actions ); -} - -/*! -Sends a Ctrl + C combination to Windows. - -Used for copy in copy-paste operations. -*/ -void sendKeyboardCtrlC() -{ - constexpr auto ctrlKey = VK_CONTROL; - constexpr auto cKey = 0x43; - - const auto pressCtrl = createInputStruct( ctrlKey, KeyStatus::Down ); - const auto pressC = createInputStruct( cKey, KeyStatus::Down ); - const auto releaseC = createInputStruct( cKey, KeyStatus::Up ); - const auto releaseCtrl = createInputStruct( ctrlKey, KeyStatus::Up ); - - constexpr auto numberOfActions = 4; - - INPUT actions[numberOfActions] - = { pressCtrl, pressC, releaseC, releaseCtrl }; - - sendKeyboardInputRaw( numberOfActions, actions ); -} - -/*! -Sends a Ctrl + V combination to Windows. - -Used for paste in copy-paste operations. -*/ -void sendKeyboardCtrlV() -{ - constexpr auto ctrlKey = VK_CONTROL; - constexpr auto vKey = 0x56; - - const auto pressCtrl = createInputStruct( ctrlKey, KeyStatus::Down ); - const auto pressV = createInputStruct( vKey, KeyStatus::Down ); - const auto releaseV = createInputStruct( vKey, KeyStatus::Up ); - const auto releaseCtrl = createInputStruct( ctrlKey, KeyStatus::Up ); - - constexpr auto numberOfActions = 4; - - INPUT actions[numberOfActions] - = { pressCtrl, pressV, releaseV, releaseCtrl }; - - sendKeyboardInputRaw( numberOfActions, actions ); -} - -/*! -Sends a media key Next Song button to Windows. -*/ -void sendMediaNextSong() -{ - sendKeyPressAndRelease( VK_MEDIA_NEXT_TRACK ); -} - -/*! -Sends a media key Previous Song button to Windows. -*/ -void sendMediaPreviousSong() -{ - sendKeyPressAndRelease( VK_MEDIA_PREV_TRACK ); -} - -/*! -Sends a media key Play/Pause button to Windows. -*/ -void sendMediaPausePlay() -{ - sendKeyPressAndRelease( VK_MEDIA_PLAY_PAUSE ); -} - -/*! -Sends a media key Stop button to Windows. -*/ -void sendMediaStopSong() -{ - sendKeyPressAndRelease( VK_MEDIA_STOP ); -} - -} // namespace keyboardinput diff --git a/src/tabcontrollers/keyboardinput/KeyboardInputX11.cpp b/src/tabcontrollers/keyboardinput/KeyboardInputX11.cpp deleted file mode 100644 index 18d3bce..0000000 --- a/src/tabcontrollers/keyboardinput/KeyboardInputX11.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "KeyboardInput.h" -#include -#include -#include -#include -#include - -namespace keyboardinput -{ -constexpr auto noModifier = 0; -void sendKeyPress( const KeySym keySymbol, const KeySym modifierSymbol ) -{ - Display* const display = XOpenDisplay( nullptr ); - - const KeyCode keycode = XKeysymToKeycode( display, keySymbol ); - if ( keycode == 0 ) - { - return; - } - - XTestGrabControl( display, True ); - - KeyCode modcode = 0; - if ( modifierSymbol != 0 ) - { - modcode = XKeysymToKeycode( display, modifierSymbol ); - XTestFakeKeyEvent( display, modcode, True, 0 ); - } - - XTestFakeKeyEvent( display, keycode, True, 0 ); - XTestFakeKeyEvent( display, keycode, False, 0 ); - - if ( modifierSymbol != 0 ) - { - XTestFakeKeyEvent( display, modcode, False, 0 ); - } - - XSync( display, False ); - XTestGrabControl( display, False ); -} - -void sendKeyboardInput( QString input ) -{ - std::vector characters = { 0 }; - for ( const auto& character : input ) - { - characters.push_back( character.toLatin1() ); - } - - for ( const auto character : characters ) - { - sendKeyPress( XStringToKeysym( &character ), noModifier ); - } -} - -void sendKeyboardEnter() -{ - sendKeyPress( XK_Return, noModifier ); -} - -void sendKeyboardBackspace( const int count ) -{ - for ( int i = 0; i < count; ++i ) - { - sendKeyPress( XK_BackSpace, noModifier ); - } -} - -void sendKeyboardAltTab() -{ - sendKeyPress( XK_Tab, XK_Alt_L ); -} - -void sendKeyboardAltEnter() -{ - sendKeyPress( XK_Return, XK_Alt_L ); -} - -void sendKeyboardCtrlC() -{ - sendKeyPress( XK_c, XK_Control_L ); -} - -void sendKeyboardCtrlV() -{ - sendKeyPress( XK_v, XK_Control_L ); -} - -void sendMediaNextSong() -{ - // noop -} - -void sendMediaPreviousSong() -{ - // noop -} - -void sendMediaPausePlay() -{ - // noop -} - -void sendMediaStopSong() -{ - // noop -} - -} // namespace keyboardinput