⎇ 2523652e2250835d1521b0c3f3fc8374f6f1ae15
renaser/kernel/src/async_system/teclado.rs
Ñawpa willay
Pi imata llamkarqan
ch'uya
feat(renaser): Fase 9 — orden-Z y ventanas flotantes
1// =============================================================================
2// renaser :: async_system/teclado.rs — el canal de scancodes del teclado
3// -----------------------------------------------------------------------------
4// El manejador de IRQ1 es el PRODUCTOR: deposita cada scancode en colas
5// lock-free, seguras frente a interrupciones. Los consumidores —las apps WASM,
6// via la capacidad `sys_get_scancode`— las drenan sin bloquear.
7//
8// FASE 5 :: cada app abre su PROPIO canal; la primera en sondear no le roba la
9// pulsacion a las demas.
10//
11// FASE 8c :: el teclado deja de DIFUNDIR a ciegas. Ahora discrimina:
12//
13// * La tecla Alt es el MODIFICADOR del sistema. Con Alt pulsada, los make
14// codes son MANDOS del compositor (ciclar el teselado, mover el foco,
15// promover, reordenar y hacer flotar ventanas): se consumen aqui, jamas
16// llegan a una app.
17// * Una tecla ordinaria se entrega SOLO a la app ENFOCADA — la que el
18// compositor senala. El censo de canales se indexa por el `indice_app`,
19// de modo que el foco —un atomico— elija el canal exacto.
20//
21// Todo esto corre en contexto de IRQ y NO bloquea ningun cerrojo cooperativo:
22// el modificador es un atomico, los mandos van a una cola lock-free.
23// =============================================================================
24
25use core::sync::atomic::{AtomicBool, Ordering};
26
27use alloc::sync::Arc;
28use alloc::vec::Vec;
29
30use crossbeam_queue::ArrayQueue;
31use spin::{Mutex, Once};
32use x86_64::instructions::interrupts;
33
34use crate::compositor::{self, Mando};
35
36/// Capacidad de la cola de scancodes de cada app. Holgada: nadie teclea tanto.
37const CAPACIDAD_COLA: usize = 256;
38
39// --- Scancodes del set 1 que el teclado interpreta como mandos del sistema. ---
40/// Alt izquierda — make (pulsada) y break (soltada).
41const ALT_MAKE: u8 = 0x38;
42const ALT_BREAK: u8 = 0xB8;
43/// Barra espaciadora — `Alt + Espacio` cicla el modo de teselado.
44const ESPACIO: u8 = 0x39;
45/// Tecla J — `Alt + J` mueve el foco a la ventana siguiente.
46const TECLA_J: u8 = 0x24;
47/// Tecla K — `Alt + K` mueve el foco a la ventana anterior.
48const TECLA_K: u8 = 0x25;
49/// Tecla H — `Alt + H` mueve la ventana enfocada atras en el orden.
50const TECLA_H: u8 = 0x23;
51/// Tecla L — `Alt + L` mueve la ventana enfocada adelante en el orden.
52const TECLA_L: u8 = 0x26;
53/// Tecla Enter — `Alt + Enter` promueve la ventana enfocada a maestra.
54const ENTER: u8 = 0x1C;
55/// Tecla F — `Alt + F` alterna la ventana enfocada entre teselada y flotante.
56const TECLA_F: u8 = 0x21;
57
58/// Un canal de teclado: la cola lock-free de scancodes de UNA aplicacion.
59pub type CanalTeclado = Arc<ArrayQueue<u8>>;
60
61/// Censo de canales, INDEXADO por el `indice_app` de cada aplicacion. Una
62/// ranura `None` es una app que no abrio canal o que fue desalojada. El
63/// indexado estable permite que el foco —un simple indice— elija el canal.
64static CANALES: Once<Mutex<Vec<Option<CanalTeclado>>>> = Once::new();
65
66/// ¿Esta la tecla Alt pulsada? El modificador de los mandos del sistema. Lo
67/// escribe y lo lee SOLO el manejador de IRQ1 — un atomico, sin cerrojo.
68static ALT_PULSADO: AtomicBool = AtomicBool::new(false);
69
70/// Funda el censo de canales del teclado. Requiere el heap ya activo; debe
71/// invocarse una sola vez, antes de habilitar las interrupciones.
72pub fn init() {
73 CANALES.call_once(|| Mutex::new(Vec::new()));
74}
75
76/// Crea un canal de teclado nuevo, AUN sin inscribir en el censo. Cada
77/// aplicacion reclama el suyo al empezar a cargarse.
78pub fn crear_canal() -> CanalTeclado {
79 Arc::new(ArrayQueue::new(CAPACIDAD_COLA))
80}
81
82/// Inscribe el canal de la app `indice` en el censo. Desde este instante, una
83/// tecla ordinaria llega a esta app cuando tiene el foco. Se invoca al final de
84/// la carga de una app: una carga fallida no debe dejar canales huerfanos.
85pub fn registrar_canal(indice: usize, canal: &CanalTeclado) {
86 if let Some(censo) = CANALES.get() {
87 // El cerrojo lo disputa el manejador de IRQ1: tomarlo con las
88 // interrupciones acalladas hace imposible el interbloqueo.
89 interrupts::without_interrupts(|| {
90 let mut censo = censo.lock();
91 while censo.len() <= indice {
92 censo.push(None);
93 }
94 censo[indice] = Some(canal.clone());
95 });
96 }
97}
98
99/// Da de baja el canal de la app `indice`. Lo invoca el `Drop` de una
100/// aplicacion desalojada: la ranura queda en `None` y la IRQ deja de enrutarle
101/// teclas, sin desplazar los indices de las demas.
102pub fn cerrar_canal(indice: usize) {
103 if let Some(censo) = CANALES.get() {
104 interrupts::without_interrupts(|| {
105 let mut censo = censo.lock();
106 if let Some(ranura) = censo.get_mut(indice) {
107 *ranura = None;
108 }
109 });
110 }
111}
112
113/// Punto de entrada DESDE el manejador de IRQ1. Rastrea el modificador Alt,
114/// intercepta los mandos del sistema y enruta la tecla ordinaria a la app
115/// enfocada. Deliberadamente breve y libre de panicos: corre en contexto de
116/// interrupcion y no bloquea ningun cerrojo cooperativo.
117pub fn recibir_scancode(scancode: u8) {
118 // 1. Rastrear la tecla Alt — el modificador de los mandos del sistema. Se
119 // consume: el modificador nunca se difunde a una app.
120 match scancode {
121 ALT_MAKE => {
122 ALT_PULSADO.store(true, Ordering::Relaxed);
123 return;
124 }
125 ALT_BREAK => {
126 ALT_PULSADO.store(false, Ordering::Relaxed);
127 return;
128 }
129 _ => {}
130 }
131
132 // 2. Con Alt pulsada, los make codes son MANDOS del compositor. Se traducen
133 // a una orden en la cola lock-free y se consumen — jamas llegan a una app.
134 if ALT_PULSADO.load(Ordering::Relaxed) {
135 match scancode {
136 ESPACIO => compositor::solicitar(Mando::CiclarLayout),
137 TECLA_J => compositor::solicitar(Mando::FocoSiguiente),
138 TECLA_K => compositor::solicitar(Mando::FocoAnterior),
139 ENTER => compositor::solicitar(Mando::Promover),
140 TECLA_L => compositor::solicitar(Mando::MoverAdelante),
141 TECLA_H => compositor::solicitar(Mando::MoverAtras),
142 TECLA_F => compositor::solicitar(Mando::Flotar),
143 _ => {}
144 }
145 return;
146 }
147
148 // 3. Tecla ordinaria: se entrega SOLO a la app que tiene el foco. El foco
149 // es un indice atomico; el censo, un vector indexado por `indice_app`.
150 if let Some(censo) = CANALES.get() {
151 if let Some(Some(canal)) = censo.lock().get(compositor::foco()) {
152 // Si el canal desborda, se descarta el scancode en silencio: mas
153 // vale perder una tecla que colapsar dentro de una interrupcion.
154 let _ = canal.push(scancode);
155 }
156 }
157}