Back to Articles

DeskHop: Building a Seamless Two-Computer KVM with Dual Raspberry Pi Picos

[ View on GitHub ]

DeskHop: Building a Seamless Two-Computer KVM with Dual Raspberry Pi Picos

Hook

Traditional KVM switches take 1-2 seconds to switch between computers. DeskHop does it instantly by maintaining simultaneous connections to both machines and using your cursor position to determine which computer should receive input.

Context

If you've ever worked with two computers simultaneously—perhaps a work laptop and personal desktop, or a development machine and testing rig—you've likely encountered the frustration of managing dual keyboards and mice cluttering your desk. Traditional KVM (Keyboard, Video, Mouse) switches offer a solution, but they're plagued by switching delays, compatibility issues, and the inconvenience of reaching for a physical button dozens of times per day.

Software solutions like Synergy and Barrier exist, but they introduce their own problems: network latency, software installation requirements on both machines, firewall configurations, and the security implications of sending keystrokes over the network. DeskHop takes a different approach entirely, implementing a hardware solution that combines the instant responsiveness of having two sets of peripherals with the desk space efficiency of a KVM switch. Created by Hrvoje Cavrak, it's a purpose-built device using two Raspberry Pi Pico boards that sits between your keyboard/mouse and your computers, making the switching experience feel completely natural.

Technical Insight

The genius of DeskHop lies in its dual-connection architecture. Unlike traditional KVM switches that physically toggle USB connections between computers, DeskHop maintains active USB device connections to both computers simultaneously. This is accomplished using two Raspberry Pi Pico boards—one acts as the USB host for your keyboard and mouse, while both act as USB devices presenting themselves to the connected computers. The boards communicate via UART, with a digital isolator chip (like the ADUM1201) providing galvanic isolation between the two output channels to prevent ground loops when connecting computers with different power sources.

The most clever aspect is how DeskHop tracks which computer should receive input. While keyboards are straightforward—you simply forward HID reports to the active output—mice require translation from relative to absolute coordinates. Most mice report movement deltas ("moved 5 pixels right"), but DeskHop maintains an internal cursor position by accumulating these deltas and tracking screen boundaries. Here's a simplified version of the coordinate tracking logic:

// Simplified from the actual implementation
typedef struct {
    int32_t x;
    int32_t y;
    uint16_t screen_width;
    uint16_t screen_height;
} mouse_abs_t;

void update_mouse_position(mouse_abs_t *state, int8_t delta_x, int8_t delta_y) {
    // Accumulate relative movements into absolute position
    state->x += delta_x;
    state->y += delta_y;
    
    // Check screen boundary crossing
    if (state->x < 0) {
        // Cursor moved past left edge, switch to left computer
        switch_output(OUTPUT_A);
        state->x = state->screen_width - 1;  // Wrap to right edge
    } else if (state->x >= state->screen_width) {
        // Cursor moved past right edge, switch to right computer
        switch_output(OUTPUT_B);
        state->x = 0;  // Wrap to left edge
    }
    
    // Clamp Y coordinate to maintain continuity
    if (state->y < 0) state->y = 0;
    if (state->y >= state->screen_height) state->y = state->screen_height - 1;
}

This absolute positioning approach enables the "magic" of moving your cursor off the edge of one monitor and having it appear on the adjacent computer's screen at the same vertical position. The switching happens instantly because the inactive computer's USB connection is never dropped—it simply stops receiving HID reports until you switch back.

The USB implementation is particularly noteworthy. DeskHop uses the TinyUSB stack included with the Pico SDK to handle both host and device roles. The host-side Pico parses incoming HID reports from your keyboard and mouse, extracts the relevant data, and transmits it via UART to the device-side Pico at 3.6864 Mbaud. The receiving Pico then reconstructs proper HID reports and sends them to the active computer. The UART protocol is simple but effective—each message contains a type byte, length, and payload, with basic checksumming to ensure data integrity.

Configuration happens through an elegant hack: when you hold a specific key combination during boot, one of the Picos presents itself as a USB mass storage device containing a configuration file. You can edit screen dimensions, hotkey mappings, and other settings in plain text, then "eject" the drive. The Pico parses the config file from its flash memory and applies the settings. This eliminates the need for compilation and flashing for basic configuration changes.

The hotkey system deserves mention too. Beyond cursor-based switching, you can configure keyboard shortcuts (like pressing both Ctrl keys simultaneously) to force a switch. The firmware monitors the keyboard HID reports for these patterns and triggers output changes accordingly. This is crucial for scenarios where mouse switching doesn't work well—like when you're gaming and need to temporarily disable absolute mode, or when you're using fullscreen applications that capture the cursor.

Gotcha

The absolute mouse positioning that makes DeskHop feel seamless is also its Achilles' heel in certain scenarios. Many games use relative mouse input and implement their own cursor locking, which conflicts with DeskHop's coordinate tracking. First-person shooters, for example, rely on infinite mouse movement—you can spin 360 degrees without running out of mousepad. When DeskHop intercepts these movements and translates them to absolute coordinates with screen boundaries, games behave erratically. The solution is a "gaming mode" that you toggle via hotkey, which passes through raw relative movements, but this disables the automatic screen-edge switching that makes DeskHop special. You're back to using hotkeys, which somewhat defeats the purpose.

Virtual machines present similar issues. If you're running VMs in fullscreen or with mouse integration enabled, DeskHop's cursor tracking can become confused about which screen is active. The VM might capture the mouse, but DeskHop still thinks you're moving the cursor toward the edge. Additionally, the hardware requirement is non-trivial. You need two Raspberry Pi Picos (around $8-12 each), a digital isolator chip ($2-5), and basic soldering skills. The project provides PCB designs, but you can also breadboard it—either way, you're building hardware, not just running software. For developers uncomfortable with electronics, this is a barrier. Finally, DeskHop is fundamentally limited to two computers. The architecture—one input, two outputs—is baked into the design. If you need to switch between three or more systems, you'll need to look elsewhere or build something more complex.

Verdict

Use DeskHop if: you have a permanent dual-computer setup (side-by-side monitors from different machines), you're comfortable with basic electronics assembly, and you primarily do productivity work like coding, writing, or design where seamless cursor-based switching dramatically improves workflow. It's particularly valuable if you frequently copy-paste between machines or reference documentation on one while coding on the other. Skip if: you need to support more than two computers, you primarily game on both systems (the absolute mouse mode will cause problems), you're not comfortable soldering and flashing firmware, or you need a solution you can set up in minutes rather than hours. In those cases, stick with software KVM solutions like Input Leap or invest in a traditional hardware KVM switch with more ports.