Crates ajoutés :
- redox-wl-input (lib) : InputBackend wrappe Arc<ConsumerHandle>
+ enum InputEvent { Key, TextInput, PointerMotion(Relative)?,
PointerButton, PointerScroll, Quit, Unhandled, Handoff }
- redox-wl-test-input (bin) : ouvre display + take CRTC + peint bleu
marine + polle events 30s en logguant chaque event
Modifs redox-wl-display :
- _consumer: ConsumerHandle → consumer: Arc<ConsumerHandle>
- + pub fn consumer() -> Arc<ConsumerHandle> pour partage avec input
Validation runtime sur Redox bootée via QEMU + monitor unix socket :
20 events injectés via `sendkey` et `mouse_button` HMP commands, tous
reçus et traduits correctement :
- a/b/c PRESS+RELEASE — keymap directe
- shift+a → 'A' uppercase — modificateur fonctionnel
- ctrl+c → ctrl PRESS + 'c' PRESS — composition fonctionnelle
- mouse_button 1/0 → PointerButton L=true/false
- Esc, Enter, Shift, Ctrl reçus avec scancode brut
Décision architecturale : un seul ConsumerHandle partagé via Arc entre
RedoxOutput (pour vie du VT) et InputBackend (lecteur unique d'events).
Sinon deux consumers = deux VTs distincts dont un seul reçoit les events.
Capture preuve : docs/phase5-blue-screen-with-input.png — bleu marine
plein écran 1280x800 confirmant que display + input fonctionnent
ensemble dans le même binaire.
docs/phase5-input-backend.md : compte-rendu complet.
Image restaurée à boot Orbital normal après session.
Leyoda 2026 – GPLv3
202 lines
8 KiB
Markdown
202 lines
8 KiB
Markdown
# Phase 5 — Input backend Redox : résultats
|
|
|
|
> Document produit le 2026-05-09 dans le cadre du plan directeur
|
|
> `REDOX_COSMIC_XWAYLAND_RS_PLAN.md`.
|
|
>
|
|
> **Périmètre** : encapsuler `inputd` proprement, exposer un enum
|
|
> `InputEvent` neutre côté compositor, valider runtime sur Redox bootée
|
|
> avec injection d'events keyboard/mouse via le monitor QEMU.
|
|
|
|
## Verdict global
|
|
|
|
**✅ Pipeline input complet validé runtime.**
|
|
|
|
Le binaire `redox-wl-test-input` a :
|
|
1. Ouvert le display via `RedoxOutput` (VT alloué = 2)
|
|
2. Activé le VT via `inputd -A`
|
|
3. Pris le CRTC et peint un fond bleu marine `0xFF103060` (preuve display)
|
|
4. Créé un `InputBackend` partageant le même `ConsumerHandle`
|
|
5. Pollé en boucle pendant 30 s, traduisant chaque event en `InputEvent`
|
|
6. Logué chaque event sur `/scheme/debug` (capté côté host via serial QEMU)
|
|
|
|
20 events injectés via le monitor QEMU (`sendkey`, `mouse_button`) ont
|
|
tous été reçus, avec les **modificateurs interprétés correctement par la
|
|
keymap** Redox (shift+a → `'A'`, ctrl+c → ctrl press + `c` press).
|
|
|
|
Capture preuve display : 
|
|
|
|
## Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────┐
|
|
│ binaire compositor │
|
|
│ │
|
|
│ ┌──────────────┐ Arc<ConsumerHandle> │
|
|
│ │ RedoxOutput │ ─────┐ │
|
|
│ │ (display) │ ▼ │
|
|
│ └──────────────┘ ┌─────────────────┐ │
|
|
│ │ InputBackend │ │
|
|
│ │ poll() ────────┼──▶ Vec<InputEvent>
|
|
│ └─────────────────┘ │
|
|
└─────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
/scheme/input/consumer (inputd, un seul VT, un seul fd)
|
|
```
|
|
|
|
**Décision architecturale clé** : un seul `ConsumerHandle` partagé via
|
|
`Arc`, pour 2 raisons :
|
|
|
|
1. **Un consumer = un VT**. Si on en ouvrait deux, on aurait deux VTs
|
|
distincts et inputd routerait les events vers le VT actif (un seul
|
|
à la fois). Le second consumer serait perpétuellement muet.
|
|
2. **`RedoxOutput` doit garder le consumer en vie** pour préserver le VT
|
|
(cf phase 4 — sinon `inputd -A <vt>` retourne "non-existent"). Mais
|
|
c'est `InputBackend` qui consomme les events. Le partage Arc résout
|
|
cette tension.
|
|
|
|
## API publique
|
|
|
|
### `redox-wl-input::InputEvent`
|
|
|
|
```rust
|
|
pub enum InputEvent {
|
|
Key { character: char, scancode: u8, pressed: bool },
|
|
TextInput { character: char },
|
|
PointerMotion { x: i32, y: i32 }, // absolu
|
|
PointerMotionRelative { dx: i32, dy: i32 },
|
|
PointerButton { left: bool, middle: bool, right: bool },
|
|
PointerScroll { dx: i32, dy: i32 },
|
|
Quit,
|
|
Unhandled { code: i64, a: i64, b: i64 }, // events orbclient pas encore mappés
|
|
Handoff, // VT switch côté inputd
|
|
}
|
|
```
|
|
|
|
L'enum est volontairement **agnostique vis-à-vis de Wayland**. Un
|
|
compositor Wayland le mappera en `wl_keyboard.key`, `wl_pointer.motion`,
|
|
etc. ; un autre frontend pourra le mapper différemment.
|
|
|
|
### `redox-wl-input::InputBackend`
|
|
|
|
```rust
|
|
impl InputBackend {
|
|
pub fn new(consumer: Arc<ConsumerHandle>) -> Self;
|
|
pub fn event_fd(&self) -> BorrowedFd<'_>; // pour subscribe à une EventQueue
|
|
pub fn event_raw_fd(&self) -> i32;
|
|
pub fn poll(&self) -> io::Result<Vec<InputEvent>>;
|
|
}
|
|
```
|
|
|
|
`poll()` est non-bloquant et draine tous les events disponibles. À
|
|
intégrer plus tard dans une `event::EventQueue` Redox pour event-driven.
|
|
|
|
## Validation runtime — extrait du log
|
|
|
|
Injection via le monitor QEMU :
|
|
```bash
|
|
for k in a b c ret; do printf "sendkey $k\n" | ncat -U /tmp/qmp.sock; done
|
|
printf "sendkey shift-a\n" | ncat -U /tmp/qmp.sock
|
|
printf "sendkey ctrl-c\n" | ncat -U /tmp/qmp.sock
|
|
printf "sendkey esc\n" | ncat -U /tmp/qmp.sock
|
|
printf "mouse_button 1\n" | ncat -U /tmp/qmp.sock
|
|
printf "mouse_button 0\n" | ncat -U /tmp/qmp.sock
|
|
```
|
|
|
|
Sortie côté binaire (lue via /scheme/debug → serial → stdout host) :
|
|
```
|
|
[input] display 1280x800, VT=2
|
|
[input] CRTC pris, fond bleu marine peint
|
|
[input] InputBackend prêt, fd events=4
|
|
[input] #0001 Key 'a' scan=0x1e PRESS
|
|
[input] #0002 Key 'a' scan=0x1e RELEASE
|
|
[input] #0003 Key 'b' scan=0x30 PRESS
|
|
[input] #0004 Key 'b' scan=0x30 RELEASE
|
|
[input] #0005 Key 'c' scan=0x2e PRESS
|
|
[input] #0006 Key 'c' scan=0x2e RELEASE
|
|
[input] #0007 Key '·' scan=0x1c PRESS ← Enter
|
|
[input] #0008 Key '·' scan=0x1c RELEASE
|
|
[input] #0009 Key '·' scan=0x2a PRESS ← Shift down
|
|
[input] #0010 Key 'A' scan=0x1e PRESS ← keymap → 'A' (uppercase)
|
|
[input] #0011 Key 'A' scan=0x1e RELEASE
|
|
[input] #0012 Key '·' scan=0x2a RELEASE ← Shift up
|
|
[input] #0013 Key '·' scan=0x1d PRESS ← Ctrl down
|
|
[input] #0014 Key 'c' scan=0x2e PRESS
|
|
[input] #0015 Key 'c' scan=0x2e RELEASE
|
|
[input] #0016 Key '·' scan=0x1d RELEASE ← Ctrl up
|
|
[input] #0017 Key '·' scan=0x01 PRESS ← Esc
|
|
[input] #0018 Key '·' scan=0x01 RELEASE
|
|
[input] #0019 PointerButton L=true M=false R=false
|
|
[input] #0020 PointerButton L=false M=false R=false
|
|
```
|
|
|
|
Note : les caractères `'·'` représentent `'\0'` (touche non-imprimable
|
|
sans char associé : modificateurs, Enter, Esc...). Le scancode reste
|
|
disponible pour l'interpréter.
|
|
|
|
## Limitations connues
|
|
|
|
### Pas de `PointerMotion` testé
|
|
Le test n'a pas reçu d'event `PointerMotion` parce que la commande QEMU
|
|
utilisée n'incluait pas `-device usb-tablet` (qui fournit des coords
|
|
absolues). Avec `make qemu` standard, ce device est inclus. À retester
|
|
quand on aura un cas d'usage souris dans le compositor.
|
|
|
|
### Mouse relatif via PS/2 non testé
|
|
Pareil, dépend de `-device ps2` ou similaire.
|
|
|
|
### Doublement des lignes dans le log
|
|
Chaque ligne `[input]` apparaît deux fois dans le log capturé. Cause :
|
|
le `DebugSink` fait `println!` (→ stdout → fbcond → framebuffer →
|
|
captured-by-screendump-not-serial) ET `writeln!(/scheme/debug)`
|
|
(→ serial → captured-by-host-stdio). Les deux finissent par converger
|
|
dans le serial mux stdio du `make qemu`. Cosmétique, pas critique.
|
|
|
|
## Ce qui est prêt pour la suite
|
|
|
|
- Phase 6 (composition multi-surfaces shm) : peut consommer `InputEvent`
|
|
pour focus/clic-pour-amener-au-premier-plan
|
|
- Phase 7 (compositor utilisable) : peut wrapper `InputBackend` dans
|
|
une `EventQueue` Redox + traiter raccourcis globaux
|
|
|
|
## Code source
|
|
|
|
```
|
|
crates/redox-wl-input/ # lib (140 lignes)
|
|
├── Cargo.toml
|
|
└── src/lib.rs # InputEvent + InputBackend
|
|
|
|
crates/redox-wl-test-input/ # bin de test (130 lignes)
|
|
├── Cargo.toml
|
|
└── src/main.rs # display bleu + poll loop + log
|
|
|
|
crates/redox-wl-display/src/lib.rs # MODIFIÉ
|
|
# _consumer → consumer: Arc<ConsumerHandle>
|
|
# + pub fn consumer() -> Arc<ConsumerHandle>
|
|
```
|
|
|
|
## Méthode de test reproductible
|
|
|
|
Image patchée : `/usr/lib/init.d/20_orbital` lance
|
|
`redox-wl-test-input` en VT=2, `30_console` vidé pour ne pas créer de
|
|
getty conflictuel.
|
|
|
|
```bash
|
|
qemu-system-x86_64 \
|
|
... \
|
|
-chardev stdio,id=debug,signal=off,mux=on \
|
|
-serial chardev:debug -mon chardev=debug \
|
|
-monitor unix:/tmp/qmp.sock,server,nowait \
|
|
-vga std -display none ... &
|
|
sleep 2 && printf "sendkey ret\n" | ncat -U /tmp/qmp.sock # bootloader
|
|
sleep 13 # boot + paint
|
|
printf "sendkey a\n" | ncat -U /tmp/qmp.sock # inject events
|
|
printf "mouse_button 1\n" | ncat -U /tmp/qmp.sock
|
|
printf "screendump /tmp/x.ppm\n" | ncat -U /tmp/qmp.sock # capture visuel
|
|
```
|
|
|
|
L'image a été restaurée à boot Orbital normal après la session.
|
|
|
|
---
|
|
|
|
*Fin du document de phase 5.*
|