Skip to content

Instantly share code, notes, and snippets.

@FixeQD
Last active March 8, 2026 21:19
Show Gist options
  • Select an option

  • Save FixeQD/175e1150cbcabb2267337dd69a4235fa to your computer and use it in GitHub Desktop.

Select an option

Save FixeQD/175e1150cbcabb2267337dd69a4235fa to your computer and use it in GitHub Desktop.
Push-to-talk cuz discord doesn't detect keybinds on my wayland bruh
#!/usr/bin/env python3
# ─────────────────────────────────────────────
# CONFIG
# ─────────────────────────────────────────────
DEVICE_PATH = "/dev/input/by-path/platform-i8042-serio-0-event-kbd"
PTT_KEY = "KEY_RIGHTCTRL"
APP_NAME = "PTT"
MAX_LOGS = 50
REFRESH_RATE = 4
COLOR_LIVE = "green"
COLOR_MUTED = "red"
COLOR_ACCENT = "cyan"
COLOR_DIM = "dim"
# ─────────────────────────────────────────────
import time
import threading
import evdev
import pulsectl
import colorama
from colorama import Fore, Style
from rich.layout import Layout
from rich.live import Live
from rich.panel import Panel
from rich.table import Table
from rich.text import Text
from datetime import datetime
from collections import deque
colorama.init()
KEY_CODE = evdev.ecodes.ecodes[PTT_KEY]
logs = deque(maxlen=MAX_LOGS)
state = {
"muted": True,
"events": 0,
"start": datetime.now(),
"last_event": "—",
"initial_mute": None,
}
LEVEL_COLORS = {
"READY": COLOR_ACCENT,
"OK": COLOR_LIVE,
"INFO": "white",
"WARN": "yellow",
"ERR": COLOR_MUTED,
}
def log(msg: str, level: str = "INFO"):
logs.append({
"time": datetime.now().strftime("%H:%M:%S"),
"level": level,
"msg": msg,
})
def render_header() -> Panel:
t = Text(justify="center")
t.append(f" {APP_NAME} ", style=f"bold {COLOR_ACCENT}")
t.append("Push To Talk", style="bold white")
return Panel(t, style=COLOR_ACCENT)
def render_status() -> Panel:
if state["muted"]:
label = Text("● MUTED", style=f"bold {COLOR_MUTED}")
border = COLOR_MUTED
else:
label = Text("▶ LIVE", style=f"bold {COLOR_LIVE}")
border = COLOR_LIVE
uptime = str(datetime.now() - state["start"]).split(".")[0]
initial_label = "muted" if state["initial_mute"] else "unmuted"
grid = Table.grid(padding=(0, 2))
grid.add_column(style=COLOR_DIM)
grid.add_column()
grid.add_row("Status", label)
grid.add_row("Key", Text(PTT_KEY, style=COLOR_ACCENT))
grid.add_row("Device", Text(DEVICE_PATH.split("/")[-1], style=COLOR_DIM))
grid.add_row("Uptime", Text(uptime, style="white"))
grid.add_row("Events", Text(str(state["events"]), style="white"))
grid.add_row("Last event", Text(state["last_event"], style=COLOR_DIM))
grid.add_row("Restore to", Text(initial_label, style=COLOR_DIM))
return Panel(grid, title="[bold]Status[/bold]", border_style=border, padding=(1, 2))
def render_logs() -> Panel:
table = Table(show_header=True, header_style=f"bold {COLOR_DIM}", box=None, expand=True)
table.add_column("Time", style=COLOR_DIM, width=10)
table.add_column("Level", width=7)
table.add_column("Message", ratio=1)
for entry in logs:
color = LEVEL_COLORS.get(entry["level"], "white")
table.add_row(
entry["time"],
f"[{color}]{entry['level']}[/{color}]",
entry["msg"],
)
return Panel(table, title="[bold]Logs[/bold]", border_style=COLOR_DIM)
def render_footer() -> Panel:
t = Text(justify="center")
t.append("Hold ", style=COLOR_DIM)
t.append(PTT_KEY, style=f"bold {COLOR_ACCENT}")
t.append(" to unmute | ", style=COLOR_DIM)
t.append("Ctrl+C", style=f"bold {COLOR_MUTED}")
t.append(" to exit", style=COLOR_DIM)
return Panel(t, style=COLOR_DIM)
def refresh(layout: Layout):
layout["header"].update(render_header())
layout["status"].update(render_status())
layout["logs"].update(render_logs())
layout["footer"].update(render_footer())
def event_loop(device, pulse, src):
for event in device.read_loop():
if event.type != evdev.ecodes.EV_KEY:
continue
key = evdev.categorize(event)
if key.scancode != KEY_CODE:
continue
if key.keystate == evdev.KeyEvent.key_hold:
continue
now = datetime.now().strftime("%H:%M:%S")
state["events"] += 1
if key.keystate == evdev.KeyEvent.key_down:
state["muted"] = False
state["last_event"] = f"unmuted @ {now}"
pulse.mute(src, False)
log("Mic UNMUTED", "OK")
elif key.keystate == evdev.KeyEvent.key_up:
state["muted"] = True
state["last_event"] = f"muted @ {now}"
pulse.mute(src, True)
log("Mic MUTED", "INFO")
def main():
pulse = pulsectl.Pulse(APP_NAME.lower())
device = evdev.InputDevice(DEVICE_PATH)
src = pulse.get_source_by_name(pulse.server_info().default_source_name)
initial_mute = bool(src.mute)
state["initial_mute"] = initial_mute
state["muted"] = True
pulse.mute(src, True)
log(f"Device → {DEVICE_PATH}", "READY")
log(f"Key → {PTT_KEY}", "READY")
log(f"Initial state → {'muted' if initial_mute else 'unmuted'}", "INFO")
log("Mic muted on startup", "INFO")
layout = Layout()
layout.split_column(
Layout(name="header", size=3),
Layout(name="main"),
Layout(name="footer", size=3),
)
layout["main"].split_row(
Layout(name="status", ratio=1),
Layout(name="logs", ratio=2),
)
t = threading.Thread(target=event_loop, args=(device, pulse, src), daemon=True)
t.start()
try:
with Live(layout, refresh_per_second=REFRESH_RATE, screen=True):
while t.is_alive():
refresh(layout)
time.sleep(1 / REFRESH_RATE)
finally:
pulse.mute(src, initial_mute)
if __name__ == "__main__":
try:
print(f"{Fore.CYAN}[{APP_NAME}]{Style.RESET_ALL} Starting...")
main()
except KeyboardInterrupt:
print(f"\n{Fore.YELLOW}[{APP_NAME}]{Style.RESET_ALL} Restored mic state and exited.")
except Exception as e:
print(f"\n{Fore.RED}[{APP_NAME}] ERR:{Style.RESET_ALL} {e}")
finally:
colorama.deinit()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment