Compare commits

...

2 commits

Author SHA1 Message Date
f78a63ab75 Add runtime input toggles and gated input sending
Some checks are pending
Build / setup (push) Waiting to run
Build / build-appimage (push) Blocked by required conditions
Build / build-steamlink (push) Blocked by required conditions
Build / build-windows-macos (push) Blocked by required conditions
2026-02-11 17:18:53 -07:00
f426032b1b Ignore local qmake and build outputs 2026-02-11 17:18:53 -07:00
10 changed files with 337 additions and 68 deletions

25
.gitignore vendored
View file

@ -4,5 +4,30 @@
**/.vs/ **/.vs/
.vscode/ .vscode/
build/ build/
.qmake.cache
.qmake.stash
/Makefile
/config.log
/config.tests/
/app/Makefile
/app/Makefile.Debug
/app/Makefile.Release
/app/release/
/app/moonlight
/h264bitstream/Makefile
/h264bitstream/Makefile.Debug
/h264bitstream/Makefile.Release
/h264bitstream/release/
/h264bitstream/libh264bitstream.a
/moonlight-common-c/Makefile
/moonlight-common-c/Makefile.Debug
/moonlight-common-c/Makefile.Release
/moonlight-common-c/release/
/moonlight-common-c/libmoonlight-common-c.a
/qmdnsengine/Makefile
/qmdnsengine/Makefile.Debug
/qmdnsengine/Makefile.Release
/qmdnsengine/release/
/qmdnsengine/libqmdnsengine.a
config.tests/*/.qmake.stash config.tests/*/.qmake.stash
config.tests/*/Makefile config.tests/*/Makefile

View file

@ -1,4 +1,5 @@
#include "input.h" #include "input.h"
#include "streaming/session.h"
#include <Limelight.h> #include <Limelight.h>
#include "SDL_compat.h" #include "SDL_compat.h"
@ -7,6 +8,12 @@
#include <QtMath> #include <QtMath>
static bool isKeyboardMouseInputAllowed()
{
auto session = Session::get();
return session == nullptr || session->isKeyboardMouseInputAllowed();
}
// How long the fingers must be stationary to start a right click // How long the fingers must be stationary to start a right click
#define LONG_PRESS_ACTIVATION_DELAY 650 #define LONG_PRESS_ACTIVATION_DELAY 650
@ -22,8 +29,10 @@
Uint32 SdlInputHandler::longPressTimerCallback(Uint32, void*) Uint32 SdlInputHandler::longPressTimerCallback(Uint32, void*)
{ {
// Raise the left click and start a right click // Raise the left click and start a right click
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT); LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
}
return 0; return 0;
} }
@ -110,7 +119,7 @@ void SdlInputHandler::handleAbsoluteFingerEvent(SDL_TouchFingerEvent* event)
} }
// Try to send it as a native pen/touch event, otherwise fall back to our touch emulation // Try to send it as a native pen/touch event, otherwise fall back to our touch emulation
if (LiGetHostFeatureFlags() & LI_FF_PEN_TOUCH_EVENTS) { if (isKeyboardMouseInputAllowed() && (LiGetHostFeatureFlags() & LI_FF_PEN_TOUCH_EVENTS)) {
#if SDL_VERSION_ATLEAST(2, 0, 22) #if SDL_VERSION_ATLEAST(2, 0, 22)
bool isPen = false; bool isPen = false;
@ -197,7 +206,9 @@ void SdlInputHandler::emulateAbsoluteFingerEvent(SDL_TouchFingerEvent* event)
short y = qMin(qMax((int)(event->y * windowHeight), dst.y), dst.y + dst.h); short y = qMin(qMax((int)(event->y * windowHeight), dst.y), dst.y + dst.h);
// Update the cursor position relative to the video region // Update the cursor position relative to the video region
LiSendMousePositionEvent(x - dst.x, y - dst.y, dst.w, dst.h); if (isKeyboardMouseInputAllowed()) {
LiSendMousePositionEvent(x - dst.x, y - dst.y, dst.w, dst.h);
}
} }
if (event->type == SDL_FINGERDOWN) { if (event->type == SDL_FINGERDOWN) {
@ -210,7 +221,9 @@ void SdlInputHandler::emulateAbsoluteFingerEvent(SDL_TouchFingerEvent* event)
nullptr); nullptr);
// Left button down on finger down // Left button down on finger down
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
}
} }
else if (event->type == SDL_FINGERUP) { else if (event->type == SDL_FINGERUP) {
m_LastTouchUpEvent = *event; m_LastTouchUpEvent = *event;
@ -220,9 +233,13 @@ void SdlInputHandler::emulateAbsoluteFingerEvent(SDL_TouchFingerEvent* event)
m_LongPressTimer = 0; m_LongPressTimer = 0;
// Left button up on finger up // Left button up on finger up
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
}
// Raise right button too in case we triggered a long press gesture // Raise right button too in case we triggered a long press gesture
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
}
} }
} }

