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. /// 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>) { fn handle_input(&mut self, event: InputEvent<LibinputInputBackend>) {
let InputEvent::Keyboard { event } = event else { match event {
return; // puntero/táctil: pendiente InputEvent::DeviceAdded { device } => {
}; eprintln!("input · dispositivo detectado: «{}»", device.name());
}
InputEvent::Keyboard { event } => {
let Some(keyboard) = self.app.keyboard.clone() else { let Some(keyboard) = self.app.keyboard.clone() else {
eprintln!("input · ¡sin teclado en el seat!");
return; return;
}; };
let code = event.key_code(); let code = event.key_code();
@@ -182,12 +187,13 @@ impl DrmState {
if !pressed { if !pressed {
return FilterResult::Forward; return FilterResult::Forward;
} }
if let Some(combo) = combo_string(mods, handle.modified_sym()) { let combo = combo_string(mods, handle.modified_sym());
if st.grabs.contains(&combo) { let grabbed = combo.as_ref().is_some_and(|c| st.grabs.contains(c));
st.pending_keybind = Some(combo); eprintln!("input · tecla {code:?} → combo {combo:?} · atajo={grabbed}");
if grabbed {
st.pending_keybind = combo;
return FilterResult::Intercept(()); return FilterResult::Intercept(());
} }
}
FilterResult::Forward FilterResult::Forward
}, },
); );
@@ -196,6 +202,9 @@ impl DrmState {
self.app.brain_feed(ev); self.app.brain_feed(ev);
} }
} }
_ => {} // puntero/táctil: pendiente
}
}
} }
/// Arranca el Cuerpo sobre DRM/KMS — fases 1, 2a y 2b. /// 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}"))?; .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!("──────────────────────────────────────────────────");
println!("mirada-compositor · escritorio en marcha sobre «{out_name}»."); println!("mirada-compositor · escritorio en marcha sobre «{out_name}».");
println!(" Lanza un cliente: WAYLAND_DISPLAY={socket_name} foot"); 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 { let mut state = DrmState {
app, app,
@@ -419,7 +439,12 @@ pub fn run() -> Result<(), Box<dyn Error>> {
let signal = event_loop.get_signal(); let signal = event_loop.get_signal();
event_loop event_loop
.run(None, &mut state, |state| { .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(); signal.stop();
} }
}) })