#!/usr/bin/env python3 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)