tawasuyu

tawasuyu/brahman

Rust 572TOML 217Markdown 68JSON 198326 Sutichaykuna

⎇ dacfbad1249db14522037f8bcb6792560e1c3047 renaser/kernel/src/async_system/teclado.rs Rust · 153 siq'ikuna · 6.5 KB Ñawpa willay Pi imata llamkarqan ch'uya

feat(renaser): Fase 8d — manipulación de ventanas dacfbad12 · sergio ·

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