# Linux for the ASUS Zenbook Duo This project adds better Linux support for the Zenbook Duo by running a small background service that reacts to the keyboard being attached/detached (USB or Bluetooth) and keeps the dual-screen experience usable. ## Quick Start (Non-technical) ### What you need - An ASUS Zenbook Duo - GNOME on Wayland, KDE Plasma on Wayland, or Niri - A Terminal and your sudo password (the installer needs to change system settings) ### Install (recommended) ```bash ./install.sh ``` Notes: - `install.sh` auto-detects GNOME, KDE Plasma, or Niri and then runs the matching setup script plus the UI installer. - If you use multiple local accounts, run the installer from the account that should own the session agent and autostart entries; the Rust runtime itself is shared machine-wide, so other users can still open the UI after install. - If you prefer to run it with sudo, use `sudo -E ./install.sh` (so per-user setup targets your user session). - If you re-run the installer, restart the session agent: `systemctl --user restart zenbook-duo-session-agent.service` - Log out and back in (needed for permission changes). ### Build (no install) ```bash ./build.sh ``` Use `./build.sh --runtime-only` to build only the Rust runtime, or `./build.sh --ui-only` to build only the Control Panel UI. Manual fallback: ```bash ./setup-gnome.sh # or ./setup-kde.sh # or ./setup-niri.sh ``` ### Optional: install or update just the Control Panel app (UI) If you only want to build/update the desktop app: ```bash ./install-ui.sh ``` Use `./install-ui.sh --build-only --dir .` to compile without installing, or `./install-ui.sh --install-only --dir .` to install already-built artifacts from the current checkout. On desktop sessions, the installer now prefers a graphical admin-password prompt for the system steps and falls back to terminal `sudo` when needed. ### Uninstall To remove the background service and system changes: ```bash ./uninstall.sh ``` To remove the optional UI app: - Fedora / RHEL-based: `sudo dnf remove zenbook-duo-control` - Debian / Ubuntu-based: `sudo apt remove zenbook-duo-control` - Arch / CachyOS: `sudo rm -f /usr/local/bin/zenbook-duo-control /usr/share/applications/zenbook-duo-control.desktop /usr/share/pixmaps/zenbook-duo-control.png` --- ## Advanced (Technical) ### Screenshots ![Zenbook Duo Control USB](sc.png) ![Zenbook Duo Control BLUETOOTH](sc2.png) ### Features | Feature | USB | Bluetooth | |---------|:---:|:---------:| | Toggle bottom screen on when keyboard removed | ✅ | ✅ | | Toggle bottom screen off when keyboard placed | ✅ | ✅ | | Toggle bluetooth on when keyboard removed | ✅ | ✅ | | Toggle bluetooth off when keyboard placed (if it was off before) | ✅ | ✅ | | Screen brightness sync | ✅ | ✅ | | Reset airplane mode on keyboard attach/detach | ✅ | N/A | | Keyboard backlight set on boot/attach | ✅ | ✅ | | Keyboard backlight sync across attach/detach | ✅ | ✅ | | Keyboard backlight cycle (F4) | ✅ | ✅ | | Correct state on boot/resume (suspend & hibernate) | ✅ | ✅ | | Auto rotation | ✅ | ✅ | | Function keys (F1 mute, F2 volume down, F3 volume up, F10 bluetooth) | ✅ | ✅ | | Function keys (F5 brightness down, F6 brightness up) | ✅ | ✅ | | Function keys (F7 swap displays) | ✅ | ✅ | | Function keys (F9 mic mute) | ✅ | ❌ | | Function keys (F11 emojis) | ✅ | ✅ (Fn+F11) | | Function keys (F8 airplane mode, F12 ASUS software) | ❌ | ❌ | | Correct state on lock/unlock | ✅ | ✅ | | Fn layer (top row) | ✅ | ✅ | Notes: - USB top row defaults to media keys; hold `Fn` for `F1`-`F12`. - Do not install hwdb remaps for `KEYBOARD_KEY_7003*` on USB (it overrides the Fn layer). ### Requirements - ASUS Zenbook Duo (USB vendor `0B05`, product `1B2C` or `1B2D` on UX8406M-class models) - Linux with GNOME on Wayland, KDE Plasma on Wayland, or Niri (tested with Fedora) - `systemd` for service management - GNOME: `gdctl` (part of `mutter`) for display configuration - KDE: `kscreen-doctor` (part of `kscreen`) for display configuration - Niri: `niri msg` for display configuration ### What `./setup-gnome.sh` / `./setup-kde.sh` / `./setup-niri.sh` change - Installs dependencies: - Common: `usbutils`, `iio-sensor-proxy`, `systemd` - GNOME: `mutter`/`gdctl` (via `setup-gnome.sh`) - KDE: `kscreen`/`kscreen-doctor` (via `setup-kde.sh`) - Niri: `niri` (via `setup-niri.sh`) - Adds your user to the `input` group (logout/login required) - Installs a udev rule for the Zenbook Duo keyboard - Installs/enables Rust runtime units: - `zenbook-duo-rust-daemon.service` (system daemon) - `zenbook-duo-rust-lifecycle.service` (boot/shutdown + sleep hook) - `zenbook-duo-session-agent.service` (user session) - The session agent is enabled from the user manager's `default.target`, then syncs the current dock state when your graphical session comes up after reboot/login - Installs Rust runtime binaries to `/usr/local/libexec/zenbook-duo` - Adds a managed sudoers.d drop-in for the exact brightness writes used by the session agent Contributor note: the desktop setup scripts are thin wrappers around `setup-common.sh`. When adding or changing supported systems, update the shared helper for common behavior and keep only package names/manual dependency hints in the per-desktop wrapper. ### Contributor compatibility checks Use the version bump helper when preparing a release: ```bash ./bump-version.sh patch # or minor, major, or an explicit version like 0.3.4 ``` Use the root check script before changing installer, runtime, or UI behavior: ```bash ./check.sh installers # shell syntax + installer smoke tests ./check.sh rust # Rust runtime unit tests ./check.sh frontend # React/TypeScript production build ./check.sh all # full compatibility pass ``` Supported matrix covered by the installer smoke tests: | Desktop backend | Setup wrapper | Display command | |-----------------|---------------|-----------------| | GNOME on Wayland | `setup-gnome.sh` | `gdctl` | | KDE Plasma on Wayland | `setup-kde.sh` | `kscreen-doctor` | | Niri | `setup-niri.sh` | `niri msg` | | Distro family | Package manager | |---------------|-----------------| | Fedora / RHEL-based | `dnf` | | Debian / Ubuntu-based | `apt` | | Arch / CachyOS | `pacman` | Compatibility checklist for maintainers: - Keep common setup behavior in `setup-common.sh`; keep desktop wrappers limited to backend-specific packages and manual dependency hints. - Keep the managed sudoers.d drop-in aligned with the exact backlight devices present on the target system; do not add wildcard command arguments to sudoers. - Keep settings defaults aligned across `setup-common.sh`, the Rust `DuoSettings` defaults, and the frontend default settings helper. The installer writes `setupCompleted=true`; a missing settings file should still show first-run setup. - Preserve GNOME, KDE, and Niri command arguments when refactoring display code unless a backend-specific behavior change is intentional and tested. - Keep desktop readiness probes centralized in the Rust session helpers so GNOME, KDE, and Niri fallback behavior stays consistent. - Update `tests/install-stdin-test.sh` whenever supported desktops, package managers, service units, defaults, or installer entrypoints change. - Run the narrow `./check.sh` target for the area you touched; run `./check.sh all` before handing off broad cross-area changes. ### Troubleshooting - Nothing happens when docking/undocking: - Check the services are running: `systemctl status zenbook-duo-rust-daemon.service` and `systemctl --user status zenbook-duo-session-agent.service` - Watch daemon logs: `journalctl -u zenbook-duo-rust-daemon.service -f` - Reboot/login or resume comes up in the wrong layout: - After login or resume, the lifecycle handler and session agent re-sync the current attached/detached state without a manual restart - Check `systemctl --user status zenbook-duo-session-agent.service`; an early `No supported session backend became ready before timeout; continuing to wait` warning is OK if the service remains active - Confirm your user manager has the desktop-session environment: `systemctl --user show-environment | grep -E 'DISPLAY|WAYLAND_DISPLAY|NIRI_SOCKET|XDG_CURRENT_DESKTOP|XDG_SESSION_DESKTOP|DESKTOP_SESSION|XDG_SESSION_TYPE'` - If those variables are missing after reinstalling, rerun `./install.sh` from an active desktop session, then log out and back in once - Keyboard media/Fn keys stop working after suspend or reattaching the keyboard: - The optional USB media remap helper is stopped before sleep and retried automatically after resume, so a manual service restart should not be needed. - If recovery still fails, check `journalctl -u zenbook-duo-rust-daemon.service -f` for `USB media remap auto-start failed` or repeated `No such device` messages. - You do not need a separate `/etc/udev/rules.d/*uinput*` rule for this project. - `KBLIGHT - Device lost, re-scanning` in a loop: - You likely need to log out and back in so your session gets the `input` group membership - If the Control Panel says `Service/Rust runtime unavailable` after switching to another local account: - Confirm the system daemon is running: `systemctl status zenbook-duo-rust-daemon.service` - If the daemon is stopped or stale, rerun `./install.sh` from the account that should own the session agent and autostart entries, then log out and back in once ### Upgrading from older versions If you previously installed a hwdb key remap, remove it so `Fn`+`F1`-`F12` works on USB: ```bash sudo rm -f /etc/udev/hwdb.d/90-zenbook-duo-keyboard.hwdb sudo systemd-hwdb update sudo udevadm trigger ``` ### Supported distros | Distro | Package Manager | |--------|----------------| | Fedora / RHEL-based | `dnf` | | Debian / Ubuntu-based | `apt` | | Arch / CachyOS | `pacman` | Other distros: install dependencies manually and run `./setup-gnome.sh`, `./setup-kde.sh`, or `./setup-niri.sh` (it exits if it cannot detect your package manager). ### Control Panel UI (Tauri + React) - Build & install: `./install-ui.sh` - Build only: `./build.sh --ui-only` - Arch / CachyOS note: `install-ui.sh` builds the UI locally, then installs `zenbook-duo-control` to `/usr/local/bin` and desktop assets under `/usr/share` - Dev mode: ```bash cd ui-tauri-react npm install npm run dev ``` ## Fedora: “Nobara-like” setup helper If you’re on Fedora and want a more “Nobara-like” out-of-box experience (RPM Fusion, codecs, common gaming tools), there’s an optional helper script: ```bash ./nobara-like.sh ``` It can also add the Nobara COPR repo definitions **disabled by default**, so you can cherry-pick packages without mixing repos during normal upgrades.