Skip to content

Multi-Machine Setup

PolyKybdHost supports a forwarder mode that lets a single PolyKybd serve multiple computers. The keyboard is physically connected to one machine, but the key displays reflect the active window on whichever machine you are currently working on.

flowchart LR
    remote["<b>Remote machine</b><br/>PolyForwarder<br/>watches active window,<br/>sends window info"]
    keyboard["<b>Keyboard machine</b><br/>PolyHost<br/>owns HID device,<br/>updates displays"]
    kbd(["PolyKybd"])
    remote -- "window reports<br/>(TCP 50163)" --> keyboard -- USB --> kbd
  • Keyboard machine: running PolyKybdHost in normal mode, physically connected to the keyboard
  • Remote machine(s): running PolyKybdHost in forwarder mode (--host <IP>), no keyboard attached

When focus changes on a remote machine, it sends the window title and app info to the keyboard machine, which then updates the key displays.

Two things are easy to miss, and each one on its own makes the whole setup look silently broken.

The network transport is off by default. PolyKybdHost does not listen for window reports until you turn the listener on — step 1 below. Without it the forwarder just logs a connection error every few seconds.

You need a remote entry in your overlay mapping. The keyboard machine only uses a forwarded window while its own focused window is an app marked remote in overlay-mapping.poly.yaml — normally the remote-desktop client you are viewing the other machine through. The shipped mapping already covers NoMachine:

nxplayer:
remote: true
title: .*NoMachine.*

Add an entry the same way for whichever client you use. While that window has focus, the keycaps follow the app focused inside the remote session; when you switch back to a local window, they follow that local window again.

1. Turn on the window-report listener (keyboard machine)

Section titled “1. Turn on the window-report listener (keyboard machine)”
Terminal window
polyctl settings set window_report_network_enabled true

Then restart PolyKybdHost — the setting is read once at startup, so it does not take effect until the daemon comes back up.

Allow inbound TCP on port 50163 in the keyboard machine’s firewall.

After the restart the log should contain:

Window-report network listener on 0.0.0.0:50163 (auth-gated, 'window.report' only)

2. Copy the authentication key to the remote machine

Section titled “2. Copy the authentication key to the remote machine”

The connection is authenticated with a shared key, so the remote machine needs a copy of the keyboard machine’s key file. It is created the first time the listener starts, so do this after step 1.

The file is called polykybd-winreport.authkey and lives in PolyKybdHost’s config folder — reachable from the tray menu under Help & About → Open config folder, or directly:

Platform Location
Windows %LOCALAPPDATA%\PolyHost\PolyHost\polykybd-winreport.authkey
macOS ~/Library/Application Support/PolyHost/polykybd-winreport.authkey
Linux ~/.config/PolyHost/polykybd-winreport.authkey

Copy it to each remote machine. It can live anywhere there — you pass its path on the command line in the next step.

Terminal window
python -m polyhost --host 192.168.1.100 --report-rpc --report-authkey-file /path/to/polykybd-winreport.authkey

Or use a file containing the IP, if the address changes:

Terminal window
python -m polyhost --host-file /path/to/host.txt --report-rpc --report-authkey-file /path/to/polykybd-winreport.authkey

If you moved the listener to another port, add --report-port <n> to match.

The forwarder puts its own icon in the remote machine’s tray. Its menu follows the same shape as the keyboard machine’s, minus everything that needs a keyboard attached:

The PolyKybdHost forwarder tray menu: a status line reading “Forwarding to 192.168.1.100”, then Pause, Check for host update, Settings, Help & About and Quit

Entry What it does
Status line Where this machine is forwarding to, and whether the reports are arriving. Clicking it is a shortcut for Pause.
Pause Stop sending this machine’s active window. Reads Resume while paused.
Check for host update… Update PolyKybdHost on this machine. There is no firmware or font entry — those belong to the machine holding the keyboard.
Settings The handful of settings that mean something here: the light/dark theme and the browser-URL options.
Help & About About, the log viewer, Open config folder, Report a Problem… and Collect logs… — the same set, for this machine’s logs.
Quit Stop forwarding and close.

Pause stops this machine’s window titles leaving it — useful when you are doing something on the remote machine that you would rather the other computer knew nothing about. Nothing is sent while it is paused, and the status line says so. Resuming sends the current window straight away, so the keycaps catch up without waiting for you to switch application.

The forwarder’s status line answers this before you open anything: it reads Forwarding to <address> when reports are landing and Cannot reach <address> when they are not, and the tray mark greys out to match.

For the detail, focus a window on the remote machine and watch the two logs.

The forwarder reports which window it saw:

Active App: 'Document1 - Word' winword 12345678

The keyboard machine’s log — the Daemon Log tab in the log viewer — shows the matching change once the remote-desktop client is focused:

Remote App Changed: "winword", Title: "Document1 - Word" Handle: 12345678

If the forwarder logs windows but the keyboard machine never mentions them, the reports are not arriving — see below.

Website-aware overlays for a forwarded browser

Section titled “Website-aware overlays for a forwarded browser”

A forwarded browser can match on its website, not just its window title. Install the browser extension on the remote machine — it reports to 127.0.0.1 there, so it needs no special configuration — and the forwarder sends the focused tab’s URL along with the window. Your urls-contains entries then apply to forwarded browsers just as they do locally, including an in-app navigation that never changes the window title.

This rides the authenticated path only: it needs the --report-rpc setup above, and the legacy relay in the next section does not carry the URL.

What you see What it means Fix
Forwarder tray: Cannot reach <address>, icon grey Reports are not arriving — the rows below say why Open the forwarder’s Help & About → Log file… for the reason
Forwarder tray: Forwarding paused Somebody pressed Pause on this machine Click Resume
Forwarder: Window-report RPC to … failed: timed out Nothing is listening, or a firewall is dropping the connection Confirm step 1 on the keyboard machine (polyctl settings get window_report_network_enabled), that it was restarted afterwards, and that port 50163 is allowed
Forwarder: Using this machine's local window-report authkey --report-authkey-file was omitted Add it, pointing at the key copied in step 2
Forwarder: control protocol mismatch … restart so versions match The two machines run incompatible PolyKybdHost versions Update both to the same version
Forwarder: Connection timed out on port 50162 The forwarder is still using the legacy relay Add --report-rpc (and the key file), or see the legacy section below
Keyboard machine: Remote overlay entries are configured but the legacy plaintext window relay (TCP 50162) is disabled Same as above, seen from the other side As above
Both logs look fine, keycaps do not change The keyboard machine’s focused window is not a remote mapping entry Focus your remote-desktop client, and check it has a remote: true entry (see Before you start)
A forwarded browser matches its title but never a urls-contains entry The URL is not reaching the keyboard machine Check the extension is installed on the remote machine and its Options page reports Connected, and that the forwarder runs with --report-rpc (the legacy relay never carries the URL)

Collecting the evidence is one click on each side: the forwarder’s Help & About submenu has the same Report a Problem… and Collect logs… entries as the keyboard machine’s, and a forwarder report says so on its first line. Because the two halves run on different computers, a bundle from one never contains the other’s log — collect from both. See Reporting a Problem.

Older versions relayed window reports over a plaintext TCP socket on port 50162 with no authentication, accepting connections from anywhere on the network. That relay is disabled by default since PolyKybdHost 0.10.5 and has been replaced by the authenticated path above.

If you have an existing setup built on it and want it back for now, enable it on the keyboard machine and restart:

Terminal window
polyctl settings set dev_legacy_plaintext_relay true

The forwarder then needs no extra flags — plain --host <IP> uses it. In the settings dialog the option only appears when developer mode is on.

A common setup: a desktop (with the keyboard) and a laptop, with the laptop on screen through a remote-desktop client. As you move between applications in that session, the forwarder on the laptop reports each focus change to the desktop, and the keycaps show the overlays for the app you are actually working in — all while the keyboard stays physically on the desk connected to the desktop.