View file

@ -6,6 +6,18 @@
#include <QtMath> #include <QtMath>
static bool isGamepadInputAllowed()
{
auto session = Session::get();
return session == nullptr || session->isGamepadInputAllowed();
}
static bool isKeyboardMouseInputAllowed()
{
auto session = Session::get();
return session == nullptr || session->isKeyboardMouseInputAllowed();
}
// How long the Start button must be pressed to toggle mouse emulation // How long the Start button must be pressed to toggle mouse emulation
#define MOUSE_EMULATION_LONG_PRESS_TIME 750 #define MOUSE_EMULATION_LONG_PRESS_TIME 750
@ -101,15 +113,17 @@ void SdlInputHandler::sendGamepadState(GamepadState* state)
} }
} }
LiSendMultiControllerEvent(state->index, if (isGamepadInputAllowed()) {
m_GamepadMask, LiSendMultiControllerEvent(state->index,
buttons, m_GamepadMask,
lt, buttons,
rt, lt,
lsX, rt,
lsY, lsX,
rsX, lsY,
rsY); rsX,
rsY);
}
} }
void SdlInputHandler::sendGamepadBatteryState(GamepadState* state, SDL_JoystickPowerLevel level) void SdlInputHandler::sendGamepadBatteryState(GamepadState* state, SDL_JoystickPowerLevel level)
@ -150,7 +164,9 @@ void SdlInputHandler::sendGamepadBatteryState(GamepadState* state, SDL_JoystickP
return; return;
} }
LiSendControllerBatteryEvent(state->index, batteryState, batteryPercentage); if (isGamepadInputAllowed()) {
LiSendControllerBatteryEvent(state->index, batteryState, batteryPercentage);
}
} }
Uint32 SdlInputHandler::mouseEmulationTimerCallback(Uint32 interval, void *param) Uint32 SdlInputHandler::mouseEmulationTimerCallback(Uint32 interval, void *param)
@ -181,7 +197,7 @@ Uint32 SdlInputHandler::mouseEmulationTimerCallback(Uint32 interval, void *param
deltaX = qAbs(deltaX) > MOUSE_EMULATION_DEADZONE ? deltaX - MOUSE_EMULATION_DEADZONE : 0; deltaX = qAbs(deltaX) > MOUSE_EMULATION_DEADZONE ? deltaX - MOUSE_EMULATION_DEADZONE : 0;
deltaY = qAbs(deltaY) > MOUSE_EMULATION_DEADZONE ? deltaY - MOUSE_EMULATION_DEADZONE : 0; deltaY = qAbs(deltaY) > MOUSE_EMULATION_DEADZONE ? deltaY - MOUSE_EMULATION_DEADZONE : 0;
if (deltaX != 0 || deltaY != 0) { if ((deltaX != 0 || deltaY != 0) && isKeyboardMouseInputAllowed()) {
LiSendMouseMoveEvent((short)deltaX, (short)deltaY); LiSendMouseMoveEvent((short)deltaX, (short)deltaY);
} }
@ -291,31 +307,49 @@ void SdlInputHandler::handleControllerButtonEvent(SDL_ControllerButtonEvent* eve
} }
else if (state->mouseEmulationTimer != 0) { else if (state->mouseEmulationTimer != 0) {
if (event->button == SDL_CONTROLLER_BUTTON_A) { if (event->button == SDL_CONTROLLER_BUTTON_A) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
}
} }
else if (event->button == SDL_CONTROLLER_BUTTON_B) { else if (event->button == SDL_CONTROLLER_BUTTON_B) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
}
} }
else if (event->button == SDL_CONTROLLER_BUTTON_X) { else if (event->button == SDL_CONTROLLER_BUTTON_X) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_MIDDLE); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_MIDDLE);
}
} }
else if (event->button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) { else if (event->button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_X1); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_X1);
}
} }
else if (event->button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) { else if (event->button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_X2); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_X2);
}
} }
else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_UP) { else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_UP) {
LiSendScrollEvent(1); if (isKeyboardMouseInputAllowed()) {
LiSendScrollEvent(1);
}
} }
else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) {
LiSendScrollEvent(-1); if (isKeyboardMouseInputAllowed()) {
LiSendScrollEvent(-1);
}
} }
else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) {
LiSendHScrollEvent(1); if (isKeyboardMouseInputAllowed()) {
LiSendHScrollEvent(1);
}
} }
else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) { else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) {
LiSendHScrollEvent(-1); if (isKeyboardMouseInputAllowed()) {
LiSendHScrollEvent(-1);
}
} }
} }
} }
@ -346,19 +380,29 @@ void SdlInputHandler::handleControllerButtonEvent(SDL_ControllerButtonEvent* eve
} }
else if (state->mouseEmulationTimer != 0) { else if (state->mouseEmulationTimer != 0) {
if (event->button == SDL_CONTROLLER_BUTTON_A) { if (event->button == SDL_CONTROLLER_BUTTON_A) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
}
} }
else if (event->button == SDL_CONTROLLER_BUTTON_B) { else if (event->button == SDL_CONTROLLER_BUTTON_B) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
}
} }
else if (event->button == SDL_CONTROLLER_BUTTON_X) { else if (event->button == SDL_CONTROLLER_BUTTON_X) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_MIDDLE); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_MIDDLE);
}
} }
else if (event->button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) { else if (event->button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_X1); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_X1);
}
} }
else if (event->button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) { else if (event->button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_X2); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_X2);
}
} }
} }
} }
@ -375,8 +419,10 @@ void SdlInputHandler::handleControllerButtonEvent(SDL_ControllerButtonEvent* eve
SDL_PushEvent(&event); SDL_PushEvent(&event);
// Clear buttons down on this gamepad // Clear buttons down on this gamepad
LiSendMultiControllerEvent(state->index, m_GamepadMask, if (isGamepadInputAllowed()) {
0, 0, 0, 0, 0, 0, 0); LiSendMultiControllerEvent(state->index, m_GamepadMask,
0, 0, 0, 0, 0, 0, 0);
}
return; return;
} }
@ -390,8 +436,41 @@ void SdlInputHandler::handleControllerButtonEvent(SDL_ControllerButtonEvent* eve
!Session::get()->getOverlayManager().isOverlayEnabled(Overlay::OverlayDebug)); !Session::get()->getOverlayManager().isOverlayEnabled(Overlay::OverlayDebug));
// Clear buttons down on this gamepad // Clear buttons down on this gamepad
LiSendMultiControllerEvent(state->index, m_GamepadMask, if (isGamepadInputAllowed()) {
0, 0, 0, 0, 0, 0, 0); LiSendMultiControllerEvent(state->index, m_GamepadMask,
0, 0, 0, 0, 0, 0, 0);
}
return;
}
if (state->buttons == (BACK_FLAG | LB_FLAG | RB_FLAG | Y_FLAG)) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Detected keyboard/mouse input toggle gamepad combo");
Session::get()->toggleKeyboardMouseInputAllowed();
if (isGamepadInputAllowed()) {
LiSendMultiControllerEvent(state->index, m_GamepadMask,
0, 0, 0, 0, 0, 0, 0);
}
return;
}
if (state->buttons == (BACK_FLAG | LB_FLAG | RB_FLAG | A_FLAG)) {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Detected gamepad input toggle gamepad combo");
bool gamepadWasEnabled = isGamepadInputAllowed();
if (gamepadWasEnabled) {
LiSendMultiControllerEvent(state->index, m_GamepadMask,
0, 0, 0, 0, 0, 0, 0);
}
Session::get()->toggleGamepadInputAllowed();
if (isGamepadInputAllowed()) {
LiSendMultiControllerEvent(state->index, m_GamepadMask,
0, 0, 0, 0, 0, 0, 0);
}
return; return;
} }
@ -418,7 +497,9 @@ void SdlInputHandler::handleControllerSensorEvent(SDL_ControllerSensorEvent* eve
memcpy(state->lastAccelEventData, event->data, sizeof(event->data)); memcpy(state->lastAccelEventData, event->data, sizeof(event->data));
state->lastAccelEventTime = event->timestamp; state->lastAccelEventTime = event->timestamp;
LiSendControllerMotionEvent((uint8_t)state->index, LI_MOTION_TYPE_ACCEL, event->data[0], event->data[1], event->data[2]); if (isGamepadInputAllowed()) {
LiSendControllerMotionEvent((uint8_t)state->index, LI_MOTION_TYPE_ACCEL, event->data[0], event->data[1], event->data[2]);
}
} }
break; break;
case SDL_SENSOR_GYRO: case SDL_SENSOR_GYRO:
@ -429,10 +510,12 @@ void SdlInputHandler::handleControllerSensorEvent(SDL_ControllerSensorEvent* eve
state->lastGyroEventTime = event->timestamp; state->lastGyroEventTime = event->timestamp;
// Convert rad/s to deg/s // Convert rad/s to deg/s
LiSendControllerMotionEvent((uint8_t)state->index, LI_MOTION_TYPE_GYRO, if (isGamepadInputAllowed()) {
event->data[0] * 57.2957795f, LiSendControllerMotionEvent((uint8_t)state->index, LI_MOTION_TYPE_GYRO,
event->data[1] * 57.2957795f, event->data[0] * 57.2957795f,
event->data[2] * 57.2957795f); event->data[1] * 57.2957795f,
event->data[2] * 57.2957795f);
}
} }
break; break;
} }
@ -460,7 +543,9 @@ void SdlInputHandler::handleControllerTouchpadEvent(SDL_ControllerTouchpadEvent*
return; return;
} }
LiSendControllerTouchEvent((uint8_t)state->index, eventType, event->finger, event->x, event->y, event->pressure); if (isGamepadInputAllowed()) {
LiSendControllerTouchEvent((uint8_t)state->index, eventType, event->finger, event->x, event->y, event->pressure);
}
} }
#endif #endif
@ -708,7 +793,9 @@ void SdlInputHandler::handleControllerDeviceEvent(SDL_ControllerDeviceEvent* eve
#endif #endif
type == LI_CTYPE_PS; type == LI_CTYPE_PS;
LiSendControllerArrivalEvent(state->index, m_GamepadMask, type, supportedButtonFlags, capabilities); if (isGamepadInputAllowed()) {
LiSendControllerArrivalEvent(state->index, m_GamepadMask, type, supportedButtonFlags, capabilities);
}
#else #else
// Send an empty event to tell the PC we've arrived // Send an empty event to tell the PC we've arrived
@ -750,8 +837,10 @@ void SdlInputHandler::handleControllerDeviceEvent(SDL_ControllerDeviceEvent* eve
state->index); state->index);
// Send a final event to let the PC know this gamepad is gone // Send a final event to let the PC know this gamepad is gone
LiSendMultiControllerEvent(state->index, m_GamepadMask, if (isGamepadInputAllowed()) {
0, 0, 0, 0, 0, 0, 0); LiSendMultiControllerEvent(state->index, m_GamepadMask,
0, 0, 0, 0, 0, 0, 0);
}
// Clear all remaining state from this slot // Clear all remaining state from this slot
SDL_memset(state, 0, sizeof(*state)); SDL_memset(state, 0, sizeof(*state));

