Virtual KVM

November 15th 2017

Tags: utilities

My current setup includes a desktop computer running Windows, and a work laptop running MacOS. In order to keep my desktop uncluttered, I have devised a virtual KVM using Synergy (1.8) and AutoHotKey. The aim was to use a single monitor, mouse and keyboard with these two systems.

Sure, I could have sprung for two monitors, though I have a nice Asus 27" 2k and little room (or budget) for much else.

First, let's look at how things are connected:

Virtual KVM setup diagram showing a mac laptop connected to displayport and a pc (host) computer connected to DVI

The desktop can actually send commands to the monitor over the DVI connection using something called "Display Data Channel". This capability lets tell our monitor to switch to another input. Some googling around on how to script this, lead me to this post in the AutoHotKey forums. From there, I was able to figure out the input "source numbers" through trial and error (3: DVI and 15: Displayport for my monitor). Though, I have found you can see exactly which input sources are available by using ControlMyMonitor (Windows):

ControlMyMonitor for Windows showing "Input Select" values of 1, 3, 15 and 17

Finally, I bind the hotkeys to Ctrl+Alt+[ and Ctrl+Alt+], which are the same hotkeys I used to switch computers in Synergy.

The final AutoHotKey script:

; From:

; Finds monitor handle
  ; Initialize Monitor handle
  hMon := DllCall("MonitorFromPoint"
    , "int64", 0 ; point on monitor
    , "uint", 1) ; flag to return primary monitor on failure

  ; Get Physical Monitor from handle
  VarSetCapacity(Physical_Monitor, 8 + 256, 0)

    , "int", hMon   ; monitor handle
    , "uint", 1   ; monitor array size
    , "int", &Physical_Monitor)   ; point to array with monitor

  return hPhysMon := NumGet(Physical_Monitor)

  DllCall("dxva2\DestroyPhysicalMonitor", "int", handle)

; Used to change the monitor source
; DVI = 3
; HDMI = 4
; DisplayPort = 15
  handle := getMonitorHandle()
    , "int", handle
    , "char", 0x60 ;VCP code for Input Source Select
    , "uint", source)

; Gets Monitor source
  handle := getMonitorHandle()
    , "int", handle
    , "char", 0x60 ;VCP code for Input Source Select
    , "Ptr", 0
    , "uint*", currentValue
    , "uint*", maximumValue)
  return currentValue

; Map monitor switch to same keys as synergy keyboard switch
  Send ^!{[}
  Send ^!{]}

Note the input source numbers referenced: 15 (Displayport) and 3 (DVI).

My Synergy config contains this section for setting up the same machine switching hotkeys:

section: options
    switchCorners = none 
    switchCornerSize = 0
    keystroke(Alt+Control+[) = ;switchToScreen(laptop-alias)
    keystroke(Alt+Control+]) = ;switchToScreen(desktop-alias)


Since I'm running Synergy 1.8, this config may not apply to Synergy 2 users. I haven't seen a reason to switch yet, but will post an update to this if I decide to.

DDC capabilities are not universal. Some monitor manufacturers may not let you do this.

While running the Synergy daemon and AutoHotKey script on the Windows desktop, startup order matters! We need to start AutoHotKey before Synergy or the AutoHotKey keybinding will never fire.

I also need to press Ctrl+Alt+] multiple times to get back to my Windows desktop. I think this is because one press triggers Synergy to switch, the next triggers the monitor switch.

Does it work?

After all of those caveats... Yes. It does. I use it every day, and I'm using it right now. If Synergy included a monitor switch capability in version 2, I would upgrade in a heartbeat.


Added notes on finding input source numbers.

By Colin Kennedy