#!/usr/bin/env nix-shell
#! nix-shell -i python3 --pure
#! nix-shell -p python3 python3Packages.pulsectl python3Packages.xlib

import sys

import pulsectl
from Xlib import XK, X, display
from Xlib.ext import record
from Xlib.protocol import rq

KEY = XK.XK_F7


def mute(state):
    with pulsectl.Pulse("list-source") as pulse:
        for source in pulse.source_list():
            if source.port_active:
                if source.mute != state:
                    pulse.mute(source, state)
                    print(f"{source.name} {'un' if not state else ''}muted")


mute(True)

local_dpy = display.Display()
record_dpy = display.Display()


def record_callback(reply):
    if reply.category != record.FromServer:
        return
    if reply.client_swapped:
        print("* received swapped protocol data, cowardly ignored")
        return
    if not len(reply.data) or reply.data[0] < 2:
        # not an event
        return

    data = reply.data
    while len(data):
        event, data = rq.EventField(None).parse_binary_value(
            data, record_dpy.display, None, None
        )

        if event.type in [X.KeyPress, X.KeyRelease]:
            keysym = local_dpy.keycode_to_keysym(event.detail, 0)

            print(KEY)
            if keysym == KEY:
                mute(event.type == X.KeyRelease)


# Check if the extension is present
if not record_dpy.has_extension("RECORD"):
    print("RECORD extension not found")
    sys.exit(1)
    r = record_dpy.record_get_version(0, 0)
    print("RECORD extension version %d.%d" % (r.major_version, r.minor_version))

# Create a recording context; we only want key and mouse events
ctx = record_dpy.record_create_context(
    0,
    [record.AllClients],
    [
        {
            "core_requests": (0, 0),
            "core_replies": (0, 0),
            "ext_requests": (0, 0, 0, 0),
            "ext_replies": (0, 0, 0, 0),
            "delivered_events": (0, 0),
            "device_events": (X.KeyPress, X.MotionNotify),
            "errors": (0, 0),
            "client_started": False,
            "client_died": False,
        }
    ],
)

# Enable the context; this only returns after a call to record_disable_context,
# while calling the callback function in the meantime
try:
    record_dpy.record_enable_context(ctx, record_callback)
except KeyboardInterrupt:
    local_dpy.record_disable_context(ctx)
    local_dpy.flush()

# Finally free the context
record_dpy.record_free_context(ctx)