pragma Singleton

// What input hardware this machine actually has.
//
// Exists so pages can hide controls for hardware that is not present. A
// touchpad card on a desktop is not merely useless -- it is misleading, because
// every switch on it appears to work: the preference is stored and Hyprland
// accepts the option for a device class it has no member of. The user is left
// toggling settings that will never affect anything, with nothing to say so.
//
// Touchpads are identified by name. libinput exposes them through the same
// "mice" list as everything else that reports pointer motion, and Hyprland
// passes the device name through, so an Elan or Synaptics touchpad arrives as
// something like "elan-touchpad". There is no device-class field to consult.
//
// Read on demand rather than polled. Input devices do come and go -- a mouse is
// unplugged, a receiver is moved -- so this also refreshes when Hyprland says
// the device list changed, which is the only moment the answer can differ.

import Quickshell
import Quickshell.Io
import Quickshell.Hyprland
import QtQuick

Singleton {
    id: root

    property var mice: []
    property var keyboards: []

    // True when anything that looks like a touchpad is attached.
    readonly property bool hasTouchpad: root.mice.some(name =>
        name.includes("touchpad") || name.includes("trackpad"))

    readonly property bool hasMouse: root.mice.length > 0

    function refresh(): void {
        if (!query.running)
            query.running = true;
    }

    Process {
        id: query
        running: true
        command: ["hyprctl", "-j", "devices"]
        stdout: StdioCollector {
            onStreamFinished: {
                try {
                    const parsed = JSON.parse(this.text);
                    root.mice = (parsed.mice ?? []).map(device => String(device.name ?? "").toLowerCase());
                    root.keyboards = (parsed.keyboards ?? []).map(device => String(device.name ?? "").toLowerCase());
                } catch (error) {
                    console.warn("InputDevices: could not parse hyprctl devices:", error);
                }
            }
        }
    }

    Connections {
        target: Hyprland
        function onRawEvent(event: var): void {
            if (event.name === "device" || event.name === "configreloaded")
                root.refresh();
        }
    }
}