View file

@ -106,6 +106,16 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, int streamWidth, i
m_SpecialKeyCombos[KeyComboPasteText].scanCode = SDL_SCANCODE_V; m_SpecialKeyCombos[KeyComboPasteText].scanCode = SDL_SCANCODE_V;
m_SpecialKeyCombos[KeyComboPasteText].enabled = true; m_SpecialKeyCombos[KeyComboPasteText].enabled = true;
m_SpecialKeyCombos[KeyComboToggleKeyboardMouseInput].keyCombo = KeyComboToggleKeyboardMouseInput;
m_SpecialKeyCombos[KeyComboToggleKeyboardMouseInput].keyCode = SDLK_k;
m_SpecialKeyCombos[KeyComboToggleKeyboardMouseInput].scanCode = SDL_SCANCODE_K;
m_SpecialKeyCombos[KeyComboToggleKeyboardMouseInput].enabled = true;
m_SpecialKeyCombos[KeyComboToggleGamepadInput].keyCombo = KeyComboToggleGamepadInput;
m_SpecialKeyCombos[KeyComboToggleGamepadInput].keyCode = SDLK_g;
m_SpecialKeyCombos[KeyComboToggleGamepadInput].scanCode = SDL_SCANCODE_G;
m_SpecialKeyCombos[KeyComboToggleGamepadInput].enabled = true;
m_SpecialKeyCombos[KeyComboTogglePointerRegionLock].keyCombo = KeyComboTogglePointerRegionLock; m_SpecialKeyCombos[KeyComboTogglePointerRegionLock].keyCombo = KeyComboTogglePointerRegionLock;
m_SpecialKeyCombos[KeyComboTogglePointerRegionLock].keyCode = SDLK_l; m_SpecialKeyCombos[KeyComboTogglePointerRegionLock].keyCode = SDLK_l;
m_SpecialKeyCombos[KeyComboTogglePointerRegionLock].scanCode = SDL_SCANCODE_L; m_SpecialKeyCombos[KeyComboTogglePointerRegionLock].scanCode = SDL_SCANCODE_L;

