Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
196f8eb
feat: touch activates screen — switch to touched computer
stefanverleysen Feb 11, 2026
ac4b0d4
refactor: address PR review — protocol versioning, platform abstracti…
stefanverleysen Feb 11, 2026
e83302c
refactor: address PR review round 2
stefanverleysen Feb 17, 2026
32e4cdb
fix: resolve touch click bugs on secondary (client) screens
stefanverleysen Feb 20, 2026
b14df00
fix: server-side touch interference and client touch click replay
stefanverleysen Mar 2, 2026
561cf70
chore: add touch event logging
nbolton Mar 2, 2026
aff75ee
fix: client touch click on fullscreen apps after screen switch
stefanverleysen Mar 3, 2026
a79838e
fix: replace timing hacks with state-driven client touch injection
stefanverleysen Mar 3, 2026
18ff1c2
fix: manage cursor visibility during touch injection to emulate Windo…
nbolton Mar 4, 2026
4e410aa
fix: enhance touch injection handling and cursor visibility for non-p…
nbolton Mar 4, 2026
a60420b
fix: remove unused cursor visibility handling for touch injection
nbolton Mar 4, 2026
d83d090
fix: improve touch detection handling for primary and secondary screens
nbolton Mar 4, 2026
0d0faa0
fix: optimize touch injection handling to prevent conflicts during to…
nbolton Mar 4, 2026
f92a5ea
Revert "fix: optimize touch injection handling to prevent conflicts d…
nbolton Mar 4, 2026
5aba33c
fix: implement touch event handling for screen activation and deactiv…
nbolton Mar 4, 2026
455b936
fix: enhance cursor handling for touch events in secondary desk proce…
nbolton Mar 4, 2026
5f0978a
fix: prevent mouse events from being processed on secondary screens w…
nbolton Mar 4, 2026
31c9be1
fix: simplify mouse event handling logic for off-screen scenarios
nbolton Mar 4, 2026
554ef09
Revert "fix: simplify mouse event handling logic for off-screen scena…
nbolton Mar 4, 2026
0fa7b7d
fix: enhance mouse event handling for touch-synthesized events when o…
nbolton Mar 4, 2026
c1abc87
Revert "fix: enhance mouse event handling for touch-synthesized event…
nbolton Mar 4, 2026
d4d53b5
feat: enhance desk entry handling for touch-triggered events
nbolton Mar 4, 2026
db49392
Revert "feat: enhance desk entry handling for touch-triggered events"
nbolton Mar 4, 2026
d642585
feat: remove fake touch click from primary event handling
nbolton Mar 4, 2026
7493cf3
fix: prevent cursor visibility by eating injected mouse events on sec…
nbolton Mar 4, 2026
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ deskflow-config.toml
/scripts/*.egg-info
/*.user
*.ui.autosave

# local strategy docs and tracking (not for upstream)
/local/
10 changes: 9 additions & 1 deletion src/gui/src/ServerConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ bool ServerConfig::operator==(const ServerConfig &sc) const
m_SwitchCornerSize == sc.m_SwitchCornerSize && m_SwitchCorners == sc.m_SwitchCorners &&
m_Hotkeys == sc.m_Hotkeys && m_pAppConfig == sc.m_pAppConfig &&
m_DisableLockToScreen == sc.m_DisableLockToScreen && m_ClipboardSharing == sc.m_ClipboardSharing &&
m_ClipboardSharingSize == sc.m_ClipboardSharingSize && m_pMainWindow == sc.m_pMainWindow;
m_ClipboardSharingSize == sc.m_ClipboardSharingSize && m_TouchActivateScreen == sc.m_TouchActivateScreen &&
m_pMainWindow == sc.m_pMainWindow;
}

void ServerConfig::save(QFile &file) const
Expand Down Expand Up @@ -127,6 +128,7 @@ void ServerConfig::commit()
settings().setValue("disableLockToScreen", disableLockToScreen());
settings().setValue("clipboardSharing", clipboardSharing());
settings().setValue("clipboardSharingSize", QVariant::fromValue(clipboardSharingSize()));
settings().setValue("touchActivateScreen", touchActivateScreen());

if (!getClientAddress().isEmpty()) {
settings().setValue("clientAddress", getClientAddress());
Expand Down Expand Up @@ -182,6 +184,9 @@ void ServerConfig::recall()
settings().value("clipboardSharingSize", (int)ServerConfig::defaultClipboardSharingSize()).toULongLong()
);
setClipboardSharing(settings().value("clipboardSharing", true).toBool());
setTouchActivateScreen(
settings().value("touchActivateScreen",
settings().value("touchInputLocal", false)).toBool());
setClientAddress(settings().value("clientAddress", "").toString());

readSettings(settings(), switchCorners(), "switchCorner", 0, static_cast<int>(NumSwitchCorners));
Expand Down Expand Up @@ -310,6 +315,9 @@ QTextStream &operator<<(QTextStream &outStream, const ServerConfig &config)
outStream << "\t"
<< "switchCornerSize = " << config.switchCornerSize() << Qt::endl;

outStream << "\t"
<< "touchActivateScreen = " << (config.touchActivateScreen() ? "true" : "false") << Qt::endl;

foreach (const Hotkey &hotkey, config.hotkeys())
outStream << hotkey;

Expand Down
9 changes: 9 additions & 0 deletions src/gui/src/ServerConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ class ServerConfig : public ScreenConfig, public deskflow::gui::IServerConfig
{
return m_ClipboardSharingSize;
}
bool touchActivateScreen() const
{
return m_TouchActivateScreen;
}
static size_t defaultClipboardSharingSize();

//
Expand Down Expand Up @@ -224,6 +228,10 @@ class ServerConfig : public ScreenConfig, public deskflow::gui::IServerConfig
{
m_ClipboardSharing = on;
}
void setTouchActivateScreen(bool on)
{
m_TouchActivateScreen = on;
}
void setConfigFile(const QString &configFile);
void setUseExternalConfig(bool useExternalConfig);
size_t setClipboardSharingSize(size_t size);
Expand Down Expand Up @@ -253,6 +261,7 @@ class ServerConfig : public ScreenConfig, public deskflow::gui::IServerConfig
int m_SwitchCornerSize = 0;
bool m_DisableLockToScreen = false;
bool m_ClipboardSharing = true;
bool m_TouchActivateScreen = false;
QString m_ClientAddress = "";
QList<bool> m_SwitchCorners;
HotkeyList m_Hotkeys;
Expand Down
9 changes: 9 additions & 0 deletions src/gui/src/ServerConfigDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ ServerConfigDialog::ServerConfigDialog(QWidget *parent, ServerConfig &config, Ap
m_pCheckBoxCornerBottomRight->setChecked(serverConfig().switchCorner(static_cast<int>(BottomRight)));
m_pSpinBoxSwitchCornerSize->setValue(serverConfig().switchCornerSize());
m_pCheckBoxDisableLockToScreen->setChecked(serverConfig().disableLockToScreen());
m_pCheckBoxTouchActivateScreen->setChecked(serverConfig().touchActivateScreen());

m_pCheckBoxEnableClipboard->setChecked(serverConfig().clipboardSharing());
int clipboardSharingSizeM = static_cast<int>(serverConfig().clipboardSharingSize() / 1024);
Expand Down Expand Up @@ -142,6 +143,10 @@ ServerConfigDialog::ServerConfigDialog(QWidget *parent, ServerConfig &config, Ap
serverConfig().setDisableLockToScreen(v);
onChange();
});
connect(m_pCheckBoxTouchActivateScreen, &QCheckBox::stateChanged, this, [this](const int &v) {
serverConfig().setTouchActivateScreen(v);
onChange();
});
connect(m_pCheckBoxCornerTopLeft, &QCheckBox::stateChanged, this, [this](const int &v) {
serverConfig().setSwitchCorner(static_cast<int>(TopLeft), v);
onChange();
Expand Down Expand Up @@ -192,6 +197,10 @@ ServerConfigDialog::ServerConfigDialog(QWidget *parent, ServerConfig &config, Ap
serverConfig().setDisableLockToScreen(v == Qt::Checked);
onChange();
});
connect(m_pCheckBoxTouchActivateScreen, &QCheckBox::checkStateChanged, this, [this](const Qt::CheckState &v) {
serverConfig().setTouchActivateScreen(v == Qt::Checked);
onChange();
});
connect(m_pCheckBoxCornerTopLeft, &QCheckBox::checkStateChanged, this, [this](const Qt::CheckState &v) {
serverConfig().setSwitchCorner(static_cast<int>(TopLeft), v == Qt::Checked);
onChange();
Expand Down
11 changes: 11 additions & 0 deletions src/gui/src/ServerConfigDialogBase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,16 @@
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="m_pCheckBoxTouchActivateScreen">
<property name="text">
<string>Switch screens on touch</string>
</property>
<property name="toolTip">
<string>Touch any screen to switch to that computer</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="m_pCheckBoxWin32KeepForeground">
<property name="enabled">
Expand Down Expand Up @@ -1168,6 +1178,7 @@ Enabling this setting will disable the server config GUI.</string>
<tabstop>m_pCheckBoxWin32KeepForeground</tabstop>
<tabstop>m_pCheckBoxIgnoreAutoConfigClient</tabstop>
<tabstop>m_pCheckBoxDisableLockToScreen</tabstop>
<tabstop>m_pCheckBoxTouchActivateScreen</tabstop>
<tabstop>m_pCheckBoxCornerTopLeft</tabstop>
<tabstop>m_pCheckBoxCornerBottomLeft</tabstop>
<tabstop>m_pCheckBoxCornerTopRight</tabstop>
Expand Down
5 changes: 4 additions & 1 deletion src/lib/base/EventTypes.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* Copyright (C) 2013-2016 Symless Ltd.
* Copyright (C) 2013-2026 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
Expand Down Expand Up @@ -115,6 +115,7 @@ REGISTER_EVENT(ClientListener, connected)

REGISTER_EVENT(ClientProxy, ready)
REGISTER_EVENT(ClientProxy, disconnected)
REGISTER_EVENT(ClientProxy, grabInput)

//
// ClientProxyUnknown
Expand Down Expand Up @@ -167,6 +168,7 @@ REGISTER_EVENT(IPrimaryScreen, hotKeyDown)
REGISTER_EVENT(IPrimaryScreen, hotKeyUp)
REGISTER_EVENT(IPrimaryScreen, fakeInputBegin)
REGISTER_EVENT(IPrimaryScreen, fakeInputEnd)
REGISTER_EVENT(IPrimaryScreen, touchActivatedPrimary)

//
// IScreen
Expand All @@ -176,6 +178,7 @@ REGISTER_EVENT(IScreen, error)
REGISTER_EVENT(IScreen, shapeChanged)
REGISTER_EVENT(IScreen, suspend)
REGISTER_EVENT(IScreen, resume)
REGISTER_EVENT(IScreen, grabInput)

//
// IpcServer
Expand Down
19 changes: 15 additions & 4 deletions src/lib/base/EventTypes.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* Copyright (C) 2013-2016 Symless Ltd.
* Copyright (C) 2013-2026 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
Expand Down Expand Up @@ -388,7 +388,7 @@ class ClientListenerEvents : public EventTypes
class ClientProxyEvents : public EventTypes
{
public:
ClientProxyEvents() : m_ready(Event::kUnknown), m_disconnected(Event::kUnknown)
ClientProxyEvents() : m_ready(Event::kUnknown), m_disconnected(Event::kUnknown), m_grabInput(Event::kUnknown)
{
}

Expand All @@ -410,11 +410,14 @@ class ClientProxyEvents : public EventTypes
*/
Event::Type disconnected();

Event::Type grabInput();

//@}

private:
Event::Type m_ready;
Event::Type m_disconnected;
Event::Type m_grabInput;
};

class ClientProxyUnknownEvents : public EventTypes
Expand Down Expand Up @@ -603,7 +606,8 @@ class IPrimaryScreenEvents : public EventTypes
m_hotKeyDown(Event::kUnknown),
m_hotKeyUp(Event::kUnknown),
m_fakeInputBegin(Event::kUnknown),
m_fakeInputEnd(Event::kUnknown)
m_fakeInputEnd(Event::kUnknown),
m_touchActivatedPrimary(Event::kUnknown)
{
}

Expand Down Expand Up @@ -650,6 +654,8 @@ class IPrimaryScreenEvents : public EventTypes
//! end of fake input event type
Event::Type fakeInputEnd();

Event::Type touchActivatedPrimary();

//@}

private:
Expand All @@ -664,6 +670,7 @@ class IPrimaryScreenEvents : public EventTypes
Event::Type m_hotKeyUp;
Event::Type m_fakeInputBegin;
Event::Type m_fakeInputEnd;
Event::Type m_touchActivatedPrimary;
};

class IScreenEvents : public EventTypes
Expand All @@ -673,7 +680,8 @@ class IScreenEvents : public EventTypes
: m_error(Event::kUnknown),
m_shapeChanged(Event::kUnknown),
m_suspend(Event::kUnknown),
m_resume(Event::kUnknown)
m_resume(Event::kUnknown),
m_grabInput(Event::kUnknown)
{
}

