Skip to content

Instantly share code, notes, and snippets.

@svalordev
Created January 31, 2026 17:00
Show Gist options
  • Select an option

  • Save svalordev/cac63601cf6bd9a9fbf958f5a45462d9 to your computer and use it in GitHub Desktop.

Select an option

Save svalordev/cac63601cf6bd9a9fbf958f5a45462d9 to your computer and use it in GitHub Desktop.
import customtkinter as ctk
import os
import threading
import time
# Configuration
ctk.set_appearance_mode("System")
ctk.set_default_color_theme("blue")
class ScreenPadControl(ctk.CTk):
def __init__(self):
super().__init__()
# Window Setup
self.title("Asus ScreenPad Controller")
self.geometry("400x320")
self.resizable(False, False)
# Hardware Path (Plippo/asus-wmi-screenpad standard)
self.brightness_path = '/sys/class/leds/asus::screenpad/brightness'
# Debounce State
self._pending_value = None
self._timer = None
# Layout
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure((0, 1, 2, 3), weight=1)
# UI Elements
self.title_label = ctk.CTkLabel(self, text="ScreenPad Brightness", font=("Roboto Medium", 20))
self.title_label.grid(row=0, column=0, pady=(20, 10))
self.value_label = ctk.CTkLabel(self, text="Reading...", font=("Roboto", 16))
self.value_label.grid(row=1, column=0)
# Slider: Note the command is now 'schedule_update'
self.slider = ctk.CTkSlider(self, from_=0, to=255, number_of_steps=255, command=self.schedule_update)
self.slider.grid(row=2, column=0, padx=20, sticky="ew")
# Buttons
self.button_frame = ctk.CTkFrame(self, fg_color="transparent")
self.button_frame.grid(row=3, column=0, pady=20)
self.btn_on = ctk.CTkButton(self.button_frame, text="ON (190)", command=lambda: self.force_update(190))
self.btn_on.pack(side="left", padx=10)
self.btn_off = ctk.CTkButton(self.button_frame, text="OFF", fg_color="#C0392B", hover_color="#922B21", command=lambda: self.force_update(0))
self.btn_off.pack(side="left", padx=10)
self.init_hardware_state()
def init_hardware_state(self):
"""Reads initial state gracefully."""
if os.access(self.brightness_path, os.R_OK):
try:
with open(self.brightness_path, 'r') as f:
val = int(f.read().strip())
self.slider.set(val)
self.value_label.configure(text=str(val))
except Exception as e:
self.value_label.configure(text="Error reading state")
else:
self.value_label.configure(text="Permission Denied")
def schedule_update(self, value):
"""Debounce logic: Updates UI immediately, defers hardware write."""
int_val = int(value)
self.value_label.configure(text=str(int_val))
self._pending_value = int_val
# Cancel existing timer if active
if self._timer is not None:
self._timer.cancel()
# Schedule write after 100ms of inactivity
self._timer = threading.Timer(0.1, self._execute_write)
self._timer.start()
def force_update(self, value):
"""Bypasses debounce for button clicks."""
self.slider.set(value)
self.value_label.configure(text=str(value))
self._pending_value = value
if self._timer: self._timer.cancel()
self._execute_write()
def _execute_write(self):
"""Performs the actual file I/O."""
if self._pending_value is None: return
try:
with open(self.brightness_path, 'w') as f:
f.write(str(self._pending_value))
except PermissionError:
# Update UI on main thread to warn user
self.after(0, lambda: self.value_label.configure(text="Sudo Required!"))
except FileNotFoundError:
self.after(0, lambda: self.value_label.configure(text="Driver Not Loaded"))
if __name__ == "__main__":
app = ScreenPadControl()
app.mainloop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment