⚠️ Early Development — Expect BugsThis project is in early, active development. Core functionality (connection, cursor movement, keyboard input) works in testing but there are known issues and many rough edges. Cursor crossing from Windows to Linux is not yet reliably working. Use at your own risk and expect things to break. Contributions and bug reports are very welcome.
A native C++17 Linux bridge for Microsoft PowerToys "Mouse Without Borders", enabling cursor and keyboard sharing between Windows and Linux systems.
Works on both X11 and Wayland via Linux's uinput kernel interface.
- Full cursor movement and click injection (left, right, middle buttons, scroll wheel)
- Keyboard injection via Virtual Key Code translation to Linux
EV_KEYcodes - Automatic reconnect on network drop
- Bidirectional TCP connection (connects out to Windows and accepts Windows's inbound connection)
- AES-256-CBC encrypted protocol matching PowerToys MWB exactly
- Dependency-light terminal UI for setup, status checks, key storage, and launching
mwb-linux-bridge/
├── CMakeLists.txt
├── Dockerfile
├── flatpak/
│ ├── dev.benm.MwbLinuxBridge.yml
│ └── build-flatpak.sh
├── gui/
│ ├── package.json
│ └── src/
├── packaging/
│ ├── 90-mwb-client-uinput.rules
│ ├── config.example
│ ├── install-uinput-rule.sh
│ ├── README.Fedora.md
│ └── mwb-linux-bridge.spec
├── README.md
├── src/
│ ├── main.cpp
│ ├── Protocol.h
│ ├── CryptoHelper.h / .cpp
│ ├── InputManager.h / .cpp
│ └── NetworkManager.h / .cpp
└── tui/
└── mwb-tui
sudo apt-get install -y build-essential cmake libssl-devmkdir build && cd build
cmake ..
make -j$(nproc)Install locally:
sudo cmake --install buildsudo usermod -aG input $USER
echo 'KERNEL=="uinput", GROUP="input", MODE="0660"' | sudo tee /etc/udev/rules.d/99-uinput.rules
sudo udevadm control --reload-rules && sudo udevadm triggerLog out and back in for group membership to take effect.
mwb-tui is the recommended setup path while the desktop GUI is parked. It uses the same config file as mwb-client and works in any normal terminal or over SSH.
From a source checkout:
./tui/mwb-tui
./tui/mwb-tui --statusAfter installing:
mwb-tui
mwb-tui --statusThe TUI can:
- configure the Windows IP/host and port
- save the PowerToys security key to
~/.config/mwb-linux-bridge/keywith private permissions, or leave the client in prompt mode - check
/dev/uinput, the selected client binary, session type, route to Windows, and TCP port reachability - install the uinput udev rule on request
- start
mwb-clientwith the saved config
Flatpak support is kept for the Electron GUI, but the current recommended path is the native client plus mwb-tui. The Flatpak bundles the Electron frontend and the native mwb-client bridge binary into one installable bundle.
Install build tools:
# Fedora
sudo dnf install flatpak flatpak-builder
# Debian / Ubuntu
sudo apt install flatpak flatpak-builderBuild and install the local Flatpak bundle:
./packaging/install-uinput-rule.sh
npm --prefix gui run dist:linux
flatpak install --user ./dist/dev.benm.MwbLinuxBridge.flatpak
flatpak run dev.benm.MwbLinuxBridgeThe bundle is written to dist/dev.benm.MwbLinuxBridge.flatpak.
Flatpak can request device access, but it cannot install host udev rules. Run ./packaging/install-uinput-rule.sh once on the host so the app can open /dev/uinput.
./build/mwb_client [--config PATH] [--host WINDOWS_IP] [--port PORT]
./build/mwb_client <WINDOWS_IP> [PORT]
WINDOWS_IP— IP address of the Windows machine running PowerToys MWBPORT— Optional, defaults to15101(keyboard/mouse channel). Do not use15100(clipboard only).- Security key — enter the key shown in PowerToys → Mouse Without Borders → Security key at the hidden prompt, or set
MWB_SECURITY_KEY.
Example:
./build/mwb_client 192.168.1.10Do not pass the security key as a command-line argument. Command-line secrets can be exposed through shell history and process listings.
Create the default config:
./build/mwb_client --init-configThen edit ~/.config/mwb-linux-bridge/config:
windows_ip=192.168.1.10
port=15101
# security_key_file=~/.config/mwb-linux-bridge/keyAfter that, run:
./build/mwb_clientSupported config keys are windows_ip, host, port, and security_key_file. If security_key_file is omitted, the client prompts for the key.
The Electron GUI is parked while the terminal UI is the recommended workflow. The code remains under gui/ for later work.
The GUI is a Linux desktop frontend for the same mwb-client binary and config file. It uses standard Electron windows, no tray-only workflow, no global shortcuts, and no compositor-specific APIs, so it can run under common desktop environments and window managers on X11 or Wayland.
Run in development:
cd gui
npm install
npm startBuild the universal Flatpak bundle:
cd gui
npm run dist:linuxThe Flatpak bundle is copied to the repo-level dist/ directory and includes both the GUI and native bridge.
Build the Fedora-native GUI RPM instead:
cd gui
npm run dist:rpmThe GUI RPM is copied to the repo-level dist/ directory. It installs the GUI as mwb-linux-bridge-gui, adds a desktop entry, and depends on the native mwb-linux-bridge package for the actual input bridge.
The GUI checks the session type, desktop name, /dev/uinput access, and the resolved mwb-client binary path. It can save connection settings to ~/.config/mwb-linux-bridge/config and, if selected, store the key in ~/.config/mwb-linux-bridge/key with private file permissions.
- Open PowerToys → Mouse Without Borders on Windows.
- Enable the feature and note your Security key.
- Add your Linux machine name (e.g.
mylinuxbox) to the machine list. - Configure which screen edge leads to the Linux machine.
- Run the client on Linux as shown above.
docker build -t mwb-linux-bridge .
docker run --rm -it --device /dev/uinput:/dev/uinput mwb-linux-bridge \
<WINDOWS_IP>This repository includes a local RPM spec under packaging/. The package installs /usr/bin/mwb-client, /usr/bin/mwb-tui, and a udev rule for active-session /dev/uinput access.
Build locally:
rpmbuild --define "_topdir /tmp/mwb-rpmbuild" -ba /tmp/mwb-rpmbuild/SPECS/mwb-linux-bridge.specAfter installing the RPM, run:
mwb-tuiOr run the client directly:
mwb-client 192.168.1.10To build the Fedora-native GUI RPM, run:
cd gui
npm run dist:rpmThe PowerToys MWB protocol uses:
- Transport: TCP on port 15101 (mouse/keyboard) and 15100 (clipboard)
- Encryption: AES-256-CBC, no padding, streaming mode
- Key derivation: PBKDF2-HMAC-SHA512, 50 000 iterations, fixed salt derived from
ulong.MaxValueencoded as UTF-16LE - IV: Fixed string
"1844674407370955"(ASCII, 16 bytes) - Magic number: 24-bit hash of the security key via 50 000 rounds of SHA-512
- Packet sizes: 32 bytes (small: mouse, keyboard, small heartbeat) or 64 bytes (big: handshake, identity, matrix)
- Handshake: Both sides exchange 10× type-126 challenge packets; each responds with a type-127 acknowledgement carrying the bitwise-NOT of the received challenge fields
- Identity: Type-51 heartbeat packets carry the machine name (ASCII, space-padded to 32 bytes) and screen dimensions
The machine name sent by this client must match the name configured in Windows's MWB machine list.
- Screen dimensions are queried with
xrandrat startup. If that fails, input injection falls back to 1920x1080. - Clipboard sync is not implemented.
- Wayland cursor warping uses a REL snap-to-corner trick; absolute positioning via
EV_ABSis ignored by most compositors forINPUT_PROP_POINTERdevices. - Security is constrained by the PowerToys compatibility protocol: AES-256-CBC has no per-message authentication tag and uses a fixed compatibility IV. Run this only on trusted LANs/VPNs.
MIT — see LICENSE.
This project is independent and is not affiliated with or endorsed by Microsoft. It interoperates with the PowerToys Mouse Without Borders protocol by studying the published open-source implementation at microsoft/PowerToys.