Skip to content

Add experimental Synergy 3 support and persist saved servers - #53

Open
joihn wants to merge 2 commits into
anasvhora284:masterfrom
joihn:codex/upstream-synergy-support
Open

joihn wants to merge 2 commits into
anasvhora284:masterfrom
joihn:codex/upstream-synergy-support

Conversation

@joihn

@joihn joihn commented Oct 1, 2026 •

Copy link
Copy Markdown

Issue Adressed

Related to #47.

Synergy difference

Synergy 3.7.2 on macOS can acknowledge screen dimensions before accepting the
client, sends relative mouse deltas as signed 16-bit values, and uses Mac physical
keycodes.

Input Leaf could report a connection before an unknown-screen refusal,
reject relative motion packets, or inject the wrong physical keys.
This change
handles those cases using the existing Synergy greeting and TLS/mTLS support.

Manually added servers also disappeared after restarting the app. Favorite
addresses were persisted but were only displayed when rediscovered. The server
list now restores saved addresses and merges them with scan results.

Changes

  • Complete the input handshake on DSOP, rather than CIAK; report unknown
    screens and protocol errors directly, and reject unsupported protocol majors.

  • Decode signed 16-bit DMRM deltas while retaining the previously accepted
    32-bit variant.

  • Map Carbon keycodes plus one to evdev for Android HID input, retaining evdev/X11
    decoding and matching key-up events when source detection changes during a chord.

  • Persist manually added, used, and favorited servers; recover addresses from
    existing favorites and connection records. Empty scans no longer hide saved servers.

  • Add an optional macOS Synergy setup/status helper and guide. Registration is a
    dry run by default; applying requires a stopped service and creates private
    backups with rollback on write failure. The helper targets observed Synergy
    settings schemas 17/8 and reports the exact screen name, LAN address hints, and
    server fingerprint.

  • Add protocol, input, persistence, and helper regression coverage; run the
    Python helper tests in the existing CI job.

  • Android instrumented smoke tests were not run locally.

manual testing

confirmed working with 2 macos tahohe macbook + pixel 10 android 17 with Shizuku

Summary by Sourcery

Add experimental Synergy 3 support while preserving server addresses across app restarts.

New Features:

  • Add experimental Synergy 3.7.2 compatibility for macOS servers, including TLS/mTLS connectivity, protocol negotiation, relative mouse motion, and physical key mapping.
  • Add a macOS setup and status helper for registering Android clients with Synergy settings and inspecting connection state.
  • Persist manually added, used, and favorited server addresses and merge saved entries with network scan results.

Bug Fixes:

  • Prevent premature successful connections when Synergy acknowledges dimensions but later rejects an unknown screen.
  • Report unsupported protocol versions, unknown screens, and malformed protocol messages as explicit connection failures.
  • Preserve correct key-up behavior when input encoding detection changes while keys are held.

Enhancements:

  • Expand server and connection messaging to use server-agnostic terminology and expose Synergy-specific failure guidance.

CI:

  • Run the Synergy setup helper's Python regression tests in CI.

Documentation:

  • Document experimental Synergy 3 setup, compatibility limits, server registration, status inspection, and validation procedures.

Tests:

  • Add regression coverage for Synergy handshakes, signed relative motion, keycode decoding, server persistence, list merging, and setup-helper behavior.

joihn added 2 commits October 1, 2026 21:31
Handle handshake acceptance, relative mouse packets, and macOS physical keycodes.
Include the macOS registration/status helper, setup guide, and regression tests.
Persist manually added, used, and favorite servers and restore them into the UI.
Recover legacy connection records and test on-disk persistence and scan merging.
@sourcery-ai

sourcery-ai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Reviewer's Guide

This PR adds experimental Synergy 3.7.2 interoperability by enforcing the post-dimension handshake, supporting signed 16-bit motion and macOS physical keycodes, while also making server addresses durable and introducing a guarded macOS setup/status helper with documentation and CI coverage.

Sequence diagram for the Synergy 3 connection handshake

sequenceDiagram
    participant App as InputLeaf
    participant Server as SynergyCore
    App->>Server: TLS/mTLS connection
    Server-->>App: Hello
    App->>Server: ClientHello
    App->>Server: QINF
    Server-->>App: DINF
    App->>Server: CIAK
    Server-->>App: CROP
    Server-->>App: DSOP
    alt Unknown screen
        Server-->>App: EUNK
        App-->>App: ConnectResult.UNKNOWN_SCREEN
    else Protocol error
        Server-->>App: BadMessage
        App-->>App: ConnectResult.PROTOCOL_ERROR
    else Accepted
        App->>App: Start readLoop
    end
Loading

Flow diagram for persistent server list merging

flowchart LR
    Saved[Saved addresses]
    Scan[Network scan results]
    Merge[mergeServerLists]
    List[Server list]
    Add[addManualServer]
    Store[saveServer]
    Add --> Store --> Saved
    Saved --> Merge
    Scan --> Merge
    Merge --> List
Loading

File-Level Changes

Change Details Files
Tighten Synergy-compatible connection negotiation and packet decoding.
  • Require a successful DSOP before declaring the handshake complete and reject unsupported protocol majors.
  • Surface unknown-screen and malformed-protocol failures without retrying or fallback.
  • Decode signed 16-bit relative mouse movement while retaining 32-bit compatibility.
app/src/main/java/com/inputleaf/android/network/InputLeapConnection.kt
app/src/main/java/com/inputleaf/android/network/ConnectResult.kt
app/src/main/java/com/inputleaf/android/network/ConnectionTransportPolicy.kt
app/src/main/java/com/inputleaf/android/protocol/ProtocolParser.kt
app/src/test/java/com/inputleaf/android/network/InputLeapConnectionTest.kt
app/src/test/java/com/inputleaf/android/protocol/ProtocolParserTest.kt
Add macOS physical-key translation and robust pressed-key tracking for HID injection.
  • Map Carbon keycodes plus Synergy’s offset to evdev and preserve existing evdev/X11 detection.
  • Cache the physical mapping between key-down and key-up events, clearing held state on disconnect or HID detach.
  • Add regression coverage for modifiers, navigation keys, ambiguous encodings, and non-Latin input.
app/src/main/java/com/inputleaf/android/inject/MacKeyCode.kt
app/src/main/java/com/inputleaf/android/inject/ProtocolScanCodeDecoder.kt
app/src/main/java/com/inputleaf/android/inject/AccessibilityInputInjector.kt
app/src/main/java/com/inputleaf/android/shizuku/ShizukuInputInjector.kt
app/src/test/java/com/inputleaf/android/inject/ProtocolScanCodeDecoderTest.kt
Persist server addresses independently from discovery and merge saved entries into the server list.
  • Store manually added, used, and favorited addresses in DataStore and recover addresses from legacy favorites, fingerprints, and transport records.
  • Keep saved servers visible across restarts and empty scans while allowing discovered metadata to replace placeholders.
  • Make preferences injectable for isolated persistence tests.
app/src/main/java/com/inputleaf/android/storage/AppPreferences.kt
app/src/main/java/com/inputleaf/android/ui/MainViewModel.kt
app/src/main/java/com/inputleaf/android/ui/ServerListScreen.kt
app/src/test/java/com/inputleaf/android/storage/AppPreferencesTest.kt
app/src/test/java/com/inputleaf/android/ui/ServerListPersistenceTest.kt
Provide an experimental macOS Synergy 3 registration and status workflow with safe settings updates.
  • Add a dry-run-by-default Python helper for schema 17/8 settings, screen registration, trust configuration, status reporting, LAN hints, and fingerprints.
  • Require stopped Synergy processes for writes, verify files are unchanged, create private backups, use atomic writes, and restore originals on failure.
  • Document setup, compatibility limits, operational guidance, and optional live testing.
scripts/synergy3_setup.py
scripts/tests/test_synergy3_setup.py
docs/synergy3-android.md
README.md
docs/TESTING.md
Integrate helper regression tests into CI and broaden user-facing terminology and error reporting.
  • Run the Python helper unit tests in the existing CI job.
  • Update connection and fingerprint messaging to refer generically to the server and explain Synergy-specific failures.
.github/workflows/ci.yml
app/src/main/java/com/inputleaf/android/ui/MainViewModel.kt
app/src/main/java/com/inputleaf/android/ui/FingerprintDialog.kt
app/src/main/java/com/inputleaf/android/ui/SettingsScreen.kt

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="app/src/main/java/com/inputleaf/android/inject/ProtocolScanCodeDecoder.kt" line_range="30" />
<code_context>
+    }
+
+    @Synchronized
+    fun clearPressedKeys() = pressedKeys.clear()

     fun toEvdev(button: Int, keysym: Int): Int {
</code_context>
<issue_to_address>
**issue (bug_risk):** `clearPressedKeys()` releases the pressed-key map but leaves the learned `encoding` unchanged. After disconnecting from a macOS server and connecting to an evdev or X11 server, the decoder continues applying the previous server's encoding and injects incorrect physical keys.

**Triggers:** When the same input injector instance reconnects to a server using a different keycode encoding.

**Suggested fix:** Reset `encoding` to null as part of decoder connection cleanup, or provide a separate reset method that clears both pressed keys and the learned encoding.

```suggestion
    fun clearPressedKeys() {
        pressedKeys.clear()
        encoding = null
    }
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

}

@Synchronized
fun clearPressedKeys() = pressedKeys.clear()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): clearPressedKeys() releases the pressed-key map but leaves the learned encoding unchanged. After disconnecting from a macOS server and connecting to an evdev or X11 server, the decoder continues applying the previous server's encoding and injects incorrect physical keys.

Triggers: When the same input injector instance reconnects to a server using a different keycode encoding.

Suggested fix: Reset encoding to null as part of decoder connection cleanup, or provide a separate reset method that clears both pressed keys and the learned encoding.

Suggested change
fun clearPressedKeys() = pressedKeys.clear()
fun clearPressedKeys() {
pressedKeys.clear()
encoding = null
}

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.

1 participant