View file

@ -165,6 +165,8 @@ private:
KeyComboToggleCursorHide, KeyComboToggleCursorHide,
KeyComboToggleMinimize, KeyComboToggleMinimize,
KeyComboPasteText, KeyComboPasteText,
KeyComboToggleKeyboardMouseInput,
KeyComboToggleGamepadInput,
KeyComboTogglePointerRegionLock, KeyComboTogglePointerRegionLock,
KeyComboQuitAndExit, KeyComboQuitAndExit,
KeyComboMax KeyComboMax

View file

@ -13,6 +13,12 @@
#define VK_NUMPAD0 0x60 #define VK_NUMPAD0 0x60
#endif #endif
static bool isKeyboardMouseInputAllowed()
{
auto session = Session::get();
return session == nullptr || session->isKeyboardMouseInputAllowed();
}
void SdlInputHandler::performSpecialKeyCombo(KeyCombo combo) void SdlInputHandler::performSpecialKeyCombo(KeyCombo combo)
{ {
switch (combo) { switch (combo) {
@ -114,7 +120,9 @@ void SdlInputHandler::performSpecialKeyCombo(KeyCombo combo)
} }
// Send this text to the PC // Send this text to the PC
LiSendUtf8TextEvent(text, (unsigned int)strlen(text)); if (isKeyboardMouseInputAllowed()) {
LiSendUtf8TextEvent(text, (unsigned int)strlen(text));
}
// SDL_GetClipboardText() allocates, so we must free // SDL_GetClipboardText() allocates, so we must free
SDL_free((void*)text); SDL_free((void*)text);
@ -126,6 +134,22 @@ void SdlInputHandler::performSpecialKeyCombo(KeyCombo combo)
break; break;
} }
case KeyComboToggleKeyboardMouseInput:
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Detected keyboard/mouse input toggle combo");
if (auto session = Session::get(); session != nullptr) {
session->toggleKeyboardMouseInputAllowed();
}
break;
case KeyComboToggleGamepadInput:
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Detected gamepad input toggle combo");
if (auto session = Session::get(); session != nullptr) {
session->toggleGamepadInputAllowed();
}
break;
case KeyComboTogglePointerRegionLock: case KeyComboTogglePointerRegionLock:
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Detected pointer region lock toggle combo"); "Detected pointer region lock toggle combo");
@ -457,9 +481,11 @@ void SdlInputHandler::handleKeyEvent(SDL_KeyboardEvent* event)
m_KeysDown.remove(keyCode); m_KeysDown.remove(keyCode);
} }
LiSendKeyboardEvent2(0x8000 | keyCode, if (isKeyboardMouseInputAllowed()) {
event->state == SDL_PRESSED ? LiSendKeyboardEvent2(0x8000 | keyCode,
KEY_ACTION_DOWN : KEY_ACTION_UP, event->state == SDL_PRESSED ?
modifiers, KEY_ACTION_DOWN : KEY_ACTION_UP,
shouldNotConvertToScanCodeOnServer ? SS_KBE_FLAG_NON_NORMALIZED : 0); modifiers,
shouldNotConvertToScanCodeOnServer ? SS_KBE_FLAG_NON_NORMALIZED : 0);
}
} }

