Compare commits
No commits in common. "parsec-features" and "master" have entirely different histories.
parsec-fea
...
master
19 changed files with 229 additions and 1514 deletions
25
.gitignore
vendored
25
.gitignore
vendored
|
|
@ -4,30 +4,5 @@
|
||||||
**/.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
|
||||||
|
|
|
||||||
2
.gitmodules
vendored
2
.gitmodules
vendored
|
|
@ -1,6 +1,6 @@
|
||||||
[submodule "moonlight-common-c/moonlight-common-c"]
|
[submodule "moonlight-common-c/moonlight-common-c"]
|
||||||
path = moonlight-common-c/moonlight-common-c
|
path = moonlight-common-c/moonlight-common-c
|
||||||
url = git.joeypayne.com:jyapayne/moonlight-common-c
|
url = https://github.com/moonlight-stream/moonlight-common-c.git
|
||||||
[submodule "qmdnsengine/qmdnsengine"]
|
[submodule "qmdnsengine/qmdnsengine"]
|
||||||
path = qmdnsengine/qmdnsengine
|
path = qmdnsengine/qmdnsengine
|
||||||
url = https://github.com/cgutman/qmdnsengine.git
|
url = https://github.com/cgutman/qmdnsengine.git
|
||||||
|
|
|
||||||
|
|
@ -179,7 +179,6 @@ SOURCES += \
|
||||||
settings/streamingpreferences.cpp \
|
settings/streamingpreferences.cpp \
|
||||||
streaming/input/abstouch.cpp \
|
streaming/input/abstouch.cpp \
|
||||||
streaming/input/gamepad.cpp \
|
streaming/input/gamepad.cpp \
|
||||||
streaming/input/sdlinputsubsystems.cpp \
|
|
||||||
streaming/input/input.cpp \
|
streaming/input/input.cpp \
|
||||||
streaming/input/keyboard.cpp \
|
streaming/input/keyboard.cpp \
|
||||||
streaming/input/mouse.cpp \
|
streaming/input/mouse.cpp \
|
||||||
|
|
@ -220,7 +219,6 @@ HEADERS += \
|
||||||
cli/quitstream.h \
|
cli/quitstream.h \
|
||||||
cli/startstream.h \
|
cli/startstream.h \
|
||||||
settings/streamingpreferences.h \
|
settings/streamingpreferences.h \
|
||||||
streaming/input/sdlinputsubsystems.h \
|
|
||||||
streaming/input/input.h \
|
streaming/input/input.h \
|
||||||
streaming/session.h \
|
streaming/session.h \
|
||||||
streaming/audio/renderers/renderer.h \
|
streaming/audio/renderers/renderer.h \
|
||||||
|
|
|
||||||
|
|
@ -4,27 +4,10 @@
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QWindow>
|
#include <QWindow>
|
||||||
|
|
||||||
#include "streaming/input/sdlinputsubsystems.h"
|
#include "settings/mappingmanager.h"
|
||||||
|
|
||||||
#define AXIS_NAVIGATION_REPEAT_DELAY 150
|
#define AXIS_NAVIGATION_REPEAT_DELAY 150
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
SdlInputSubsystems::LeaseOptions guiNavSubsystemLeaseOptions()
|
|
||||||
{
|
|
||||||
SdlInputSubsystems::LeaseOptions options = {};
|
|
||||||
options.joystick = true;
|
|
||||||
options.gameController = true;
|
|
||||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
|
||||||
options.haptic = false;
|
|
||||||
#endif
|
|
||||||
options.applyMappings = true;
|
|
||||||
options.flushControllerDeviceEvents = true;
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
SdlGamepadKeyNavigation::SdlGamepadKeyNavigation(StreamingPreferences* prefs)
|
SdlGamepadKeyNavigation::SdlGamepadKeyNavigation(StreamingPreferences* prefs)
|
||||||
: m_Prefs(prefs),
|
: m_Prefs(prefs),
|
||||||
m_Enabled(false),
|
m_Enabled(false),
|
||||||
|
|
@ -48,13 +31,32 @@ void SdlGamepadKeyNavigation::enable()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SdlInputSubsystems::acquire("GuiGamepadNavigation", guiNavSubsystemLeaseOptions())) {
|
// We have to initialize and uninitialize this in enable()/disable()
|
||||||
|
// because we need to get out of the way of the Session class. If it
|
||||||
|
// doesn't get to reinitialize the GC subsystem, it won't get initial
|
||||||
|
// arrival events. Additionally, there's a race condition between
|
||||||
|
// our QML objects being destroyed and SDL being deinitialized that
|
||||||
|
// this solves too.
|
||||||
|
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Failed to acquire SDL input subsystems for GUI gamepad navigation");
|
"SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) failed: %s",
|
||||||
|
SDL_GetError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MappingManager mappingManager;
|
||||||
|
mappingManager.applyMappings();
|
||||||
|
|
||||||
|
// Drop all pending gamepad add events. SDL will generate these for us
|
||||||
|
// on first init of the GC subsystem. We can't depend on them due to
|
||||||
|
// overlapping lifetimes of SdlGamepadKeyNavigation instances, so we
|
||||||
|
// will attach ourselves.
|
||||||
|
//
|
||||||
|
// NB: We use SDL_JoystickUpdate() instead of SDL_PumpEvents() because
|
||||||
|
// the latter can do a bit more work that we want (like handling video
|
||||||
|
// events that we intentionally do not want to process yet).
|
||||||
SDL_JoystickUpdate();
|
SDL_JoystickUpdate();
|
||||||
|
SDL_FlushEvent(SDL_CONTROLLERDEVICEADDED);
|
||||||
|
|
||||||
// Open all currently attached game controllers
|
// Open all currently attached game controllers
|
||||||
int numJoysticks = SDL_NumJoysticks();
|
int numJoysticks = SDL_NumJoysticks();
|
||||||
|
|
@ -88,7 +90,7 @@ void SdlGamepadKeyNavigation::disable()
|
||||||
m_Gamepads.removeAt(0);
|
m_Gamepads.removeAt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SdlInputSubsystems::release("GuiGamepadNavigation", guiNavSubsystemLeaseOptions());
|
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SdlGamepadKeyNavigation::notifyWindowFocus(bool hasFocus)
|
void SdlGamepadKeyNavigation::notifyWindowFocus(bool hasFocus)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
#include "renderers/sdl.h"
|
#include "renderers/sdl.h"
|
||||||
|
|
||||||
#include <Limelight.h>
|
#include <Limelight.h>
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#define TRY_INIT_RENDERER(renderer, opusConfig) \
|
#define TRY_INIT_RENDERER(renderer, opusConfig) \
|
||||||
{ \
|
{ \
|
||||||
|
|
@ -184,7 +183,7 @@ void Session::arDecodeAndPlaySample(char* sampleData, int sampleLength)
|
||||||
s_ActiveSession->m_AudioSampleCount++;
|
s_ActiveSession->m_AudioSampleCount++;
|
||||||
|
|
||||||
// If audio is muted, don't decode or play the audio
|
// If audio is muted, don't decode or play the audio
|
||||||
if (s_ActiveSession->m_AudioMuted.load(std::memory_order_relaxed)) {
|
if (s_ActiveSession->m_AudioMuted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -218,27 +217,6 @@ void Session::arDecodeAndPlaySample(char* sampleData, int sampleLength)
|
||||||
if (samplesDecoded > 0) {
|
if (samplesDecoded > 0) {
|
||||||
SDL_assert(desiredBufferSize >= frameSize * samplesDecoded);
|
SDL_assert(desiredBufferSize >= frameSize * samplesDecoded);
|
||||||
desiredBufferSize = frameSize * samplesDecoded;
|
desiredBufferSize = frameSize * samplesDecoded;
|
||||||
|
|
||||||
const float volume = s_ActiveSession->getAudioVolumeScalar();
|
|
||||||
if (volume <= 0.0f) {
|
|
||||||
SDL_memset(buffer, 0, desiredBufferSize);
|
|
||||||
}
|
|
||||||
else if (volume < 1.0f) {
|
|
||||||
const int totalSamples = samplesDecoded * s_ActiveSession->m_ActiveAudioConfig.channelCount;
|
|
||||||
if (s_ActiveSession->m_AudioRenderer->getAudioBufferFormat() == IAudioRenderer::AudioFormat::Float32NE) {
|
|
||||||
float* output = (float*)buffer;
|
|
||||||
for (int i = 0; i < totalSamples; i++) {
|
|
||||||
output[i] = SDL_clamp(output[i] * volume, -1.0f, 1.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
short* output = (short*)buffer;
|
|
||||||
for (int i = 0; i < totalSamples; i++) {
|
|
||||||
const int scaled = (int) std::lround((float)output[i] * volume);
|
|
||||||
output[i] = (short)SDL_clamp(scaled, -32768, 32767);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
desiredBufferSize = 0;
|
desiredBufferSize = 0;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "streaming/session.h"
|
|
||||||
|
|
||||||
#include <Limelight.h>
|
#include <Limelight.h>
|
||||||
#include "SDL_compat.h"
|
#include "SDL_compat.h"
|
||||||
|
|
@ -8,12 +7,6 @@
|
||||||
|
|
||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
|
|
||||||
static bool isKeyboardMouseInputAllowed()
|
|
||||||
{
|
|
||||||
auto session = Session::get();
|
|
||||||
return session == nullptr || session->isMouseInputAllowed();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
||||||
|
|
||||||
|
|
@ -29,10 +22,8 @@ static bool isKeyboardMouseInputAllowed()
|
||||||
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
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -119,7 +110,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 (isKeyboardMouseInputAllowed() && (LiGetHostFeatureFlags() & LI_FF_PEN_TOUCH_EVENTS)) {
|
if (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;
|
||||||
|
|
||||||
|
|
@ -206,9 +197,7 @@ 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
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendMousePositionEvent(x - dst.x, y - dst.y, dst.w, dst.h);
|
||||||
LiSendMousePositionEvent(x - dst.x, y - dst.y, dst.w, dst.h);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event->type == SDL_FINGERDOWN) {
|
if (event->type == SDL_FINGERDOWN) {
|
||||||
|
|
@ -221,9 +210,7 @@ void SdlInputHandler::emulateAbsoluteFingerEvent(SDL_TouchFingerEvent* event)
|
||||||
nullptr);
|
nullptr);
|
||||||
|
|
||||||
// Left button down on finger down
|
// Left button down on finger down
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (event->type == SDL_FINGERUP) {
|
else if (event->type == SDL_FINGERUP) {
|
||||||
m_LastTouchUpEvent = *event;
|
m_LastTouchUpEvent = *event;
|
||||||
|
|
@ -233,13 +220,9 @@ void SdlInputHandler::emulateAbsoluteFingerEvent(SDL_TouchFingerEvent* event)
|
||||||
m_LongPressTimer = 0;
|
m_LongPressTimer = 0;
|
||||||
|
|
||||||
// Left button up on finger up
|
// Left button up on finger up
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
||||||
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
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,33 +2,16 @@
|
||||||
|
|
||||||
#include <Limelight.h>
|
#include <Limelight.h>
|
||||||
#include "SDL_compat.h"
|
#include "SDL_compat.h"
|
||||||
#include "streaming/input/sdlinputsubsystems.h"
|
#include "settings/mappingmanager.h"
|
||||||
|
|
||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
|
|
||||||
static bool isGamepadInputAllowed()
|
|
||||||
{
|
|
||||||
auto session = Session::get();
|
|
||||||
return session == nullptr || session->isGamepadInputAllowed();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isMouseInputAllowed()
|
|
||||||
{
|
|
||||||
auto session = Session::get();
|
|
||||||
return session == nullptr || session->isMouseInputAllowed();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
||||||
|
|
||||||
// How long between polling the gamepad to send virtual mouse input
|
// How long between polling the gamepad to send virtual mouse input
|
||||||
#define MOUSE_EMULATION_POLLING_INTERVAL 50
|
#define MOUSE_EMULATION_POLLING_INTERVAL 50
|
||||||
|
|
||||||
#define HOTPLUG_REENUMERATION_INTERVAL_MS 2000
|
|
||||||
#define HOTPLUG_REENUMERATION_MAX_INTERVAL_MS 8000
|
|
||||||
#define HOTPLUG_REENUMERATION_MIN_ZERO_POLLS 4
|
|
||||||
#define HOTPLUG_REENUMERATION_MIN_LAST_SEEN_MS 500
|
|
||||||
|
|
||||||
// Determines how fast the mouse will move each interval
|
// Determines how fast the mouse will move each interval
|
||||||
#define MOUSE_EMULATION_MOTION_MULTIPLIER 4
|
#define MOUSE_EMULATION_MOTION_MULTIPLIER 4
|
||||||
|
|
||||||
|
|
@ -57,7 +40,7 @@ SdlInputHandler::findStateForGamepad(SDL_JoystickID id)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < MAX_GAMEPADS; i++) {
|
for (i = 0; i < MAX_GAMEPADS; i++) {
|
||||||
if (m_GamepadState[i].controller != nullptr && m_GamepadState[i].jsId == id) {
|
if (m_GamepadState[i].jsId == id) {
|
||||||
SDL_assert(!m_MultiController || m_GamepadState[i].index == i);
|
SDL_assert(!m_MultiController || m_GamepadState[i].index == i);
|
||||||
return &m_GamepadState[i];
|
return &m_GamepadState[i];
|
||||||
}
|
}
|
||||||
|
|
@ -68,191 +51,6 @@ SdlInputHandler::findStateForGamepad(SDL_JoystickID id)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
GamepadState*
|
|
||||||
SdlInputHandler::ensureStateForGamepad(SDL_JoystickID id)
|
|
||||||
{
|
|
||||||
GamepadState* state = findStateForGamepad(id);
|
|
||||||
if (state != nullptr) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanupDetachedGamepads();
|
|
||||||
|
|
||||||
const int joystickCount = SDL_NumJoysticks();
|
|
||||||
for (int deviceIndex = 0; deviceIndex < joystickCount; deviceIndex++) {
|
|
||||||
if (!SDL_IsGameController(deviceIndex)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SDL_JoystickGetDeviceInstanceID(deviceIndex) != id) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Recovering gamepad state for missing add event (instance ID: %d)",
|
|
||||||
id);
|
|
||||||
|
|
||||||
SDL_ControllerDeviceEvent controllerEvent = {};
|
|
||||||
controllerEvent.type = SDL_CONTROLLERDEVICEADDED;
|
|
||||||
controllerEvent.which = deviceIndex;
|
|
||||||
handleControllerDeviceEvent(&controllerEvent);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return findStateForGamepad(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SdlInputHandler::pollForMissingGamepads()
|
|
||||||
{
|
|
||||||
static uint32_t s_LastForcedReenumerationTick = 0;
|
|
||||||
static uint32_t s_ReenumerationIntervalMs = HOTPLUG_REENUMERATION_INTERVAL_MS;
|
|
||||||
static uint32_t s_ReenumerationAttempts = 0;
|
|
||||||
static uint32_t s_ConsecutiveZeroPolls = 0;
|
|
||||||
|
|
||||||
SDL_JoystickUpdate();
|
|
||||||
SDL_GameControllerUpdate();
|
|
||||||
|
|
||||||
uint32_t now = SDL_GetTicks();
|
|
||||||
|
|
||||||
auto recoverUntrackedGamepads = [this](int joystickCount) {
|
|
||||||
for (int deviceIndex = 0; deviceIndex < joystickCount; deviceIndex++) {
|
|
||||||
if (!SDL_IsGameController(deviceIndex)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_JoystickID jsId = SDL_JoystickGetDeviceInstanceID(deviceIndex);
|
|
||||||
if (jsId < 0 || findStateForGamepad(jsId) != nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Polling recovered missing gamepad add event (device index: %d, instance ID: %d)",
|
|
||||||
deviceIndex,
|
|
||||||
jsId);
|
|
||||||
|
|
||||||
SDL_ControllerDeviceEvent controllerEvent = {};
|
|
||||||
controllerEvent.type = SDL_CONTROLLERDEVICEADDED;
|
|
||||||
controllerEvent.which = deviceIndex;
|
|
||||||
handleControllerDeviceEvent(&controllerEvent);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int joystickCount = SDL_NumJoysticks();
|
|
||||||
if (joystickCount != m_LastJoystickCount) {
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Detected joystick count change: %d -> %d",
|
|
||||||
m_LastJoystickCount,
|
|
||||||
joystickCount);
|
|
||||||
m_LastJoystickCount = joystickCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (joystickCount > 0) {
|
|
||||||
m_LastNonZeroJoystickTick = now;
|
|
||||||
s_ConsecutiveZeroPolls = 0;
|
|
||||||
s_ReenumerationAttempts = 0;
|
|
||||||
s_ReenumerationIntervalMs = HOTPLUG_REENUMERATION_INTERVAL_MS;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
s_ConsecutiveZeroPolls++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < MAX_GAMEPADS; i++) {
|
|
||||||
GamepadState* state = &m_GamepadState[i];
|
|
||||||
if (state->controller == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool presentInDeviceList = false;
|
|
||||||
for (int deviceIndex = 0; deviceIndex < joystickCount; deviceIndex++) {
|
|
||||||
if (SDL_JoystickGetDeviceInstanceID(deviceIndex) == state->jsId) {
|
|
||||||
presentInDeviceList = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (presentInDeviceList) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Polling detected disconnected gamepad instance %d in slot %d; cleaning up",
|
|
||||||
state->jsId,
|
|
||||||
i);
|
|
||||||
|
|
||||||
SDL_ControllerDeviceEvent controllerEvent = {};
|
|
||||||
controllerEvent.type = SDL_CONTROLLERDEVICEREMOVED;
|
|
||||||
controllerEvent.which = state->jsId;
|
|
||||||
handleControllerDeviceEvent(&controllerEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
recoverUntrackedGamepads(joystickCount);
|
|
||||||
|
|
||||||
bool shouldAttemptReenumeration =
|
|
||||||
joystickCount == 0 &&
|
|
||||||
m_LastNonZeroJoystickTick != 0 &&
|
|
||||||
s_ConsecutiveZeroPolls >= HOTPLUG_REENUMERATION_MIN_ZERO_POLLS &&
|
|
||||||
SDL_TICKS_PASSED(now, m_LastNonZeroJoystickTick + HOTPLUG_REENUMERATION_MIN_LAST_SEEN_MS);
|
|
||||||
|
|
||||||
if (shouldAttemptReenumeration) {
|
|
||||||
if (SDL_TICKS_PASSED(now, s_LastForcedReenumerationTick + s_ReenumerationIntervalMs)) {
|
|
||||||
s_LastForcedReenumerationTick = now;
|
|
||||||
s_ReenumerationAttempts++;
|
|
||||||
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"No joysticks visible after reconciliation; forcing last-resort SDL re-enumeration (attempt %u, interval %u ms)",
|
|
||||||
s_ReenumerationAttempts,
|
|
||||||
s_ReenumerationIntervalMs);
|
|
||||||
|
|
||||||
if (SdlInputSubsystems::reenumerateGamepadSubsystems("StreamInputHotplug")) {
|
|
||||||
joystickCount = SDL_NumJoysticks();
|
|
||||||
if (joystickCount != m_LastJoystickCount) {
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Detected joystick count change after re-enumeration: %d -> %d",
|
|
||||||
m_LastJoystickCount,
|
|
||||||
joystickCount);
|
|
||||||
m_LastJoystickCount = joystickCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
recoverUntrackedGamepads(joystickCount);
|
|
||||||
|
|
||||||
if (joystickCount > 0) {
|
|
||||||
m_LastNonZeroJoystickTick = now;
|
|
||||||
s_ConsecutiveZeroPolls = 0;
|
|
||||||
s_ReenumerationAttempts = 0;
|
|
||||||
s_ReenumerationIntervalMs = HOTPLUG_REENUMERATION_INTERVAL_MS;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
s_ReenumerationIntervalMs = qMin(s_ReenumerationIntervalMs * 2,
|
|
||||||
static_cast<uint32_t>(HOTPLUG_REENUMERATION_MAX_INTERVAL_MS));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
s_ReenumerationIntervalMs = qMin(s_ReenumerationIntervalMs * 2,
|
|
||||||
static_cast<uint32_t>(HOTPLUG_REENUMERATION_MAX_INTERVAL_MS));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SdlInputHandler::cleanupDetachedGamepads()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < MAX_GAMEPADS; i++) {
|
|
||||||
if (m_GamepadState[i].controller == nullptr ||
|
|
||||||
SDL_GameControllerGetAttached(m_GamepadState[i].controller)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Found detached gamepad in slot %d without removal event; cleaning up",
|
|
||||||
i);
|
|
||||||
|
|
||||||
SDL_ControllerDeviceEvent controllerEvent = {};
|
|
||||||
controllerEvent.type = SDL_CONTROLLERDEVICEREMOVED;
|
|
||||||
controllerEvent.which = m_GamepadState[i].jsId;
|
|
||||||
handleControllerDeviceEvent(&controllerEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SdlInputHandler::sendGamepadState(GamepadState* state)
|
void SdlInputHandler::sendGamepadState(GamepadState* state)
|
||||||
{
|
{
|
||||||
SDL_assert(m_GamepadMask == 0x1 || m_MultiController);
|
SDL_assert(m_GamepadMask == 0x1 || m_MultiController);
|
||||||
|
|
@ -303,17 +101,15 @@ void SdlInputHandler::sendGamepadState(GamepadState* state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isGamepadInputAllowed()) {
|
LiSendMultiControllerEvent(state->index,
|
||||||
LiSendMultiControllerEvent(state->index,
|
m_GamepadMask,
|
||||||
m_GamepadMask,
|
buttons,
|
||||||
buttons,
|
lt,
|
||||||
lt,
|
rt,
|
||||||
rt,
|
lsX,
|
||||||
lsX,
|
lsY,
|
||||||
lsY,
|
rsX,
|
||||||
rsX,
|
rsY);
|
||||||
rsY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SdlInputHandler::sendGamepadBatteryState(GamepadState* state, SDL_JoystickPowerLevel level)
|
void SdlInputHandler::sendGamepadBatteryState(GamepadState* state, SDL_JoystickPowerLevel level)
|
||||||
|
|
@ -354,9 +150,7 @@ void SdlInputHandler::sendGamepadBatteryState(GamepadState* state, SDL_JoystickP
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isGamepadInputAllowed()) {
|
LiSendControllerBatteryEvent(state->index, batteryState, batteryPercentage);
|
||||||
LiSendControllerBatteryEvent(state->index, batteryState, batteryPercentage);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Uint32 SdlInputHandler::mouseEmulationTimerCallback(Uint32 interval, void *param)
|
Uint32 SdlInputHandler::mouseEmulationTimerCallback(Uint32 interval, void *param)
|
||||||
|
|
@ -387,7 +181,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) && isMouseInputAllowed()) {
|
if (deltaX != 0 || deltaY != 0) {
|
||||||
LiSendMouseMoveEvent((short)deltaX, (short)deltaY);
|
LiSendMouseMoveEvent((short)deltaX, (short)deltaY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -397,7 +191,7 @@ Uint32 SdlInputHandler::mouseEmulationTimerCallback(Uint32 interval, void *param
|
||||||
void SdlInputHandler::handleControllerAxisEvent(SDL_ControllerAxisEvent* event)
|
void SdlInputHandler::handleControllerAxisEvent(SDL_ControllerAxisEvent* event)
|
||||||
{
|
{
|
||||||
SDL_JoystickID gameControllerId = event->which;
|
SDL_JoystickID gameControllerId = event->which;
|
||||||
GamepadState* state = ensureStateForGamepad(gameControllerId);
|
GamepadState* state = findStateForGamepad(gameControllerId);
|
||||||
if (state == NULL) {
|
if (state == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -467,7 +261,7 @@ void SdlInputHandler::handleControllerButtonEvent(SDL_ControllerButtonEvent* eve
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GamepadState* state = ensureStateForGamepad(event->which);
|
GamepadState* state = findStateForGamepad(event->which);
|
||||||
if (state == NULL) {
|
if (state == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -497,49 +291,31 @@ 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) {
|
||||||
if (isMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (event->button == SDL_CONTROLLER_BUTTON_B) {
|
else if (event->button == SDL_CONTROLLER_BUTTON_B) {
|
||||||
if (isMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (event->button == SDL_CONTROLLER_BUTTON_X) {
|
else if (event->button == SDL_CONTROLLER_BUTTON_X) {
|
||||||
if (isMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_MIDDLE);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_MIDDLE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (event->button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
|
else if (event->button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
|
||||||
if (isMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_X1);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_X1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (event->button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) {
|
else if (event->button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) {
|
||||||
if (isMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_X2);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_X2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_UP) {
|
else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_UP) {
|
||||||
if (isMouseInputAllowed()) {
|
LiSendScrollEvent(1);
|
||||||
LiSendScrollEvent(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) {
|
else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) {
|
||||||
if (isMouseInputAllowed()) {
|
LiSendScrollEvent(-1);
|
||||||
LiSendScrollEvent(-1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) {
|
else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) {
|
||||||
if (isMouseInputAllowed()) {
|
LiSendHScrollEvent(1);
|
||||||
LiSendHScrollEvent(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) {
|
else if (event->button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) {
|
||||||
if (isMouseInputAllowed()) {
|
LiSendHScrollEvent(-1);
|
||||||
LiSendHScrollEvent(-1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -570,29 +346,19 @@ 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) {
|
||||||
if (isMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (event->button == SDL_CONTROLLER_BUTTON_B) {
|
else if (event->button == SDL_CONTROLLER_BUTTON_B) {
|
||||||
if (isMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (event->button == SDL_CONTROLLER_BUTTON_X) {
|
else if (event->button == SDL_CONTROLLER_BUTTON_X) {
|
||||||
if (isMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_MIDDLE);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_MIDDLE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (event->button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
|
else if (event->button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
|
||||||
if (isMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_X1);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_X1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (event->button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) {
|
else if (event->button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) {
|
||||||
if (isMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_X2);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_X2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -609,10 +375,8 @@ void SdlInputHandler::handleControllerButtonEvent(SDL_ControllerButtonEvent* eve
|
||||||
SDL_PushEvent(&event);
|
SDL_PushEvent(&event);
|
||||||
|
|
||||||
// Clear buttons down on this gamepad
|
// Clear buttons down on this gamepad
|
||||||
if (isGamepadInputAllowed()) {
|
LiSendMultiControllerEvent(state->index, m_GamepadMask,
|
||||||
LiSendMultiControllerEvent(state->index, m_GamepadMask,
|
0, 0, 0, 0, 0, 0, 0);
|
||||||
0, 0, 0, 0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -626,67 +390,8 @@ 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
|
||||||
if (isGamepadInputAllowed()) {
|
LiSendMultiControllerEvent(state->index, m_GamepadMask,
|
||||||
LiSendMultiControllerEvent(state->index, m_GamepadMask,
|
0, 0, 0, 0, 0, 0, 0);
|
||||||
0, 0, 0, 0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state->buttons == (BACK_FLAG | LB_FLAG | RB_FLAG | B_FLAG)) {
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Detected control panel toggle gamepad combo");
|
|
||||||
|
|
||||||
Session::get()->toggleControlPanelVisibility();
|
|
||||||
|
|
||||||
if (isGamepadInputAllowed()) {
|
|
||||||
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 input toggle gamepad combo");
|
|
||||||
|
|
||||||
Session::get()->toggleKeyboardInputAllowed();
|
|
||||||
|
|
||||||
if (isGamepadInputAllowed()) {
|
|
||||||
LiSendMultiControllerEvent(state->index, m_GamepadMask,
|
|
||||||
0, 0, 0, 0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state->buttons == (BACK_FLAG | LB_FLAG | RB_FLAG | UP_FLAG)) {
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Detected mouse input toggle gamepad combo");
|
|
||||||
|
|
||||||
Session::get()->toggleMouseInputAllowed();
|
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -700,7 +405,7 @@ void SdlInputHandler::handleControllerButtonEvent(SDL_ControllerButtonEvent* eve
|
||||||
|
|
||||||
void SdlInputHandler::handleControllerSensorEvent(SDL_ControllerSensorEvent* event)
|
void SdlInputHandler::handleControllerSensorEvent(SDL_ControllerSensorEvent* event)
|
||||||
{
|
{
|
||||||
GamepadState* state = ensureStateForGamepad(event->which);
|
GamepadState* state = findStateForGamepad(event->which);
|
||||||
if (state == NULL) {
|
if (state == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -713,9 +418,7 @@ 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;
|
||||||
|
|
||||||
if (isGamepadInputAllowed()) {
|
LiSendControllerMotionEvent((uint8_t)state->index, LI_MOTION_TYPE_ACCEL, event->data[0], event->data[1], event->data[2]);
|
||||||
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:
|
||||||
|
|
@ -726,12 +429,10 @@ 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
|
||||||
if (isGamepadInputAllowed()) {
|
LiSendControllerMotionEvent((uint8_t)state->index, LI_MOTION_TYPE_GYRO,
|
||||||
LiSendControllerMotionEvent((uint8_t)state->index, LI_MOTION_TYPE_GYRO,
|
event->data[0] * 57.2957795f,
|
||||||
event->data[0] * 57.2957795f,
|
event->data[1] * 57.2957795f,
|
||||||
event->data[1] * 57.2957795f,
|
event->data[2] * 57.2957795f);
|
||||||
event->data[2] * 57.2957795f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -739,7 +440,7 @@ void SdlInputHandler::handleControllerSensorEvent(SDL_ControllerSensorEvent* eve
|
||||||
|
|
||||||
void SdlInputHandler::handleControllerTouchpadEvent(SDL_ControllerTouchpadEvent* event)
|
void SdlInputHandler::handleControllerTouchpadEvent(SDL_ControllerTouchpadEvent* event)
|
||||||
{
|
{
|
||||||
GamepadState* state = ensureStateForGamepad(event->which);
|
GamepadState* state = findStateForGamepad(event->which);
|
||||||
if (state == NULL) {
|
if (state == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -759,9 +460,7 @@ void SdlInputHandler::handleControllerTouchpadEvent(SDL_ControllerTouchpadEvent*
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isGamepadInputAllowed()) {
|
LiSendControllerTouchEvent((uint8_t)state->index, eventType, event->finger, event->x, event->y, event->pressure);
|
||||||
LiSendControllerTouchEvent((uint8_t)state->index, eventType, event->finger, event->x, event->y, event->pressure);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -770,7 +469,7 @@ void SdlInputHandler::handleControllerTouchpadEvent(SDL_ControllerTouchpadEvent*
|
||||||
|
|
||||||
void SdlInputHandler::handleJoystickBatteryEvent(SDL_JoyBatteryEvent* event)
|
void SdlInputHandler::handleJoystickBatteryEvent(SDL_JoyBatteryEvent* event)
|
||||||
{
|
{
|
||||||
GamepadState* state = ensureStateForGamepad(event->which);
|
GamepadState* state = findStateForGamepad(event->which);
|
||||||
if (state == NULL) {
|
if (state == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -785,8 +484,6 @@ void SdlInputHandler::handleControllerDeviceEvent(SDL_ControllerDeviceEvent* eve
|
||||||
GamepadState* state;
|
GamepadState* state;
|
||||||
|
|
||||||
if (event->type == SDL_CONTROLLERDEVICEADDED) {
|
if (event->type == SDL_CONTROLLERDEVICEADDED) {
|
||||||
cleanupDetachedGamepads();
|
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
const char* name;
|
const char* name;
|
||||||
SDL_GameController* controller;
|
SDL_GameController* controller;
|
||||||
|
|
@ -802,17 +499,15 @@ void SdlInputHandler::handleControllerDeviceEvent(SDL_ControllerDeviceEvent* eve
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_JoystickID jsId = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller));
|
|
||||||
|
|
||||||
// SDL_CONTROLLERDEVICEADDED can be reported multiple times for the same
|
// SDL_CONTROLLERDEVICEADDED can be reported multiple times for the same
|
||||||
// gamepad in rare cases, because SDL doesn't fixup the device index in
|
// gamepad in rare cases, because SDL doesn't fixup the device index in
|
||||||
// the SDL_CONTROLLERDEVICEADDED event if an unopened gamepad disappears
|
// the SDL_CONTROLLERDEVICEADDED event if an unopened gamepad disappears
|
||||||
// before we've processed the add event.
|
// before we've processed the add event.
|
||||||
for (int i = 0; i < MAX_GAMEPADS; i++) {
|
for (int i = 0; i < MAX_GAMEPADS; i++) {
|
||||||
if (m_GamepadState[i].controller != nullptr && m_GamepadState[i].jsId == jsId) {
|
if (m_GamepadState[i].controller == controller) {
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Received duplicate add event for joystick instance ID: %d",
|
"Received duplicate add event for controller index: %d",
|
||||||
jsId);
|
event->which);
|
||||||
SDL_GameControllerClose(controller);
|
SDL_GameControllerClose(controller);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -868,7 +563,7 @@ void SdlInputHandler::handleControllerDeviceEvent(SDL_ControllerDeviceEvent* eve
|
||||||
}
|
}
|
||||||
|
|
||||||
state->controller = controller;
|
state->controller = controller;
|
||||||
state->jsId = jsId;
|
state->jsId = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(state->controller));
|
||||||
|
|
||||||
hapticCaps = 0;
|
hapticCaps = 0;
|
||||||
#if SDL_VERSION_ATLEAST(2, 0, 18)
|
#if SDL_VERSION_ATLEAST(2, 0, 18)
|
||||||
|
|
@ -1013,9 +708,7 @@ void SdlInputHandler::handleControllerDeviceEvent(SDL_ControllerDeviceEvent* eve
|
||||||
#endif
|
#endif
|
||||||
type == LI_CTYPE_PS;
|
type == LI_CTYPE_PS;
|
||||||
|
|
||||||
if (isGamepadInputAllowed()) {
|
LiSendControllerArrivalEvent(state->index, m_GamepadMask, type, supportedButtonFlags, capabilities);
|
||||||
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
|
||||||
|
|
@ -1057,10 +750,8 @@ 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
|
||||||
if (isGamepadInputAllowed()) {
|
LiSendMultiControllerEvent(state->index, m_GamepadMask,
|
||||||
LiSendMultiControllerEvent(state->index, m_GamepadMask,
|
0, 0, 0, 0, 0, 0, 0);
|
||||||
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));
|
||||||
|
|
@ -1072,49 +763,29 @@ void SdlInputHandler::handleJoystickArrivalEvent(SDL_JoyDeviceEvent* event)
|
||||||
{
|
{
|
||||||
SDL_assert(event->type == SDL_JOYDEVICEADDED);
|
SDL_assert(event->type == SDL_JOYDEVICEADDED);
|
||||||
|
|
||||||
if (SDL_IsGameController(event->which)) {
|
if (!SDL_IsGameController(event->which)) {
|
||||||
SDL_ControllerDeviceEvent controllerEvent = {};
|
char guidStr[33];
|
||||||
controllerEvent.type = SDL_CONTROLLERDEVICEADDED;
|
SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(event->which),
|
||||||
controllerEvent.which = event->which;
|
guidStr, sizeof(guidStr));
|
||||||
handleControllerDeviceEvent(&controllerEvent);
|
const char* name = SDL_JoystickNameForIndex(event->which);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char guidStr[33];
|
|
||||||
SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(event->which),
|
|
||||||
guidStr, sizeof(guidStr));
|
|
||||||
const char* name = SDL_JoystickNameForIndex(event->which);
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Joystick discovered with no mapping: %s %s",
|
|
||||||
name ? name : "<UNKNOWN>",
|
|
||||||
guidStr);
|
|
||||||
SDL_Joystick* joy = SDL_JoystickOpen(event->which);
|
|
||||||
if (joy != nullptr) {
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Number of axes: %d | Number of buttons: %d | Number of hats: %d",
|
"Joystick discovered with no mapping: %s %s",
|
||||||
SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy),
|
name ? name : "<UNKNOWN>",
|
||||||
SDL_JoystickNumHats(joy));
|
guidStr);
|
||||||
SDL_JoystickClose(joy);
|
SDL_Joystick* joy = SDL_JoystickOpen(event->which);
|
||||||
|
if (joy != nullptr) {
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Number of axes: %d | Number of buttons: %d | Number of hats: %d",
|
||||||
|
SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy),
|
||||||
|
SDL_JoystickNumHats(joy));
|
||||||
|
SDL_JoystickClose(joy);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Unable to open joystick for query: %s",
|
||||||
|
SDL_GetError());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Unable to open joystick for query: %s",
|
|
||||||
SDL_GetError());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SdlInputHandler::handleJoystickRemovalEvent(SDL_JoyDeviceEvent* event)
|
|
||||||
{
|
|
||||||
SDL_assert(event->type == SDL_JOYDEVICEREMOVED);
|
|
||||||
|
|
||||||
if (findStateForGamepad(event->which) == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_ControllerDeviceEvent controllerEvent = {};
|
|
||||||
controllerEvent.type = SDL_CONTROLLERDEVICEREMOVED;
|
|
||||||
controllerEvent.which = event->which;
|
|
||||||
handleControllerDeviceEvent(&controllerEvent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SdlInputHandler::rumble(unsigned short controllerNumber, unsigned short lowFreqMotor, unsigned short highFreqMotor)
|
void SdlInputHandler::rumble(unsigned short controllerNumber, unsigned short lowFreqMotor, unsigned short highFreqMotor)
|
||||||
|
|
@ -1249,21 +920,15 @@ QString SdlInputHandler::getUnmappedGamepads()
|
||||||
{
|
{
|
||||||
QString ret;
|
QString ret;
|
||||||
|
|
||||||
SdlInputSubsystems::LeaseOptions options = {};
|
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0) {
|
||||||
options.joystick = true;
|
|
||||||
options.gameController = true;
|
|
||||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
|
||||||
options.haptic = false;
|
|
||||||
#endif
|
|
||||||
options.applyMappings = true;
|
|
||||||
options.flushControllerDeviceEvents = false;
|
|
||||||
|
|
||||||
if (!SdlInputSubsystems::acquire("UnmappedGamepadProbe", options)) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Failed to acquire SDL input subsystems for unmapped gamepad probe");
|
"SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) failed: %s",
|
||||||
return ret;
|
SDL_GetError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MappingManager mappingManager;
|
||||||
|
mappingManager.applyMappings();
|
||||||
|
|
||||||
int numJoysticks = SDL_NumJoysticks();
|
int numJoysticks = SDL_NumJoysticks();
|
||||||
for (int i = 0; i < numJoysticks; i++) {
|
for (int i = 0; i < numJoysticks; i++) {
|
||||||
if (!SDL_IsGameController(i)) {
|
if (!SDL_IsGameController(i)) {
|
||||||
|
|
@ -1305,7 +970,7 @@ QString SdlInputHandler::getUnmappedGamepads()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SdlInputSubsystems::release("UnmappedGamepadProbe", options);
|
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
|
||||||
|
|
||||||
// Flush stale events so they aren't processed by the main session event loop
|
// Flush stale events so they aren't processed by the main session event loop
|
||||||
SDL_FlushEvents(SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED);
|
SDL_FlushEvents(SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#include <Limelight.h>
|
#include <Limelight.h>
|
||||||
#include "SDL_compat.h"
|
#include "SDL_compat.h"
|
||||||
#include "streaming/session.h"
|
#include "streaming/session.h"
|
||||||
#include "streaming/input/sdlinputsubsystems.h"
|
#include "settings/mappingmanager.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
|
@ -9,23 +9,6 @@
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
SdlInputSubsystems::LeaseOptions streamInputSubsystemLeaseOptions()
|
|
||||||
{
|
|
||||||
SdlInputSubsystems::LeaseOptions options = {};
|
|
||||||
options.joystick = true;
|
|
||||||
options.gameController = true;
|
|
||||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
|
||||||
options.haptic = true;
|
|
||||||
#endif
|
|
||||||
options.applyMappings = true;
|
|
||||||
options.flushControllerDeviceEvents = true;
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, int streamWidth, int streamHeight)
|
SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, int streamWidth, int streamHeight)
|
||||||
: m_MultiController(prefs.multiController),
|
: m_MultiController(prefs.multiController),
|
||||||
m_GamepadMouse(prefs.gamepadMouse),
|
m_GamepadMouse(prefs.gamepadMouse),
|
||||||
|
|
@ -36,8 +19,6 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, int streamWidth, i
|
||||||
m_PendingMouseButtonsAllUpOnVideoRegionLeave(false),
|
m_PendingMouseButtonsAllUpOnVideoRegionLeave(false),
|
||||||
m_PointerRegionLockActive(false),
|
m_PointerRegionLockActive(false),
|
||||||
m_PointerRegionLockToggledByUser(false),
|
m_PointerRegionLockToggledByUser(false),
|
||||||
m_LastJoystickCount(-1),
|
|
||||||
m_LastNonZeroJoystickTick(0),
|
|
||||||
m_FakeCaptureActive(false),
|
m_FakeCaptureActive(false),
|
||||||
m_CaptureSystemKeysMode(prefs.captureSysKeysMode),
|
m_CaptureSystemKeysMode(prefs.captureSysKeysMode),
|
||||||
m_MouseCursorCapturedVisibilityState(SDL_DISABLE),
|
m_MouseCursorCapturedVisibilityState(SDL_DISABLE),
|
||||||
|
|
@ -105,11 +86,6 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, int streamWidth, i
|
||||||
m_SpecialKeyCombos[KeyComboToggleStatsOverlay].scanCode = SDL_SCANCODE_S;
|
m_SpecialKeyCombos[KeyComboToggleStatsOverlay].scanCode = SDL_SCANCODE_S;
|
||||||
m_SpecialKeyCombos[KeyComboToggleStatsOverlay].enabled = true;
|
m_SpecialKeyCombos[KeyComboToggleStatsOverlay].enabled = true;
|
||||||
|
|
||||||
m_SpecialKeyCombos[KeyComboToggleControlPanel].keyCombo = KeyComboToggleControlPanel;
|
|
||||||
m_SpecialKeyCombos[KeyComboToggleControlPanel].keyCode = SDLK_p;
|
|
||||||
m_SpecialKeyCombos[KeyComboToggleControlPanel].scanCode = SDL_SCANCODE_P;
|
|
||||||
m_SpecialKeyCombos[KeyComboToggleControlPanel].enabled = true;
|
|
||||||
|
|
||||||
m_SpecialKeyCombos[KeyComboToggleMouseMode].keyCombo = KeyComboToggleMouseMode;
|
m_SpecialKeyCombos[KeyComboToggleMouseMode].keyCombo = KeyComboToggleMouseMode;
|
||||||
m_SpecialKeyCombos[KeyComboToggleMouseMode].keyCode = SDLK_m;
|
m_SpecialKeyCombos[KeyComboToggleMouseMode].keyCode = SDLK_m;
|
||||||
m_SpecialKeyCombos[KeyComboToggleMouseMode].scanCode = SDL_SCANCODE_M;
|
m_SpecialKeyCombos[KeyComboToggleMouseMode].scanCode = SDL_SCANCODE_M;
|
||||||
|
|
@ -130,36 +106,6 @@ 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[KeyComboToggleKeyboardInput].keyCombo = KeyComboToggleKeyboardInput;
|
|
||||||
m_SpecialKeyCombos[KeyComboToggleKeyboardInput].keyCode = SDLK_k;
|
|
||||||
m_SpecialKeyCombos[KeyComboToggleKeyboardInput].scanCode = SDL_SCANCODE_K;
|
|
||||||
m_SpecialKeyCombos[KeyComboToggleKeyboardInput].enabled = true;
|
|
||||||
|
|
||||||
m_SpecialKeyCombos[KeyComboToggleMouseInput].keyCombo = KeyComboToggleMouseInput;
|
|
||||||
m_SpecialKeyCombos[KeyComboToggleMouseInput].keyCode = SDLK_o;
|
|
||||||
m_SpecialKeyCombos[KeyComboToggleMouseInput].scanCode = SDL_SCANCODE_O;
|
|
||||||
m_SpecialKeyCombos[KeyComboToggleMouseInput].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[KeyComboVolumeUp].keyCombo = KeyComboVolumeUp;
|
|
||||||
m_SpecialKeyCombos[KeyComboVolumeUp].keyCode = SDLK_u;
|
|
||||||
m_SpecialKeyCombos[KeyComboVolumeUp].scanCode = SDL_SCANCODE_U;
|
|
||||||
m_SpecialKeyCombos[KeyComboVolumeUp].enabled = true;
|
|
||||||
|
|
||||||
m_SpecialKeyCombos[KeyComboVolumeDown].keyCombo = KeyComboVolumeDown;
|
|
||||||
m_SpecialKeyCombos[KeyComboVolumeDown].keyCode = SDLK_j;
|
|
||||||
m_SpecialKeyCombos[KeyComboVolumeDown].scanCode = SDL_SCANCODE_J;
|
|
||||||
m_SpecialKeyCombos[KeyComboVolumeDown].enabled = true;
|
|
||||||
|
|
||||||
m_SpecialKeyCombos[KeyComboToggleMute].keyCombo = KeyComboToggleMute;
|
|
||||||
m_SpecialKeyCombos[KeyComboToggleMute].keyCode = SDLK_n;
|
|
||||||
m_SpecialKeyCombos[KeyComboToggleMute].scanCode = SDL_SCANCODE_N;
|
|
||||||
m_SpecialKeyCombos[KeyComboToggleMute].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;
|
||||||
|
|
@ -201,11 +147,45 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, int streamWidth, i
|
||||||
SDL_SetHint(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES, streamIgnoreDevices.toUtf8());
|
SDL_SetHint(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES, streamIgnoreDevices.toUtf8());
|
||||||
SDL_SetHint(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT, streamIgnoreDevicesExcept.toUtf8());
|
SDL_SetHint(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT, streamIgnoreDevicesExcept.toUtf8());
|
||||||
|
|
||||||
if (!SdlInputSubsystems::acquire("StreamInput", streamInputSubsystemLeaseOptions())) {
|
// We must initialize joystick explicitly before gamecontroller in order
|
||||||
|
// to ensure we receive gamecontroller attach events for gamepads where
|
||||||
|
// SDL doesn't have a built-in mapping. By starting joystick first, we
|
||||||
|
// can allow mapping manager to update the mappings before GC attach
|
||||||
|
// events are generated.
|
||||||
|
SDL_assert(!SDL_WasInit(SDL_INIT_JOYSTICK));
|
||||||
|
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != 0) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Failed to acquire SDL input subsystems for streaming input");
|
"SDL_InitSubSystem(SDL_INIT_JOYSTICK) failed: %s",
|
||||||
|
SDL_GetError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MappingManager mappingManager;
|
||||||
|
mappingManager.applyMappings();
|
||||||
|
|
||||||
|
// Flush gamepad arrival and departure events which may be queued before
|
||||||
|
// starting the gamecontroller subsystem again. This prevents us from
|
||||||
|
// receiving duplicate arrival and departure events for the same gamepad.
|
||||||
|
SDL_FlushEvent(SDL_CONTROLLERDEVICEADDED);
|
||||||
|
SDL_FlushEvent(SDL_CONTROLLERDEVICEREMOVED);
|
||||||
|
|
||||||
|
// We need to reinit this each time, since you only get
|
||||||
|
// an initial set of gamepad arrival events once per init.
|
||||||
|
SDL_assert(!SDL_WasInit(SDL_INIT_GAMECONTROLLER));
|
||||||
|
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) failed: %s",
|
||||||
|
SDL_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
||||||
|
SDL_assert(!SDL_WasInit(SDL_INIT_HAPTIC));
|
||||||
|
if (SDL_InitSubSystem(SDL_INIT_HAPTIC) != 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"SDL_InitSubSystem(SDL_INIT_HAPTIC) failed: %s",
|
||||||
|
SDL_GetError());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Initialize the gamepad mask with currently attached gamepads to avoid
|
// Initialize the gamepad mask with currently attached gamepads to avoid
|
||||||
// causing gamepads to unexpectedly disappear and reappear on the host
|
// causing gamepads to unexpectedly disappear and reappear on the host
|
||||||
// during stream startup as we detect currently attached gamepads one at a time.
|
// during stream startup as we detect currently attached gamepads one at a time.
|
||||||
|
|
@ -239,7 +219,16 @@ SdlInputHandler::~SdlInputHandler()
|
||||||
SDL_RemoveTimer(m_RightButtonReleaseTimer);
|
SDL_RemoveTimer(m_RightButtonReleaseTimer);
|
||||||
SDL_RemoveTimer(m_DragTimer);
|
SDL_RemoveTimer(m_DragTimer);
|
||||||
|
|
||||||
SdlInputSubsystems::release("StreamInput", streamInputSubsystemLeaseOptions());
|
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_HAPTIC);
|
||||||
|
SDL_assert(!SDL_WasInit(SDL_INIT_HAPTIC));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
|
||||||
|
SDL_assert(!SDL_WasInit(SDL_INIT_GAMECONTROLLER));
|
||||||
|
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||||
|
SDL_assert(!SDL_WasInit(SDL_INIT_JOYSTICK));
|
||||||
|
|
||||||
// Return background event handling to off
|
// Return background event handling to off
|
||||||
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "0");
|
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "0");
|
||||||
|
|
@ -279,50 +268,6 @@ void SdlInputHandler::raiseAllKeys()
|
||||||
m_KeysDown.clear();
|
m_KeysDown.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SdlInputHandler::raiseAllMouseButtons()
|
|
||||||
{
|
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_MIDDLE);
|
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
|
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_X1);
|
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_X2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SdlInputHandler::raiseAllGamepadInputs()
|
|
||||||
{
|
|
||||||
uint16_t raisedIndexMask = 0;
|
|
||||||
|
|
||||||
for (auto &state : m_GamepadState) {
|
|
||||||
if (state.controller == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.buttons = 0;
|
|
||||||
state.lt = 0;
|
|
||||||
state.rt = 0;
|
|
||||||
state.lsX = 0;
|
|
||||||
state.lsY = 0;
|
|
||||||
state.rsX = 0;
|
|
||||||
state.rsY = 0;
|
|
||||||
state.emulatedClickpadButtonDown = false;
|
|
||||||
|
|
||||||
if ((raisedIndexMask & (1 << state.index)) != 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
LiSendMultiControllerEvent(state.index,
|
|
||||||
m_GamepadMask,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0);
|
|
||||||
raisedIndexMask |= (1 << state.index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SdlInputHandler::notifyMouseLeave()
|
void SdlInputHandler::notifyMouseLeave()
|
||||||
{
|
{
|
||||||
// SDL on Windows doesn't send the mouse button up until the mouse re-enters the window
|
// SDL on Windows doesn't send the mouse button up until the mouse re-enters the window
|
||||||
|
|
|
||||||
|
|
@ -116,10 +116,6 @@ public:
|
||||||
|
|
||||||
void handleJoystickArrivalEvent(SDL_JoyDeviceEvent* event);
|
void handleJoystickArrivalEvent(SDL_JoyDeviceEvent* event);
|
||||||
|
|
||||||
void handleJoystickRemovalEvent(SDL_JoyDeviceEvent* event);
|
|
||||||
|
|
||||||
void pollForMissingGamepads();
|
|
||||||
|
|
||||||
void sendText(QString& string);
|
void sendText(QString& string);
|
||||||
|
|
||||||
void rumble(uint16_t controllerNumber, uint16_t lowFreqMotor, uint16_t highFreqMotor);
|
void rumble(uint16_t controllerNumber, uint16_t lowFreqMotor, uint16_t highFreqMotor);
|
||||||
|
|
@ -138,10 +134,6 @@ public:
|
||||||
|
|
||||||
void raiseAllKeys();
|
void raiseAllKeys();
|
||||||
|
|
||||||
void raiseAllMouseButtons();
|
|
||||||
|
|
||||||
void raiseAllGamepadInputs();
|
|
||||||
|
|
||||||
void notifyMouseLeave();
|
void notifyMouseLeave();
|
||||||
|
|
||||||
void notifyFocusLost();
|
void notifyFocusLost();
|
||||||
|
|
@ -169,17 +161,10 @@ private:
|
||||||
KeyComboUngrabInput,
|
KeyComboUngrabInput,
|
||||||
KeyComboToggleFullScreen,
|
KeyComboToggleFullScreen,
|
||||||
KeyComboToggleStatsOverlay,
|
KeyComboToggleStatsOverlay,
|
||||||
KeyComboToggleControlPanel,
|
|
||||||
KeyComboToggleMouseMode,
|
KeyComboToggleMouseMode,
|
||||||
KeyComboToggleCursorHide,
|
KeyComboToggleCursorHide,
|
||||||
KeyComboToggleMinimize,
|
KeyComboToggleMinimize,
|
||||||
KeyComboPasteText,
|
KeyComboPasteText,
|
||||||
KeyComboToggleKeyboardInput,
|
|
||||||
KeyComboToggleMouseInput,
|
|
||||||
KeyComboToggleGamepadInput,
|
|
||||||
KeyComboVolumeUp,
|
|
||||||
KeyComboVolumeDown,
|
|
||||||
KeyComboToggleMute,
|
|
||||||
KeyComboTogglePointerRegionLock,
|
KeyComboTogglePointerRegionLock,
|
||||||
KeyComboQuitAndExit,
|
KeyComboQuitAndExit,
|
||||||
KeyComboMax
|
KeyComboMax
|
||||||
|
|
@ -188,11 +173,6 @@ private:
|
||||||
GamepadState*
|
GamepadState*
|
||||||
findStateForGamepad(SDL_JoystickID id);
|
findStateForGamepad(SDL_JoystickID id);
|
||||||
|
|
||||||
GamepadState*
|
|
||||||
ensureStateForGamepad(SDL_JoystickID id);
|
|
||||||
|
|
||||||
void cleanupDetachedGamepads();
|
|
||||||
|
|
||||||
void sendGamepadState(GamepadState* state);
|
void sendGamepadState(GamepadState* state);
|
||||||
|
|
||||||
void sendGamepadBatteryState(GamepadState* state, SDL_JoystickPowerLevel level);
|
void sendGamepadBatteryState(GamepadState* state, SDL_JoystickPowerLevel level);
|
||||||
|
|
@ -235,8 +215,6 @@ private:
|
||||||
bool m_PointerRegionLockToggledByUser;
|
bool m_PointerRegionLockToggledByUser;
|
||||||
|
|
||||||
int m_GamepadMask;
|
int m_GamepadMask;
|
||||||
int m_LastJoystickCount;
|
|
||||||
uint32_t m_LastNonZeroJoystickTick;
|
|
||||||
GamepadState m_GamepadState[MAX_GAMEPADS];
|
GamepadState m_GamepadState[MAX_GAMEPADS];
|
||||||
QSet<short> m_KeysDown;
|
QSet<short> m_KeysDown;
|
||||||
bool m_FakeCaptureActive;
|
bool m_FakeCaptureActive;
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,6 @@
|
||||||
#define VK_NUMPAD0 0x60
|
#define VK_NUMPAD0 0x60
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool isKeyboardMouseInputAllowed()
|
|
||||||
{
|
|
||||||
auto session = Session::get();
|
|
||||||
return session == nullptr || session->isKeyboardInputAllowed();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SdlInputHandler::performSpecialKeyCombo(KeyCombo combo)
|
void SdlInputHandler::performSpecialKeyCombo(KeyCombo combo)
|
||||||
{
|
{
|
||||||
switch (combo) {
|
switch (combo) {
|
||||||
|
|
@ -64,14 +58,6 @@ void SdlInputHandler::performSpecialKeyCombo(KeyCombo combo)
|
||||||
!Session::get()->getOverlayManager().isOverlayEnabled(Overlay::OverlayDebug));
|
!Session::get()->getOverlayManager().isOverlayEnabled(Overlay::OverlayDebug));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KeyComboToggleControlPanel:
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Detected control panel toggle combo");
|
|
||||||
if (auto session = Session::get(); session != nullptr) {
|
|
||||||
session->toggleControlPanelVisibility();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KeyComboToggleMouseMode:
|
case KeyComboToggleMouseMode:
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"Detected mouse mode toggle combo");
|
"Detected mouse mode toggle combo");
|
||||||
|
|
@ -128,9 +114,7 @@ void SdlInputHandler::performSpecialKeyCombo(KeyCombo combo)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send this text to the PC
|
// Send this text to the PC
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendUtf8TextEvent(text, (unsigned int)strlen(text));
|
||||||
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);
|
||||||
|
|
@ -142,54 +126,6 @@ void SdlInputHandler::performSpecialKeyCombo(KeyCombo combo)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case KeyComboToggleKeyboardInput:
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Detected keyboard input toggle combo");
|
|
||||||
if (auto session = Session::get(); session != nullptr) {
|
|
||||||
session->toggleKeyboardInputAllowed();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KeyComboToggleMouseInput:
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Detected mouse input toggle combo");
|
|
||||||
if (auto session = Session::get(); session != nullptr) {
|
|
||||||
session->toggleMouseInputAllowed();
|
|
||||||
}
|
|
||||||
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 KeyComboVolumeUp:
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Detected volume up combo");
|
|
||||||
if (auto session = Session::get(); session != nullptr) {
|
|
||||||
session->adjustAudioVolume(0.05f);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KeyComboVolumeDown:
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Detected volume down combo");
|
|
||||||
if (auto session = Session::get(); session != nullptr) {
|
|
||||||
session->adjustAudioVolume(-0.05f);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KeyComboToggleMute:
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Detected audio mute toggle combo");
|
|
||||||
if (auto session = Session::get(); session != nullptr) {
|
|
||||||
session->toggleAudioMute();
|
|
||||||
}
|
|
||||||
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");
|
||||||
|
|
@ -521,11 +457,9 @@ void SdlInputHandler::handleKeyEvent(SDL_KeyboardEvent* event)
|
||||||
m_KeysDown.remove(keyCode);
|
m_KeysDown.remove(keyCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendKeyboardEvent2(0x8000 | keyCode,
|
||||||
LiSendKeyboardEvent2(0x8000 | keyCode,
|
event->state == SDL_PRESSED ?
|
||||||
event->state == SDL_PRESSED ?
|
KEY_ACTION_DOWN : KEY_ACTION_UP,
|
||||||
KEY_ACTION_DOWN : KEY_ACTION_UP,
|
modifiers,
|
||||||
modifiers,
|
shouldNotConvertToScanCodeOnServer ? SS_KBE_FLAG_NON_NORMALIZED : 0);
|
||||||
shouldNotConvertToScanCodeOnServer ? SS_KBE_FLAG_NON_NORMALIZED : 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,9 @@
|
||||||
#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->isMouseInputAllowed();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SdlInputHandler::handleMouseButtonEvent(SDL_MouseButtonEvent* event)
|
void SdlInputHandler::handleMouseButtonEvent(SDL_MouseButtonEvent* event)
|
||||||
{
|
{
|
||||||
int button;
|
int button;
|
||||||
|
|
@ -69,12 +62,10 @@ void SdlInputHandler::handleMouseButtonEvent(SDL_MouseButtonEvent* event)
|
||||||
button = BUTTON_RIGHT;
|
button = BUTTON_RIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendMouseButtonEvent(event->state == SDL_PRESSED ?
|
||||||
LiSendMouseButtonEvent(event->state == SDL_PRESSED ?
|
BUTTON_ACTION_PRESS :
|
||||||
BUTTON_ACTION_PRESS :
|
BUTTON_ACTION_RELEASE,
|
||||||
BUTTON_ACTION_RELEASE,
|
button);
|
||||||
button);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SdlInputHandler::handleMouseMotionEvent(SDL_MouseMotionEvent* event)
|
void SdlInputHandler::handleMouseMotionEvent(SDL_MouseMotionEvent* event)
|
||||||
|
|
@ -143,9 +134,7 @@ void SdlInputHandler::handleMouseMotionEvent(SDL_MouseMotionEvent* event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mouseInVideoRegion || m_MouseWasInVideoRegion || m_PendingMouseButtonsAllUpOnVideoRegionLeave) {
|
if (mouseInVideoRegion || m_MouseWasInVideoRegion || m_PendingMouseButtonsAllUpOnVideoRegionLeave) {
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendMousePositionEvent((short)x, (short)y, dst.w, dst.h);
|
||||||
LiSendMousePositionEvent((short)x, (short)y, dst.w, dst.h);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adjust the cursor visibility if applicable
|
// Adjust the cursor visibility if applicable
|
||||||
|
|
@ -161,9 +150,7 @@ void SdlInputHandler::handleMouseMotionEvent(SDL_MouseMotionEvent* event)
|
||||||
m_MouseWasInVideoRegion = mouseInVideoRegion;
|
m_MouseWasInVideoRegion = mouseInVideoRegion;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendMouseMoveEvent(xrel, yrel);
|
||||||
LiSendMouseMoveEvent(xrel, yrel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -200,9 +187,7 @@ 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
|
||||||
|
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendHighResScrollEvent((short)(event->preciseY * 120)); // WHEEL_DELTA
|
||||||
LiSendHighResScrollEvent((short)(event->preciseY * 120)); // WHEEL_DELTA
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event->preciseX != 0.0f) {
|
if (event->preciseX != 0.0f) {
|
||||||
|
|
@ -217,9 +202,7 @@ 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
|
||||||
|
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendHighResHScrollEvent((short)(event->preciseX * 120)); // WHEEL_DELTA
|
||||||
LiSendHighResHScrollEvent((short)(event->preciseX * 120)); // WHEEL_DELTA
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (event->y != 0) {
|
if (event->y != 0) {
|
||||||
|
|
@ -233,9 +216,7 @@ void SdlInputHandler::handleMouseWheelEvent(SDL_MouseWheelEvent* event)
|
||||||
event->y = SDL_clamp(event->y, -1, 1);
|
event->y = SDL_clamp(event->y, -1, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendScrollEvent((signed char)event->y);
|
||||||
LiSendScrollEvent((signed char)event->y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event->x != 0) {
|
if (event->x != 0) {
|
||||||
|
|
@ -249,9 +230,7 @@ void SdlInputHandler::handleMouseWheelEvent(SDL_MouseWheelEvent* event)
|
||||||
event->x = SDL_clamp(event->x, -1, 1);
|
event->x = SDL_clamp(event->x, -1, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendHScrollEvent((signed char)event->x);
|
||||||
LiSendHScrollEvent((signed char)event->x);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
#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->isMouseInputAllowed();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
||||||
|
|
||||||
|
|
@ -23,17 +16,13 @@ static bool isKeyboardMouseInputAllowed()
|
||||||
|
|
||||||
Uint32 SdlInputHandler::releaseLeftButtonTimerCallback(Uint32, void*)
|
Uint32 SdlInputHandler::releaseLeftButtonTimerCallback(Uint32, void*)
|
||||||
{
|
{
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Uint32 SdlInputHandler::releaseRightButtonTimerCallback(Uint32, void*)
|
Uint32 SdlInputHandler::releaseRightButtonTimerCallback(Uint32, void*)
|
||||||
{
|
{
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,9 +39,7 @@ Uint32 SdlInputHandler::dragTimerCallback(Uint32, void *param)
|
||||||
me->m_DragButton = BUTTON_LEFT;
|
me->m_DragButton = BUTTON_LEFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, me->m_DragButton);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, me->m_DragButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -112,7 +99,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) && isKeyboardMouseInputAllowed()) {
|
if (deltaX != 0 || deltaY != 0) {
|
||||||
LiSendMouseMoveEvent(deltaX, deltaY);
|
LiSendMouseMoveEvent(deltaX, deltaY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -146,9 +133,7 @@ void SdlInputHandler::handleRelativeFingerEvent(SDL_TouchFingerEvent* event)
|
||||||
|
|
||||||
// Release any drag
|
// Release any drag
|
||||||
if (m_DragButton != 0) {
|
if (m_DragButton != 0) {
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, m_DragButton);
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, m_DragButton);
|
|
||||||
}
|
|
||||||
m_DragButton = 0;
|
m_DragButton = 0;
|
||||||
}
|
}
|
||||||
// 2 finger tap
|
// 2 finger tap
|
||||||
|
|
@ -158,9 +143,7 @@ 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
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
|
||||||
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);
|
||||||
|
|
@ -171,9 +154,7 @@ 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
|
||||||
if (isKeyboardMouseInputAllowed()) {
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
||||||
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);
|
||||||
|
|
|
||||||
|
|
@ -1,191 +0,0 @@
|
||||||
#include "streaming/input/sdlinputsubsystems.h"
|
|
||||||
|
|
||||||
#include "settings/mappingmanager.h"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
int s_JoystickRefs = 0;
|
|
||||||
int s_GameControllerRefs = 0;
|
|
||||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
|
||||||
int s_HapticRefs = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool retainSubsystem(Uint32 subsystem, int& refs, const char* subsystemName, const char* ownerTag)
|
|
||||||
{
|
|
||||||
if (refs == 0 && SDL_InitSubSystem(subsystem) != 0) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Failed to initialize %s subsystem for %s: %s",
|
|
||||||
subsystemName,
|
|
||||||
ownerTag,
|
|
||||||
SDL_GetError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
refs++;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void releaseSubsystem(Uint32 subsystem, int& refs, const char* subsystemName, const char* ownerTag)
|
|
||||||
{
|
|
||||||
if (refs <= 0) {
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Ignoring unbalanced release of %s subsystem for %s",
|
|
||||||
subsystemName,
|
|
||||||
ownerTag);
|
|
||||||
refs = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
refs--;
|
|
||||||
if (refs == 0) {
|
|
||||||
SDL_QuitSubSystem(subsystem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace SdlInputSubsystems {
|
|
||||||
|
|
||||||
bool acquire(const char* ownerTag, const LeaseOptions& options)
|
|
||||||
{
|
|
||||||
bool acquiredJoystick = false;
|
|
||||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
|
||||||
bool acquiredGameController = false;
|
|
||||||
bool acquiredHaptic = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (options.joystick) {
|
|
||||||
if (!retainSubsystem(SDL_INIT_JOYSTICK, s_JoystickRefs, "joystick", ownerTag)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
acquiredJoystick = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.gameController) {
|
|
||||||
if (!retainSubsystem(SDL_INIT_GAMECONTROLLER, s_GameControllerRefs, "gamecontroller", ownerTag)) {
|
|
||||||
if (acquiredJoystick) {
|
|
||||||
releaseSubsystem(SDL_INIT_JOYSTICK, s_JoystickRefs, "joystick", ownerTag);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
|
||||||
acquiredGameController = true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
|
||||||
if (options.haptic) {
|
|
||||||
if (!retainSubsystem(SDL_INIT_HAPTIC, s_HapticRefs, "haptic", ownerTag)) {
|
|
||||||
if (acquiredGameController) {
|
|
||||||
releaseSubsystem(SDL_INIT_GAMECONTROLLER, s_GameControllerRefs, "gamecontroller", ownerTag);
|
|
||||||
}
|
|
||||||
if (acquiredJoystick) {
|
|
||||||
releaseSubsystem(SDL_INIT_JOYSTICK, s_JoystickRefs, "joystick", ownerTag);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
acquiredHaptic = true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (options.applyMappings) {
|
|
||||||
MappingManager mappingManager;
|
|
||||||
mappingManager.applyMappings();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.flushControllerDeviceEvents) {
|
|
||||||
SDL_FlushEvent(SDL_CONTROLLERDEVICEADDED);
|
|
||||||
SDL_FlushEvent(SDL_CONTROLLERDEVICEREMOVED);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void release(const char* ownerTag, const LeaseOptions& options)
|
|
||||||
{
|
|
||||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
|
||||||
if (options.haptic) {
|
|
||||||
releaseSubsystem(SDL_INIT_HAPTIC, s_HapticRefs, "haptic", ownerTag);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (options.gameController) {
|
|
||||||
releaseSubsystem(SDL_INIT_GAMECONTROLLER, s_GameControllerRefs, "gamecontroller", ownerTag);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.joystick) {
|
|
||||||
releaseSubsystem(SDL_INIT_JOYSTICK, s_JoystickRefs, "joystick", ownerTag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasExclusiveGamepadOwnership()
|
|
||||||
{
|
|
||||||
if (s_JoystickRefs != 1 || s_GameControllerRefs != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
|
||||||
if (s_HapticRefs != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool reenumerateGamepadSubsystems(const char* ownerTag)
|
|
||||||
{
|
|
||||||
if (!hasExclusiveGamepadOwnership()) {
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Skipping subsystem re-enumeration for %s due to shared ownership (joystick=%d gamecontroller=%d)",
|
|
||||||
ownerTag,
|
|
||||||
s_JoystickRefs,
|
|
||||||
s_GameControllerRefs);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
|
||||||
SDL_QuitSubSystem(SDL_INIT_HAPTIC);
|
|
||||||
#endif
|
|
||||||
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
|
|
||||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
|
||||||
|
|
||||||
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != 0) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Failed to reinitialize joystick subsystem for %s: %s",
|
|
||||||
ownerTag,
|
|
||||||
SDL_GetError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Failed to reinitialize gamecontroller subsystem for %s: %s",
|
|
||||||
ownerTag,
|
|
||||||
SDL_GetError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
|
||||||
if (SDL_InitSubSystem(SDL_INIT_HAPTIC) != 0) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Failed to reinitialize haptic subsystem for %s: %s",
|
|
||||||
ownerTag,
|
|
||||||
SDL_GetError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
MappingManager mappingManager;
|
|
||||||
mappingManager.applyMappings();
|
|
||||||
|
|
||||||
SDL_JoystickUpdate();
|
|
||||||
SDL_GameControllerUpdate();
|
|
||||||
|
|
||||||
SDL_FlushEvents(SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED);
|
|
||||||
SDL_FlushEvents(SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMAPPED);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "SDL_compat.h"
|
|
||||||
|
|
||||||
namespace SdlInputSubsystems {
|
|
||||||
|
|
||||||
struct LeaseOptions {
|
|
||||||
bool joystick;
|
|
||||||
bool gameController;
|
|
||||||
#if !SDL_VERSION_ATLEAST(2, 0, 9)
|
|
||||||
bool haptic;
|
|
||||||
#endif
|
|
||||||
bool applyMappings;
|
|
||||||
bool flushControllerDeviceEvents;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool acquire(const char* ownerTag, const LeaseOptions& options);
|
|
||||||
|
|
||||||
void release(const char* ownerTag, const LeaseOptions& options);
|
|
||||||
|
|
||||||
bool hasExclusiveGamepadOwnership();
|
|
||||||
|
|
||||||
bool reenumerateGamepadSubsystems(const char* ownerTag);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -28,8 +28,6 @@
|
||||||
#define SDL_CODE_GAMECONTROLLER_SET_MOTION_EVENT_STATE 103
|
#define SDL_CODE_GAMECONTROLLER_SET_MOTION_EVENT_STATE 103
|
||||||
#define SDL_CODE_GAMECONTROLLER_SET_CONTROLLER_LED 104
|
#define SDL_CODE_GAMECONTROLLER_SET_CONTROLLER_LED 104
|
||||||
#define SDL_CODE_GAMECONTROLLER_SET_ADAPTIVE_TRIGGERS 105
|
#define SDL_CODE_GAMECONTROLLER_SET_ADAPTIVE_TRIGGERS 105
|
||||||
#define SDL_CODE_HIDE_STATUS_OVERLAY 106
|
|
||||||
#define SDL_CODE_SET_INPUT_POLICY 107
|
|
||||||
|
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
|
|
||||||
|
|
@ -62,8 +60,7 @@ CONNECTION_LISTENER_CALLBACKS Session::k_ConnCallbacks = {
|
||||||
Session::clRumbleTriggers,
|
Session::clRumbleTriggers,
|
||||||
Session::clSetMotionEventState,
|
Session::clSetMotionEventState,
|
||||||
Session::clSetControllerLED,
|
Session::clSetControllerLED,
|
||||||
Session::clSetAdaptiveTriggers,
|
Session::clSetAdaptiveTriggers
|
||||||
Session::clSetInputPolicy
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Session* Session::s_ActiveSession;
|
Session* Session::s_ActiveSession;
|
||||||
|
|
@ -178,8 +175,27 @@ void Session::clConnectionStatusUpdate(int connectionStatus)
|
||||||
"Connection status update: %d",
|
"Connection status update: %d",
|
||||||
connectionStatus);
|
connectionStatus);
|
||||||
|
|
||||||
s_ActiveSession->m_ConnectionStatus.store(connectionStatus, std::memory_order_relaxed);
|
if (!s_ActiveSession->m_Preferences->connectionWarnings) {
|
||||||
s_ActiveSession->refreshControlPanelOverlay();
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_ActiveSession->m_MouseEmulationRefCount > 0) {
|
||||||
|
// Don't display the overlay if mouse emulation is already using it
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (connectionStatus)
|
||||||
|
{
|
||||||
|
case CONN_STATUS_POOR:
|
||||||
|
s_ActiveSession->m_OverlayManager.updateOverlayText(Overlay::OverlayStatusUpdate,
|
||||||
|
s_ActiveSession->m_StreamConfig.bitrate > 5000 ?
|
||||||
|
"Slow connection to PC\nReduce your bitrate" : "Poor connection to PC");
|
||||||
|
s_ActiveSession->m_OverlayManager.setOverlayState(Overlay::OverlayStatusUpdate, true);
|
||||||
|
break;
|
||||||
|
case CONN_STATUS_OKAY:
|
||||||
|
s_ActiveSession->m_OverlayManager.setOverlayState(Overlay::OverlayStatusUpdate, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::clSetHdrMode(bool enabled)
|
void Session::clSetHdrMode(bool enabled)
|
||||||
|
|
@ -258,20 +274,6 @@ void Session::clSetAdaptiveTriggers(uint16_t controllerNumber, uint8_t eventFlag
|
||||||
SDL_PushEvent(&setControllerLEDEvent);
|
SDL_PushEvent(&setControllerLEDEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::clSetInputPolicy(uint8_t allowKeyboard, uint8_t allowMouse, uint8_t allowGamepad, uint8_t reason)
|
|
||||||
{
|
|
||||||
SDL_Event setInputPolicyEvent = {};
|
|
||||||
setInputPolicyEvent.type = SDL_USEREVENT;
|
|
||||||
setInputPolicyEvent.user.code = SDL_CODE_SET_INPUT_POLICY;
|
|
||||||
setInputPolicyEvent.user.data1 = nullptr;
|
|
||||||
setInputPolicyEvent.user.data2 = (void*)(uintptr_t)(
|
|
||||||
((uintptr_t)allowKeyboard << 24) |
|
|
||||||
((uintptr_t)allowMouse << 16) |
|
|
||||||
((uintptr_t)allowGamepad << 8) |
|
|
||||||
(uintptr_t)reason);
|
|
||||||
SDL_PushEvent(&setInputPolicyEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
|
bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
|
||||||
SDL_Window* window, int videoFormat, int width, int height,
|
SDL_Window* window, int videoFormat, int width, int height,
|
||||||
|
|
@ -554,14 +556,6 @@ 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_ManualAudioMuted(false),
|
|
||||||
m_AudioVolumeScalar(1.0f),
|
|
||||||
m_AllowGamepadInput(true),
|
|
||||||
m_AllowKeyboardInput(false),
|
|
||||||
m_AllowMouseInput(false),
|
|
||||||
m_ControlPanelVisible(true),
|
|
||||||
m_ConnectionStatus(CONN_STATUS_OKAY),
|
|
||||||
m_StatusOverlayGeneration(0),
|
|
||||||
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),
|
||||||
|
|
@ -575,285 +569,6 @@ Session::Session(NvComputer* computer, NvApp& app, StreamingPreferences *prefere
|
||||||
m_AudioSampleCount(0),
|
m_AudioSampleCount(0),
|
||||||
m_DropAudioEndTime(0)
|
m_DropAudioEndTime(0)
|
||||||
{
|
{
|
||||||
m_TemporaryStatusOverlayText[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::setGamepadInputAllowed(bool allowed)
|
|
||||||
{
|
|
||||||
if (!allowed && m_InputHandler != nullptr) {
|
|
||||||
m_InputHandler->raiseAllGamepadInputs();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_AllowGamepadInput.store(allowed, std::memory_order_relaxed);
|
|
||||||
sendInputPermissionStateToHost(LI_SESSION_INPUT_POLICY_REASON_USER_TOGGLE);
|
|
||||||
notifyInputPermissionState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::setKeyboardInputAllowed(bool allowed)
|
|
||||||
{
|
|
||||||
const bool previous = m_AllowKeyboardInput.exchange(allowed, std::memory_order_relaxed);
|
|
||||||
if (previous && !allowed && m_InputHandler != nullptr) {
|
|
||||||
m_InputHandler->raiseAllKeys();
|
|
||||||
}
|
|
||||||
|
|
||||||
sendInputPermissionStateToHost(LI_SESSION_INPUT_POLICY_REASON_USER_TOGGLE);
|
|
||||||
notifyInputPermissionState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::setMouseInputAllowed(bool allowed)
|
|
||||||
{
|
|
||||||
const bool previous = m_AllowMouseInput.exchange(allowed, std::memory_order_relaxed);
|
|
||||||
if (previous && !allowed && m_InputHandler != nullptr) {
|
|
||||||
m_InputHandler->raiseAllMouseButtons();
|
|
||||||
}
|
|
||||||
|
|
||||||
sendInputPermissionStateToHost(LI_SESSION_INPUT_POLICY_REASON_USER_TOGGLE);
|
|
||||||
notifyInputPermissionState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::setAudioVolumeScalar(float scalar)
|
|
||||||
{
|
|
||||||
scalar = SDL_clamp(scalar, 0.0f, 1.0f);
|
|
||||||
m_AudioVolumeScalar.store(scalar, std::memory_order_relaxed);
|
|
||||||
notifyAudioVolumeState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::adjustAudioVolume(float delta)
|
|
||||||
{
|
|
||||||
const float current = getAudioVolumeScalar();
|
|
||||||
const float next = SDL_clamp(current + delta, 0.0f, 1.0f);
|
|
||||||
setAudioVolumeScalar(next);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::toggleAudioMute()
|
|
||||||
{
|
|
||||||
const bool muted = !m_ManualAudioMuted.load(std::memory_order_relaxed);
|
|
||||||
m_ManualAudioMuted.store(muted, std::memory_order_relaxed);
|
|
||||||
|
|
||||||
updateEffectiveAudioMuteState();
|
|
||||||
notifyAudioVolumeState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::notifyAudioVolumeState()
|
|
||||||
{
|
|
||||||
char buffer[64];
|
|
||||||
if (m_ManualAudioMuted.load(std::memory_order_relaxed)) {
|
|
||||||
SDL_snprintf(buffer, sizeof(buffer), "Volume: MUTED");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const int percent = (int)SDL_roundf(getAudioVolumeScalar() * 100.0f);
|
|
||||||
SDL_snprintf(buffer, sizeof(buffer), "Volume: %d%%", percent);
|
|
||||||
}
|
|
||||||
|
|
||||||
showTemporaryStatusOverlay(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::setKeyboardMouseInputAllowed(bool allowed)
|
|
||||||
{
|
|
||||||
const bool previousKeyboard = m_AllowKeyboardInput.exchange(allowed, std::memory_order_relaxed);
|
|
||||||
if (previousKeyboard && !allowed && m_InputHandler != nullptr) {
|
|
||||||
m_InputHandler->raiseAllKeys();
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool previousMouse = m_AllowMouseInput.exchange(allowed, std::memory_order_relaxed);
|
|
||||||
if (previousMouse && !allowed && m_InputHandler != nullptr) {
|
|
||||||
m_InputHandler->raiseAllMouseButtons();
|
|
||||||
}
|
|
||||||
|
|
||||||
sendInputPermissionStateToHost(LI_SESSION_INPUT_POLICY_REASON_USER_TOGGLE);
|
|
||||||
notifyInputPermissionState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::toggleGamepadInputAllowed()
|
|
||||||
{
|
|
||||||
setGamepadInputAllowed(!isGamepadInputAllowed());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::toggleKeyboardInputAllowed()
|
|
||||||
{
|
|
||||||
setKeyboardInputAllowed(!isKeyboardInputAllowed());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::toggleMouseInputAllowed()
|
|
||||||
{
|
|
||||||
setMouseInputAllowed(!isMouseInputAllowed());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::toggleKeyboardMouseInputAllowed()
|
|
||||||
{
|
|
||||||
setKeyboardMouseInputAllowed(!isKeyboardMouseInputAllowed());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::toggleControlPanelVisibility()
|
|
||||||
{
|
|
||||||
const bool visible = !m_ControlPanelVisible.load(std::memory_order_relaxed);
|
|
||||||
m_ControlPanelVisible.store(visible, std::memory_order_relaxed);
|
|
||||||
showTemporaryStatusOverlay(visible ? "Control panel shown" : "Control panel hidden");
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::notifyInputPermissionState()
|
|
||||||
{
|
|
||||||
char buffer[160];
|
|
||||||
SDL_snprintf(buffer,
|
|
||||||
sizeof(buffer),
|
|
||||||
"Input policy: host controlled\nKeyboard: %s\nMouse: %s\nGamepad: %s",
|
|
||||||
isKeyboardInputAllowed() ? "ON" : "OFF",
|
|
||||||
isMouseInputAllowed() ? "ON" : "OFF",
|
|
||||||
isGamepadInputAllowed() ? "ON" : "OFF");
|
|
||||||
|
|
||||||
showTemporaryStatusOverlay(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::sendInputPermissionStateToHost(uint8_t reason)
|
|
||||||
{
|
|
||||||
const bool allowKeyboard = isKeyboardInputAllowed();
|
|
||||||
const bool allowMouse = isMouseInputAllowed();
|
|
||||||
const bool allowGamepad = isGamepadInputAllowed();
|
|
||||||
const int err = LiSendSessionInputPolicy(allowKeyboard,
|
|
||||||
allowMouse,
|
|
||||||
allowGamepad,
|
|
||||||
reason);
|
|
||||||
|
|
||||||
if (err != 0 && err != LI_ERR_UNSUPPORTED) {
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Failed to send input policy update to host: %d",
|
|
||||||
err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Uint32 Session::statusOverlayTimeoutCallback(Uint32, void* param)
|
|
||||||
{
|
|
||||||
SDL_Event event = {};
|
|
||||||
event.type = SDL_USEREVENT;
|
|
||||||
event.user.code = SDL_CODE_HIDE_STATUS_OVERLAY;
|
|
||||||
event.user.data1 = param;
|
|
||||||
SDL_PushEvent(&event);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::refreshControlPanelOverlay()
|
|
||||||
{
|
|
||||||
if (!m_ControlPanelVisible.load(std::memory_order_relaxed)) {
|
|
||||||
if (m_TemporaryStatusOverlayText[0] != '\0') {
|
|
||||||
m_OverlayManager.updateOverlayText(Overlay::OverlayStatusUpdate, m_TemporaryStatusOverlayText);
|
|
||||||
m_OverlayManager.setOverlayState(Overlay::OverlayStatusUpdate, true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_OverlayManager.setOverlayState(Overlay::OverlayStatusUpdate, false);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char volumeState[24];
|
|
||||||
if (m_ManualAudioMuted.load(std::memory_order_relaxed)) {
|
|
||||||
SDL_snprintf(volumeState, sizeof(volumeState), "MUTED");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const int percent = (int)SDL_roundf(getAudioVolumeScalar() * 100.0f);
|
|
||||||
SDL_snprintf(volumeState, sizeof(volumeState), "%d%%", percent);
|
|
||||||
}
|
|
||||||
|
|
||||||
char panelText[640];
|
|
||||||
SDL_snprintf(panelText,
|
|
||||||
sizeof(panelText),
|
|
||||||
"Stream Controls\n"
|
|
||||||
"Keyboard: %s (KB: Ctrl+Alt+Shift+K, Pad: Select+L1+R1+Y)\n"
|
|
||||||
"Mouse: %s (KB: Ctrl+Alt+Shift+O, Pad: Select+L1+R1+DPad Up)\n"
|
|
||||||
"Pad: %s (KB: Ctrl+Alt+Shift+G, Pad: Select+L1+R1+A)\n"
|
|
||||||
"Vol: %s (KB: U/J, mute N; Pad: none)\n"
|
|
||||||
"UI: ON (KB: Ctrl+Alt+Shift+P, Pad: Select+L1+R1+B)\n"
|
|
||||||
"Input policy: host controlled",
|
|
||||||
isKeyboardInputAllowed() ? "ON" : "OFF",
|
|
||||||
isMouseInputAllowed() ? "ON" : "OFF",
|
|
||||||
isGamepadInputAllowed() ? "ON" : "OFF",
|
|
||||||
volumeState);
|
|
||||||
|
|
||||||
size_t used = SDL_strlen(panelText);
|
|
||||||
if (used < sizeof(panelText) && m_MouseEmulationRefCount > 0) {
|
|
||||||
SDL_snprintf(panelText + used,
|
|
||||||
sizeof(panelText) - used,
|
|
||||||
"\nMouse mode: ACTIVE (hold Start to disable)");
|
|
||||||
used = SDL_strlen(panelText);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used < sizeof(panelText) &&
|
|
||||||
m_Preferences->connectionWarnings &&
|
|
||||||
m_ConnectionStatus.load(std::memory_order_relaxed) == CONN_STATUS_POOR) {
|
|
||||||
SDL_snprintf(panelText + used,
|
|
||||||
sizeof(panelText) - used,
|
|
||||||
"\nNetwork: %s",
|
|
||||||
m_StreamConfig.bitrate > 5000 ? "Slow (reduce bitrate)" : "Poor");
|
|
||||||
used = SDL_strlen(panelText);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used < sizeof(panelText) && m_TemporaryStatusOverlayText[0] != '\0') {
|
|
||||||
SDL_snprintf(panelText + used,
|
|
||||||
sizeof(panelText) - used,
|
|
||||||
"\nStatus: %s",
|
|
||||||
m_TemporaryStatusOverlayText);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_OverlayManager.updateOverlayText(Overlay::OverlayStatusUpdate, panelText);
|
|
||||||
m_OverlayManager.setOverlayState(Overlay::OverlayStatusUpdate, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::showTemporaryStatusOverlay(const char* text, Uint32 timeoutMs)
|
|
||||||
{
|
|
||||||
if (text == nullptr || text[0] == '\0') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_snprintf(m_TemporaryStatusOverlayText,
|
|
||||||
sizeof(m_TemporaryStatusOverlayText),
|
|
||||||
"%s",
|
|
||||||
text);
|
|
||||||
refreshControlPanelOverlay();
|
|
||||||
|
|
||||||
const uint32_t generation = m_StatusOverlayGeneration.fetch_add(1, std::memory_order_relaxed) + 1;
|
|
||||||
SDL_AddTimer(timeoutMs, statusOverlayTimeoutCallback, (void*)(uintptr_t)generation);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::applyHostInputPolicy(bool allowKeyboard, bool allowMouse, bool allowGamepad, uint8_t reason)
|
|
||||||
{
|
|
||||||
const bool previousKeyboard = m_AllowKeyboardInput.exchange(allowKeyboard, std::memory_order_relaxed);
|
|
||||||
if (previousKeyboard && !allowKeyboard && m_InputHandler != nullptr) {
|
|
||||||
m_InputHandler->raiseAllKeys();
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool previousMouse = m_AllowMouseInput.exchange(allowMouse, std::memory_order_relaxed);
|
|
||||||
if (previousMouse && !allowMouse && m_InputHandler != nullptr) {
|
|
||||||
m_InputHandler->raiseAllMouseButtons();
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool previousGamepad = m_AllowGamepadInput.exchange(allowGamepad, std::memory_order_relaxed);
|
|
||||||
if (previousGamepad && !allowGamepad && m_InputHandler != nullptr) {
|
|
||||||
m_InputHandler->raiseAllGamepadInputs();
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool policyChanged =
|
|
||||||
previousKeyboard != allowKeyboard ||
|
|
||||||
previousMouse != allowMouse ||
|
|
||||||
previousGamepad != allowGamepad;
|
|
||||||
if (reason == LI_SESSION_INPUT_POLICY_REASON_STREAM_START ||
|
|
||||||
reason == LI_SESSION_INPUT_POLICY_REASON_HOST_ACK ||
|
|
||||||
reason == LI_SESSION_INPUT_POLICY_REASON_HOST_OVERRIDE ||
|
|
||||||
!policyChanged) {
|
|
||||||
refreshControlPanelOverlay();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
notifyInputPermissionState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::updateEffectiveAudioMuteState()
|
|
||||||
{
|
|
||||||
bool muted = m_ManualAudioMuted.load(std::memory_order_relaxed);
|
|
||||||
if (!muted && m_Preferences->muteOnFocusLoss && m_Window != nullptr) {
|
|
||||||
muted = SDL_GetKeyboardFocus() != m_Window;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_AudioMuted.store(muted, std::memory_order_relaxed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Session::~Session()
|
Session::~Session()
|
||||||
|
|
@ -1826,8 +1541,14 @@ void Session::notifyMouseEmulationMode(bool enabled)
|
||||||
m_MouseEmulationRefCount += enabled ? 1 : -1;
|
m_MouseEmulationRefCount += enabled ? 1 : -1;
|
||||||
SDL_assert(m_MouseEmulationRefCount >= 0);
|
SDL_assert(m_MouseEmulationRefCount >= 0);
|
||||||
|
|
||||||
showTemporaryStatusOverlay(enabled ? "Gamepad mouse mode enabled" : "Gamepad mouse mode disabled");
|
// We re-use the status update overlay for mouse mode notification
|
||||||
refreshControlPanelOverlay();
|
if (m_MouseEmulationRefCount > 0) {
|
||||||
|
m_OverlayManager.updateOverlayText(Overlay::OverlayStatusUpdate, "Gamepad mouse mode active\nLong press Start to deactivate");
|
||||||
|
m_OverlayManager.setOverlayState(Overlay::OverlayStatusUpdate, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_OverlayManager.setOverlayState(Overlay::OverlayStatusUpdate, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AsyncConnectionStartThread : public QThread
|
class AsyncConnectionStartThread : public QThread
|
||||||
|
|
@ -2026,17 +1747,6 @@ void Session::start()
|
||||||
// We're now active
|
// We're now active
|
||||||
s_ActiveSession = this;
|
s_ActiveSession = this;
|
||||||
|
|
||||||
m_AllowGamepadInput.store(true, std::memory_order_relaxed);
|
|
||||||
m_AllowKeyboardInput.store(false, std::memory_order_relaxed);
|
|
||||||
m_AllowMouseInput.store(false, std::memory_order_relaxed);
|
|
||||||
m_ManualAudioMuted.store(false, std::memory_order_relaxed);
|
|
||||||
m_AudioMuted.store(false, std::memory_order_relaxed);
|
|
||||||
m_AudioVolumeScalar.store(1.0f, std::memory_order_relaxed);
|
|
||||||
m_ControlPanelVisible.store(true, std::memory_order_relaxed);
|
|
||||||
m_ConnectionStatus.store(CONN_STATUS_OKAY, std::memory_order_relaxed);
|
|
||||||
m_StatusOverlayGeneration.fetch_add(1, std::memory_order_relaxed);
|
|
||||||
m_TemporaryStatusOverlayText[0] = '\0';
|
|
||||||
|
|
||||||
// Initialize the gamepad code with our preferences
|
// Initialize the gamepad code with our preferences
|
||||||
// NB: m_InputHandler must be initialize before starting the connection.
|
// NB: m_InputHandler must be initialize before starting the connection.
|
||||||
m_InputHandler = new SdlInputHandler(*m_Preferences, m_StreamConfig.width, m_StreamConfig.height);
|
m_InputHandler = new SdlInputHandler(*m_Preferences, m_StreamConfig.width, m_StreamConfig.height);
|
||||||
|
|
@ -2239,7 +1949,6 @@ void Session::exec()
|
||||||
|
|
||||||
// Toggle the stats overlay if requested by the user
|
// Toggle the stats overlay if requested by the user
|
||||||
m_OverlayManager.setOverlayState(Overlay::OverlayDebug, m_Preferences->showPerformanceOverlay);
|
m_OverlayManager.setOverlayState(Overlay::OverlayDebug, m_Preferences->showPerformanceOverlay);
|
||||||
refreshControlPanelOverlay();
|
|
||||||
|
|
||||||
// Switch to async logging mode when we enter the SDL loop
|
// Switch to async logging mode when we enter the SDL loop
|
||||||
StreamUtils::enterAsyncLoggingMode();
|
StreamUtils::enterAsyncLoggingMode();
|
||||||
|
|
@ -2247,14 +1956,7 @@ void Session::exec()
|
||||||
// Hijack this thread to be the SDL main thread. We have to do this
|
// Hijack this thread to be the SDL main thread. We have to do this
|
||||||
// because we want to suspend all Qt processing until the stream is over.
|
// because we want to suspend all Qt processing until the stream is over.
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
uint32_t nextGamepadPollTime = SDL_GetTicks();
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
uint32_t now = SDL_GetTicks();
|
|
||||||
if (SDL_TICKS_PASSED(now, nextGamepadPollTime)) {
|
|
||||||
m_InputHandler->pollForMissingGamepads();
|
|
||||||
nextGamepadPollTime = now + 250;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if SDL_VERSION_ATLEAST(2, 0, 18) && !defined(STEAM_LINK)
|
#if SDL_VERSION_ATLEAST(2, 0, 18) && !defined(STEAM_LINK)
|
||||||
// SDL 2.0.18 has a proper wait event implementation that uses platform
|
// SDL 2.0.18 has a proper wait event implementation that uses platform
|
||||||
// support to block on events rather than polling on Windows, macOS, X11,
|
// support to block on events rather than polling on Windows, macOS, X11,
|
||||||
|
|
@ -2266,7 +1968,6 @@ void Session::exec()
|
||||||
// issues that could cause indefinite timeouts, delayed joystick detection,
|
// issues that could cause indefinite timeouts, delayed joystick detection,
|
||||||
// and other problems.
|
// and other problems.
|
||||||
if (!SDL_WaitEventTimeout(&event, 1000)) {
|
if (!SDL_WaitEventTimeout(&event, 1000)) {
|
||||||
updateEffectiveAudioMuteState();
|
|
||||||
presence.runCallbacks();
|
presence.runCallbacks();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -2283,14 +1984,10 @@ void Session::exec()
|
||||||
// ARM core in the Steam Link, so we will wait 10 ms instead.
|
// ARM core in the Steam Link, so we will wait 10 ms instead.
|
||||||
SDL_Delay(10);
|
SDL_Delay(10);
|
||||||
#endif
|
#endif
|
||||||
updateEffectiveAudioMuteState();
|
|
||||||
presence.runCallbacks();
|
presence.runCallbacks();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
updateEffectiveAudioMuteState();
|
|
||||||
|
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_QUIT:
|
case SDL_QUIT:
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
|
@ -2332,21 +2029,6 @@ void Session::exec()
|
||||||
m_InputHandler->setAdaptiveTriggers((uint16_t)(uintptr_t)event.user.data1,
|
m_InputHandler->setAdaptiveTriggers((uint16_t)(uintptr_t)event.user.data1,
|
||||||
(DualSenseOutputReport *)event.user.data2);
|
(DualSenseOutputReport *)event.user.data2);
|
||||||
break;
|
break;
|
||||||
case SDL_CODE_SET_INPUT_POLICY: {
|
|
||||||
const uintptr_t packed = (uintptr_t)event.user.data2;
|
|
||||||
const bool allowKeyboard = ((packed >> 24) & 0xFF) != 0;
|
|
||||||
const bool allowMouse = ((packed >> 16) & 0xFF) != 0;
|
|
||||||
const bool allowGamepad = ((packed >> 8) & 0xFF) != 0;
|
|
||||||
const uint8_t reason = (uint8_t)(packed & 0xFF);
|
|
||||||
applyHostInputPolicy(allowKeyboard, allowMouse, allowGamepad, reason);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SDL_CODE_HIDE_STATUS_OVERLAY:
|
|
||||||
if ((uint32_t)(uintptr_t)event.user.data1 == m_StatusOverlayGeneration.load(std::memory_order_relaxed)) {
|
|
||||||
m_TemporaryStatusOverlayText[0] = '\0';
|
|
||||||
refreshControlPanelOverlay();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
SDL_assert(false);
|
SDL_assert(false);
|
||||||
}
|
}
|
||||||
|
|
@ -2356,9 +2038,15 @@ void Session::exec()
|
||||||
// Early handling of some events
|
// Early handling of some events
|
||||||
switch (event.window.event) {
|
switch (event.window.event) {
|
||||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||||
|
if (m_Preferences->muteOnFocusLoss) {
|
||||||
|
m_AudioMuted = true;
|
||||||
|
}
|
||||||
m_InputHandler->notifyFocusLost();
|
m_InputHandler->notifyFocusLost();
|
||||||
break;
|
break;
|
||||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||||
|
if (m_Preferences->muteOnFocusLoss) {
|
||||||
|
m_AudioMuted = false;
|
||||||
|
}
|
||||||
m_InputHandler->notifyFocusGained();
|
m_InputHandler->notifyFocusGained();
|
||||||
break;
|
break;
|
||||||
case SDL_WINDOWEVENT_LEAVE:
|
case SDL_WINDOWEVENT_LEAVE:
|
||||||
|
|
@ -2545,7 +2233,6 @@ void Session::exec()
|
||||||
|
|
||||||
// After a window resize, we need to reset the pointer lock region
|
// After a window resize, we need to reset the pointer lock region
|
||||||
m_InputHandler->updatePointerRegionLock();
|
m_InputHandler->updatePointerRegionLock();
|
||||||
refreshControlPanelOverlay();
|
|
||||||
|
|
||||||
SDL_UnlockMutex(m_DecoderLock);
|
SDL_UnlockMutex(m_DecoderLock);
|
||||||
break;
|
break;
|
||||||
|
|
@ -2596,9 +2283,6 @@ void Session::exec()
|
||||||
case SDL_JOYDEVICEADDED:
|
case SDL_JOYDEVICEADDED:
|
||||||
m_InputHandler->handleJoystickArrivalEvent(&event.jdevice);
|
m_InputHandler->handleJoystickArrivalEvent(&event.jdevice);
|
||||||
break;
|
break;
|
||||||
case SDL_JOYDEVICEREMOVED:
|
|
||||||
m_InputHandler->handleJoystickRemovalEvent(&event.jdevice);
|
|
||||||
break;
|
|
||||||
case SDL_FINGERDOWN:
|
case SDL_FINGERDOWN:
|
||||||
case SDL_FINGERMOTION:
|
case SDL_FINGERMOTION:
|
||||||
case SDL_FINGERUP:
|
case SDL_FINGERUP:
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#include <QSemaphore>
|
#include <QSemaphore>
|
||||||
#include <QQuickWindow>
|
#include <QQuickWindow>
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
#include <Limelight.h>
|
#include <Limelight.h>
|
||||||
#include <opus_multistream.h>
|
#include <opus_multistream.h>
|
||||||
|
|
@ -126,47 +125,6 @@ public:
|
||||||
|
|
||||||
void setShouldExit(bool quitHostApp = false);
|
void setShouldExit(bool quitHostApp = false);
|
||||||
|
|
||||||
bool isGamepadInputAllowed() const
|
|
||||||
{
|
|
||||||
return m_AllowGamepadInput.load(std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isKeyboardInputAllowed() const
|
|
||||||
{
|
|
||||||
return m_AllowKeyboardInput.load(std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isMouseInputAllowed() const
|
|
||||||
{
|
|
||||||
return m_AllowMouseInput.load(std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isKeyboardMouseInputAllowed() const
|
|
||||||
{
|
|
||||||
return isKeyboardInputAllowed() && isMouseInputAllowed();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setGamepadInputAllowed(bool allowed);
|
|
||||||
void setKeyboardInputAllowed(bool allowed);
|
|
||||||
void setMouseInputAllowed(bool allowed);
|
|
||||||
void setKeyboardMouseInputAllowed(bool allowed);
|
|
||||||
void toggleGamepadInputAllowed();
|
|
||||||
void toggleKeyboardInputAllowed();
|
|
||||||
void toggleMouseInputAllowed();
|
|
||||||
void toggleKeyboardMouseInputAllowed();
|
|
||||||
void toggleControlPanelVisibility();
|
|
||||||
void notifyInputPermissionState();
|
|
||||||
|
|
||||||
float getAudioVolumeScalar() const
|
|
||||||
{
|
|
||||||
return m_AudioVolumeScalar.load(std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setAudioVolumeScalar(float scalar);
|
|
||||||
void adjustAudioVolume(float delta);
|
|
||||||
void toggleAudioMute();
|
|
||||||
void notifyAudioVolumeState();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void stageStarting(QString stage);
|
void stageStarting(QString stage);
|
||||||
|
|
||||||
|
|
@ -264,9 +222,6 @@ private:
|
||||||
static
|
static
|
||||||
void clSetAdaptiveTriggers(uint16_t controllerNumber, uint8_t eventFlags, uint8_t typeLeft, uint8_t typeRight, uint8_t *left, uint8_t *right);
|
void clSetAdaptiveTriggers(uint16_t controllerNumber, uint8_t eventFlags, uint8_t typeLeft, uint8_t typeRight, uint8_t *left, uint8_t *right);
|
||||||
|
|
||||||
static
|
|
||||||
void clSetInputPolicy(uint8_t allowKeyboard, uint8_t allowMouse, uint8_t allowGamepad, uint8_t reason);
|
|
||||||
|
|
||||||
static
|
static
|
||||||
int arInit(int audioConfiguration,
|
int arInit(int audioConfiguration,
|
||||||
const POPUS_MULTISTREAM_CONFIGURATION opusConfig,
|
const POPUS_MULTISTREAM_CONFIGURATION opusConfig,
|
||||||
|
|
@ -287,15 +242,6 @@ private:
|
||||||
static
|
static
|
||||||
int drSubmitDecodeUnit(PDECODE_UNIT du);
|
int drSubmitDecodeUnit(PDECODE_UNIT du);
|
||||||
|
|
||||||
static
|
|
||||||
Uint32 statusOverlayTimeoutCallback(Uint32 interval, void* param);
|
|
||||||
|
|
||||||
void refreshControlPanelOverlay();
|
|
||||||
void showTemporaryStatusOverlay(const char* text, Uint32 timeoutMs = 1500);
|
|
||||||
void applyHostInputPolicy(bool allowKeyboard, bool allowMouse, bool allowGamepad, uint8_t reason);
|
|
||||||
void sendInputPermissionStateToHost(uint8_t reason);
|
|
||||||
void updateEffectiveAudioMuteState();
|
|
||||||
|
|
||||||
StreamingPreferences* m_Preferences;
|
StreamingPreferences* m_Preferences;
|
||||||
bool m_IsFullScreen;
|
bool m_IsFullScreen;
|
||||||
SupportedVideoFormatList m_SupportedVideoFormats; // Sorted in order of descending priority
|
SupportedVideoFormatList m_SupportedVideoFormats; // Sorted in order of descending priority
|
||||||
|
|
@ -308,15 +254,7 @@ private:
|
||||||
IVideoDecoder* m_VideoDecoder;
|
IVideoDecoder* m_VideoDecoder;
|
||||||
SDL_mutex* m_DecoderLock;
|
SDL_mutex* m_DecoderLock;
|
||||||
bool m_AudioDisabled;
|
bool m_AudioDisabled;
|
||||||
std::atomic<bool> m_AudioMuted;
|
bool m_AudioMuted;
|
||||||
std::atomic<bool> m_ManualAudioMuted;
|
|
||||||
std::atomic<float> m_AudioVolumeScalar;
|
|
||||||
std::atomic<bool> m_AllowGamepadInput;
|
|
||||||
std::atomic<bool> m_AllowKeyboardInput;
|
|
||||||
std::atomic<bool> m_AllowMouseInput;
|
|
||||||
std::atomic<bool> m_ControlPanelVisible;
|
|
||||||
std::atomic<int> m_ConnectionStatus;
|
|
||||||
std::atomic<uint32_t> m_StatusOverlayGeneration;
|
|
||||||
Uint32 m_FullScreenFlag;
|
Uint32 m_FullScreenFlag;
|
||||||
QQuickWindow* m_QtWindow;
|
QQuickWindow* m_QtWindow;
|
||||||
bool m_UnexpectedTermination;
|
bool m_UnexpectedTermination;
|
||||||
|
|
@ -340,7 +278,6 @@ private:
|
||||||
OPUS_MULTISTREAM_CONFIGURATION m_OriginalAudioConfig;
|
OPUS_MULTISTREAM_CONFIGURATION m_OriginalAudioConfig;
|
||||||
int m_AudioSampleCount;
|
int m_AudioSampleCount;
|
||||||
Uint32 m_DropAudioEndTime;
|
Uint32 m_DropAudioEndTime;
|
||||||
char m_TemporaryStatusOverlayText[160];
|
|
||||||
|
|
||||||
Overlay::OverlayManager m_OverlayManager;
|
Overlay::OverlayManager m_OverlayManager;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ OverlayManager::OverlayManager() :
|
||||||
m_Overlays[OverlayType::OverlayDebug].color = {0xD0, 0xD0, 0x00, 0xFF};
|
m_Overlays[OverlayType::OverlayDebug].color = {0xD0, 0xD0, 0x00, 0xFF};
|
||||||
m_Overlays[OverlayType::OverlayDebug].fontSize = 20;
|
m_Overlays[OverlayType::OverlayDebug].fontSize = 20;
|
||||||
|
|
||||||
m_Overlays[OverlayType::OverlayStatusUpdate].color = {0xF0, 0xF0, 0xF0, 0xFF};
|
m_Overlays[OverlayType::OverlayStatusUpdate].color = {0xCC, 0x00, 0x00, 0xFF};
|
||||||
m_Overlays[OverlayType::OverlayStatusUpdate].fontSize = 24;
|
m_Overlays[OverlayType::OverlayStatusUpdate].fontSize = 36;
|
||||||
|
|
||||||
// While TTF will usually not be initialized here, it is valid for that not to
|
// While TTF will usually not be initialized here, it is valid for that not to
|
||||||
// be the case, since Session destruction is deferred and could overlap with
|
// be the case, since Session destruction is deferred and could overlap with
|
||||||
|
|
@ -146,45 +146,16 @@ void OverlayManager::notifyOverlayUpdated(OverlayType type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Surface* newSurface = nullptr;
|
|
||||||
if (m_Overlays[type].enabled) {
|
|
||||||
// The _Wrapped variant is required for line breaks to work
|
|
||||||
SDL_Surface* textSurface = TTF_RenderText_Blended_Wrapped(m_Overlays[type].font,
|
|
||||||
m_Overlays[type].text,
|
|
||||||
m_Overlays[type].color,
|
|
||||||
1024);
|
|
||||||
if (textSurface != nullptr && type == OverlayStatusUpdate) {
|
|
||||||
constexpr int kHorizontalPadding = 18;
|
|
||||||
constexpr int kVerticalPadding = 12;
|
|
||||||
|
|
||||||
SDL_Surface* panelSurface = SDL_CreateRGBSurfaceWithFormat(0,
|
|
||||||
textSurface->w + (kHorizontalPadding * 2),
|
|
||||||
textSurface->h + (kVerticalPadding * 2),
|
|
||||||
32,
|
|
||||||
SDL_PIXELFORMAT_ARGB8888);
|
|
||||||
if (panelSurface != nullptr) {
|
|
||||||
SDL_FillRect(panelSurface,
|
|
||||||
nullptr,
|
|
||||||
SDL_MapRGBA(panelSurface->format, 0x00, 0x00, 0x00, 0xA0));
|
|
||||||
|
|
||||||
SDL_Rect destination = {kHorizontalPadding, kVerticalPadding, textSurface->w, textSurface->h};
|
|
||||||
SDL_SetSurfaceBlendMode(textSurface, SDL_BLENDMODE_BLEND);
|
|
||||||
SDL_BlitSurface(textSurface, nullptr, panelSurface, &destination);
|
|
||||||
SDL_FreeSurface(textSurface);
|
|
||||||
newSurface = panelSurface;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
newSurface = textSurface;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
newSurface = textSurface;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exchange the old surface with the new one
|
// Exchange the old surface with the new one
|
||||||
SDL_Surface* oldSurface = (SDL_Surface*)SDL_AtomicSetPtr((void**)&m_Overlays[type].surface,
|
SDL_Surface* oldSurface = (SDL_Surface*)SDL_AtomicSetPtr(
|
||||||
newSurface);
|
(void**)&m_Overlays[type].surface,
|
||||||
|
m_Overlays[type].enabled ?
|
||||||
|
// The _Wrapped variant is required for line breaks to work
|
||||||
|
TTF_RenderText_Blended_Wrapped(m_Overlays[type].font,
|
||||||
|
m_Overlays[type].text,
|
||||||
|
m_Overlays[type].color,
|
||||||
|
1024)
|
||||||
|
: nullptr);
|
||||||
|
|
||||||
// Notify the renderer
|
// Notify the renderer
|
||||||
m_Renderer->notifyOverlayUpdated(type);
|
m_Renderer->notifyOverlayUpdated(type);
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 611a2e7f8f6583d6d6aad30f0c8a02d6c07ab085
|
Subproject commit 6250fa29ee87873716045e3b64f1f229374324e8
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
JOBS="${JOBS:-$(nproc)}"
|
|
||||||
SKIP_BUILD=0
|
|
||||||
|
|
||||||
for arg in "$@"; do
|
|
||||||
case "$arg" in
|
|
||||||
--skip-build)
|
|
||||||
SKIP_BUILD=1
|
|
||||||
;;
|
|
||||||
--jobs=*)
|
|
||||||
JOBS="${arg#*=}"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unknown argument: $arg"
|
|
||||||
echo "Usage: $0 [--skip-build] [--jobs=N]"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ ! -f /run/.containerenv ]]; then
|
|
||||||
echo "Run this script inside your toolbox container."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! command -v dnf >/dev/null 2>&1; then
|
|
||||||
echo "This script expects a Fedora/RHEL-like toolbox with dnf."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
||||||
cd "$REPO_ROOT"
|
|
||||||
|
|
||||||
FEDORA_VER="$(rpm -E %fedora)"
|
|
||||||
|
|
||||||
if ! rpm -q rpmfusion-free-release >/dev/null 2>&1; then
|
|
||||||
sudo dnf -y install "https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-${FEDORA_VER}.noarch.rpm"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! rpm -q rpmfusion-nonfree-release >/dev/null 2>&1; then
|
|
||||||
sudo dnf -y install "https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-${FEDORA_VER}.noarch.rpm"
|
|
||||||
fi
|
|
||||||
|
|
||||||
sudo dnf -y install \
|
|
||||||
ffmpeg ffmpeg-devel \
|
|
||||||
git make gcc gcc-c++ pkgconf-pkg-config \
|
|
||||||
qt6-qtbase-devel qt6-qtdeclarative-devel qt6-qtquickcontrols2-devel qt6-qtsvg-devel qt6-qtwayland-devel \
|
|
||||||
SDL2-devel SDL2_ttf-devel \
|
|
||||||
opus-devel openssl-devel \
|
|
||||||
libva-utils libva-devel libdrm-devel mesa-libEGL-devel mesa-libGL-devel \
|
|
||||||
libX11-devel libXext-devel libXrandr-devel libXfixes-devel libXi-devel libXcursor-devel
|
|
||||||
|
|
||||||
if rpm -q libva-intel-media-driver >/dev/null 2>&1; then
|
|
||||||
sudo dnf -y swap libva-intel-media-driver intel-media-driver --allowerasing
|
|
||||||
elif ! rpm -q intel-media-driver >/dev/null 2>&1; then
|
|
||||||
sudo dnf -y install intel-media-driver
|
|
||||||
fi
|
|
||||||
|
|
||||||
git submodule update --init --recursive
|
|
||||||
|
|
||||||
if command -v vainfo >/dev/null 2>&1; then
|
|
||||||
if ! vainfo 2>/dev/null | grep -q 'VAProfileHEVCMain'; then
|
|
||||||
echo "Warning: HEVC decode profile not detected in VAAPI."
|
|
||||||
fi
|
|
||||||
if ! vainfo 2>/dev/null | grep -q 'VAProfileH264High'; then
|
|
||||||
echo "Warning: H264 decode profile not detected in VAAPI."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -rf Makefile */Makefile */Makefile.* app/release app/debug
|
|
||||||
qmake6 moonlight-qt.pro
|
|
||||||
|
|
||||||
if [[ "$SKIP_BUILD" -eq 0 ]]; then
|
|
||||||
make release -j"$JOBS"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Done."
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue