Skip to content

Touch activates screen v6#166

Draft
nbolton wants to merge 25 commits intomasterfrom
feat/touch-activates-screen-v6
Draft

Touch activates screen v6#166
nbolton wants to merge 25 commits intomasterfrom
feat/touch-activates-screen-v6

Conversation

@nbolton
Copy link
Member

@nbolton nbolton commented Mar 4, 2026

Based on #147

Fixes:

  • Touch on first client touch bug
  • Cursor not hidden on touch
  • Client local mouse not working

stefanverleysen and others added 25 commits March 3, 2026 13:07
Add a touchActivateScreen option that switches keyboard/mouse focus
to whichever computer the user touches. Works bidirectionally between
server and clients, and detects touch in all applications including
Chrome, Electron, UWP, and legacy Win32 apps.

Touch detection uses three independent paths for broad hardware
coverage: low-level mouse hook (dwExtraInfo MI_WP_SIGNATURE), raw
input (RIDEV_INPUTSINK on desk thread for WM_INPUT), and WM_POINTER
messages (Win8+ API). All three converge through debounced event
dispatch to the server's screen-switch logic.

Raw input is registered on the desk thread window rather than the
main window because the main event loop uses QS_ALLPOSTMESSAGE,
which never wakes for WM_INPUT messages.

Cursor hiding on touchscreen clients uses a full-screen hider window
with a blank cursor class instead of ShowCursor(FALSE), which is
unreliable on touch hardware. WS_EX_TRANSPARENT is toggled on
leave/enter for correct hit-testing.

The server synthesizes a click and forces the foreground window after
touch-triggered switches so the window under the touch point receives
focus. A 500ms cooldown prevents edge-triggered switches from
immediately undoing touch switches.

Tested on:
- Server: ASUS 3090DEV, i9-12900K, RTX 3090, Windows 11 Enterprise
  Build 26100 (64-bit), USB HID touch screen (VID 0457 / PID 0819)
- Client: Microsoft Surface Book (1st gen), integrated touchscreen,
  Windows 11
- Applications tested: Chrome, Cursor (Electron), Windows Settings
  (UWP), Notepad, Synergy GUI, Start menu, File Explorer
…on, comment cleanup

- Create ClientProxy1_9 for kMsgCGrabScreen (was incorrectly in ClientProxy1_0,
  breaking backward compatibility with older clients)
- Bump protocol version 1.8 → 1.9 for touch-activated screen switching
- Move Windows-specific SetForegroundWindow logic from Server.cpp to
  MSWindowsScreen::activateWindowAt() via platform abstraction chain
- Remove dead mouseDown/mouseUp calls (PrimaryClient ignores them)
- Remove #if WINAPI_MSWINDOWS and Windows.h include from Server.cpp
- Clean up comments: keep only "why" comments, remove "what" comments

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rename grabScreen -> grabInput (avoid "screen" ambiguity)
- Strip "what" comments, keep only "why" explanations
- Remove Win7/Win8 backwards-compat guards (direct WM_POINTER/GetPointerType)
- Fix cursor hiding on secondary touchscreen clients (WM_MOUSEMOVE hider dismissal)
- Update copyright dates to 2012-2026
- Drop compat table entry, clean up empty virtuals and doxygen blocks
- Save foreground window in secondary deskLeave so deskEnter can
  restore it; fixes SetForegroundWindow failing on re-enter which
  required a double-tap to click after switching
- Skip hider auto-hide on touch-generated WM_MOUSEMOVE by checking
  the MI_WP_SIGNATURE touch signature via GetMessageExtraInfo
- Restrict WM_INPUT raw touch handler to primary screens; on clients
  GetCursorPos returns the parked center position, not the touch
  point, causing clicks to land at screen center
- Only eat touch events in the LL hook when in relay mode, not watch
  mode; fixes touch on server's secondary touchscreens acting as a
  giant cursor on the primary monitor
- Move TOUCH_SIGNATURE defines to dfwhook.h shared header
- Add diagnostic logging to activateWindowAt and click replay path

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server: skip LL hook touch handling in watch mode to prevent
double-tap requirement on the server's own touchscreen. Register
raw input for touch only when cursor leaves (deskLeave) and
unregister on return (deskEnter). Replace GetCursorPos with proper
HID preparsed data parsing for accurate touch coordinates.

Client: replay consumed first-touch as InjectTouchInput on the
desk thread, with mouse_event fallback for processes without
UIAccess. Handle WM_POINTERACTIVATE with PA_NOACTIVATE to prevent
the hider window from stealing focus on touch. Add 100ms settle
delay after deskEnter before replay so full-screen apps can
resume input processing.

Plumbing: add fakeTouchClick virtual method through
IPlatformScreen/Screen/MSWindowsScreen to route touch replay
through the platform layer. Link hid.lib on Windows for HID
preparsed data APIs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Async touch injection via PostThreadMessage chain (no Sleep calls)
- WS_EX_LAYERED hider (alpha=1) prevents DWM fullscreen occlusion
- Local cursor restored on real mouse movement (position check, not timing)
- Fix InjectTouchInput pointer ID (pointerId=1, InitializeTouchInjection(2))
- WM_INPUT touch detection on secondary with m_isOnScreen guard
- Foreground window restored before injection
- Bidirectional touch switch cooldown
- Remove m_deskLeaveTime, m_touchHideTime, WM_TIMER, polling loops

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants