Files
acer-predator-PH18-73-led-c…/ph18_rgb_menu.py
T
2026-05-27 07:09:37 +02:00

178 lines
5.2 KiB
Python

#!/usr/bin/env python3
"""Interactive menu for PH18 HID RGB controls."""
from __future__ import annotations
import re
import subprocess
import sys
from pathlib import Path
HEX_COLOR_RE = re.compile(r"^[0-9a-fA-F]{6}$")
CSV_COLOR_RE = re.compile(r"^\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*$")
SCRIPT_DIR = Path(__file__).resolve().parent
HID_RGB_SCRIPT = SCRIPT_DIR / "ph18_hid_rgb.py"
def prompt_menu_choice() -> str:
"""Prompt for the main menu action."""
print("\nPH18 RGB Menu")
print("1. List detected HID devices and mappings")
print("2. Set keyboard single static color")
print("3. Set keyboard 4-zone static colors")
print("4. Switch keyboard to dynamic mode")
print("5. Set rear/logo/bar static color")
print("6. Turn rear/logo/bar off")
print("7. Set rear/logo/bar progressbar effect")
print("0. Exit")
return input("Choose an option: ").strip()
def prompt_yes_no(question: str, *, default_yes: bool = True) -> bool:
"""Prompt for a yes/no answer."""
suffix = " [Y/n]: " if default_yes else " [y/N]: "
raw = input(question + suffix).strip().lower()
if not raw:
return default_yes
return raw in {"y", "yes"}
def _valid_csv_color(value: str) -> bool:
if not CSV_COLOR_RE.match(value):
return False
try:
parts = [int(part.strip()) for part in value.split(",")]
except ValueError:
return False
return len(parts) == 3 and all(0 <= part <= 255 for part in parts)
def prompt_color(question: str) -> str:
"""Prompt for a color in hex (RRGGBB) or CSV (R,G,B)."""
while True:
raw = input(f"{question} (RRGGBB or R,G,B): ").strip()
if HEX_COLOR_RE.match(raw):
return raw.lower()
if _valid_csv_color(raw):
return raw
print("Invalid color format.")
def prompt_target() -> str:
"""Prompt for zone target."""
options = {"1": "rear", "2": "logo", "3": "bar", "4": "all"}
print("\nTarget:")
print("1. rear")
print("2. logo")
print("3. bar")
print("4. all")
while True:
choice = input("Choose target: ").strip()
target = options.get(choice)
if target:
return target
print("Invalid choice.")
def prompt_brightness() -> str:
"""Prompt for brightness byte."""
while True:
raw = input("Brightness [0-255] (default 25): ").strip()
if not raw:
return "25"
try:
value = int(raw, 10)
except ValueError:
print("Invalid number.")
continue
if 0 <= value <= 255:
return str(value)
print("Brightness must be 0..255.")
def run_hid_rgb(args: list[str]) -> int:
"""Run ph18_hid_rgb.py with provided arguments."""
cmd = [sys.executable, str(HID_RGB_SCRIPT), *args]
print(f"\n$ {' '.join(cmd)}")
result = subprocess.run(cmd, check=False)
if result.returncode != 0:
print(f"Command failed with exit code {result.returncode}")
return result.returncode
def action_keyboard_static() -> None:
color = prompt_color("Keyboard color")
args = ["keyboard", "--color", color]
if not prompt_yes_no("Apply MagKey/WASD overlay color too?", default_yes=True):
args.append("--no-magkeys")
run_hid_rgb(args)
def action_keyboard_zones() -> None:
z1 = prompt_color("Zone 1 color (left)")
z2 = prompt_color("Zone 2 color")
z3 = prompt_color("Zone 3 color")
z4 = prompt_color("Zone 4 color (right)")
args = ["keyboard-zones", "--z1", z1, "--z2", z2, "--z3", z3, "--z4", z4]
if not prompt_yes_no("Apply MagKey/WASD overlay from zone1 color?", default_yes=True):
args.append("--no-magkeys")
run_hid_rgb(args)
def action_keyboard_dynamic() -> None:
repeats = input("Dynamic repeats (default 2): ").strip() or "2"
run_hid_rgb(["keyboard-dynamic", "--repeats", repeats])
def action_zone_static() -> None:
target = prompt_target()
color = prompt_color("Zone color")
brightness = prompt_brightness()
run_hid_rgb(["zone", target, "static", "--color", color, "--brightness", brightness])
def action_zone_off() -> None:
target = prompt_target()
run_hid_rgb(["zone", target, "off"])
def action_zone_progressbar() -> None:
target = prompt_target()
run_hid_rgb(["zone", target, "progressbar"])
def main() -> int:
"""Run the interactive RGB menu."""
if not HID_RGB_SCRIPT.exists():
print(f"Missing script: {HID_RGB_SCRIPT}")
return 1
if hasattr(sys, "getuid") and sys.getuid() != 0:
print("Tip: run with sudo for write operations (e.g. `sudo python3 ph18_rgb_menu.py`).")
actions = {
"1": lambda: run_hid_rgb(["list"]),
"2": action_keyboard_static,
"3": action_keyboard_zones,
"4": action_keyboard_dynamic,
"5": action_zone_static,
"6": action_zone_off,
"7": action_zone_progressbar,
}
while True:
choice = prompt_menu_choice()
if choice == "0":
print("Bye.")
return 0
action = actions.get(choice)
if action is None:
print("Invalid option.")
continue
action()
if __name__ == "__main__":
raise SystemExit(main())