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.
- 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)
One-line install:
curl -fsSL https://raw.githubusercontent.com/zakstam/zenbook-duo-linux/main/install.sh | bash- Download this repo (GitHub "Code" → "Download ZIP"), then extract it.
- Open a Terminal in the extracted folder.
- Run the installer and answer the prompts:
./install.shNotes:
install.shauto-detects GNOME, KDE Plasma, or Niri and then runs the matching setup script plus the UI installer.- 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).
Manual fallback:
./setup-gnome.sh
# or
./setup-kde.sh
# or
./setup-niri.shIf you only want to build/update the desktop app:
./install-ui.shOn desktop sessions, the installer now prefers a graphical admin-password prompt for the system steps and falls back to terminal sudo when needed.
To remove the background service and system changes:
./uninstall.shTo 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
| 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
FnforF1-F12. - Do not install hwdb remaps for
KEYBOARD_KEY_7003*on USB (it overrides the Fn layer).
- ASUS Zenbook Duo (USB vendor
0B05, product1B2C) - Linux with GNOME on Wayland, KDE Plasma on Wayland, or Niri (tested with Fedora)
systemdfor service management- GNOME:
gdctl(part ofmutter) for display configuration - KDE:
kscreen-doctor(part ofkscreen) for display configuration - Niri:
niri msgfor display configuration
- Installs dependencies:
- Common:
usbutils,iio-sensor-proxy,systemd - GNOME:
mutter/gdctl(viasetup-gnome.sh) - KDE:
kscreen/kscreen-doctor(viasetup-kde.sh) - Niri:
niri(viasetup-niri.sh)
- Common:
- Adds your user to the
inputgroup (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 sudoers rules for 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.
Use the version bump helper when preparing a release:
./bump-version.sh patch # or minor, major, or an explicit version like 0.3.4Use the root check script before changing installer, runtime, or UI behavior:
./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 passSupported 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 settings defaults aligned across
setup-common.sh, the RustDuoSettingsdefaults, and the frontend default settings helper. The installer writessetupCompleted=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.shwhenever supported desktops, package managers, service units, defaults, or installer entrypoints change. - Run the narrow
./check.shtarget for the area you touched; run./check.sh allbefore handing off broad cross-area changes.
- Nothing happens when docking/undocking:
- Check the services are running:
systemctl status zenbook-duo-rust-daemon.serviceandsystemctl --user status zenbook-duo-session-agent.service - Watch daemon logs:
journalctl -u zenbook-duo-rust-daemon.service -f
- Check the services are running:
- 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 earlyNo supported session backend became ready before timeout; continuing to waitwarning 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.shfrom 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 -fforUSB media remap auto-start failedor repeatedNo such devicemessages. - You do not need a separate
/etc/udev/rules.d/*uinput*rule for this project.
KBLIGHT - Device lost, re-scanningin a loop:- You likely need to log out and back in so your session gets the
inputgroup membership
- You likely need to log out and back in so your session gets the
If you previously installed a hwdb key remap, remove it so Fn+F1-F12 works on USB:
sudo rm -f /etc/udev/hwdb.d/90-zenbook-duo-keyboard.hwdb
sudo systemd-hwdb update
sudo udevadm trigger| 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).
- Build & install:
./install-ui.sh - Arch / CachyOS note:
install-ui.shbuilds the UI locally, then installszenbook-duo-controlto/usr/local/binand desktop assets under/usr/share - Dev mode:
cd ui-tauri-react
npm install
npm run devIf 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:
./nobara-like.shIt can also add the Nobara COPR repo definitions disabled by default, so you can cherry-pick packages without mixing repos during normal upgrades.