Expand Down Expand Up @@ -708,13 +716,16 @@ class IScreenEvents : public EventTypes
*/
Event::Type resume();

Event::Type grabInput();

//@}

private:
Event::Type m_error;
Event::Type m_shapeChanged;
Event::Type m_suspend;
Event::Type m_resume;
Event::Type m_grabInput;
};

class ClipboardEvents : public EventTypes
Expand Down
17 changes: 16 additions & 1 deletion src/lib/client/Client.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012-2026 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
Expand Down Expand Up @@ -29,6 +29,7 @@
#include "deskflow/DropHelper.h"
#include "deskflow/FileChunk.h"
#include "deskflow/IPlatformScreen.h"
#include "deskflow/IPrimaryScreen.h"
#include "deskflow/PacketStreamFilter.h"
#include "deskflow/ProtocolUtil.h"
#include "deskflow/Screen.h"
Expand Down Expand Up @@ -87,6 +88,10 @@ Client::Client(
m_events->adoptHandler(
m_events->forIScreen().resume(), getEventTarget(), new TMethodEventJob<Client>(this, &Client::handleResume)
);
m_events->adoptHandler(
m_events->forIScreen().grabInput(), m_screen->getEventTarget(),
new TMethodEventJob<Client>(this, &Client::handleGrabInput)
);

if (m_args.m_enableDragDrop) {
m_events->adoptHandler(
Expand All @@ -107,6 +112,7 @@ Client::~Client()

m_events->removeHandler(m_events->forIScreen().suspend(), getEventTarget());
m_events->removeHandler(m_events->forIScreen().resume(), getEventTarget());
m_events->removeHandler(m_events->forIScreen().grabInput(), m_screen->getEventTarget());

cleanupTimer();
cleanupScreen();
Expand Down Expand Up @@ -719,6 +725,15 @@ void Client::handleResume(const Event &, void *)
}
}

void Client::handleGrabInput(const Event &event, void *)
{
IPrimaryScreen::MotionInfo *info = static_cast<IPrimaryScreen::MotionInfo *>(event.getData());
if (m_server != NULL) {
LOG((CLOG_DEBUG1 "requesting grab input at %d,%d", info->m_x, info->m_y));
m_server->grabInput(info->m_x, info->m_y);
}
}

void Client::handleFileChunkSending(const Event &event, void *)
{
sendFileChunk(event.getDataObject());
Expand Down
3 changes: 2 additions & 1 deletion src/lib/client/Client.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012-2026 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
Expand Down Expand Up @@ -220,6 +220,7 @@ class Client : public IClient, public INode
void handleHello(const Event &, void *);
void handleSuspend(const Event &event, void *);
void handleResume(const Event &event, void *);
void handleGrabInput(const Event &event, void *);
void handleFileChunkSending(const Event &, void *);
void handleFileRecieveCompleted(const Event &, void *);
void handleStopRetry(const Event &, void *);
Expand Down
8 changes: 7 additions & 1 deletion src/lib/client/ServerProxy.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012-2026 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
Expand Down Expand Up @@ -372,6 +372,12 @@ bool ServerProxy::onGrabClipboard(ClipboardID id)
return true;
}

void ServerProxy::grabInput(SInt32 x, SInt32 y)
{
LOG((CLOG_DEBUG1 "requesting grab input at %d,%d", x, y));
ProtocolUtil::writef(m_stream, kMsgCGrabInput, x, y);
}

void ServerProxy::onClipboardChanged(ClipboardID id, const IClipboard *clipboard)
{
String data = IClipboard::marshall(clipboard);
Expand Down
4 changes: 3 additions & 1 deletion src/lib/client/ServerProxy.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012-2026 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
Expand Down Expand Up @@ -61,6 +61,8 @@ class ServerProxy
bool onGrabClipboard(ClipboardID);
void onClipboardChanged(ClipboardID, const IClipboard *);

void grabInput(SInt32 x, SInt32 y);

//@}

// sending file chunk to server
Expand Down
5 changes: 4 additions & 1 deletion src/lib/deskflow/IPlatformScreen.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012-2026 Symless Ltd.
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
Expand Down Expand Up @@ -200,6 +200,9 @@ class IPlatformScreen : public IScreen, public IPrimaryScreen, public ISecondary
virtual void pollPressedKeys(KeyButtonSet &pressedKeys) const = 0;
virtual void clearStaleModifiers() = 0;

virtual void activateWindowAt(SInt32 x, SInt32 y) { /* do nothing */ }
virtual void fakeTouchClick(SInt32 x, SInt32 y) { /* do nothing */ }

// Drag-and-drop overrides
virtual String &getDraggingFilename() = 0;
virtual void clearDraggingFilename() = 0;
Expand Down
10 changes: 10 additions & 0 deletions src/lib/deskflow/Screen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,11 @@ void Screen::mouseWheel(SInt32 xDelta, SInt32 yDelta) const
m_screen->fakeMouseWheel(xDelta, yDelta);
}

void Screen::fakeTouchClick(SInt32 x, SInt32 y)
{
m_screen->fakeTouchClick(x, y);
}

void Screen::resetOptions()
{
// reset options
Expand Down Expand Up @@ -488,6 +493,11 @@ void Screen::leaveSecondary()
m_screen->fakeAllKeysUp();
}

void Screen::activateWindowAt(SInt32 x, SInt32 y)
{
m_screen->activateWindowAt(x, y);
}

String Screen::getSecureInputApp() const
{
return m_screen->getSecureInputApp();
Expand Down
Loading