# Phase 13.1.c — Curseur souris : conversion HID→pixel > Document produit le 2026-05-16, suite de > [`phase13-1-b-observations.md`](phase13-1-b-observations.md). > > **Scope** : isoler et corriger le bug B.1 listé en 13.1.b — « curseur > software ne suit pas la souris correctement, reste coincé en bas-droite > de l'écran à `(width-1, height-1)` ». Diagnostic via instrumentation > ciblée, fix conforme à l'algo d'orbital upstream, validation runtime. > > **Verdict** : ✅ **13.1.c validée** — le curseur suit fidèlement la > souris, les coordonnées de clic sont dans la plage écran. ## Cause racine Sous Redox + QEMU, `ps2d` délivre les coords absolues du pointer dans un **espace virtuel 16-bit (0..65535)**, pas en pixels écran. Notre branche `PointerMotion` faisait une assignation directe : ```rust self.cursor_x = *x; // x ∈ 0..65535 ⇒ cursor_x ∈ 0..65535 ``` Le `clamp_cursor()` ajouté en 13.1.b saturait alors à `screen_w - 1` à chaque event → cursor coincé en bas-droite. Le bug B.1 13.1.b n'était pas une dérive de deltas accumulés mais une **mauvaise interprétation de l'unité d'entrée**. ## Diagnostic Instrumentation `tracing::debug!(target: "cursor", ...)` ajoutée dans les deux branches motion de `WaylandFrontend::forward_input` pour logger les valeurs brutes reçues. Avec `RUST_LOG=info,cursor=debug` (devenu le filtre par défaut de `init_tracing`), une session de tests motion délibérés a révélé : ``` DEBUG cursor: ABS x=61642 y=15564 screen=1280x800 DEBUG cursor: ABS x=50174 y=20970 screen=1280x800 DEBUG cursor: ABS x=43006 y=23592 screen=1280x800 DEBUG cursor: ABS x=42084 y=23918 screen=1280x800 ``` Valeurs maximales observées ≈ 62000 / 24000 sur écran 1280×800, ratio ~50× pour x et ~30× pour y. Hypothèse 16-bit confirmée par la doc upstream orbital : ``` // orbital/src/scheme.rs:1576 // ps2d gives us absolute mouse events with x and y in the range 0..65535. ``` ## Fix Conversion fixed-point en pixel via la même formule qu'orbital (`orbital/src/scheme.rs:1583-1586`) : ```rust let scaled_x = ((*x as i64) * (self.screen_w as i64)) / 65536; let scaled_y = ((*y as i64) * (self.screen_h as i64)) / 65536; self.cursor_x = scaled_x as i32; self.cursor_y = scaled_y as i32; self.clamp_cursor(); // garde-fou pour valeurs hors-spec ``` Diviseur `65536` (pas `65535`) volontaire — fixed-point 16-bit, donne `max output = screen - 1` quand `input = 65535`. Cohérent avec l'arithmétique d'orbital. Le `clamp_cursor` ajouté en 13.1.b reste utile comme garde-fou (si un device sort de la plage 0..65535) mais ne masque plus le bug principal. ## Validation runtime Test sur écran 1280×800 (fenêtre QEMU graphique, après reboot Redox frais). Mouvement délibéré de la souris du coin haut-gauche au coin bas-droit en passant par le centre. Logs filtrés : ``` DEBUG cursor: ABS x=18994 y=19660 → pixel (370,239) screen=1280x800 ← haut-gauche DEBUG cursor: ABS x=33176 y=33094 → pixel (647,403) screen=1280x800 ← centre DEBUG cursor: ABS x=64560 y=11714 → pixel (1260,142) screen=1280x800 ← haut-droit DEBUG cursor: ABS x=37476 y=33176 → pixel (731,404) screen=1280x800 ← retour centre ``` Coordonnées pixel cohérentes avec la position physique de la souris, toutes dans la plage `0..1279 × 0..799`. Pas de saturation au coin. Clics au passage : ``` DEBUG redox_wl_wayland_frontend: left-click @ (522, 303) → hit_test = None DEBUG redox_wl_wayland_frontend: left-click @ (746, 175) → hit_test = None DEBUG redox_wl_wayland_frontend: left-click @ (370, 239) → hit_test = None ``` `hit_test = None` attendu : aucun client n'était lancé pendant ce test. Les coords sont en revanche bien dans l'espace écran et pourront matcher un toplevel quand un client tournera. ## Bonus DX (developer experience) Type pénible de taper `RUST_LOG=info,redox_wl_wayland_frontend::cursor=debug` dans la fenêtre QEMU graphique (pas de copier-coller possible). Modification du filtre par défaut dans `init_tracing` : ```rust EnvFilter::new("info,cursor=debug") ``` Tu tapes juste `redox-wl-compositor`, tu vois les traces cursor sans spam des ticks. Override toujours possible via `RUST_LOG=` au launch. ## Sous-bug B.2 (page fault ion) — non traité Reste documenté pour follow-up upstream. Repro fiable : 1. Lancer un job background Wayland (`redox-wl-real-client-simple-window &`) 2. Tuer le compositor avant que le client n'exit (`Ctrl+Q` sans avoir pressé ESC d'abord) 3. ion crashe avec page fault `0x70` À reporter sur `gitlab.redox-os.org/redox-os/ion`. Hors scope du compositor. ## Critère de fin 13.1.c > Le curseur software du compositor suit fidèlement les déplacements > souris dans toute l'aire de la fenêtre QEMU graphique, sans saturer > à un bord, sans dérive monotone. Les coordonnées de clic sont dans > la plage écran et `hit_test` peut matcher une surface visible. **✅ Validé 2026-05-16.** Conversion HID→pixel alignée sur l'algo upstream d'orbital, instrumentation laissée en place pour debug futur. ## Fichiers modifiés ``` crates/redox-wl-wayland-frontend/src/lib.rs # Conversion 0..65535 → pixels écran dans PointerMotion # Traces tracing target="cursor" crates/redox-wl-compositor/src/main.rs # Filtre tracing par défaut "info,cursor=debug" docs/phase13-1-c-cursor.md # ce document ``` ## Limites connues - `PointerMotionRelative` (deltas relatifs) reste instrumenté mais n'a jamais été observé sous QEMU PS/2 + qemu-xhci. Si un jour Redox passe à de la souris purement relative, on aura un second `set_screen_size` + clamp à valider. - L'aspect ratio entre l'espace HID 65536² et l'écran 1280×800 n'est pas carré (1.6 vs 1) — la précision diagonale peut sembler légèrement décalée. Strictement OK pour 13.1.c, à observer en 13.2+ avec un vrai client graphique qui dessine sous le curseur (drag, drawing).