initial commit

This commit is contained in:
2026-09-26 17:37:13 +02:00
commit 839bebd8d4
226 changed files with 58701 additions and 0 deletions
+239
View File
@@ -0,0 +1,239 @@
# 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.