[client] ds: refactor app and cursor state into app.c and core.c

This commit is contained in:
Geoffrey McRae 2021-01-29 05:13:26 +11:00
parent 33fed48277
commit 4e1c0cc0d0
7 changed files with 210 additions and 219 deletions

View File

@ -297,10 +297,8 @@ static int sdlEventFilter(void * userdata, SDL_Event * event)
break; break;
app_updateCursorPos(event->motion.x, event->motion.y); app_updateCursorPos(event->motion.x, event->motion.y);
if (app_cursorIsGrabbed()) app_handleMouseRelitive(event->motion.xrel, event->motion.yrel,
app_handleMouseGrabbed(event->motion.xrel, event->motion.yrel); event->motion.xrel, event->motion.yrel);
else
app_handleMouseNormal(event->motion.xrel, event->motion.yrel);
break; break;
case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONDOWN:
@ -457,8 +455,7 @@ static void sdlWarpPointer(int x, int y, bool exiting)
static void sdlRealignPointer(void) static void sdlRealignPointer(void)
{ {
// no need to care about grab, realign only happens in normal mode app_handleMouseRelitive(0.0, 0.0, 0.0, 0.0);
app_handleMouseNormal(0, 0);
} }
static bool sdlIsValidPointerPos(int x, int y) static bool sdlIsValidPointerPos(int x, int y)

View File

@ -808,7 +808,7 @@ static void x11GenericEvent(XGenericEventCookie *cookie)
app_updateCursorPos(device->event_x, device->event_y); app_updateCursorPos(device->event_x, device->event_y);
if (!x11.pointerGrabbed) if (!x11.pointerGrabbed)
app_handleMouseNormal(0.0, 0.0); app_handleMouseRelitive(0.0, 0.0, 0.0, 0.0);
return; return;
} }
@ -857,17 +857,7 @@ static void x11GenericEvent(XGenericEventCookie *cookie)
prev_axis[0] = axis[0]; prev_axis[0] = axis[0];
prev_axis[1] = axis[1]; prev_axis[1] = axis[1];
if (app_cursorIsGrabbed()) app_handleMouseRelitive(axis[0], axis[1], raw_axis[0], raw_axis[1]);
{
if (app_cursorWantsRaw())
app_handleMouseGrabbed(raw_axis[0], raw_axis[1]);
else
app_handleMouseGrabbed(axis[0], axis[1]);
}
else
if (app_cursorInWindow())
app_handleMouseNormal(axis[0], axis[1]);
return; return;
} }
} }
@ -1077,7 +1067,7 @@ static void x11WarpPointer(int x, int y, bool exiting)
static void x11RealignPointer(void) static void x11RealignPointer(void)
{ {
app_handleMouseNormal(0, 0); app_handleMouseRelitive(0.0, 0.0, 0.0, 0.0);
} }
static bool x11IsValidPointerPos(int x, int y) static bool x11IsValidPointerPos(int x, int y)

View File

@ -37,16 +37,16 @@ LG_MsgAlert;
bool app_isRunning(void); bool app_isRunning(void);
bool app_inputEnabled(void); bool app_inputEnabled(void);
bool app_cursorIsGrabbed(void);
bool app_cursorWantsRaw(void);
bool app_cursorInWindow(void);
void app_updateCursorPos(double x, double y); void app_updateCursorPos(double x, double y);
void app_updateWindowPos(int x, int y); void app_updateWindowPos(int x, int y);
void app_handleResizeEvent(int w, int h, const struct Border border); void app_handleResizeEvent(int w, int h, const struct Border border);
void app_handleMouseGrabbed(double ex, double ey);
void app_handleMouseNormal(double ex, double ey); void app_handleMouseRelitive(double normx, double normy,
double rawx, double rawy);
void app_handleMouseBasic(void); void app_handleMouseBasic(void);
void app_resyncMouseBasic(void); void app_resyncMouseBasic(void);
void app_handleButtonPress(int button); void app_handleButtonPress(int button);
void app_handleButtonRelease(int button); void app_handleButtonRelease(int button);
void app_handleKeyPress(int scancode); void app_handleKeyPress(int scancode);

View File

