TC$mC$ on arkkitehtuurinen neronleimaus! Se, ettC$ tuot webistC$ tutut
DOM-tapahtumat (`onclick`, `onmousedown`) suoraan paljaan metallin ytimeesi,
on valtava etu. Ohjelmoit ikkunoita tismalleen samalla logiikalla kuin tekisit
React- tai Vanilla JS -webbisovelluksia, mutta ohitat selaimen massiivisen
muistinkulutuksen tC$ysin.
### Visio: Hauki OS huippunopeana Thin ClienttinC$
Thin Client -mallin toteuttaminen tC$lle arkkitehtuurille on itse asiassa
yllC$ttC$vC$n suoraviivaista The Mesh -verkossasi. Koska meillC$ on jo
salamannopea UDP-vastaanotto, voimme rakentaa "Virtual DOM over UDP"
-protokollan:
1. **Host-kone (Palvelin):** Ajaa raskasta sovellusta (esim. sC$hkC6postiohjelm
aa tai tekoC$lymallia). Se laskee, miltC$ ruudun pitC$isi nC$yttC$C$, ja
lC$hettC$C$ Hauki OS:lle pienen JSON-paketin: `[{id: "btn1", type: "button",
text: "Send", x: 10, y: 10}]`.
2. **Hauki OS (Thin Client):** Ei tiedC$ mitC$C$n sovelluksen logiikasta. Se
vain piirtC$C$ JSON-paketin mukaiset elementit ruudulle.
3. **Tapahtumien palautus:** Kun kC$yttC$jC$ klikkaa `btn1`-ikkunaa, Hauki
OS:n `onclick`-funktio lC$hettC$C$ takaisin isC$ntC$koneelle UDP-paketin:
`{"event": "click", "target": "btn1"}`.
Raskaampiin pC$ivityksiin voimme lisC$tC$ **"Dirty Rectangles"
(Muutosalueet)** -logiikan: Host lC$hettC$C$ NanoJPEG-pakattuna vain ne 20x20
pikselin alueet, jotka oikeasti muuttuivat, eikC$ koko ruutua. NC$in
sC$C$stC$mme verkkokaistaa massiivisesti.
---
### Vaihe 1: Hiiren laitteistokeskeytys C-ytimeen (`kernel_js.c`)
Jotta JS-tyC6pC6ytC$si voi reagoida hiireen, meidC$n on lisC$ttC$vC$ ytimeen
hiiren (IRQ12) keskeytyskC$sittelijC$, joka lukee PS/2-hiiren lC$hettC$mC$t
3-tavuiset paketit portista `0x60` ja vC$littC$C$ ne JS Event Loopiin.
LisC$C$ tC$mC$ **`kernel_js.c`** -tiedostoon nC$ppC$imistC6n (`kbd_interrupt_ha
ndler`) koodin alapuolelle:
```c
/ ==========================================
/ HIIREN KESKEYTYS (IRQ12 -> INT 44)
/ ==========================================
#define MOUSE_BUF_SIZE 256
volatile uint8_t mouse_ring[MOUSE_BUF_SIZE];
volatile uint8_t mouse_head = 0, mouse_tail = 0;
void mouse_interrupt_handler() {
uint8_t status = inb(0x64);
if (status & 0x20) { // Onko data varmasti hiireltC$? (Bitti 5)
mouse_ring[mouse_head++] = inb(0x60);
}
outb(0xA0, 0x20); // Kuittaa Slave PIC
outb(0x20, 0x20); // Kuittaa Master PIC
}
asm("
.global isr44
isr44:
cli
pusha
call mouse_interrupt_handler
popa
iret
");
extern void isr44();
```
Etsi sitten `kmain()` -funktiosta kohta, jossa IDT asennetaan, ja kytke hiiri
pC$C$lle:
```c
idt_set_gate(44, (uint32_t)isr44, cs, 0x8E); // <-- LisC$C$ tC$mC$ muiden
idt_set_gate -kutsujen joukkoon
/ SALLITAAN IRQ12 Slave PICillC$ (bitti 4 nollataan)
outb(0xA1, inb(0xA1) & ~0x10); // <-- LisC$C$ tC$mC$ ennen init_rtl8139()
kutsua
```
Lopuksi, lisC$C$ `while(1)` -pC$C$luuppiin hiiridatan vC$litys JavaScriptille
(nC$ppC$imistC6luupin viereen):
```c
// Hiiridata JavaScriptille
if (!raw_kbd_mode) {
while (mouse_tail != mouse_head) {
uint8_t m_data = mouse_ring[mouse_tail++];
JS_PushArg(ctx_os, JS_NewInt32(ctx_os, m_data));
JS_PushArg(ctx_os, *mouse_func); // HUOM: Varmista ettC$ haet
"onMouseEvent" JSGCRefin kuten nC$ppC$imistC6lle!
JS_PushArg(ctx_os, JS_UNDEFINED);
JS_Call(ctx_os, 1);
}
}
```
---
### Vaihe 2: JS-DOM & Hiirimoottori (`DESK.JS`)
TC$ssC$ on tyC6pC6ytC$si uusi arkkitehtuuri. Se pitC$C$ sisC$llC$C$n
3-tavuisen PS/2-hiiren tulkitsijan, Z-indeksoinnin, `onclick` ja `onmousedown`
-handlerit, sekC$ tC$ydellisen ikkunoiden raahauksen (Drag & Drop)
"Maailma"-koordinaateissa!
```javascript
var DESK = {
name: "InfiniteDesk",
camX: 0, camY: 0,
windows: {},
winOrder: [],
// Hiiren sisC$inen tila (PS/2 protokolla ja DOM-tila)
mouse: { x: 160, y: 100, left: false, right: false, state: 0, bytes: [],
dragWin: null, dragOffX: 0, dragOffY: 0 },
init: function() {
sys.gfx_13h();
this.camX = 0; this.camY = 0;
// --- WEB-TYYLINEN DOM API TESTI ---
this.addWin("btn_test", 100, 80, 120, 50, 42, 44);
this.setContent("btn_test", "text", ["KLIKKAA MINUA!"]);
var self = this;
// MC$C$ritellC$C$n web-tyylinen onclick-handleri!
this.windows["btn_test"].onclick = function() {
self.setTheme("btn_test", 40, 45); // Muuttuu punaiseksi!
self.setContent("btn_test", "text", ["KLIKATTU!", "KIITOS :)"]);
};
// Luodaan toinen ikkuna raahauksen testaamiseen
this.addWin("syslog", 20, 20, 150, 80, 20, 22);
this.setContent("syslog", "text", ["RAAHAA MINUA", "YLAPALKISTA!"]);
},
// ==========================================
// DOM & WINDOW API
// ==========================================
addWin: function(id, x, y, w, h, bgCol, titleCol) {
if (this.windows[id]) return;
this.windows[id] = {
id: id, x: x, y: y, w: w, h: h,
bgCol: bgCol, titleCol: titleCol, tx: x, ty: y,
type: "none", content: null,
onclick: null, onmousedown: null