View file

@ -1,9 +1,16 @@
#include "input.h" #include "input.h"
#include "streaming/session.h"
#include <Limelight.h> #include <Limelight.h>
#include "SDL_compat.h" #include "SDL_compat.h"
#include "streaming/streamutils.h" #include "streaming/streamutils.h"
static bool isKeyboardMouseInputAllowed()
{
auto session = Session::get();
return session == nullptr || session->isKeyboardMouseInputAllowed();
}
void SdlInputHandler::handleMouseButtonEvent(SDL_MouseButtonEvent* event) void SdlInputHandler::handleMouseButtonEvent(SDL_MouseButtonEvent* event)
{ {
int button; int button;
@ -62,10 +69,12 @@ void SdlInputHandler::handleMouseButtonEvent(SDL_MouseButtonEvent* event)
button = BUTTON_RIGHT; button = BUTTON_RIGHT;
} }
LiSendMouseButtonEvent(event->state == SDL_PRESSED ? if (isKeyboardMouseInputAllowed()) {
BUTTON_ACTION_PRESS : LiSendMouseButtonEvent(event->state == SDL_PRESSED ?
BUTTON_ACTION_RELEASE, BUTTON_ACTION_PRESS :
button); BUTTON_ACTION_RELEASE,
button);
}
} }
void SdlInputHandler::handleMouseMotionEvent(SDL_MouseMotionEvent* event) void SdlInputHandler::handleMouseMotionEvent(SDL_MouseMotionEvent* event)
@ -134,7 +143,9 @@ void SdlInputHandler::handleMouseMotionEvent(SDL_MouseMotionEvent* event)
} }
} }
if (mouseInVideoRegion || m_MouseWasInVideoRegion || m_PendingMouseButtonsAllUpOnVideoRegionLeave) { if (mouseInVideoRegion || m_MouseWasInVideoRegion || m_PendingMouseButtonsAllUpOnVideoRegionLeave) {
LiSendMousePositionEvent((short)x, (short)y, dst.w, dst.h); if (isKeyboardMouseInputAllowed()) {
LiSendMousePositionEvent((short)x, (short)y, dst.w, dst.h);
}
} }
// Adjust the cursor visibility if applicable // Adjust the cursor visibility if applicable
@ -150,7 +161,9 @@ void SdlInputHandler::handleMouseMotionEvent(SDL_MouseMotionEvent* event)
m_MouseWasInVideoRegion = mouseInVideoRegion; m_MouseWasInVideoRegion = mouseInVideoRegion;
} }
else { else {
LiSendMouseMoveEvent(xrel, yrel); if (isKeyboardMouseInputAllowed()) {
LiSendMouseMoveEvent(xrel, yrel);
}
} }
} }
@ -187,7 +200,9 @@ void SdlInputHandler::handleMouseWheelEvent(SDL_MouseWheelEvent* event)
event->preciseY = SDL_clamp(event->preciseY, -1.0f, 1.0f); event->preciseY = SDL_clamp(event->preciseY, -1.0f, 1.0f);
#endif #endif
LiSendHighResScrollEvent((short)(event->preciseY * 120)); // WHEEL_DELTA if (isKeyboardMouseInputAllowed()) {
LiSendHighResScrollEvent((short)(event->preciseY * 120)); // WHEEL_DELTA
}
} }
if (event->preciseX != 0.0f) { if (event->preciseX != 0.0f) {
@ -202,7 +217,9 @@ void SdlInputHandler::handleMouseWheelEvent(SDL_MouseWheelEvent* event)
event->preciseX = SDL_clamp(event->preciseX, -1.0f, 1.0f); event->preciseX = SDL_clamp(event->preciseX, -1.0f, 1.0f);
#endif #endif
LiSendHighResHScrollEvent((short)(event->preciseX * 120)); // WHEEL_DELTA if (isKeyboardMouseInputAllowed()) {
LiSendHighResHScrollEvent((short)(event->preciseX * 120)); // WHEEL_DELTA
}
} }
#else #else
if (event->y != 0) { if (event->y != 0) {
@ -216,7 +233,9 @@ void SdlInputHandler::handleMouseWheelEvent(SDL_MouseWheelEvent* event)
event->y = SDL_clamp(event->y, -1, 1); event->y = SDL_clamp(event->y, -1, 1);
#endif #endif
LiSendScrollEvent((signed char)event->y); if (isKeyboardMouseInputAllowed()) {
LiSendScrollEvent((signed char)event->y);
}
} }
if (event->x != 0) { if (event->x != 0) {
@ -230,7 +249,9 @@ void SdlInputHandler::handleMouseWheelEvent(SDL_MouseWheelEvent* event)
event->x = SDL_clamp(event->x, -1, 1); event->x = SDL_clamp(event->x, -1, 1);
#endif #endif
LiSendHScrollEvent((signed char)event->x); if (isKeyboardMouseInputAllowed()) {
LiSendHScrollEvent((signed char)event->x);
}
} }
#endif #endif
} }

