Add files via upload

This commit is contained in:
Mohamed Mahjoub
2026-09-11 20:30:34 +01:00
committed by GitHub
parent 07f3af3441
commit c7c02edb60
35 changed files with 3975 additions and 13 deletions

152
macropad-handshake.py Normal file
View File

@@ -0,0 +1,152 @@
#!/usr/bin/env python3
"""
macropad-handshake - find out how your pad wants to be talked to.
Sends only the benign "version check" report upstream uses on connect:
all zeros, no configuration payload. It cannot change your keybinds.
It tries each report id with two different transfer methods, and checks
after every attempt whether the device survived. If the pad resets, the
script waits for it to come back before continuing.
Usage:
python3 macropad-handshake.py /dev/hidraw10
"""
import fcntl
import glob
import os
import sys
import time
REPORT_IDS = [0, 2, 3]
PAYLOAD_LEN = 64
G = "\033[32m"; R = "\033[31m"; Y = "\033[33m"; B = "\033[1m"; DIM = "\033[2m"; O = "\033[0m"
def hidioc_sfeature(size):
"""_IOWR('H', 0x06, size) - the SET_FEATURE ioctl hidraw exposes."""
return (3 << 30) | (size << 16) | (ord('H') << 8) | 0x06
def device_present(path):
return os.path.exists(path)
def wait_for_device(path, timeout=6.0):
"""After a reset the node usually reappears with the same name."""
start = time.time()
while time.time() - start < timeout:
if os.path.exists(path):
time.sleep(0.4) # let udev reapply the ACL
return True
time.sleep(0.2)
return False
def try_write(path, report_id, method):
"""
Returns (ok, detail). 'ok' means the device accepted the transfer
without erroring and was still present afterwards.
"""
data = bytes([report_id]) + bytes(PAYLOAD_LEN)
try:
if method == "write":
fd = os.open(path, os.O_WRONLY)
try:
os.write(fd, data)
finally:
os.close(fd)
else: # feature report via ioctl
fd = os.open(path, os.O_RDWR)
try:
buf = bytearray(data)
fcntl.ioctl(fd, hidioc_sfeature(len(buf)), buf)
finally:
os.close(fd)
except OSError as e:
return False, f"{e.__class__.__name__}: {e.strerror} (errno {e.errno})"
except Exception as e:
return False, str(e)
time.sleep(0.3)
if not device_present(path):
return False, "device vanished - firmware reset"
return True, "accepted"
def main():
if len(sys.argv) > 1:
path = sys.argv[1]
else:
cands = sorted(glob.glob("/dev/hidraw*"))
print("Pass the device path, e.g.:")
print(f" python3 {sys.argv[0]} /dev/hidraw10")
print(f"\n{DIM}Available: {' '.join(cands)}{O}")
return 1
if not os.path.exists(path):
print(f"{R}{path} doesn't exist.{O}")
return 1
if not os.access(path, os.W_OK):
print(f"{R}{path} isn't writable.{O} Check your udev rule.")
return 1
print(f"{B}Handshake probe on {path}{O}")
print(f"{DIM}Sending zero-filled version-check reports only.")
print(f"Your saved keybinds are not touched.{O}\n")
results = []
for method in ("write", "feature"):
label = "interrupt OUT (write)" if method == "write" else "SET_FEATURE (ioctl)"
print(f"{B}{label}{O}")
for rid in REPORT_IDS:
if not device_present(path):
print(f" {DIM}waiting for device to come back...{O}")
if not wait_for_device(path):
print(f" {R}device did not return. Replug it and rerun.{O}")
return 1
ok, detail = try_write(path, rid, method)
mark = f"{G}OK {O}" if ok else f"{R}FAIL {O}"
print(f" report id {rid}: {mark} {detail}")
results.append((method, rid, ok, detail))
if not ok and "vanished" in detail:
if not wait_for_device(path):
print(f" {R}device did not come back.{O} Replug and rerun.")
return 1
print()
# ------------------------------------------------------------ verdict
print(f"{B}Verdict{O}")
good = [(m, r) for m, r, ok, _ in results if ok]
if not good:
print(f" {R}Nothing was accepted.{O}")
print(" This pad may not use the MacroPad protocol at all, or it")
print(" wants a vendor-specific unlock sequence first.")
print("\n Worth trying: the other config interface, if the probe found one.")
return 1
print(f" {G}Accepted combinations:{O}")
for m, r in good:
how = "write" if m == "write" else "feature"
print(f" report id {r} via {how}")
m, r = good[0]
print(f"\n Upstream picks the first report id that accepts a write,")
print(f" so your pad looks like {B}protocol version {r}{O}.")
print(f"\n Try a real binding with:")
extra = "" if m == "write" else " (needs --feature support adding)"
print(f" python3 macropad.py set key1 ctrl+c --report-id {r}{extra}")
return 0
if __name__ == "__main__":
sys.exit(main())