Llevo muchísimo tiempo utilizando Parsec como mi compañero de aventuras para Remote Desktop y para poder jugar desde cualquier parte. Siempre me ha funcionado muy bien, pero tiene un pequeño “gran” inconveniente para mi caso de uso: llevan una eternidad sin sacar una aplicación oficial para iOS. Tienen app para Android, sí, pero como yo utilizo fuertemente el ecosistema de Apple, esto siempre ha supuesto una piedra en el camino.
Así que decidí dar el salto a Moonlight. Concretamente, me he montado el chiringuito a través de Apollo, el fork de Sunshine. La experiencia de vídeo y respuesta es excelente, pero enseguida me di cuenta de que había ciertas cosas que necesitaba imperiosamente y que no estaban muy afinadas.
🔧 El problema: El portapapeles en Moonlight
Para un programa específico que utilizo a diario, necesito recibir lo copiado en el portapapeles (clipboard) de forma rápida y transparente. Resulta que Moonlight, aunque tiene una forma de copiar texto, no lo hace automáticamente. Por si fuera poco, requiere usar una combinación de teclas diferente, lo que corta por completo el flujo de trabajo.
🔧 La solución: Sincronización bidireccional
Como no me iba a quedar de brazos cruzados, decidimos buscar una forma de compartir los portapapeles directamente entre Windows y el Mac. La solución pasaba por crear un pequeño script en bash para el lado de macOS que hiciera uso de Netcat (nc) para enviar y recibir datos en texto plano.
Os dejo por aquí los códigos que utilizo para que la magia ocurra. En el Mac uso un script bash con Netcat (nc), y en Windows un script de PowerShell que hace de espejo.
🍎 Lado Mac (clip-sync.sh)
#!/bin/bash
echo "クリップボード双方向同期中..."
echo "Windows -> Mac (ポート9999) / Mac -> Windows (ポート9998)"
echo ""
WINDOWS_IP="192.168.50.2"
ULTIMO=""
RECIBIDO=""
# Listener en background: recibe de Windows
while true; do
contenido=$(nc -l 9999)
RECIBIDO="$contenido"
echo "$contenido" | pbcopy
preview=$(echo "$contenido" | head -c 80 | tr '\n' ' ')
echo "受信 $(date '+%H:%M:%S') Win->Mac: $preview"
done &
# Sender: envía a Windows cuando cambia el portapapeles local
while true; do
actual=$(pbpaste)
if [ "$actual" != "$ULTIMO" ] && [ "$actual" != "$RECIBIDO" ]; then
echo "$actual" | nc -w 1 $WINDOWS_IP 9998
preview=$(echo "$actual" | head -c 80 | tr '\n' ' ')
echo "送信 $(date '+%H:%M:%S') Mac->Win: $preview"
ULTIMO="$actual"
RECIBIDO=""
fi
sleep 0.1
done
🪟 Lado Windows (clip-sync.ps1)
Para Windows, el script es algo más complejo porque maneja directamente los sockets de red de .NET para asegurar que la codificación UTF8 sea perfecta:
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
chcp 65001 | Out-Null
$mac = "192.168.50.2" # IP de tu Mac
$puertoEnvio = 9999
$puertoRecibe = 9998
$ultimo = ""
$recibido = ""
Write-Host "クリップボード双方向同期中..." -ForegroundColor Cyan
Write-Host "Windows -> Mac (ポート$puertoEnvio) / Mac -> Windows (ポート$puertoRecibe)`n" -ForegroundColor Gray
$listener = [System.Net.Sockets.TcpListener]::new([System.Net.IPAddress]::Any, $puertoRecibe)
$listener.Start()
Write-Host "受信待機中 (ポート$puertoRecibe)..." -ForegroundColor Gray
while ($true) {
if ($listener.Pending()) {
$client = $listener.AcceptTcpClient()
$stream = $client.GetStream()
$bytes = New-Object byte[] 65536
$len = $stream.Read($bytes, 0, $bytes.Length)
$texto = [System.Text.Encoding]::UTF8.GetString($bytes, 0, $len)
$client.Close()
Set-Clipboard -Value $texto
$recibido = $texto
$ultimo = $texto
$preview = if ($texto.Length -gt 80) { $texto.Substring(0,80) + "..." } else { $texto }
$preview = $preview -replace "`r`n|`n", " "
Write-Host "受信 $(Get-Date -Format 'HH:mm:ss') Mac->Win: $preview" -ForegroundColor Yellow
}
$actual = (Get-Clipboard -Raw)
if ($actual -and $actual -ne $ultimo) {
try {
$client = New-Object System.Net.Sockets.TcpClient($mac, $puertoEnvio)
$stream = $client.GetStream()
$bytes = [System.Text.Encoding]::UTF8.GetBytes($actual)
$stream.Write($bytes, 0, $bytes.Length)
$client.Close()
$preview = if ($actual.Length -gt 80) { $actual.Substring(0,80) + "..." } else { $actual }
$preview = $preview -replace "`r`n|`n", " "
Write-Host "送信 $(Get-Date -Format 'HH:mm:ss') Win->Mac: $preview" -ForegroundColor Green
} catch {
Write-Host "エラー $(Get-Date -Format 'HH:mm:ss') Macに接続できません" -ForegroundColor Red
}
$ultimo = $actual
}
Start-Sleep -Milliseconds 300
}
Básicamente, lo que hace el script de Mac es levantar un proceso en segundo plano escuchando en el puerto 9999 todo lo que venga desde Windows y meterlo directamente al pbcopy. A su vez, el script de Windows escucha en el puerto 9998 y utiliza Set-Clipboard para actualizar el portapapeles local.
Con esto corriendo en ambas máquinas, ya he podido hacer un buen uso del clipboard sin tener que pelearme con atajos de teclado extraños de Moonlight. Otra pequeña victoria para el cacharreo.