Download Game! Currently 108 players. Last logged in:HarrowedTenuTailsConquer

Blitzer's Blog >> 72736

Back to blogs index
Posted: 23 Sep 2026 16:11 [ permalink ]
Olet aivan oikeassa  AT-SPI:n *kuuluisi* nC$hdC$ nC$mC$ asiat, sillC$ muuten
esimerkiksi ruudunlukijasovellukset (kuten Orca) olisivat tC$ysin sokeita
selaimen osoitepalkille, mikC$ sotisi esteettC6myysstandardeja vastaan.

TC$ssC$ piilee kuitenkin usein Linuxin ja selainten (erityisesti
Chromen/Chromiumin) vC$linen sudenkuoppa: **Chrome ei aina oletuksena
kC$ynnistC$ tC$yttC$ esteettC6myyspuuta (Accessibility Tree) sC$C$stC$C$kseen
resursseja**, ellei se tunnista, ettC$ ruudunlukija on aktiivinen.

Voimme tutkia tC$mC$n tC$ydellisesti rakentamalla erillisen `atspi_scanner.py`
-tyC6kalun. TC$mC$ skripti kuuntelee hiiren klikkauksia ja yrittC$C$ tulostaa
kohteesta koko AT-SPI-vanhempipuun (Parent Hierarchy). NC$in nC$emme
tarkalleen, mitC$ kC$yttC6jC$rjestelmC$ ja selain meille tC$llC$ hetkellC$
paljastavat.

### 1. Luo uusi tiedosto: `atspi_scanner.py`

Tallenna tC$mC$ samaan kansioon muiden skriptien kanssa (`/mnt/mesh_shared/play
book-studio/`). TC$mC$ tyC6kalu jC$ljittC$C$ elementin juuresta alkaen, jotta
nC$emme, piilottaako Chrome osoitepalkin jonkin nimettC6mC$n paneelin
sisC$C$n.

```python
import pyatspi
from pynput import mouse

def print_element_info(element, depth=0):
    if not element: return
    indent = "  " * depth
    name = element.name or "[Ei nimeC$]"
    role = element.getRoleName()
    print(f"{indent}-> Rooli: {role: <20} | Nimi: '{name}'")

def on_click(x, y, button, pressed):
    if pressed and button == mouse.Button.left:
        print(f"
[*] Klikkaus koordinaateissa: X:{int(x)}, Y:{int(y)}")
        desktop = pyatspi.Registry.getDesktop(0)
        found = False
        
        for i in range(desktop.getChildCount()):
            app = desktop.getChildAtIndex(i)
            if not app: continue
            
            try:
                comp = app.queryComponent()
                # Tarkistetaan osuuko klikkaus sovelluksen ikkunaan
                if comp and comp.contains(x, y, pyatspi.DESKTOP_COORDS):
                    element = comp.getAccessibleAtPoint(x, y,
pyatspi.DESKTOP_COORDS)
                    if element:
                        found = True
                        print(f"[+] Osuma sovelluksessa: {app.name}")
                        print("    Vanhempipuu (Hierarkia):")
                        
                        # KerC$tC$C$n koko hierarkia elementistC$ ylC6spC$in
                        hierarchy = []
                        curr = element
                        while curr:
                            hierarchy.append(curr)
                            curr = curr.parent
                        
                        # Tulostetaan ylhC$C$ltC$ alaspC$in (Juuresta ->
Klikattuun kohteeseen)
                        for depth, el in enumerate(reversed(hierarchy)):
                            print_element_info(el, depth)
                        break # Lopetetaan etsintC$ tC$hC$n sovellukseen
            except Exception as e:
                pass
                
        if not found:
            print("[-] AT-SPI ei lC6ytC$nyt MITCCN elementtiC$ nC$istC$
koordinaateista.")

print("======================================================")
print("  AT-SPI Skanneri kC$ynnistetty")
print(" Klikkaa mitC$ tahansa ruudulla hiiren vasemmalla napilla.")
print(" (Paina Ctrl+C pC$C$tteessC$ lopettaaksesi)")
print("======================================================")

with mouse.Listener(on_click=on_click) as listener:
    listener.join()

```

### 2. Aja skanneri ja testaa

Aja skripti terminaalissa:
`python3 atspi_scanner.py`

Kokeile nyt klikata selaimessa eri paikkoja:

1. Klikkaa keskelle verkkosivua (DOM-alueelle).
2. Klikkaa selaimen vC$lilehteC$ (Tab).
3. Klikkaa osoitepalkkia.

**MitC$ luultavimmin tapahtuu:**
Jos AT-SPI tulostaa Chromen kohdalla vain "Tuntematon" tai lopettaa etsinnC$n
pC$C$ikkunaan, Chrome ei tC$llC$ hetkellC$ paljasta UI:taan.

**Ratkaisu Chromen herC$ttC$miseen:**
Mene selaimella osoitteeseen `chrome://accessibility/`. YlimpC$nC$ pitC$isi
lukea "Native accessibility API support". Jos siinC$ ei ole rastia tai se on
"Off", sivu sisC$ltC$C$ linkit sen kytkemiseksi pC$C$lle. Vaihtoehtoisesti
selain voidaan kC$ynnistC$C$ Linuxissa lipulla:
`google-chrome --force-renderer-accessibility`

### 3. Varasuunnitelma: OCR Post-Processing (Loistava idea!)

Jos AT-SPI osoittautuu Linux/X11 -komboilla liian epC$luotettavaksi tai
raskaaksi jatkuvassa kC$ytC6ssC$, ehdotuksesi kuvapohjaisesta
jC$lkiprosessoinnista on **tC$ydellinen arkkitehtuurinen varaventtiili**.

Koska arkistoimme nyt kuvat jC$rjestelmC$llisesti, se toimisi tismalleen
nC$in:

1. Opetusputki tuottaa YAML-koodin.
2. JC$lkikC$sittelyskripti etsii kaikki askeleet, joissa on `target: "body"`
ja `state_ref: "step_N"`.
3. Skripti avaa kyseisen askeleen `states/step_N/clean_bitmap.jpg` -kuvan.
4. Skripti leikkaa kuvasta pienen 100x40 pikselin laatikon suoraan `Raw
coords` -pisteen ympC$riltC$.
5. Skripti lC$hettC$C$ tC$mC$n pienen kuvan OCR:lle (tai suoraan Valvomon
LLM:lle).
6. OCR vastaa: "Kuvassa lukee: web.whatsapp.com".
7. Skripti pC$ivittC$C$ automaattisesti YAML-koodin: `target:
"ocr='web.whatsapp.com'"`.

TC$mC$ tekee koko jC$rjestelmC$stC$ riippumattoman selaimen AT-SPI-tuen
ailahteluista ja sitoo automaation puhtaasti siihen visuaaliseen
todellisuuteen, jonka myC6s ihminen nC$kee.

Kokeile ensin tuota skanneria, niin nC$hdC$C$n puhuuko kC$yttC6jC$rjestelmC$si
kieltC$, vai siirrymmekC6 suoraan konenC$C6n hyC6dyntC$miseen myC6s DOMin
ulkopuolella!