Confirmed on the MK-09 (8808:660a, 9 keys): the vendor's .NET configurator was decompiled for the wire format and every frame was then written to a real pad and read back. Keys, media keys and multikey sequences are supported; lighting from the command line. The firmware acts on every other output report, so each report is sent twice (as the vendor software does) and every write is verified by reading the key back. The app now keeps one state file per pad and starts with a known layout for a known USB id, and the editor asks the backend whether a binding fits before offering to write it. The actions listener and the udev rule cover every supported vendor. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
36 lines
1.0 KiB
Python
36 lines
1.0 KiB
Python
"""
|
|
One device family per backend.
|
|
|
|
Everything above this line works in terms of a Layout and a set of control
|
|
ids and doesn't care what the hardware speaks. Everything below it is one
|
|
pad family's protocol. Adding a family means writing the six methods in
|
|
base.py and listing the class here.
|
|
"""
|
|
|
|
from .ch57x import CH57x
|
|
from .itprotech import Itprotech
|
|
from .sayo import Sayo
|
|
|
|
REGISTRY = (CH57x(), Sayo(), Itprotech()) # tried in order; first to claim a device wins
|
|
DEFAULT = REGISTRY[0]
|
|
|
|
|
|
def for_vid_pid(vid, pid):
|
|
for backend in REGISTRY:
|
|
if backend.claims(str(vid).lower(), str(pid).lower()):
|
|
return backend
|
|
return None
|
|
|
|
|
|
def for_device(device):
|
|
# Falls back rather than returning None, so callers that only ever see
|
|
# one family stay simple. Use for_vid_pid when "nobody owns this" is an
|
|
# answer you need to act on.
|
|
if device is None:
|
|
return DEFAULT
|
|
return for_vid_pid(device.vid, device.pid) or DEFAULT
|
|
|
|
|
|
def known_ids():
|
|
return [(b.vid, b.pids, b.name) for b in REGISTRY]
|