diff --git a/.env.example b/.env.example index 1e670a3..d7f4da9 100644 --- a/.env.example +++ b/.env.example @@ -7,6 +7,8 @@ GUAC_PASSWORD= HATCH_HTTPS_PORT=443 HATCH_HTTPS_HOST_PORT=8443 HATCH_START_URL=about:blank +# Maps remote Super/Cmd-style shortcuts to Linux Ctrl shortcuts. +HATCH_MAC_SHORTCUTS=1 # Normally leave this blank. Only use --no-sandbox as a last-resort workaround. CHROMIUM_EXTRA_FLAGS= # Defaults generate a self-signed certificate inside the container. diff --git a/Dockerfile b/Dockerfile index 02ce1f0..08b1c4c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -42,6 +42,7 @@ ENV DEBIAN_FRONTEND=noninteractive \ RDP_USER=oauth \ HATCH_HTTPS_PORT=443 \ HATCH_START_URL=about:blank \ + HATCH_MAC_SHORTCUTS=1 \ CHROMIUM_EXTRA_FLAGS="" \ CATALINA_HOME=/usr/local/tomcat \ GUACAMOLE_HOME=/etc/guacamole \ @@ -78,6 +79,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ openssl \ procps \ supervisor \ + xbindkeys \ + xdotool \ x11-xserver-utils \ xorg \ xorgxrdp \ diff --git a/INSTALL.md b/INSTALL.md index 81e7300..ed1a596 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -133,6 +133,7 @@ GUAC_USER= GUAC_PASSWORD= HATCH_HTTPS_PORT=443 HATCH_START_URL=about:blank +HATCH_MAC_SHORTCUTS=1 CHROMIUM_EXTRA_FLAGS= HATCH_TLS_CERT=/etc/hatch/tls/hatch.crt HATCH_TLS_KEY=/etc/hatch/tls/hatch.key @@ -142,6 +143,8 @@ HATCH_TLS_DAYS=365 Leave `RDP_PASSWORD` blank to generate a password at startup. Leave `GUAC_USER` and `GUAC_PASSWORD` blank to reuse the RDP credentials for Guacamole. +`HATCH_MAC_SHORTCUTS=1` maps remote `Super`/Mac-style shortcuts such as `Cmd+V`, `Cmd+C`, and `Cmd+L` to the Linux `Ctrl` shortcuts expected by Chromium. Set it to `0` to disable this shortcut bridge. + ## Docker Compose Option ```bash diff --git a/PRD.md b/PRD.md index a20a328..cb5db62 100644 --- a/PRD.md +++ b/PRD.md @@ -18,6 +18,7 @@ Hatch must provide browser-based desktop access through HTTPS from the container - The generated Guacamole credentials are printed to container logs and usable when the container is started detached. - Docker users can map any host port to container port `443`, for example `-p 8443:443`. - Host-network OAuth callback mode remains documented for cases where Chromium must reach a callback listener on host loopback. +- The default desktop session maps remote Super/Mac-style shortcuts such as paste, copy, and address-bar focus to the Linux Ctrl shortcuts expected by Chromium, with an environment variable to disable the mapping. - Default Docker and Docker Compose starts do not show Chromium's unsupported `--no-sandbox` warning. - The README presents the HTTPS Guacamole flow as the primary quickstart and keeps Docker Compose as a lower-priority option. - An E2E smoke test validates the HTTPS Guacamole login path and confirms the browser desktop starts. diff --git a/README.md b/README.md index c9ba75c..9ace786 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,7 @@ GUAC_USER= GUAC_PASSWORD= HATCH_HTTPS_PORT=443 HATCH_START_URL=about:blank +HATCH_MAC_SHORTCUTS=1 CHROMIUM_EXTRA_FLAGS= HATCH_TLS_CERT=/etc/hatch/tls/hatch.crt HATCH_TLS_KEY=/etc/hatch/tls/hatch.key @@ -101,6 +102,8 @@ HATCH_TLS_DAYS=365 Leave `RDP_PASSWORD` blank to generate a random password. Leave `GUAC_USER` and `GUAC_PASSWORD` blank to reuse the RDP credentials for the Guacamole login. +`HATCH_MAC_SHORTCUTS=1` maps remote `Super`/Mac-style shortcuts such as `Cmd+V`, `Cmd+C`, and `Cmd+L` to the Linux `Ctrl` shortcuts expected by Chromium. Set it to `0` to disable this shortcut bridge. + To use your own certificate, mount the certificate and key into the container and set `HATCH_TLS_CERT` and `HATCH_TLS_KEY`. ## Docker Compose Option diff --git a/config/startwm.sh b/config/startwm.sh index 9dd7ec9..7830a04 100644 --- a/config/startwm.sh +++ b/config/startwm.sh @@ -8,6 +8,33 @@ export XDG_CACHE_HOME="$HOME/.cache" export XDG_RUNTIME_DIR="/tmp/runtime-$USER_NAME" mkdir -p "$XDG_CONFIG_HOME" "$XDG_CACHE_HOME" "$XDG_RUNTIME_DIR" chmod 700 "$XDG_RUNTIME_DIR" +case "${HATCH_MAC_SHORTCUTS:-1}" in + 1|true|TRUE|yes|YES|on|ON) + if command -v xbindkeys >/dev/null 2>&1 && command -v xdotool >/dev/null 2>&1; then + cat > "$XDG_CONFIG_HOME/hatch-mac-shortcuts.xbindkeysrc" <<'EOF' +"xdotool key --clearmodifiers ctrl+v" + Mod4 + v +"xdotool key --clearmodifiers ctrl+c" + Mod4 + c +"xdotool key --clearmodifiers ctrl+x" + Mod4 + x +"xdotool key --clearmodifiers ctrl+a" + Mod4 + a +"xdotool key --clearmodifiers ctrl+l" + Mod4 + l +"xdotool key --clearmodifiers ctrl+t" + Mod4 + t +"xdotool key --clearmodifiers ctrl+w" + Mod4 + w +"xdotool key --clearmodifiers ctrl+r" + Mod4 + r +"xdotool key --clearmodifiers ctrl+shift+v" + Mod4 + Shift + v +EOF + xbindkeys -f "$XDG_CONFIG_HOME/hatch-mac-shortcuts.xbindkeysrc" & + fi + ;; +esac openbox-session & OPENBOX_PID=$! sleep 1 diff --git a/docker-compose.yml b/docker-compose.yml index 5da8a1e..34c54b0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,6 +15,7 @@ services: GUAC_PASSWORD: ${GUAC_PASSWORD:-} HATCH_HTTPS_PORT: ${HATCH_HTTPS_PORT:-443} HATCH_START_URL: ${HATCH_START_URL:-about:blank} + HATCH_MAC_SHORTCUTS: ${HATCH_MAC_SHORTCUTS:-1} CHROMIUM_EXTRA_FLAGS: ${CHROMIUM_EXTRA_FLAGS:-} HATCH_TLS_CERT: ${HATCH_TLS_CERT:-/etc/hatch/tls/hatch.crt} HATCH_TLS_KEY: ${HATCH_TLS_KEY:-/etc/hatch/tls/hatch.key} diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh index cc20b20..191ea46 100644 --- a/scripts/entrypoint.sh +++ b/scripts/entrypoint.sh @@ -40,7 +40,7 @@ if [ ! -s /etc/xrdp/key.pem ] || [ ! -s /etc/xrdp/cert.pem ]; then xrdp-keygen x mkdir -p /run/xrdp chmod 0755 /run/xrdp rm -f /run/xrdp/xrdp.pid /run/xrdp/xrdp-sesman.pid -export RDP_USER RDP_PASSWORD HATCH_HTTPS_PORT HATCH_START_URL CHROMIUM_EXTRA_FLAGS GUACAMOLE_HOME GUACD_HOSTNAME GUACD_PORT WEBAPP_CONTEXT +export RDP_USER RDP_PASSWORD HATCH_HTTPS_PORT HATCH_START_URL HATCH_MAC_SHORTCUTS CHROMIUM_EXTRA_FLAGS GUACAMOLE_HOME GUACD_HOSTNAME GUACD_PORT WEBAPP_CONTEXT /usr/local/bin/hatch-guacamole-config echo "Hatch starting" echo "RDP user: $RDP_USER"