81 lines
2.2 KiB
Plaintext
81 lines
2.2 KiB
Plaintext
|
#!/usr/bin/env python3
|
||
|
|
||
|
import sys
|
||
|
import pulsectl
|
||
|
|
||
|
from Xlib import X, XK, 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)
|
||
|
|
||
|
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)
|