View file

@ -1,10 +1,17 @@
#include "input.h" #include "input.h"
#include "streaming/session.h"
#include <Limelight.h> #include <Limelight.h>
#include "SDL_compat.h" #include "SDL_compat.h"
#include <QtMath> #include <QtMath>
static bool isKeyboardMouseInputAllowed()
{
auto session = Session::get();
return session == nullptr || session->isKeyboardMouseInputAllowed();
}
// How long the mouse button will be pressed for a tap to click gesture // How long the mouse button will be pressed for a tap to click gesture
#define TAP_BUTTON_RELEASE_DELAY 100 #define TAP_BUTTON_RELEASE_DELAY 100
@ -16,13 +23,17 @@
Uint32 SdlInputHandler::releaseLeftButtonTimerCallback(Uint32, void*) Uint32 SdlInputHandler::releaseLeftButtonTimerCallback(Uint32, void*)
{ {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
}
return 0; return 0;
} }
Uint32 SdlInputHandler::releaseRightButtonTimerCallback(Uint32, void*) Uint32 SdlInputHandler::releaseRightButtonTimerCallback(Uint32, void*)
{ {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
}
return 0; return 0;
} }
@ -39,7 +50,9 @@ Uint32 SdlInputHandler::dragTimerCallback(Uint32, void *param)
me->m_DragButton = BUTTON_LEFT; me->m_DragButton = BUTTON_LEFT;
} }
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, me->m_DragButton); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, me->m_DragButton);
}
return 0; return 0;
} }
@ -99,7 +112,7 @@ void SdlInputHandler::handleRelativeFingerEvent(SDL_TouchFingerEvent* event)
// than the client window dimensions. // than the client window dimensions.
short deltaX = static_cast<short>(event->dx * m_StreamWidth); short deltaX = static_cast<short>(event->dx * m_StreamWidth);
short deltaY = static_cast<short>(event->dy * m_StreamHeight); short deltaY = static_cast<short>(event->dy * m_StreamHeight);
if (deltaX != 0 || deltaY != 0) { if ((deltaX != 0 || deltaY != 0) && isKeyboardMouseInputAllowed()) {
LiSendMouseMoveEvent(deltaX, deltaY); LiSendMouseMoveEvent(deltaX, deltaY);
} }
} }
@ -133,7 +146,9 @@ void SdlInputHandler::handleRelativeFingerEvent(SDL_TouchFingerEvent* event)
// Release any drag // Release any drag
if (m_DragButton != 0) { if (m_DragButton != 0) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, m_DragButton); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, m_DragButton);
}
m_DragButton = 0; m_DragButton = 0;
} }
// 2 finger tap // 2 finger tap
@ -143,7 +158,9 @@ void SdlInputHandler::handleRelativeFingerEvent(SDL_TouchFingerEvent* event)
m_TouchDownEvent[0].timestamp = 0; m_TouchDownEvent[0].timestamp = 0;
// Press down the right mouse button // Press down the right mouse button
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
}
// Queue a timer to release it in 100 ms // Queue a timer to release it in 100 ms
SDL_RemoveTimer(m_RightButtonReleaseTimer); SDL_RemoveTimer(m_RightButtonReleaseTimer);
@ -154,7 +171,9 @@ void SdlInputHandler::handleRelativeFingerEvent(SDL_TouchFingerEvent* event)
// 1 finger tap // 1 finger tap
else if (event->timestamp - m_TouchDownEvent[0].timestamp < 250) { else if (event->timestamp - m_TouchDownEvent[0].timestamp < 250) {
// Press down the left mouse button // Press down the left mouse button
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT); if (isKeyboardMouseInputAllowed()) {
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
}
// Queue a timer to release it in 100 ms // Queue a timer to release it in 100 ms
SDL_RemoveTimer(m_LeftButtonReleaseTimer); SDL_RemoveTimer(m_LeftButtonReleaseTimer);

View file

@ -556,6 +556,8 @@ Session::Session(NvComputer* computer, NvApp& app, StreamingPreferences *prefere
m_VideoDecoder(nullptr), m_VideoDecoder(nullptr),
m_DecoderLock(SDL_CreateMutex()), m_DecoderLock(SDL_CreateMutex()),
m_AudioMuted(false), m_AudioMuted(false),
m_AllowGamepadInput(true),
m_AllowKeyboardMouseInput(true),
m_QtWindow(nullptr), m_QtWindow(nullptr),
m_UnexpectedTermination(true), // Failure prior to streaming is unexpected m_UnexpectedTermination(true), // Failure prior to streaming is unexpected
m_InputHandler(nullptr), m_InputHandler(nullptr),
@ -571,6 +573,45 @@ Session::Session(NvComputer* computer, NvApp& app, StreamingPreferences *prefere
{ {
} }
void Session::setGamepadInputAllowed(bool allowed)
{
m_AllowGamepadInput.store(allowed, std::memory_order_relaxed);
notifyInputPermissionState();
}
void Session::setKeyboardMouseInputAllowed(bool allowed)
{
bool previous = m_AllowKeyboardMouseInput.exchange(allowed, std::memory_order_relaxed);
if (previous && !allowed && m_InputHandler != nullptr) {
m_InputHandler->raiseAllKeys();
}
notifyInputPermissionState();
}
void Session::toggleGamepadInputAllowed()
{
setGamepadInputAllowed(!isGamepadInputAllowed());
}
void Session::toggleKeyboardMouseInputAllowed()
{
setKeyboardMouseInputAllowed(!isKeyboardMouseInputAllowed());
}
void Session::notifyInputPermissionState()
{
char buffer[96];
SDL_snprintf(buffer,
sizeof(buffer),
"Keyboard/Mouse: %s\nGamepad: %s",
isKeyboardMouseInputAllowed() ? "ON" : "OFF",
isGamepadInputAllowed() ? "ON" : "OFF");
m_OverlayManager.updateOverlayText(Overlay::OverlayStatusUpdate, buffer);
m_OverlayManager.setOverlayState(Overlay::OverlayStatusUpdate, true);
}
Session::~Session() Session::~Session()
{ {
// NB: This may not get destroyed for a long time! Don't put any non-trivial cleanup here. // NB: This may not get destroyed for a long time! Don't put any non-trivial cleanup here.

View file

@ -2,6 +2,7 @@
#include <QSemaphore> #include <QSemaphore>
#include <QQuickWindow> #include <QQuickWindow>
#include <atomic>
#include <Limelight.h> #include <Limelight.h>
#include <opus_multistream.h> #include <opus_multistream.h>
@ -125,6 +126,22 @@ public:
void setShouldExit(bool quitHostApp = false); void setShouldExit(bool quitHostApp = false);
bool isGamepadInputAllowed() const
{
return m_AllowGamepadInput.load(std::memory_order_relaxed);
}
bool isKeyboardMouseInputAllowed() const
{
return m_AllowKeyboardMouseInput.load(std::memory_order_relaxed);
}
void setGamepadInputAllowed(bool allowed);
void setKeyboardMouseInputAllowed(bool allowed);
void toggleGamepadInputAllowed();
void toggleKeyboardMouseInputAllowed();
void notifyInputPermissionState();
signals: signals:
void stageStarting(QString stage); void stageStarting(QString stage);
@ -255,6 +272,8 @@ private:
SDL_mutex* m_DecoderLock; SDL_mutex* m_DecoderLock;
bool m_AudioDisabled; bool m_AudioDisabled;
bool m_AudioMuted; bool m_AudioMuted;
std::atomic<bool> m_AllowGamepadInput;
std::atomic<bool> m_AllowKeyboardMouseInput;
Uint32 m_FullScreenFlag; Uint32 m_FullScreenFlag;
QQuickWindow* m_QtWindow; QQuickWindow* m_QtWindow;
bool m_UnexpectedTermination; bool m_UnexpectedTermination;