feat: add KDE Show Desktop automation
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
* - Screenshot (spectacle CLI)
|
||||
* - Input simulato (ydotool: click, type, mousemove)
|
||||
* - Gestione finestre (KWin scripting via D-Bus)
|
||||
* - Mostra Desktop (KWin D-Bus / KGlobalAccel, compatibile Wayland)
|
||||
* - Ispezione UI (AT-SPI via python-dbus)
|
||||
*
|
||||
* Include la prassi di verifica UI come promptGuidelines e una skill /skill:kde-verify.
|
||||
@@ -73,6 +74,62 @@ print(found ? "ok" : "notfound");`;
|
||||
return "script KWin eseguito per " + resourceClass;
|
||||
}
|
||||
|
||||
/** Legge lo stato Mostra Desktop esposto da KWin. */
|
||||
async function readShowDesktopState(): Promise<string> {
|
||||
return (await run("qdbus6", [
|
||||
"org.kde.KWin",
|
||||
"/KWin",
|
||||
"org.freedesktop.DBus.Properties.Get",
|
||||
"org.kde.KWin",
|
||||
"showingDesktop",
|
||||
])).trim();
|
||||
}
|
||||
|
||||
/** Attende lo stato desiderato, perché showDesktop è Q_NOREPLY e asincrono. */
|
||||
async function waitShowDesktopState(expected?: string): Promise<string> {
|
||||
let state = await readShowDesktopState();
|
||||
for (let i = 0; expected && state !== expected && i < 10; i++) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
state = await readShowDesktopState();
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
/** Imposta o alterna la modalità Mostra Desktop via API D-Bus native Wayland. */
|
||||
async function setShowDesktop(action: string): Promise<string> {
|
||||
if (action !== "show" && action !== "hide" && action !== "toggle") {
|
||||
throw new Error(`azione non valida: ${action}; usare show, hide oppure toggle`);
|
||||
}
|
||||
|
||||
let expected: string | undefined;
|
||||
if (action === "toggle") {
|
||||
const before = await readShowDesktopState();
|
||||
expected = before === "true" ? "false" : before === "false" ? "true" : undefined;
|
||||
// KGlobalAccel esegue l'azione registrata da KWin senza simulare input.
|
||||
await run("qdbus6", [
|
||||
"org.kde.kglobalaccel",
|
||||
"/component/kwin",
|
||||
"org.kde.kglobalaccel.Component.invokeShortcut",
|
||||
"Show Desktop",
|
||||
]);
|
||||
} else {
|
||||
expected = action === "show" ? "true" : "false";
|
||||
// dbus-send tipizza esplicitamente il booleano; qdbus6 su questa build
|
||||
// lo interpreta in modo non affidabile se passato come stringa "true".
|
||||
await run("dbus-send", [
|
||||
"--session",
|
||||
"--dest=org.kde.KWin",
|
||||
"--type=method_call",
|
||||
"/KWin",
|
||||
"org.kde.KWin.showDesktop",
|
||||
`boolean:${action === "show"}`,
|
||||
]);
|
||||
}
|
||||
|
||||
const state = await waitShowDesktopState(expected);
|
||||
return `Mostra Desktop: azione=${action}; showingDesktop=${state}`;
|
||||
}
|
||||
|
||||
/** Ispeziona l'albero AT-SPI (applicazioni + primi children). */
|
||||
async function inspectUI(depth: number): Promise<string> {
|
||||
const py = `
|
||||
@@ -109,11 +166,12 @@ export default function kdeAutomation(pi: ExtensionAPI) {
|
||||
pi.on("before_agent_start", async (event) => {
|
||||
const guidelines = event.systemPromptOptions.promptGuidelines ?? [];
|
||||
const kdeGuidelines = [
|
||||
"KDE AUTOMATION (desktop Plasma 6 Wayland): per verifiche UI usa i tool kde_* (kde_screenshot, kde_click, kde_type, kde_mousemove, kde_window_activate, kde_ui_inspect).",
|
||||
"KDE AUTOMATION (desktop Plasma 6 Wayland): per verifiche UI usa i tool kde_* (kde_screenshot, kde_click, kde_type, kde_mousemove, kde_window_activate, kde_ui_inspect, kde_show_desktop).",
|
||||
" - Prassi di verifica: 1) kde_screenshot per catturare lo stato; 2) analizza l'immagine (agy_analyze se serve visione); 3) azione (kde_click/kde_type/kde_window_activate); 4) kde_screenshot di verifica e confronta.",
|
||||
" - ydotool usa la mappa tastiera US: con layout IT i caratteri speciali (trattini, @, ecc.) vanno specificati con keycode o attenzione.",
|
||||
" - Su Wayland non esiste iniezione input nativa: ydotool (via /dev/uinput) è il metodo; il daemon si avvia da solo (sudoers NOPASSWD configurato).",
|
||||
" - Per finestre: kde_window_activate con resourceClass (es. org.kde.konsole, org.kde.dolphin).",
|
||||
" - Per Mostra Desktop usa kde_show_desktop: show/hide sono deterministici, toggle invoca KGlobalAccel; evitare xdotool/ydotool per questa azione.",
|
||||
" - Dettagli completi: skill /skill:kde-verify e memoria qmem (project host-enne2-gk35).",
|
||||
];
|
||||
return {
|
||||
@@ -142,7 +200,8 @@ export default function kdeAutomation(pi: ExtensionAPI) {
|
||||
"2. Analizza l'immagine (read o agy_analyze per visione)",
|
||||
"3. Azione: kde_window_activate (resourceClass) / kde_click (x,y,button) / kde_type (text)",
|
||||
"4. kde_screenshot di verifica e confronta con lo stato atteso",
|
||||
"Nota: ydotool usa mappa US (layout IT: caratteri speciali diversi).",
|
||||
"5. Per nascondere/ripristinare tutte le finestre: kde_show_desktop (show|hide|toggle)",
|
||||
"Nota: ydotool usa mappa US (layout IT: caratteri speciali diversi); per Show Desktop usare D-Bus.",
|
||||
"Daemon: si avvia da solo via sudoers NOPASSWD (ydotoold).",
|
||||
].join("\n");
|
||||
ctx.ui.notify(text, "info");
|
||||
@@ -180,6 +239,22 @@ export default function kdeAutomation(pi: ExtensionAPI) {
|
||||
},
|
||||
});
|
||||
|
||||
// --- tool: kde_show_desktop ---
|
||||
pi.registerTool({
|
||||
name: "kde_show_desktop",
|
||||
label: "KDE Show Desktop",
|
||||
description:
|
||||
"Mostra o nasconde tutte le finestre con l'API D-Bus nativa di KWin su Plasma Wayland. action=show nasconde le finestre, hide le ripristina, toggle invoca l'azione globale KWin. Restituisce e verifica la proprietà showingDesktop.",
|
||||
parameters: Type.Object({
|
||||
action: Type.Optional(Type.String({ description: "show | hide | toggle (default show)" })),
|
||||
}),
|
||||
async execute(_id, params) {
|
||||
const action = params.action ?? "show";
|
||||
const result = await setShowDesktop(action);
|
||||
return { content: [{ type: "text", text: result }], details: { action } };
|
||||
},
|
||||
});
|
||||
|
||||
// --- tool: kde_click ---
|
||||
pi.registerTool({
|
||||
name: "kde_click",
|
||||
|
||||
@@ -12,9 +12,10 @@ Prassi operativa per verificare e automatizzare applicazioni a schermo su KDE Pl
|
||||
## Ciclo di verifica
|
||||
|
||||
1. **Cattura**: `kde_screenshot` (mode=fullscreen|active|window|region, output=/tmp/x.png)
|
||||
2. **Analizza**: leggi l'immagine con `read` (se il modello supporta immagini) o `agy_analyze` (visione Gemini) per descrivere lo stato
|
||||
2. **Analizza**: leggi direttamente l'immagine con il tool `read` (invio nativo come allegato multimodale) per descrivere lo stato a schermo
|
||||
3. **Azione**: `kde_window_activate` (resourceClass) → `kde_click` (x,y,button) → `kde_type` (text)
|
||||
4. **Verifica**: nuovo `kde_screenshot` e confronta con lo stato atteso
|
||||
5. **Mostra Desktop**: usa `kde_show_desktop` con `action=show|hide|toggle` per nascondere o ripristinare le finestre senza simulare input
|
||||
|
||||
## Strumenti
|
||||
|
||||
@@ -26,6 +27,7 @@ Prassi operativa per verificare e automatizzare applicazioni a schermo su KDE Pl
|
||||
| `kde_mousemove` | ydotool mousemove (x, y) |
|
||||
| `kde_window_activate` | KWin scripting: attiva finestra per resourceClass |
|
||||
| `kde_ui_inspect` | AT-SPI: elenca applicazioni e controlli |
|
||||
| `kde_show_desktop` | KWin D-Bus: mostra/nasconde tutte le finestre su Wayland |
|
||||
|
||||
## Comandi diretti (se i tool non bastano)
|
||||
|
||||
@@ -46,6 +48,14 @@ qdbus6 org.kde.KWin /KWin org.kde.KWin.queryWindowInfo # info finestra attiva
|
||||
qdbus6 org.kde.KWin /Scripting org.kde.kwin.Scripting.loadScript /tmp/script.js
|
||||
qdbus6 org.kde.KWin /Scripting org.kde.kwin.Scripting.start
|
||||
|
||||
# Mostra Desktop (stato esplicito, robusto su Plasma Wayland)
|
||||
dbus-send --session --dest=org.kde.KWin --type=method_call /KWin org.kde.KWin.showDesktop boolean:true
|
||||
dbus-send --session --dest=org.kde.KWin --type=method_call /KWin org.kde.KWin.showDesktop boolean:false
|
||||
# Toggle via azione globale KWin
|
||||
qdbus6 org.kde.kglobalaccel /component/kwin org.kde.kglobalaccel.Component.invokeShortcut "Show Desktop"
|
||||
# Verifica stato
|
||||
qdbus6 org.kde.KWin /KWin org.freedesktop.DBus.Properties.Get org.kde.KWin showingDesktop
|
||||
|
||||
# Clipboard (workaround per inserire testo)
|
||||
qdbus6 org.kde.klipper /klipper org.kde.klipper.klipper.setClipboardContents "testo"
|
||||
```
|
||||
@@ -56,4 +66,5 @@ qdbus6 org.kde.klipper /klipper org.kde.klipper.klipper.setClipboardContents "te
|
||||
- **Wayland non ha iniezione input nativa**: ydotool (via /dev/uinput) è il metodo; il daemon si avvia da solo (sudoers NOPASSWD per ydotoold configurato).
|
||||
- **resourceClass comuni**: org.kde.konsole, org.kde.dolphin, org.kde.plasma-systemmonitor, firefox, org.kde.discover.
|
||||
- **AT-SPI**: il bus è su unix:path=/run/user/1000/at-spi/bus_1; per uso avanzato serve pyatspi (non installato).
|
||||
- **Mostra Desktop**: `org.kde.KWin.showDesktop(bool)` è esposto su `/KWin`; su questa macchina usare `dbus-send` con `boolean:true|false` perché `qdbus6` non tipizza sempre correttamente il booleano. Per toggle usare KGlobalAccel `invokeShortcut "Show Desktop"`.
|
||||
- **Dettagli e lezioni**: memoria qmem project `host-enne2-gk35` (record automazione KDE).
|
||||
|
||||
Reference in New Issue
Block a user