Working 10-zone plugin using the 0x44 live colour reports on the 0xFF90 vendor interface (data then commit). Includes Python tools used to identify the device, confirm the protocol and map zones. Output is dimmer than onboard effects; investigation pending. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01EcbUcbNpyPn7cGpe4t6y5y
79 lines
2.3 KiB
Python
79 lines
2.3 KiB
Python
"""Interactive zone mapper: lights one LED slot at a time in white (all others
|
|
off) and records which keys you see lit. Results go to tools/zone_map.json.
|
|
|
|
.venv\\Scripts\\python tools\\zone_walk.py # slots 0..19
|
|
.venv\\Scripts\\python tools\\zone_walk.py --start 5 # resume from slot 5
|
|
"""
|
|
import argparse
|
|
import json
|
|
import pathlib
|
|
import threading
|
|
import time
|
|
|
|
import eve
|
|
|
|
OUT = pathlib.Path(__file__).with_name("zone_map.json")
|
|
|
|
|
|
class Streamer(threading.Thread):
|
|
"""Keeps re-sending the current frame so the keyboard never times out."""
|
|
|
|
def __init__(self, total, fps=10):
|
|
super().__init__(daemon=True)
|
|
self.colors = [(0, 0, 0)] * total
|
|
self.fps = fps
|
|
self.lock = threading.Lock()
|
|
self.running = True
|
|
|
|
def set(self, colors):
|
|
with self.lock:
|
|
self.colors = list(colors)
|
|
|
|
def run(self):
|
|
dev = eve.open_device()
|
|
dev.set_nonblocking(True)
|
|
try:
|
|
while self.running:
|
|
with self.lock:
|
|
packets = eve.build_packets(self.colors)
|
|
for p in packets:
|
|
dev.write(p)
|
|
while dev.read(eve.REPORT_LEN):
|
|
pass
|
|
time.sleep(1 / self.fps)
|
|
finally:
|
|
dev.close()
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--start", type=int, default=0)
|
|
ap.add_argument("--total", type=int, default=20)
|
|
args = ap.parse_args()
|
|
|
|
results = json.loads(OUT.read_text()) if OUT.exists() else {}
|
|
streamer = Streamer(args.total)
|
|
streamer.start()
|
|
|
|
print("For each slot, type the keys that are lit (e.g. 'Esc, F1-F4, ~ 1 2 Tab Q')")
|
|
print("Just press Enter if NOTHING is lit. Type q to stop.\n")
|
|
try:
|
|
for slot in range(args.start, args.total):
|
|
colors = [(0, 0, 0)] * args.total
|
|
colors[slot] = (255, 255, 255)
|
|
streamer.set(colors)
|
|
answer = input(f"Slot {slot:2} lit white -> which keys? ").strip()
|
|
if answer.lower() == "q":
|
|
break
|
|
results[str(slot)] = answer or "(nothing)"
|
|
OUT.write_text(json.dumps(results, indent=2))
|
|
finally:
|
|
streamer.running = False
|
|
streamer.join(timeout=2)
|
|
|
|
print(f"\nSaved to {OUT}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|