Pass through focus-gain clicks to the host in absolute mouse mode

This commit is contained in:
Cameron Gutman 2020-05-06 18:58:43 -07:00
parent 97c15c7876
commit 05e82c24f8
3 changed files with 96 additions and 2 deletions

View file

@ -19,6 +19,8 @@ SdlInputHandler::SdlInputHandler(StreamingPreferences& prefs, NvComputer*, int s
m_StreamHeight(streamHeight),
m_AbsoluteMouseMode(prefs.absoluteMouseMode),
m_AbsoluteTouchMode(prefs.absoluteTouchMode),
m_PendingFocusGain(false),
m_PendingFocusButtonUp(0),
m_LeftButtonReleaseTimer(0),
m_RightButtonReleaseTimer(0),
m_DragTimer(0),
@ -203,12 +205,44 @@ void SdlInputHandler::notifyFocusGained()
#if defined(Q_OS_WIN32) || defined(Q_OS_DARWIN)
int mouseX, mouseY;
Uint32 mouseState = SDL_GetGlobalMouseState(&mouseX, &mouseY);
if (mouseState & SDL_BUTTON(SDL_BUTTON_LEFT)) {
if (mouseState != 0) {
int x, y, width, height;
SDL_GetWindowPosition(m_Window, &x, &y);
SDL_GetWindowSize(m_Window, &width, &height);
if (mouseX > x && mouseX < x+width && mouseY > y && mouseY < y+height) {
setCaptureActive(true);
if (m_AbsoluteMouseMode) {
// We won't receive mouse events until the mouse gesture ends after gaining
// focus. To allow users to click directly into the unfocused window, we'll
// emulate mouse events using SDL_GetGlobalMouseState().
m_PendingFocusGain = true;
if (mouseState & SDL_BUTTON_LMASK) {
m_PendingFocusButtonUp = SDL_BUTTON_LEFT;
}
else if (mouseState & SDL_BUTTON_RMASK) {
m_PendingFocusButtonUp = SDL_BUTTON_RIGHT;
}
else if (mouseState & SDL_BUTTON_MMASK) {
m_PendingFocusButtonUp = SDL_BUTTON_MIDDLE;
}
else if (mouseState & SDL_BUTTON_X1MASK) {
m_PendingFocusButtonUp = SDL_BUTTON_X1;
}
else if (mouseState & SDL_BUTTON_X2MASK) {
m_PendingFocusButtonUp = SDL_BUTTON_X2;
}
else {
SDL_assert(false);
m_PendingFocusGain = false;
}
// Update the mouse position then send the button down event
sendSyntheticMouseState(SDL_MOUSEMOTION, 0);
sendSyntheticMouseState(SDL_MOUSEBUTTONDOWN, m_PendingFocusButtonUp);
}
else if (mouseState & SDL_BUTTON_LMASK) {
setCaptureActive(true);
}
}
}
#endif

View file

@ -77,6 +77,8 @@ public:
void setCaptureActive(bool active);
void sendSyntheticMouseState(Uint32 state, Uint32 button);
static
QString getUnmappedGamepads();
@ -127,6 +129,9 @@ private:
bool m_AbsoluteMouseMode;
bool m_AbsoluteTouchMode;
bool m_PendingFocusGain;
Uint32 m_PendingFocusButtonUp;
SDL_TouchFingerEvent m_TouchDownEvent[MAX_FINGERS];
SDL_TimerID m_LeftButtonReleaseTimer;
SDL_TimerID m_RightButtonReleaseTimer;

View file

@ -111,6 +111,46 @@ void SdlInputHandler::handleMouseWheelEvent(SDL_MouseWheelEvent* event)
}
}
void SdlInputHandler::sendSyntheticMouseState(Uint32 type, Uint32 button) {
int mouseX, mouseY;
int windowX, windowY;
SDL_Event event;
Uint32 buttonState = SDL_GetGlobalMouseState(&mouseX, &mouseY);
SDL_GetWindowPosition(m_Window, &windowX, &windowY);
switch (type) {
case SDL_MOUSEMOTION:
event.motion.type = type;
event.motion.timestamp = SDL_GetTicks();
event.motion.windowID = SDL_GetWindowID(m_Window);
event.motion.which = 0;
event.motion.state = buttonState;
event.motion.x = mouseX - windowX;
event.motion.y = mouseY - windowY;
event.motion.xrel = 0;
event.motion.yrel = 0;
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
event.button.type = type;
event.button.timestamp = SDL_GetTicks();
event.button.windowID = SDL_GetWindowID(m_Window);
event.button.which = 0;
event.button.button = button;
event.button.state = type == SDL_MOUSEBUTTONDOWN ? SDL_PRESSED : SDL_RELEASED;
event.button.clicks = 1;
event.button.x = mouseX - windowX;
event.button.y = mouseY - windowY;
break;
default:
SDL_assert(false);
}
SDL_PushEvent(&event);
}
Uint32 SdlInputHandler::mouseMoveTimerCallback(Uint32 interval, void *param)
{
auto me = reinterpret_cast<SdlInputHandler*>(param);
@ -122,5 +162,20 @@ Uint32 SdlInputHandler::mouseMoveTimerCallback(Uint32 interval, void *param)
LiSendMouseMoveEvent(deltaX, deltaY);
}
if (me->m_PendingFocusGain && me->m_AbsoluteMouseMode) {
Uint32 buttonState = SDL_GetGlobalMouseState(NULL, NULL);
// Update the position first
me->sendSyntheticMouseState(SDL_MOUSEMOTION, 0);
// If the button has come up since last time, send that too
if ((buttonState & SDL_BUTTON(me->m_PendingFocusButtonUp)) == 0) {
me->sendSyntheticMouseState(SDL_MOUSEBUTTONUP, me->m_PendingFocusButtonUp);
// Focus gain has completed
me->m_PendingFocusGain = false;
}
}
return interval;
}