Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions src/lib/platform/MSWindowsDesks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,15 @@ void MSWindowsDesks::fakeTouchClick(SInt32 x, SInt32 y) const
sendMessage(DESKFLOW_MSG_FAKE_TOUCH, static_cast<WPARAM>(x), static_cast<LPARAM>(y));
}

void MSWindowsDesks::setPendingTouchClick(SInt32 x, SInt32 y)
{
m_pendingTouchX = x;
m_pendingTouchY = y;
m_pendingTouchUp = true;
m_touchLifted = true;
LOG((CLOG_DEBUG "touch: LL hook path, pending click at %d,%d for deskEnter replay", x, y));
}

void MSWindowsDesks::fakeMouseMove(SInt32 x, SInt32 y) const
{
sendMessage(DESKFLOW_MSG_FAKE_MOVE, static_cast<WPARAM>(x), static_cast<LPARAM>(y));
Expand Down Expand Up @@ -883,12 +892,21 @@ MSWindowsDesks::HidTouchDevice MSWindowsDesks::initHidTouchDevice(HANDLE hDevice

USAGE usage = vc.IsRange ? vc.Range.UsageMin : vc.NotRange.Usage;
auto &ci = collections[vc.LinkCollection];

// Windows sign-extends LogicalMax into a LONG using BitSize bits.
// A 16-bit descriptor with max 0xFFFF becomes -1 as a signed LONG.
// Reconstruct the unsigned value from the bit width.
LONG logMax = vc.LogicalMax;
if (logMax < 0 && vc.BitSize > 0 && vc.BitSize < 32) {
logMax = static_cast<LONG>((1UL << vc.BitSize) - 1);
}

if (usage == HID_USAGE_GENERIC_X) {
ci.hasX = true;
ci.maxX = vc.LogicalMax > 0 ? vc.LogicalMax : vc.PhysicalMax;
ci.maxX = logMax > 0 ? logMax : vc.PhysicalMax;
} else if (usage == HID_USAGE_GENERIC_Y) {
ci.hasY = true;
ci.maxY = vc.LogicalMax > 0 ? vc.LogicalMax : vc.PhysicalMax;
ci.maxY = logMax > 0 ? logMax : vc.PhysicalMax;
}
}

Expand Down Expand Up @@ -954,6 +972,9 @@ bool MSWindowsDesks::parseHidTouch(const RAWINPUT *raw, const HidTouchDevice &de
// Touch digitizer maps to the primary monitor, not the virtual desktop
SInt32 pw = GetSystemMetrics(SM_CXSCREEN);
SInt32 ph = GetSystemMetrics(SM_CYSCREEN);
if (dev.logicalMaxX == 0 || dev.logicalMaxY == 0) {
return false;
}
outX = static_cast<SInt32>(rawX * pw / dev.logicalMaxX);
outY = static_cast<SInt32>(rawY * ph / dev.logicalMaxY);
LOG((CLOG_DEBUG1 "touch HID: raw=%lu,%lu logMax=%lu,%lu primary=%dx%d -> %d,%d",
Expand Down
2 changes: 2 additions & 0 deletions src/lib/platform/MSWindowsDesks.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ class MSWindowsDesks
*/
void fakeMouseButton(ButtonID id, bool press);

void setPendingTouchClick(SInt32 x, SInt32 y);

//! Fake mouse move
/*!
Synthesize a mouse move to the absolute coordinates \c x,y.
Expand Down
24 changes: 20 additions & 4 deletions src/lib/platform/MSWindowsHook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ static bool g_fakeServerInput = false;
static BOOL g_isPrimary = TRUE;
static BOOL g_isOnScreen = TRUE;
static bool g_touchActivateScreen = false;
static SInt32 g_xCenter = 0;
static SInt32 g_yCenter = 0;

MSWindowsHook::MSWindowsHook()
{
Expand Down Expand Up @@ -166,6 +168,12 @@ void MSWindowsHook::setIsOnScreen(bool onScreen)
g_isOnScreen = onScreen ? TRUE : FALSE;
}

void MSWindowsHook::setCursorCenter(SInt32 x, SInt32 y)
{
g_xCenter = x;
g_yCenter = y;
}

static void keyboardGetState(BYTE keys[256], DWORD vkCode, bool kf_up)
{
// we have to use GetAsyncKeyState() rather than GetKeyState() because
Expand Down Expand Up @@ -615,12 +623,20 @@ static LRESULT CALLBACK mouseLLHook(int code, WPARAM wParam, LPARAM lParam)
if (isTouchEvent && (wParam == WM_LBUTTONDOWN || wParam == WM_MOUSEMOVE)) {
SInt32 x = static_cast<SInt32>(info->pt.x);
SInt32 y = static_cast<SInt32>(info->pt.y);
LOG((CLOG_DEBUG "hook: touch at %d,%d posting DESKFLOW_MSG_TOUCH", x, y));
PostThreadMessage(g_threadID, DESKFLOW_MSG_TOUCH, x, y);
if (g_isPrimary) {
LOG((CLOG_DEBUG "hook: eating touch event (relay mode)"));

// Filter out warp-echo: the server warps the cursor to center after
// a switch, which generates a synthetic mouse event at that position.
// Without this filter, the echo triggers an immediate switch-back.
SInt32 dxc = x - g_xCenter;
SInt32 dyc = y - g_yCenter;
if (dxc >= -1 && dxc <= 1 && dyc >= -1 && dyc <= 1) {
LOG((CLOG_DEBUG2 "hook: ignoring touch at cursor center %d,%d", x, y));
return 1;
}

LOG((CLOG_DEBUG "hook: touch at %d,%d posting DESKFLOW_MSG_TOUCH", x, y));
PostThreadMessage(g_threadID, DESKFLOW_MSG_TOUCH, x, y);
// let the touch event pass through to the app so the click registers
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/lib/platform/MSWindowsHook.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,6 @@ class MSWindowsHook
void setIsPrimary(bool primary);

void setIsOnScreen(bool onScreen);

void setCursorCenter(SInt32 x, SInt32 y);
};
3 changes: 3 additions & 0 deletions src/lib/platform/MSWindowsScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,7 @@ bool MSWindowsScreen::onPreDispatch(HWND hwnd, UINT message, WPARAM wParam, LPAR
MotionInfo::alloc(x, y));
} else {
LOG((CLOG_INFO "hook: touch requesting grab input at %d,%d", x, y));
m_desks->setPendingTouchClick(x, y);
sendEvent(m_events->forIScreen().grabInput(),
MotionInfo::alloc(x, y));
}
Expand Down Expand Up @@ -1640,6 +1641,8 @@ void MSWindowsScreen::updateScreenShape()

// tell the desks
m_desks->setShape(m_x, m_y, m_w, m_h, m_xCenter, m_yCenter, m_multimon);

m_hook.setCursorCenter(m_xCenter, m_yCenter);
}

void MSWindowsScreen::handleFixes(const Event &, void *)
Expand Down
11 changes: 11 additions & 0 deletions src/lib/server/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,17 @@ BaseClientProxy *Server::mapToNeighbor(BaseClientProxy *src, EDirection srcSide,
// move inwards because that side can't provoke a jump.
avoidJumpZone(dst, srcSide, x, y);

// Clamp entry coordinates 1px inside the destination screen.
// avoidJumpZone only adjusts the crossing axis; the parallel axis can
// land exactly on the edge, which the cursor-warp logic treats as still
// being on the source side, bouncing the cursor back immediately.
SInt32 cx, cy, cw, ch;
dst->getShape(cx, cy, cw, ch);
if (x < cx + 1) x = cx + 1;
if (x > cx + cw - 2) x = cx + cw - 2;
if (y < cy + 1) y = cy + 1;
if (y > cy + ch - 2) y = cy + ch - 2;

return dst;
}

Expand Down