Deskhop
Fast Desktop Switching Device
Install / Use
/learn @hrvach/DeskhopREADME
DeskHop - Fast Desktop Switching
Did you ever notice how, in the crazy world of tech, there's always that one quirky little project trying to solve a problem so niche that its only competitors might be a left-handed screwdriver and a self-hiding alarm clock?
I use two different computers in my daily workflow and share a single keyboard/mouse pair between them. Trying several USB switching boxes found on Amazon made me realize they all suffer from similar issues - it takes a while to switch, the process is quite clumsy when trying to find the button and frankly, it just doesn't get any better with time.
All I wanted was a way to use a keyboard shortcut to quickly switch outputs, paired with the ability to do the same by magically moving the mouse pointer between monitors. This project enables you to do both, even if your computers run different operating systems!

Features
- Completely free and open source
- No noticeable delay when switching
- Simply drag the mouse pointer between computers
- No software installed
- Affordable and obtainable components (<15€)
- 3D printable snap-fit case
- Full Galvanic isolation between your outputs
- Works with Linux, macOS and Windows
User Manual is now available
How it works
The device acts as an intermediary between your keyboard/mouse and the computer, establishing and maintaining connections with both computers at once. Then it chooses where to forward your mouse and keystrokes to, depending on your selection. Keyboard follows the mouse and vice versa, so just dragging the mouse to the other desktop will switch both.
Mouse
To get the mouse cursor to magically jump across, the mouse hid report descriptor was changed to use absolute coordinates and then the mouse reports (that still come in relative movements) accumulate internally, keeping the accurate tally on the position.
When you try to leave the monitor area in the direction of the other monitor, it keeps the Y coordinate and swaps the maximum X for a minimum X, then flips the outputs. This ensures that the cursor seamlessly appears at the same height on the other monitor, enhancing the perception of a smooth transition.

The actual switch happens at the very moment when one arrow stops moving and the other one starts.
Keyboard
Acting as a USB Host and querying your keyboard periodically, it looks for a preconfigured hotkey in the hid report (usually Ctrl + Caps Lock for me). When found, it will forward all subsequent characters to the other output.
To have a visual indication which output you are using at any given moment, you can repurpose keyboard LEDs and have them provide the necessary feedback.
It also remembers the LED state for each computer, so you can pick up exactly how you left it.

How to build
To avoid version mismatch and reported path issues when building, as well as to save you from having to download a large SDK, the project now bundles minimal pico sdk and tinyusb.
On a Debian/Ubuntu systems, make sure to install these:
apt update
apt install \
build-essential \
cmake \
gcc-arm-none-eabi \
libnewlib-arm-none-eabi \
python3
You should be able to build by running:
cmake -S . -B build
cmake --build build
additionally, to rebuild web UI check webconfig/ and execute ./render.py, you'll need jinja2 installed.
An alternative can be to use docker via 'docker compose' or 'docker-compose':
docker-compose -f misc/docker.yml run --rm build_container
This ensures reproducible builds.
To rebuild the disk, check disk/ folder and run ./create.sh, tweak to your system if needed. You'll need dosfstools (to provide mkdosfs),
Using a pre-built image
Alternatively, you can use the pre-built images. Since version 0.6 there is only a single universal image. You need the .uf2 file which you simply copy to the device in one of the following ways:
Upgrading firmware
Option 1 - (firmware 0.6 and later) Put the device in "config mode" by simultaneously pressing left ctrl + right shift + c + o. Device your keyboard is plugged into will reboot and turn into a USB drive called "DESKHOP". All you need to do is copy the .uf2 file to it. Once image is verified, device will flash and reboot, then proceed to upgrade the other board. During this operation the led will blink. Once it's done, it will write flash and reboot, completing the operation.
Note - This is not an actual generic USB drive, you can't use it to copy files to it.
Option 2 - Using the ROM bootloader - hold the on-board button while connecting each Pico and copy the uf2 to the flash drive that appears. Images later than 0.6 support holding the button without having to fiddle around the power supply, but the "hold button while plugging" should always work, regardless of device state.
Option 3 - CDC Flash Command (Debug builds only) - If the firmware was built with DH_DEBUG_CDC_FLASH=ON, you can trigger bootloader mode via CDC serial command:
echo -n 'flash' > /dev/tty.usbmodem11104
This immediately resets the device into bootloader mode where it appears as "RPI-RP2" drive. This feature is intended for development workflows.
Misc features
Mouse slowdown
Ever tried to move that YT video slider to a specific position but your mouse moves too jumpy and suddenly you are moving your hand super-carefully like you're 5 and playing "Operation" all over again?
Press right CTRL + right ALT to toggle a slow-mouse mode. The mouse pointer will slow down considerably, enabling you to get the finer precision work done and still have your mouse moving normally by quickly pressing the same keys again.
Switch Lock
If you want to lock yourself to one screen, use RIGHT CTRL + K.
This will make sure you won't accidentally leave your current screen. To turn off, press the same key combo again.
Lock Both Screens
You can lock both computers at once by using RIGHT CTRL + L.
To make use of this feature, first set up the OS for each output in config (since the shortcuts are different).
Gaming Mode
If you're gaming, there is a chance your game might not work properly with absolute mouse mode. To address that issue, a gaming mode is introduced, toggled by LEFT CTRL + RIGHT SHIFT + G. When in gaming mode, you are locked to the current screen and your mouse behaves like a standard relative mouse. This should also fix various virtual machine issues, currently unsupported operating systems etc.
Screensaver
Supposedly built in to prevent computer from entering standby, but truth be told - it is just fun to watch. Off by default, will make your mouse pointer bounce around the screen like a Pong ball. When enabled, it activates after a period of inactivity defined in user config header and automatically switches off as soon as you send any output towards that screen.
Potential usage example - I have a buggy USB dock that won't resume video from standby, so not allowing it to sleep can be a handy workaround.
Hardware
The circuit is based on two Raspberry Pi Pico boards, chosen because they are cheap (4.10 € / pc), can be hand soldered and most suppliers have them in stock.
The Picos are connected using UART and separated by an Analog Devices ADuM1201 dual-channel digital isolator (~3€) or a much cheaper, faster and pin-compatible TI ISO7721DR (~1.5€) which is the preferred choice.
While they normally don't have support for dual USB, thanks to an amazing project where USB is implemented using the programmable IO wizardry found in RP2040, there is support for it to act both as an USB host and device.
PCB [updated]
To keep things as simple as possible for DIY builds, the traces were kept on one side and the number of parts kept to a minimum.

USB D+/D- differential lines should be identical in length, but they are slightly asymmetrical on purpose to counter the length difference on the corresponding GPIO traces PICO PCB itself, so the overall lengths should match.
Zd (differential impedance) is aimed as 90 ohm (managed to get ~107, close enough :)).
The thickness is designed to be 1.6 mm for snap-fit to work as expected.
There are 2 versions of the PCB (no major differences for the user). Original (v1.0) is easier to solder and assemble, while v1.1 offers some upgrades like:
-
added ESD protection (TPD4E1U06DBVR)
-
added VBUS capacitor for the keyboard/mouse connectors
-
silkscreen orientation markings
-
holes for clone boards with headers pre-soldered and easier alignment
-
USB 27 ohm resistors
This version is slightly more difficult to hand solder due to the small transient voltage suppressor IC and 0805 resistors, but it's totally doable. TVS can in theory be omitted (not advised) and it will still work.
Upcoming - board with bare rp2040s that doesn't need Picos, is smaller and more convenient.
Case
Since I'm not very good with 3d, the case is simple and basic but does the job. It should be easy to print, uses ~33g of filament and takes a couple of hours.
Horizontal PCB movements are countered by pegs sliding through holes and vertical movements by snap-fit lugs on the sides - no screws required. The case was given a slight redesign to feature the logo and two additional snap-fit lugs, so it provides a better seal.
Micro USB connectors on both boards are offset from the side of the case, so slightly larger holes should allow for
