Path: blob/master/payloads/library/general/Piano_Player/piano_player.py
2968 views
import argparse1from pathlib import Path234OS_DETECT_EXTENSION = Path(__file__).resolve().parents[4] / "payloads" / "extensions" / "os_detect.txt"567def parse_args():8parser = argparse.ArgumentParser()9parser.add_argument("notes", metavar="NOTES_FILE", help="Path to notes file")10parser.add_argument("payload", metavar="PAYLOAD_FILE", help="Save payload code to this file")11parser.add_argument("-p", "--press-mode", help="Deploy with press mode", action="store_true")12return parser.parse_args()131415def generate_keymap(maps: str) -> dict:16keymap = {}17for exp in maps.split(" "):18note, key = exp.split("=")19keymap[note] = key20return keymap212223def notes_to_code(roll: list, keymap: dict, tick: int, url: str, press_mode: bool) -> str:24# Adjust tick to account for note held duration25adjusted_tick = tick - 2026if adjusted_tick < 20:27raise Exception(f"tick ({tick}) is too low! Must be at least 40ms.")2829code = ""30indent = ""31# Head32if not press_mode:33with open(OS_DETECT_EXTENSION) as f:34code += f.read() + "\n"35code += f"""IF ($_OS == WINDOWS) THEN36GUI r37ELSE IF ($_OS == MACOS) THEN38COMMAND SPACE39ELSE IF ($_OS == LINUX) THEN40CONTROL ESCAPE41ELSE42GUI43END_IF4445DELAY 100046STRING {url}47ENTER48DELAY 2000\n49"""50else:51indent = " "52code += "ATTACKMODE HID STORAGE\n\n"5354# Function (common)55code += f"""FUNCTION tick()56DELAY {adjusted_tick}57END_FUNCTION\n58"""5960if press_mode:61code += """WHILE TRUE62WAIT_FOR_BUTTON_PRESS63"""6465# Each row is one or more note press, or a rest. Notes and rests are66# held for 20ms (not configurable), but the total interval between rows is67# approx. the specified tick time.68for row in roll:69notes = [n for n in row.split(" ") if n != "---"]70for note in notes:71code += f"{indent}HOLD {keymap[note]}\n"72code += f"{indent}DELAY 20\n"73for note in notes:74code += f"{indent}RELEASE {keymap[note]}\n"75code += f"{indent}tick()\n"76if press_mode:77code += "END_WHILE"7879return code808182if __name__ == "__main__":83args = parse_args()84with open(args.notes) as f:85notes = [line.strip() for line in f.readlines()]8687tick = int(notes[0].split("ms")[0])88url = notes[1]89keymap = generate_keymap(notes[2])90roll = notes[4:]9192with open(args.payload, "w") as f:93f.write(notes_to_code(roll, keymap, tick, url, args.press_mode))949596