feat: Wayland, only set a side to a border if if has a neighboring screen

move protocolTypes Direction enum to new base/DirectionTypes
use the direction info when calling
fixes #8572
fixes #8452
fixes #8605
fixes #8005
This commit is contained in:
sithlord48
2025-07-13 10:26:11 -04:00
committed by Nick Bolton
parent ae5ba4e51f
commit f51abad8cc
17 changed files with 153 additions and 86 deletions

View File

@ -4,6 +4,7 @@
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
add_library(base STATIC add_library(base STATIC
DirectionTypes.h
Event.cpp Event.cpp
Event.h Event.h
EventQueue.cpp EventQueue.cpp

View File

@ -0,0 +1,47 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#pragma once
#include <cstdint>
/**
* @brief Screen edge directions for mouse movement
*
* Used to specify which edge of a screen the mouse cursor crosses
* when moving between primary and secondary screens.
*
* @since Protocol version 1.0
*/
enum class Direction : uint8_t
{
NoDirection, ///< No specific direction
Left, ///< Left edge of screen
Right, ///< Right edge of screen
Top, ///< Top edge of screen
Bottom, ///< Bottom edge of screen
FirstDirection = Direction::Left, ///< First valid direction value
LastDirection = Direction::Bottom, ///< Last valid direction value
NumDirections = Direction::LastDirection - Direction::FirstDirection + 1 ///< Total number of directions
};
/**
* @brief Bitmask values for screen edge directions
*
* Used to create bitmasks representing multiple screen edges.
* Useful for configuration and edge detection.
*
* @since Protocol version 1.0
*/
enum class DirectionMask
{
NoDirMask = 0, ///< No direction mask
LeftMask = 1 << static_cast<int>(Direction::Left), ///< Left edge mask
RightMask = 1 << static_cast<int>(Direction::Right), ///< Right edge mask
TopMask = 1 << static_cast<int>(Direction::Top), ///< Top edge mask
BottomMask = 1 << static_cast<int>(Direction::Bottom) ///< Bottom edge mask
};

View File

@ -155,6 +155,7 @@ public:
// IPrimaryScreen overrides // IPrimaryScreen overrides
void reconfigure(uint32_t activeSides) override = 0; void reconfigure(uint32_t activeSides) override = 0;
uint32_t activeSides() override = 0;
void warpCursor(int32_t x, int32_t y) override = 0; void warpCursor(int32_t x, int32_t y) override = 0;
uint32_t registerHotKey(KeyID key, KeyModifierMask mask) override = 0; uint32_t registerHotKey(KeyID key, KeyModifierMask mask) override = 0;
void unregisterHotKey(uint32_t id) override = 0; void unregisterHotKey(uint32_t id) override = 0;

View File

@ -85,6 +85,12 @@ public:
*/ */
virtual void reconfigure(uint32_t activeSides) = 0; virtual void reconfigure(uint32_t activeSides) = 0;
/**
* @brief activeSides
* @return a bitmask of DirectionMask indicating which sides of the primary screen are linked to clients
*/
virtual uint32_t activeSides() = 0;
//! Warp cursor //! Warp cursor
/*! /*!
Warp the cursor to the absolute coordinates \c x,y. Also Warp the cursor to the absolute coordinates \c x,y. Also

View File

@ -34,6 +34,7 @@ public:
// IPrimaryScreen overrides // IPrimaryScreen overrides
void reconfigure(uint32_t activeSides) override = 0; void reconfigure(uint32_t activeSides) override = 0;
uint32_t activeSides() override = 0;
void warpCursor(int32_t x, int32_t y) override = 0; void warpCursor(int32_t x, int32_t y) override = 0;
uint32_t registerHotKey(KeyID key, KeyModifierMask mask) override = 0; uint32_t registerHotKey(KeyID key, KeyModifierMask mask) override = 0;
void unregisterHotKey(uint32_t id) override = 0; void unregisterHotKey(uint32_t id) override = 0;

View File

@ -7,10 +7,9 @@
#pragma once #pragma once
#include "base/DirectionTypes.h"
#include "base/EventTypes.h" #include "base/EventTypes.h"
#include <cstdint>
/** /**
* @file ProtocolTypes.h * @file ProtocolTypes.h
* @brief Deskflow Network Protocol Specification and Implementation * @brief Deskflow Network Protocol Specification and Implementation
@ -150,43 +149,6 @@ static constexpr uint32_t PROTOCOL_MAX_STRING_LENGTH = 1024 * 1024;
* @{ * @{
*/ */
/**
* @brief Screen edge directions for mouse movement
*
* Used to specify which edge of a screen the mouse cursor crosses
* when moving between primary and secondary screens.
*
* @since Protocol version 1.0
*/
enum class Direction : uint8_t
{
NoDirection, ///< No specific direction
Left, ///< Left edge of screen
Right, ///< Right edge of screen
Top, ///< Top edge of screen
Bottom, ///< Bottom edge of screen
FirstDirection = Direction::Left, ///< First valid direction value
LastDirection = Direction::Bottom, ///< Last valid direction value
NumDirections = Direction::LastDirection - Direction::FirstDirection + 1 ///< Total number of directions
};
/**
* @brief Bitmask values for screen edge directions
*
* Used to create bitmasks representing multiple screen edges.
* Useful for configuration and edge detection.
*
* @since Protocol version 1.0
*/
enum class DirectionMask
{
NoDirMask = 0, ///< No direction mask
LeftMask = 1 << static_cast<int>(Direction::Left), ///< Left edge mask
RightMask = 1 << static_cast<int>(Direction::Right), ///< Right edge mask
TopMask = 1 << static_cast<int>(Direction::Top), ///< Top edge mask
BottomMask = 1 << static_cast<int>(Direction::Bottom) ///< Bottom edge mask
};
/** /**
* @brief File transfer data chunk types * @brief File transfer data chunk types
* *

View File

@ -177,9 +177,15 @@ void EiScreen::getCursorPos(int32_t &x, int32_t &y) const
y = m_cursorY; y = m_cursorY;
} }
void EiScreen::reconfigure(uint32_t) void EiScreen::reconfigure(uint32_t activeSides)
{ {
// do nothing LOG((CLOG_DEBUG "active sides: %x", activeSides));
m_activeSides = activeSides;
}
std::uint32_t EiScreen::activeSides()
{
return m_activeSides;
} }
void EiScreen::warpCursor(int32_t x, int32_t y) void EiScreen::warpCursor(int32_t x, int32_t y)

View File

@ -43,6 +43,7 @@ public:
// IPrimaryScreen overrides // IPrimaryScreen overrides
void reconfigure(std::uint32_t activeSides) override; void reconfigure(std::uint32_t activeSides) override;
std::uint32_t activeSides() override;
void warpCursor(std::int32_t x, std::int32_t y) override; void warpCursor(std::int32_t x, std::int32_t y) override;
std::uint32_t registerHotKey(KeyID key, KeyModifierMask mask) override; std::uint32_t registerHotKey(KeyID key, KeyModifierMask mask) override;
void unregisterHotKey(std::uint32_t id) override; void unregisterHotKey(std::uint32_t id) override;
@ -128,6 +129,7 @@ private:
std::uint32_t m_sequenceNumber = 0; std::uint32_t m_sequenceNumber = 0;
std::uint32_t m_activeSides = 0;
std::uint32_t m_x = 0; std::uint32_t m_x = 0;
std::uint32_t m_y = 0; std::uint32_t m_y = 0;
std::uint32_t m_w = 0; std::uint32_t m_w = 0;

View File

@ -115,6 +115,11 @@ void MSWindowsHook::setSides(uint32_t sides)
g_zoneSides = sides; g_zoneSides = sides;
} }
uint32_t MSWindowsHook::getSides()
{
return g_zoneSides;
}
void MSWindowsHook::setZone(int32_t x, int32_t y, int32_t w, int32_t h, int32_t jumpZoneSize) void MSWindowsHook::setZone(int32_t x, int32_t y, int32_t w, int32_t h, int32_t jumpZoneSize)
{ {
g_zoneSize = jumpZoneSize; g_zoneSize = jumpZoneSize;

View File

@ -56,6 +56,7 @@ public:
int cleanup(); int cleanup();
void setSides(uint32_t sides); void setSides(uint32_t sides);
uint32_t getSides();
void setZone(int32_t x, int32_t y, int32_t w, int32_t h, int32_t jumpZoneSize); void setZone(int32_t x, int32_t y, int32_t w, int32_t h, int32_t jumpZoneSize);

View File

@ -507,6 +507,11 @@ void MSWindowsScreen::reconfigure(uint32_t activeSides)
m_hook.setSides(activeSides); m_hook.setSides(activeSides);
} }
uint32_t MSWindowsScreen::activeSides()
{
return m_hook.getSides();
}
void MSWindowsScreen::warpCursor(int32_t x, int32_t y) void MSWindowsScreen::warpCursor(int32_t x, int32_t y)
{ {
// warp mouse // warp mouse

View File

@ -86,6 +86,7 @@ public:
// IPrimaryScreen overrides // IPrimaryScreen overrides
void reconfigure(uint32_t activeSides) override; void reconfigure(uint32_t activeSides) override;
uint32_t activeSides() override;
void warpCursor(int32_t x, int32_t y) override; void warpCursor(int32_t x, int32_t y) override;
uint32_t registerHotKey(KeyID key, KeyModifierMask mask) override; uint32_t registerHotKey(KeyID key, KeyModifierMask mask) override;
void unregisterHotKey(uint32_t id) override; void unregisterHotKey(uint32_t id) override;

View File

@ -64,6 +64,7 @@ public:
// IPrimaryScreen overrides // IPrimaryScreen overrides
void reconfigure(uint32_t activeSides) override; void reconfigure(uint32_t activeSides) override;
uint32_t activeSides() override;
void warpCursor(int32_t x, int32_t y) override; void warpCursor(int32_t x, int32_t y) override;
uint32_t registerHotKey(KeyID key, KeyModifierMask mask) override; uint32_t registerHotKey(KeyID key, KeyModifierMask mask) override;
void unregisterHotKey(uint32_t id) override; void unregisterHotKey(uint32_t id) override;
@ -229,6 +230,7 @@ private:
// the display // the display
CGDirectDisplayID m_displayID; CGDirectDisplayID m_displayID;
uint32_t m_activeSides = 0;
// screen shape stuff // screen shape stuff
int32_t m_x, m_y; int32_t m_x, m_y;
int32_t m_w, m_h; int32_t m_w, m_h;

View File

@ -244,9 +244,15 @@ void OSXScreen::getCursorPos(int32_t &x, int32_t &y) const
CFRelease(event); CFRelease(event);
} }
void OSXScreen::reconfigure(uint32_t) void OSXScreen::reconfigure(uint32_t activeSides)
{ {
// do nothing LOG((CLOG_DEBUG "active sides: %x", activeSides));
m_activeSides = activeSides;
}
uint32_t OSXScreen::activeSides()
{
return m_activeSides;
} }
void OSXScreen::warpCursor(int32_t x, int32_t y) void OSXScreen::warpCursor(int32_t x, int32_t y)

View File

@ -7,6 +7,7 @@
*/ */
#include "platform/PortalInputCapture.h" #include "platform/PortalInputCapture.h"
#include "base/DirectionTypes.h"
#include "base/Event.h" #include "base/Event.h"
#include "base/Log.h" #include "base/Log.h"
#include "base/TMethodJob.h" #include "base/TMethodJob.h"
@ -252,10 +253,15 @@ void PortalInputCapture::handleDeactivated(
void PortalInputCapture::handleZonesChanged(XdpInputCaptureSession *session, const GVariant *) void PortalInputCapture::handleZonesChanged(XdpInputCaptureSession *session, const GVariant *)
{ {
for (auto b : m_barriers) for (auto b : m_barriers)
g_object_unref(b); g_object_unref(b);
m_barriers.clear(); m_barriers.clear();
const auto activeSides = m_screen->activeSides();
using enum DirectionMask;
// May not correctly handle different sized screens
auto zones = xdp_input_capture_session_get_zones(session); auto zones = xdp_input_capture_session_get_zones(session);
while (zones != nullptr) { while (zones != nullptr) {
guint w; guint w;
@ -271,47 +277,55 @@ void PortalInputCapture::handleZonesChanged(XdpInputCaptureSession *session, con
int y1; int y1;
int y2; int y2;
// Hardcoded behaviour: our pointer barriers are always at the edges of auto id = 0;
// all zones. Since the implementation is supposed to reject the ones in
// the wrong place, we can just install barriers everywhere and let EIS if (activeSides & static_cast<int>(LeftMask)) {
// figure it out. Also a lot easier to implement for now though it doesn't id++;
// cover differently-sized screens... x1 = x;
auto id = m_barriers.size() + 1; y1 = y;
x1 = x; x2 = x;
y1 = y; y2 = y + h - 1;
x2 = x + w - 1; LOG_DEBUG("barrier (left) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2);
y2 = y; m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER(g_object_new(
LOG_DEBUG("barrier (top) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2); XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr
m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER( )));
g_object_new(XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr) }
));
id = m_barriers.size() + 1; if (activeSides & static_cast<int>(RightMask)) {
x1 = x + w; id++;
y1 = y; x1 = x + w;
x2 = x + w; y1 = y;
y2 = y + h - 1; x2 = x + w;
LOG_DEBUG("barrier (right) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2); y2 = y + h - 1;
m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER( LOG_DEBUG("barrier (right) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2);
g_object_new(XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr) m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER(g_object_new(
)); XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr
id = m_barriers.size() + 1; )));
x1 = x; }
y1 = y;
x2 = x; if (activeSides & static_cast<int>(TopMask)) {
y2 = y + h - 1; id++;
LOG_DEBUG("barrier (left) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2); x1 = x;
m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER( y1 = y;
g_object_new(XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr) x2 = x + w - 1;
)); y2 = y;
id = m_barriers.size() + 1; LOG_DEBUG("barrier (top) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2);
x1 = x; m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER(g_object_new(
y1 = y + h; XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr
x2 = x + w - 1; )));
y2 = y + h; }
LOG_DEBUG("barrier (bottom) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2);
m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER( if (activeSides & static_cast<int>(BottomMask)) {
g_object_new(XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr) id++;
)); x1 = x;
y1 = y + h;
x2 = x + w - 1;
y2 = y + h;
LOG_DEBUG("barrier (bottom) %zd at %d,%d-%d,%d", id, x1, y1, x2, y2);
m_barriers.push_back(XDP_INPUT_CAPTURE_POINTER_BARRIER(g_object_new(
XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER, "id", id, "x1", x1, "y1", y1, "x2", x2, "y2", y2, nullptr
)));
}
zones = zones->next; zones = zones->next;
} }

View File

@ -477,9 +477,14 @@ void XWindowsScreen::getCursorPos(int32_t &x, int32_t &y) const
} }
} }
void XWindowsScreen::reconfigure(uint32_t) void XWindowsScreen::reconfigure(uint32_t activeSides)
{ {
// do nothing m_activeSides = activeSides;
}
uint32_t XWindowsScreen::activeSides()
{
return m_activeSides;
} }
void XWindowsScreen::warpCursor(int32_t x, int32_t y) void XWindowsScreen::warpCursor(int32_t x, int32_t y)

View File

@ -46,6 +46,7 @@ public:
// IPrimaryScreen overrides // IPrimaryScreen overrides
void reconfigure(uint32_t activeSides) override; void reconfigure(uint32_t activeSides) override;
uint32_t activeSides() override;
void warpCursor(int32_t x, int32_t y) override; void warpCursor(int32_t x, int32_t y) override;
uint32_t registerHotKey(KeyID key, KeyModifierMask mask) override; uint32_t registerHotKey(KeyID key, KeyModifierMask mask) override;
void unregisterHotKey(uint32_t id) override; void unregisterHotKey(uint32_t id) override;
@ -175,6 +176,7 @@ private:
// true if mouse has entered the screen // true if mouse has entered the screen
bool m_isOnScreen; bool m_isOnScreen;
uint32_t m_activeSides = 0;
// screen shape stuff // screen shape stuff
int32_t m_x = 0; int32_t m_x = 0;
int32_t m_y = 0; int32_t m_y = 0;