Skip to content
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Build artifacts
build/
build-*/
.rpmbuild-local/

# Working/research files not for public release
gemini/
Expand Down
13 changes: 13 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ add_executable(mwb_client
src/main.cpp
src/PeerRecovery.cpp
src/SecretStore.cpp
src/TopologyModel.cpp
src/ClipboardManager.cpp
src/CryptoHelper.cpp
src/InputManager.cpp
Expand Down Expand Up @@ -85,6 +86,8 @@ include(CTest)
find_package(PkgConfig QUIET)

if (BUILD_TESTING)
find_program(PYTHON3_EXECUTABLE python3)

add_executable(mwb_client_unit_tests
tests/test_main.cpp
src/AppConfig.cpp
Expand Down Expand Up @@ -184,12 +187,22 @@ if (BUILD_TESTING)
add_test(NAME mwb_input_device_capability_tests COMMAND mwb_input_device_capability_tests)
add_test(NAME mwb_input_latency_tests COMMAND mwb_input_latency_tests)
add_test(NAME mwb_topology_model_tests COMMAND mwb_topology_model_tests)
if (PYTHON3_EXECUTABLE)
add_test(NAME mwb_topology_config_docs
COMMAND "${PYTHON3_EXECUTABLE}"
"${CMAKE_CURRENT_SOURCE_DIR}/tests/topology_config_docs_test.py"
"${CMAKE_CURRENT_SOURCE_DIR}/docs/topology.md"
)
endif()
add_test(NAME mwb_mouse_trace_tests COMMAND mwb_mouse_trace_tests)
add_test(NAME mwb_media_key_bridge_tests COMMAND mwb_media_key_bridge_tests)
add_test(NAME mwb_protocol_security_tests COMMAND mwb_protocol_security_tests)
add_test(NAME mwb_clipboard_socket_security_tests COMMAND mwb_clipboard_socket_security_tests)
add_test(NAME mwb_client_help COMMAND mwb_client --help)
add_test(NAME mwb_client_doctor COMMAND mwb_client doctor --config "${CMAKE_CURRENT_BINARY_DIR}/missing-doctor-config.ini")
add_test(NAME mwb_client_topology_explain
COMMAND mwb_client topology explain "${CMAKE_CURRENT_SOURCE_DIR}/tests/simple.topology"
)
add_test(NAME mwb_client_doctor_categories
COMMAND ${CMAKE_COMMAND}
"-DMWB_CLIENT=$<TARGET_FILE:mwb_client>"
Expand Down
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ Recommended first-run flow for most users:
2. **Launch Setup UI:** Run `./mwb-desktop-ui.sh menu`
3. **Configure:**
- Go to **Settings** -> Enter your Windows Host IP and Security Key.
4. **Pair with Windows:**
4. **Use PowerToys layout for normal setups:**
- If this Linux/Fedora machine has one monitor, do not configure topology. Let Windows PowerToys Mouse Without Borders own the Linux/Windows machine placement.
- If topology was enabled while testing, choose **Use PowerToys Layout Only** to set `topology_enabled=false`.
5. **Pair with Windows:**
- In the same UI, use the **Export Helper** option.
- Run the exported `.ps1` script on your Windows machine to register the Linux peer.
5. **Start:** Choose **Start Service** or launch the tray with `./build/mwb_tray`.
6. **Start:** Choose **Start Service** or launch the tray with `./build/mwb_tray`.
7. **Advanced layouts only:** Open **Advanced Topology/Layout** if you have multiple Linux monitors, stacked/asymmetric edges, wrap behavior, or wrong-edge handoff problems.

For the full beta setup, health-check, diagnostics, connection-quality, and packaging-verification workflow, see [docs/beta-workflow.md](docs/beta-workflow.md).

Expand Down Expand Up @@ -98,9 +102,11 @@ See the full [documentation section](#detailed-documentation) for environment va
User-facing beta operations:

- [Guided Windows pairing and export helper](docs/beta-workflow.md#guided-pairing-and-export-helper)
- [Topology/layout wizard](docs/beta-workflow.md#topologylayout-wizard)
- [Health checks and diagnostics bundle](docs/beta-workflow.md#health-check)
- [Connection quality and latency reporting](docs/beta-workflow.md#connection-quality)
- [Packaging verification](docs/beta-workflow.md#packaging-verification)
- [Topology config contract and layout wizard expectations](docs/topology.md)
- [Migration from other keyboard/mouse sharing tools](docs/migration.md)
- [Compatibility matrix and platform caveats](docs/compatibility.md)

Expand All @@ -111,7 +117,11 @@ User-facing beta operations:
This repository started as a fork of [chrischip/mwb-client-linux](https://github.com/chrischip/mwb-client-linux) and has been substantially expanded with service management, rich clipboard support, and recovery tooling.

### Configuration (`config.ini`)
Supports `key_file`, `key_secret_id` (keyring), `screen_width/height` overrides, and more. Default path: `~/.config/mwb-client/config.ini`.
Supports `key_file`, `key_secret_id` (keyring), `screen_width/height` overrides, `topology_enabled`, `topology_file`, and more. Default path: `~/.config/mwb-client/config.ini`.

Display-level topology is a separate opt-in contract. The default runtime remains MWB-compatible machine placement unless topology is explicitly enabled; see [docs/topology.md](docs/topology.md) for examples, wrap policies, validation, and cross-machine handoff behavior.

Windows PowerToys still owns the Windows-side machine layout. InputFlow topology does not edit PowerToys per-display geometry; it only tells Linux which local display edge should hand off back to Windows. Keep the PowerToys machine position and the InputFlow topology links consistent.

### Screen Sizing
The client detects screen size in this order:
Expand Down
25 changes: 24 additions & 1 deletion docs/beta-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ Use the desktop controller for the guided path:

1. Open **Settings** and enter the Windows host IP, local machine name, port, and exactly one authentication source: inline key, `key_file`, or Secret Service key ID.
2. Use **Connection Behavior** to choose automatic reconnect behavior before starting the service.
3. Export a Windows helper from Linux when the UI exposes the action, or use the CLI fallback:
3. For one Linux/Fedora monitor, leave topology disabled and use the normal PowerToys layout path.
4. Optionally run **Advanced Topology/Layout** only if you have multiple Linux displays, stacked/asymmetric edges, wrap behavior, or wrong-edge handoff problems.
5. Export a Windows helper from Linux when the UI exposes the action, or use the CLI fallback:

```bash
./build/mwb_client export-windows-pair \
Expand All @@ -31,6 +33,27 @@ Keep the exported `.ps1` private because it contains pairing material. Delete it

![Pairing helper walkthrough](screenshots/pairing-helper.svg)

## Advanced Topology/Layout Wizard

Open the wizard from the desktop controller only when the normal PowerToys layout is not enough:

```bash
./mwb-desktop-ui.sh layout-wizard
```

The wizard asks for a plain-language layout, Linux/Windows machine names, display size, wrap policy, and output file name. It shows a preview of the exact topology file before making changes. For one Linux monitor, prefer **Use PowerToys Layout Only** instead.

Only after confirmation, the wizard writes the topology file under `~/.config/mwb-client/` and updates `config.ini`:

```ini
topology_enabled=true
topology_file=/home/example/.config/mwb-client/topology-side-by-side.topology
```

When topology is enabled, configured cross-machine edge transitions are enforced at runtime. Same-machine transitions remain local, and invalid topology falls back to the existing behavior with a warning.

Use **Explain Current Topology** after saving. It translates the topology into English and reminds users that Windows PowerToys still owns the Windows-side machine layout. Keep the PowerToys machine placement and the InputFlow topology edges consistent.

## Health Check

Run the built-in doctor before filing a beta issue or after changing package/service setup:
Expand Down
5 changes: 4 additions & 1 deletion docs/compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ InputFlow is a native Linux peer for Microsoft PowerToys Mouse Without Borders (
| Clipboard receive/send | Supported beta path | Requires local helpers: `wl-clipboard` on Wayland or `xclip`/`xsel` on X11. Availability is reported by `doctor`. |
| systemd user service | Opt-in | Packaging includes a user unit, but users should enable/start it only after validating config, key source, and `/dev/uinput` access. |
| Network trust model | Trusted LAN/subnet | Use on a trusted local network. Do not expose MWB ports to untrusted networks or the public internet. |
| Display-level topology config | Opt-in | The contract is documented in [Topology Config Contract](topology.md), and the default runtime remains MWB-compatible machine placement unless topology is enabled. |

## Linux Session Details

Expand Down Expand Up @@ -53,4 +54,6 @@ The systemd user service is a convenience, not a required first step. During mig

## Topology Expectations

Current compatibility is machine-level MWB placement. The roadmap includes separating machines from displays, configurable wrap policies, AAB/BAA/ABA layouts, stacked layouts, asymmetric layouts, and dry-run path previews that show pointer routes before applying a layout.
Current default compatibility is machine-level MWB placement. Display-level topology is intentionally gated and opt-in so InputFlow can remain compatible with PowerToys MWB unless the user enables explicit machine/display links.

The topology contract separates machines from displays and supports configurable wrap policies, AAB/BAA/ABA layouts, stacked layouts, asymmetric layouts, and cross-machine edge handoff. See [Topology Config Contract](topology.md) for the file format and validation expectations.
6 changes: 3 additions & 3 deletions docs/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ For the guided pairing flow, see [Public Beta Workflow](beta-workflow.md#guided-
| --- | --- |
| Server | A peer that currently owns the local pointer and sends input to another peer. This role is situational, not a fixed machine type. |
| Client | A peer receiving remote input. This role is also situational. |
| Screen | A machine entry in the current MWB layout. Multi-display topology is tracked separately on the roadmap. |
| Screen | A machine entry in the current MWB layout. Display-level topology is a separate opt-in contract. |
| Screen name | `machine_name` / MWB peer name. Names must match what the other peer expects. |
| Configuration file | `~/.config/mwb-client/config.ini` for InputFlow; PowerToys MWB settings on Windows. |
| Shared secret / password | MWB security key. InputFlow can read it from an inline `key`, `key_file`, or Secret Service `key_secret_id`. |
Expand Down Expand Up @@ -75,6 +75,6 @@ Avoid publishing configs, helper scripts, logs, or screenshots that expose keys,

## Topology Roadmap

InputFlow currently focuses on MWB-compatible machine placement. The topology roadmap includes a cleaner machine/display split, explicit wrap policies, AAB/BAA/ABA layouts, stacked layouts, asymmetric layouts, and dry-run path previews so users can inspect pointer transitions before applying them.
InputFlow defaults to MWB-compatible machine placement. Optional topology adds a cleaner machine/display split, explicit wrap policies, AAB/BAA/ABA layouts, stacked layouts, asymmetric layouts, and configured cross-machine edge handoff.

Until those features are user-facing, treat topology as machine-level MWB placement and verify changes in PowerToys MWB after exporting.
Until the runtime topology feature gate is enabled and validated for your setup, treat topology as machine-level MWB placement and verify changes in PowerToys MWB after exporting. If you are testing the layout wizard or runtime topology branch, use the [Topology Config Contract](topology.md) and keep `wrap=none` with explicit links until validation output matches the intended handoff behavior.
170 changes: 170 additions & 0 deletions docs/topology.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
# Topology Files

InputFlow topology files describe machines, their individual displays, explicit border links, and optional wrap fallback. The runtime consumes these files only when `topology_enabled=true` and `topology_file=...` are set in `config.ini`.

This is additive to the beta flow. If topology is disabled, missing, or invalid, InputFlow keeps the existing single-screen runtime behavior.

## Normal Single-Monitor Setup

Do not use topology for a normal one-monitor Linux/Fedora setup. Keep `topology_enabled=false` and let Windows PowerToys Mouse Without Borders own the Linux/Windows machine placement.

Use the controller action **Use PowerToys Layout Only** if you enabled topology while testing and want to return to the simple path.

CLI equivalent:

```bash
./mwb-desktop-ui.sh disable-topology
```

## Advanced Topology Setup

Use topology only when the normal PowerToys-style machine layout is not enough:

1. Open **InputFlow Controller**.
2. Click **Advanced Topology/Layout**.
3. Pick the layout that matches your desk:
- **Linux left, Windows right**: one Linux display beside Windows.
- **Linux above Windows**: one display stacked above the other.
- **Two Linux displays, then Windows**: Linux | Linux | Windows.
- **Windows, then two Linux displays**: Windows | Linux | Linux.
- **Linux split around Windows**: Linux | Windows | Linux.
- **Advanced/manual topology**: asymmetric or unusual layouts.
4. Confirm the preview.
5. Click **Explain Current Topology** and confirm the English explanation matches your desk.
6. Restart the InputFlow service when prompted.

CLI equivalent:

```bash
mwb_client topology explain --config ~/.config/mwb-client/config.ini
```

## PowerToys Layout Interaction

Windows PowerToys Mouse Without Borders still owns the Windows-side machine layout. InputFlow topology does not rewrite PowerToys `settings.json` or per-display geometry on Windows.

Keep both sides consistent:

- Use **export-windows-pair** or the Windows helper to place the Linux machine next to Windows at the MWB machine level.
- Use InputFlow topology to describe the Linux-side displays and the exact Linux edge that returns control to Windows.
- If PowerToys says Linux is left of Windows, do not make the Linux topology return to Windows from an unrelated edge.
- If these disagree, cursor movement will feel wrong because Windows and Linux will be making different assumptions.

Mental model: PowerToys decides **which machines are neighbors**. InputFlow topology decides **which Linux display edge performs the handoff**.

## Format

Topology files are line-based `key=value` files:

| Key | Format |
| --- | --- |
| `wrap` | `none`, `horizontal`, `vertical`, or `both` |
| `machine` | `MACHINE_ID` |
| `display` | `DISPLAY_ID,MACHINE_ID,X,Y,WIDTH,HEIGHT` |
| `link` | `SOURCE_DISPLAY,EXIT_EDGE,TARGET_DISPLAY,ENTRY_EDGE` |

Edges are `left`, `right`, `up`, or `down`. Explicit links win over wrap fallback. Display coordinates are per-machine logical geometry, not physical millimeters.

The layout wizard writes this format after a dry-run preview. Manual files should stay in `~/.config/mwb-client/*.topology`.

## Examples

### AAB

```ini
# topology-example: aab
wrap=none
machine=A
machine=B
display=A1,A,0,0,1920,1080
display=A2,A,1920,0,1920,1080
display=B1,B,3840,0,1920,1080
link=A1,right,A2,left
link=A2,left,A1,right
link=A2,right,B1,left
link=B1,left,A2,right
```

### BAA

```ini
# topology-example: baa
wrap=none
machine=A
machine=B
display=B1,B,0,0,1920,1080
display=A1,A,1920,0,1920,1080
display=A2,A,3840,0,1920,1080
link=B1,right,A1,left
link=A1,left,B1,right
link=A1,right,A2,left
link=A2,left,A1,right
```

### ABA

```ini
# topology-example: aba
wrap=none
machine=A
machine=B
display=A1,A,0,0,1920,1080
display=B1,B,1920,0,1920,1080
display=A2,A,3840,0,1920,1080
link=A1,right,B1,left
link=B1,left,A1,right
link=B1,right,A2,left
link=A2,left,B1,right
```

### Stacked

```ini
# topology-example: stacked
wrap=none
machine=A
machine=B
display=A1,A,0,0,1920,1080
display=B1,B,0,1080,1920,1080
link=A1,down,B1,up
link=B1,up,A1,down
```

### Asymmetric

```ini
# topology-example: asymmetric
wrap=none
machine=A
machine=B
display=A1,A,0,0,3840,2160
display=B1,B,3840,540,1920,1080
link=A1,right,B1,left
link=B1,left,A1,right
```

### Horizontal Wrap

```ini
# topology-example: wrap-horizontal
wrap=horizontal
machine=A
machine=B
display=A1,A,0,0,1920,1080
display=A2,A,1920,0,1920,1080
display=B1,B,3840,0,1920,1080
link=A2,right,B1,left
link=B1,left,A2,right
```

## Runtime Contract

`topology_enabled=false` is the default. Enabling topology loads and validates the topology file during startup. Invalid topology logs a warning and falls back to the existing behavior instead of blocking startup.

The current runtime uses topology to resolve edge transitions before local mouse injection. Same-machine transitions stay local. Cross-machine transitions send a mapped MWB mouse move back to the active peer and suppress the local edge move, so the pointer can return to the Windows side on configured borders.

## Troubleshooting

Use the diagnostics bundle when reporting topology bugs. It records `topology_enabled`, `topology_file`, load/validation status, display geometry, session type, and recent runtime logs.

If movement is unexpected, set `wrap=none` and add explicit `link=` lines for each intended transition. If the wizard output is wrong, edit the `.topology` file directly and restart the user service.
Loading