fix(mirada-compositor): backend DRM — salida garantizada + logs de teclado

Tras la primera prueba en hardware (el bucle arranca y compone el fondo,
pero el teclado no responde y no había forma de salir):

- Salida garantizada: el backend DRM se cierra solo a los 60 s (env
  MIRADA_DRM_TIMEOUT, 0 lo desactiva). Así una prueba nunca deja la
  pantalla atrapada aunque el teclado falle.
- handle_input instrumentado: registra cada dispositivo de entrada que
  libinput descubre y cada tecla con su combo y si es un atajo — para
  diagnosticar por qué no llega la entrada.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
sergio
2026-05-21 02:14:50 +00:00
parent fe221869d2
commit 782244b743
@@ -161,11 +161,16 @@ impl DrmState {
}
/// Procesa un evento de `libinput` — por ahora, sólo el teclado.
/// Va instrumentado: registra los dispositivos que encuentra y cada
/// tecla, para diagnosticar la entrada sin el hardware delante.
fn handle_input(&mut self, event: InputEvent<LibinputInputBackend>) {
let InputEvent::Keyboard { event } = event else {
return; // puntero/táctil: pendiente
};
match event {
InputEvent::DeviceAdded { device } => {
eprintln!("input · dispositivo detectado: «{}»", device.name());
}
InputEvent::Keyboard { event } => {
let Some(keyboard) = self.app.keyboard.clone() else {
eprintln!("input · ¡sin teclado en el seat!");
return;
};
let code = event.key_code();
@@ -182,12 +187,13 @@ impl DrmState {
if !pressed {
return FilterResult::Forward;
}
if let Some(combo) = combo_string(mods, handle.modified_sym()) {
if st.grabs.contains(&combo) {
st.pending_keybind = Some(combo);
let combo = combo_string(mods, handle.modified_sym());
let grabbed = combo.as_ref().is_some_and(|c| st.grabs.contains(c));
eprintln!("input · tecla {code:?} → combo {combo:?} · atajo={grabbed}");
if grabbed {
st.pending_keybind = combo;
return FilterResult::Intercept(());
}
}
FilterResult::Forward
},
);
@@ -196,6 +202,9 @@ impl DrmState {
self.app.brain_feed(ev);
}
}
_ => {} // puntero/táctil: pendiente
}
}
}
/// Arranca el Cuerpo sobre DRM/KMS — fases 1, 2a y 2b.
@@ -399,10 +408,21 @@ pub fn run() -> Result<(), Box<dyn Error>> {
})
.map_err(|e| format!("insert timer: {e}"))?;
// Salida garantizada mientras depuramos: se cierra solo a los N s
// (env `MIRADA_DRM_TIMEOUT`, 0 lo desactiva) — así nunca te quedas
// atrapado si el teclado aún no responde.
let timeout_secs: u64 = std::env::var("MIRADA_DRM_TIMEOUT")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(60);
println!("──────────────────────────────────────────────────");
println!("mirada-compositor · escritorio en marcha sobre «{out_name}».");
println!(" Lanza un cliente: WAYLAND_DISPLAY={socket_name} foot");
println!(" Salir: Super+Shift+e.");
println!(" Salir: Super+Shift+e · o Ctrl+C en esta TTY.");
if timeout_secs > 0 {
println!(" Se cerrará solo a los {timeout_secs}s (MIRADA_DRM_TIMEOUT=0 lo quita).");
}
let mut state = DrmState {
app,
@@ -419,7 +439,12 @@ pub fn run() -> Result<(), Box<dyn Error>> {
let signal = event_loop.get_signal();
event_loop
.run(None, &mut state, |state| {
if !state.app.running {
let timed_out =
timeout_secs > 0 && state.start.elapsed() > Duration::from_secs(timeout_secs);
if !state.app.running || timed_out {
if timed_out {
println!("mirada-compositor · tope de tiempo — cerrando.");
}
signal.stop();
}
})