@ -40,27 +40,6 @@ bool app_isRunning(void)
g_state.state == APP_STATE_RESTART; g_state.state == APP_STATE_RESTART;
} }
bool app_inputEnabled(void)
{
return g_params.useSpiceInput && !g_state.ignoreInput &&
((g_cursor.grab && g_params.captureInputOnly) || !g_params.captureInputOnly);
}
bool app_cursorInWindow(void)
{
return g_cursor.inWindow;
}
bool app_cursorIsGrabbed(void)
{
return g_cursor.grab;
}
bool app_cursorWantsRaw(void)
{
return g_params.rawMouse;
}
void app_updateCursorPos(double x, double y) void app_updateCursorPos(double x, double y)
{ {
g_cursor.pos.x = x; g_cursor.pos.x = x;
@ -71,7 +50,7 @@ void app_updateCursorPos(double x, double y)
void app_handleFocusEvent(bool focused) void app_handleFocusEvent(bool focused)
{ {
g_state.focused = focused; g_state.focused = focused;
if (!app_inputEnabled()) if (!core_inputEnabled())
return; return;
if (!focused) if (!focused)
@ -89,7 +68,7 @@ void app_handleEnterEvent(bool entered)
if (entered) if (entered)
{ {
g_cursor.inWindow = true; g_cursor.inWindow = true;
if (!app_inputEnabled()) if (!core_inputEnabled())
return; return;
g_cursor.realign = true; g_cursor.realign = true;
@ -99,7 +78,7 @@ void app_handleEnterEvent(bool entered)
g_cursor.inWindow = false; g_cursor.inWindow = false;
core_setCursorInView(false); core_setCursorInView(false);
if (!app_inputEnabled()) if (!core_inputEnabled())
return; return;
if (!g_params.alwaysShowCursor) if (!g_params.alwaysShowCursor)
@ -182,36 +161,9 @@ void spiceClipboardNotice(const SpiceDataType type)
g_state.ds->cbNotice(cb_spiceTypeToLGType(type)); g_state.ds->cbNotice(cb_spiceTypeToLGType(type));
} }
void app_handleMouseGrabbed(double ex, double ey)
{
if (!app_inputEnabled())
return;
int x, y;
if (g_params.rawMouse && !g_cursor.sens)
{
/* raw unscaled input are always round numbers */
x = floor(ex);
y = floor(ey);
}
else
{
/* apply sensitivity */
ex = (ex / 10.0) * (g_cursor.sens + 10);
ey = (ey / 10.0) * (g_cursor.sens + 10);
util_cursorToInt(ex, ey, &x, &y);
}
if (x == 0 && y == 0)
return;
if (!spice_mouse_motion(x, y))
DEBUG_ERROR("failed to send mouse motion message");
}
void app_handleButtonPress(int button) void app_handleButtonPress(int button)
{ {
if (!app_inputEnabled() || !g_cursor.inView) if (!core_inputEnabled() || !g_cursor.inView)
return; return;
g_cursor.buttons |= (1U << button); g_cursor.buttons |= (1U << button);
@ -222,7 +174,7 @@ void app_handleButtonPress(int button)
void app_handleButtonRelease(int button) void app_handleButtonRelease(int button)
{ {
if (!app_inputEnabled()) if (!core_inputEnabled())
return; return;
g_cursor.buttons &= ~(1U << button); g_cursor.buttons &= ~(1U << button);
@ -246,7 +198,7 @@ void app_handleKeyPress(int sc)
return; return;
} }
if (!app_inputEnabled()) if (!core_inputEnabled())
return; return;
if (g_params.ignoreWindowsKeys && (sc == KEY_LEFTMETA || sc == KEY_RIGHTMETA)) if (g_params.ignoreWindowsKeys && (sc == KEY_LEFTMETA || sc == KEY_RIGHTMETA))
@ -291,7 +243,7 @@ void app_handleKeyRelease(int sc)
g_state.escapeActive = false; g_state.escapeActive = false;
} }
if (!app_inputEnabled()) if (!core_inputEnabled())
return; return;
// avoid sending key up events when we didn't send a down // avoid sending key up events when we didn't send a down
@ -314,146 +266,19 @@ void app_handleKeyRelease(int sc)
} }
} }
void app_handleMouseNormal(double ex, double ey) void app_handleMouseRelitive(double normx, double normy,
double rawx, double rawy)
{ {
// prevent cursor handling outside of capture if the position is not known if (g_cursor.grab)
if (!g_cursor.guest.valid)
return;
if (!app_inputEnabled())
return;
/* scale the movement to the guest */
if (g_cursor.useScale && g_params.scaleMouseInput)
{ {
ex *= g_cursor.scale.x / g_cursor.dpiScale; if (g_params.rawMouse)
ey *= g_cursor.scale.y / g_cursor.dpiScale; core_handleMouseGrabbed(rawx, rawy);
} else
core_handleMouseGrabbed(normx, normy);
bool testExit = true;
if (!g_cursor.inView)
{
const bool inView =
g_cursor.pos.x >= g_state.dstRect.x &&
g_cursor.pos.x < g_state.dstRect.x + g_state.dstRect.w &&
g_cursor.pos.y >= g_state.dstRect.y &&
g_cursor.pos.y < g_state.dstRect.y + g_state.dstRect.h;
core_setCursorInView(inView);
if (inView)
g_cursor.realign = true;
}
/* nothing to do if we are outside the viewport */
if (!g_cursor.inView)
return;
/*
* do not pass mouse events to the guest if we do not have focus, this must be
* done after the inView test has been performed so that when focus is gained
* we know if we should be drawing the cursor.
*/
if (!g_state.focused)
return;
/* if we have been instructed to realign */
if (g_cursor.realign)
{
g_cursor.realign = false;
struct DoublePoint guest;
util_localCurToGuest(&guest);
/* add the difference to the offset */
ex += guest.x - (g_cursor.guest.x + g_cursor.guest.hx);
ey += guest.y - (g_cursor.guest.y + g_cursor.guest.hy);
/* don't test for an exit as we just entered, we can get into a enter/exit
* loop otherwise */
testExit = false;
}
/* if we are in "autoCapture" and the delta was large don't test for exit */
if (g_params.autoCapture &&
(fabs(ex) > 100.0 / g_cursor.scale.x || fabs(ey) > 100.0 / g_cursor.scale.y))
testExit = false;
/* if any buttons are held we should not allow exit to happen */
if (g_cursor.buttons)
testExit = false;
if (testExit)
{
/* translate the move to the guests orientation */
struct DoublePoint move = {.x = ex, .y = ey};
util_rotatePoint(&move);
/* translate the guests position to our coordinate space */
struct DoublePoint local;
util_guestCurToLocal(&local);
/* check if the move would push the cursor outside the guest's viewport */
if (
local.x + move.x < g_state.dstRect.x ||
local.y + move.y < g_state.dstRect.y ||
local.x + move.x >= g_state.dstRect.x + g_state.dstRect.w ||
local.y + move.y >= g_state.dstRect.y + g_state.dstRect.h)
{
local.x += move.x;
local.y += move.y;
const int tx = (local.x <= 0.0) ? floor(local.x) : ceil(local.x);
const int ty = (local.y <= 0.0) ? floor(local.y) : ceil(local.y);
if (core_isValidPointerPos(
g_state.windowPos.x + g_state.border.left + tx,
g_state.windowPos.y + g_state.border.top + ty))
{
core_setCursorInView(false);
/* preempt the window leave flag if the warp will leave our window */
if (tx < 0 || ty < 0 || tx > g_state.windowW || ty > g_state.windowH)
g_cursor.inWindow = false;
/* ungrab the pointer and move the local cursor to the exit point */
g_state.ds->ungrabPointer();
core_warpPointer(tx, ty, true);
return;
}
}
}
int x, y;
util_cursorToInt(ex, ey, &x, &y);
if (x == 0 && y == 0)
return;
if (g_params.autoCapture)
{
g_cursor.delta.x += x;
g_cursor.delta.y += y;
if (fabs(g_cursor.delta.x) > 50.0 || fabs(g_cursor.delta.y) > 50.0)
{
g_cursor.delta.x = 0;
g_cursor.delta.y = 0;
core_warpPointer(g_state.windowCX, g_state.windowCY, false);
}
g_cursor.guest.x = g_state.srcSize.x / 2;
g_cursor.guest.y = g_state.srcSize.y / 2;
} }
else else
{ if (g_cursor.inWindow)
/* assume the mouse will move to the location we attempt to move it to so we core_handleMouseNormal(normx, normy);
* avoid warp out of window issues. The cursorThread will correct this if
* wrong after the movement has ocurred on the guest */
g_cursor.guest.x += x;
g_cursor.guest.y += y;
}
if (!spice_mouse_motion(x, y))
DEBUG_ERROR("failed to send mouse motion message");
} }
static inline double clamp(double x, double min, double max) static inline double clamp(double x, double min, double max)
@ -473,7 +298,7 @@ void app_handleMouseBasic()
if (!g_cursor.guest.valid || !g_state.haveSrcSize || !g_state.focused) if (!g_cursor.guest.valid || !g_state.haveSrcSize || !g_state.focused)
return; return;
if (!app_inputEnabled()) if (!core_inputEnabled())
return; return;
const bool inView = const bool inView =
@ -529,7 +354,7 @@ void app_handleResizeEvent(int w, int h, const struct Border border)
g_state.windowCY = h / 2; g_state.windowCY = h / 2;
core_updatePositionInfo(); core_updatePositionInfo();
if (app_inputEnabled()) if (core_inputEnabled())
{ {
/* if the window is moved/resized causing a loss of focus while grabbed, it /* if the window is moved/resized causing a loss of focus while grabbed, it
* makes it impossible to re-focus the window, so we quietly re-enter * makes it impossible to re-focus the window, so we quietly re-enter

View File

@ -30,6 +30,12 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#define RESIZE_TIMEOUT (10 * 1000) // 10ms #define RESIZE_TIMEOUT (10 * 1000) // 10ms
bool core_inputEnabled(void)
{
return g_params.useSpiceInput && !g_state.ignoreInput &&
((g_cursor.grab && g_params.captureInputOnly) || !g_params.captureInputOnly);
}
void core_setCursorInView(bool enable) void core_setCursorInView(bool enable)
{ {
// if the state has not changed, don't do anything else // if the state has not changed, don't do anything else
@ -291,3 +297,172 @@ void core_stopFrameThread(void)
g_state.frameThread = NULL; g_state.frameThread = NULL;
} }
void core_handleMouseGrabbed(double ex, double ey)
{
if (!core_inputEnabled())
return;
int x, y;
if (g_params.rawMouse && !g_cursor.sens)
{
/* raw unscaled input are always round numbers */
x = floor(ex);
y = floor(ey);
}
else
{
/* apply sensitivity */
ex = (ex / 10.0) * (g_cursor.sens + 10);
ey = (ey / 10.0) * (g_cursor.sens + 10);
util_cursorToInt(ex, ey, &x, &y);
}
if (x == 0 && y == 0)
return;
if (!spice_mouse_motion(x, y))
DEBUG_ERROR("failed to send mouse motion message");
}
void core_handleMouseNormal(double ex, double ey)
{
// prevent cursor handling outside of capture if the position is not known
if (!g_cursor.guest.valid)
return;
if (!core_inputEnabled())
return;
/* scale the movement to the guest */
if (g_cursor.useScale && g_params.scaleMouseInput)
{
ex *= g_cursor.scale.x / g_cursor.dpiScale;
ey *= g_cursor.scale.y / g_cursor.dpiScale;
}
bool testExit = true;
if (!g_cursor.inView)
{
const bool inView =
g_cursor.pos.x >= g_state.dstRect.x &&
g_cursor.pos.x < g_state.dstRect.x + g_state.dstRect.w &&
g_cursor.pos.y >= g_state.dstRect.y &&
g_cursor.pos.y < g_state.dstRect.y + g_state.dstRect.h;
core_setCursorInView(inView);
if (inView)
g_cursor.realign = true;
}
/* nothing to do if we are outside the viewport */
if (!g_cursor.inView)
return;
/*
* do not pass mouse events to the guest if we do not have focus, this must be
* done after the inView test has been performed so that when focus is gained
* we know if we should be drawing the cursor.
*/
if (!g_state.focused)
return;
/* if we have been instructed to realign */
if (g_cursor.realign)
{
g_cursor.realign = false;
struct DoublePoint guest;
util_localCurToGuest(&guest);
/* add the difference to the offset */
ex += guest.x - (g_cursor.guest.x + g_cursor.guest.hx);
ey += guest.y - (g_cursor.guest.y + g_cursor.guest.hy);
/* don't test for an exit as we just entered, we can get into a enter/exit
* loop otherwise */
testExit = false;
}
/* if we are in "autoCapture" and the delta was large don't test for exit */
if (g_params.autoCapture &&
(fabs(ex) > 100.0 / g_cursor.scale.x || fabs(ey) > 100.0 / g_cursor.scale.y))
testExit = false;
/* if any buttons are held we should not allow exit to happen */
if (g_cursor.buttons)
testExit = false;
if (testExit)
{
/* translate the move to the guests orientation */
struct DoublePoint move = {.x = ex, .y = ey};
util_rotatePoint(&move);
/* translate the guests position to our coordinate space */
struct DoublePoint local;
util_guestCurToLocal(&local);
/* check if the move would push the cursor outside the guest's viewport */
if (
local.x + move.x < g_state.dstRect.x ||
local.y + move.y < g_state.dstRect.y ||
local.x + move.x >= g_state.dstRect.x + g_state.dstRect.w ||
local.y + move.y >= g_state.dstRect.y + g_state.dstRect.h)
{
local.x += move.x;
local.y += move.y;
const int tx = (local.x <= 0.0) ? floor(local.x) : ceil(local.x);
const int ty = (local.y <= 0.0) ? floor(local.y) : ceil(local.y);
if (core_isValidPointerPos(
g_state.windowPos.x + g_state.border.left + tx,
g_state.windowPos.y + g_state.border.top + ty))
{
core_setCursorInView(false);
/* preempt the window leave flag if the warp will leave our window */
if (tx < 0 || ty < 0 || tx > g_state.windowW || ty > g_state.windowH)
g_cursor.inWindow = false;
/* ungrab the pointer and move the local cursor to the exit point */
g_state.ds->ungrabPointer();
core_warpPointer(tx, ty, true);
return;
}
}
}
int x, y;
util_cursorToInt(ex, ey, &x, &y);
if (x == 0 && y == 0)
return;
if (g_params.autoCapture)
{
g_cursor.delta.x += x;
g_cursor.delta.y += y;
if (fabs(g_cursor.delta.x) > 50.0 || fabs(g_cursor.delta.y) > 50.0)
{
g_cursor.delta.x = 0;
g_cursor.delta.y = 0;
core_warpPointer(g_state.windowCX, g_state.windowCY, false);
}
g_cursor.guest.x = g_state.srcSize.x / 2;
g_cursor.guest.y = g_state.srcSize.y / 2;
}
else
{
/* assume the mouse will move to the location we attempt to move it to so we
* avoid warp out of window issues. The cursorThread will correct this if
* wrong after the movement has ocurred on the guest */
g_cursor.guest.x += x;
g_cursor.guest.y += y;
}
if (!spice_mouse_motion(x, y))
DEBUG_ERROR("failed to send mouse motion message");
}

View File

@ -22,6 +22,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include <stdbool.h> #include <stdbool.h>
bool core_inputEnabled(void);
void core_setCursorInView(bool enable); void core_setCursorInView(bool enable);
void core_setGrab(bool enable); void core_setGrab(bool enable);
void core_setGrabQuiet(bool enable); void core_setGrabQuiet(bool enable);
@ -31,5 +32,8 @@ void core_alignToGuest(void);
bool core_isValidPointerPos(int x, int y); bool core_isValidPointerPos(int x, int y);
bool core_startFrameThread(void); bool core_startFrameThread(void);
void core_stopFrameThread(void); void core_stopFrameThread(void);
void core_handleMouseGrabbed(double ex, double ey);
void core_handleMouseNormal(double ex, double ey);
#endif #endif

View File

@ -87,7 +87,7 @@ static void lgInit(void)
g_cursor.guest.valid = false; g_cursor.guest.valid = false;
// if spice is not in use, hide the local cursor // if spice is not in use, hide the local cursor
if (!app_inputEnabled() && g_params.hideMouse) if (!core_inputEnabled() && g_params.hideMouse)
g_state.ds->showPointer(false); g_state.ds->showPointer(false);
else else
g_state.ds->showPointer(true); g_state.ds->showPointer(true);
@ -296,7 +296,7 @@ static int cursorThread(void * unused)
g_cursor.guest.valid = true; g_cursor.guest.valid = true;
// if the state just became valid // if the state just became valid
if (valid != true && app_inputEnabled()) if (valid != true && core_inputEnabled())
{ {
core_alignToGuest(); core_alignToGuest();
app_resyncMouseBasic(); app_resyncMouseBasic();