From 343f5940e89198db987bb91e0e1ba0bbfbb28e22 Mon Sep 17 00:00:00 2001 From: AR2000 Date: Wed, 3 Apr 2024 21:35:02 +0200 Subject: [PATCH] v0.1 --- edledsync.py | 311 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 311 insertions(+) create mode 100755 edledsync.py diff --git a/edledsync.py b/edledsync.py new file mode 100755 index 0000000..b1f0705 --- /dev/null +++ b/edledsync.py @@ -0,0 +1,311 @@ +#!/bin/python3 +from openrgb import OpenRGBClient +from openrgb.utils import DeviceType, RGBColor +from watchdog.observers import Observer +from watchdog.events import FileSystemEventHandler +import json +import xmltodict +from os.path import basename +from enum import IntFlag +from pathlib import Path +from functools import wraps + + +def after(runAfter): + def inner(fun): + @wraps(fun) + def wrapper(*args, **kwds): + res = fun(*args, **kwds) + runAfter() + return res + + return wrapper + + return inner + + +qwertyToAzerty = { + "A": "Q", + "Z": "W", + "E": "E", + "R": "R", + "T": "T", + "Y": "Y", + "U": "U", + "I": "I", + "O": "O", + "P": "P", + "Q": "A", + "S": "S", + "D": "D", + "F": "F", + "G": "G", + "H": "H", + "J": "J", + "K": "K", + "L": "L", + "M": ";", + "W": "Z", + "X": "X", + "C": "C", + "V": "V", + "B": "B", + "N": "N", + ",": ";", + ";": "M", + ":": "M", +} +COLORS = { + "ELITE_ORANGE": RGBColor(255, 106, 0), + "BLUE": RGBColor(0, 255, 255), + "DEFAULT": RGBColor(0, 255, 255), + "MOVEMENT": RGBColor(0, 255, 255), + "ATTACK": RGBColor(255, 0, 0), + "MENU": RGBColor(255, 255, 255), + "UTIL": RGBColor(0, 255, 0), + "INVENTORY": RGBColor(255, 255, 0), + "OFF": RGBColor(0, 0, 0), +} + +ED_SAVE_PATH = Path( + "/home/ar2000/.steam/steam/steamapps/compatdata/359320/pfx/drive_c/users/steamuser/Saved Games/Frontier Developments/Elite Dangerous/Status.json" +) +ED_BINDINGS_CUSTOM_PATH = Path( + "/home/ar2000/.steam/steam/steamapps/compatdata/359320/pfx/drive_c/users/steamuser/AppData/Local/Frontier Developments/Elite Dangerous/Options/Bindings/" +) +ED_BINDINGS_TEMPLATE_PATH = Path( + "/home/ar2000/.steam/steam/steamapps/common/Elite Dangerous/Products/elite-dangerous-odyssey-64/ControlSchemes/" +) +file = None + +ON_FOOT_KEYS = { + "HumanoidForwardButton": COLORS["MOVEMENT"], + "HumanoidBackwardButton": COLORS["MOVEMENT"], + "HumanoidStrafeLeftButton": COLORS["MOVEMENT"], + "HumanoidStrafeRightButton": COLORS["MOVEMENT"], + "HumanoidRotateLeftButton": COLORS["MOVEMENT"], + "HumanoidRotateRightButton": COLORS["MOVEMENT"], + "HumanoidPitchUpButton": COLORS["MOVEMENT"], + "HumanoidPitchDownButton": COLORS["MOVEMENT"], + "HumanoidSprintButton": COLORS["MOVEMENT"], + "HumanoidWalkButton": COLORS["MOVEMENT"], + "HumanoidCrouchButton": COLORS["MOVEMENT"], + "HumanoidJumpButton": COLORS["MOVEMENT"], + "HumanoidPrimaryInteractButton": COLORS["MENU"], + "HumanoidSecondaryInteractButton": COLORS["MENU"], + "HumanoidItemWheelButton": COLORS["MENU"], + "HumanoidEmoteWheelButton": COLORS["MENU"], + "HumanoidItemWheelButton_XAxis": COLORS["MENU"], + "HumanoidItemWheelButton_XLeft": COLORS["MENU"], + "HumanoidItemWheelButton_XRight": COLORS["MENU"], + "HumanoidItemWheelButton_YAxis": COLORS["MENU"], + "HumanoidItemWheelButton_YUp": COLORS["MENU"], + "HumanoidItemWheelButton_YDown": COLORS["MENU"], + "HumanoidPrimaryFireButton": COLORS["ATTACK"], + "HumanoidZoomButton": COLORS["DEFAULT"], + "HumanoidThrowGrenadeButton": COLORS["ATTACK"], + "HumanoidMeleeButton": COLORS["ATTACK"], + "HumanoidReloadButton": COLORS["UTIL"], + "HumanoidSelectPrimaryWeaponButton": COLORS["INVENTORY"], + "HumanoidSelectSecondaryWeaponButton": COLORS["INVENTORY"], + "HumanoidSelectUtilityWeaponButton": COLORS["INVENTORY"], + "HumanoidSelectNextWeaponButton": COLORS["INVENTORY"], + "HumanoidSelectPreviousWeaponButton": COLORS["INVENTORY"], + "HumanoidHideWeaponButton": COLORS["UTIL"], + "HumanoidSelectNextGrenadeTypeButton": COLORS["INVENTORY"], + "HumanoidSelectPreviousGrenadeTypeButton": COLORS["INVENTORY"], + "HumanoidToggleFlashlightButton": COLORS["UTIL"], + "HumanoidToggleNightVisionButton": COLORS["UTIL"], + "HumanoidToggleShieldsButton": COLORS["UTIL"], + "HumanoidToggleToolModeButton": COLORS["UTIL"], + "HumanoidToggleMissionHelpPanelButton": COLORS["MENU"], + "HumanoidOpenAccessPanelButton": COLORS["MENU"], + "HumanoidConflictContextualUIButton": COLORS["MENU"], + "PhotoCameraToggle_Humanoid": COLORS["MENU"], + "GalaxyMapOpen_Humanoid": COLORS["MENU"], + "SystemMapOpen_Humanoid": COLORS["MENU"], + "FocusCommsPanel_Humanoid": COLORS["MENU"], + "QuickCommsPanel_Humanoid": COLORS["MENU"], +} + +KEYS_TR = { + f"{a}{b}": f"{a} {b}" + for a in ["Up", "Down", "Left", "Right"] + for b in ["Arrow", "Alt", "Shift", "Control"] +} +configured_on_foot_keys, keybindgs = {}, {} + + +class StatusFlag(IntFlag): + DOCKED = 1 << 0 + LANDED = 1 << 1 + LANDING_GEAR_DOWN = 1 << 2 + SHIELDS_UP = 1 << 3 + SUPERCRUISE = 1 << 4 + FLIGHTASSIST_OFF = 1 << 5 + HARDPOINTS_DEPLOYED = 1 << 6 + IN_WING = 1 << 7 + LIGHTS_ON = 1 << 8 + CARGO_SCOOP_DEPLOYED = 1 << 9 + SILENT_RUNNING = 1 << 10 + SCOOPING_FUEL = 1 << 11 + SRV_HANDBRAKE = 1 << 12 + SRV_USING_TURRET_VIEW = 1 << 13 + SRV_TURRET_RETRACTED = 1 << 14 + SRV_DRIVEASSIST = 1 << 15 + FSD_MASSLOCKED = 1 << 16 + FSD_CHARGING = 1 << 17 + FSD_COOLDOWN = 1 << 18 + LOW_FUEL = 1 << 19 + OVER_HEATING = 1 << 20 + HAS_LAT_LONG = 1 << 21 + IS_IN_DANGER = 1 << 22 + BEING_INTERDICTED = 1 << 23 + IN_MAINSHIP = 1 << 24 + IN_FIGHTER = 1 << 25 + IN_SRV = 1 << 26 + HUD_IN_ANALYSIS_MODE = 1 << 27 + NIGHT_VISION = 1 << 28 + ALTITUDE_FROM_AVERAGE_RADIUS = 1 << 29 + FSDJUMP = 1 << 30 + SRV_HIGHBEAM = 1 << 31 + + +class StatusFlag2(IntFlag): + ON_FOOT = 1 << 0 + IN_TAXI = 1 << 1 + IN_MULTICREW = 1 << 2 + ON_FOOT_IN_STATION = 1 << 3 + ON_FOOT_ON_PLANET = 1 << 4 + AIM_DOWN_SIGHT = 1 << 5 + LOW_OXYGEN = 1 << 6 + LOW_HEALTH = 1 << 7 + COLD = 1 << 8 + HOT = 1 << 9 + VERY_COLD = 1 << 10 + VERY_HOT = 1 << 11 + GLIDE_MODE = 1 << 12 + ON_FOOT_INHANGAR = 1 << 13 + ON_FOOT_SOCIAL_SPACE = 1 << 14 + ON_FOOT_EXTERIOR = 1 << 15 + BREATHABLE_ATMOSPHERE = 1 << 16 + TELEPRESENCE_MULTICREW = 1 << 17 + PHYSICAL_MULTICREW = 1 << 18 + FSD_HYPERDRIVE_CHARGING = 1 << 19 + + +def setKeysColor(device, keys: list | str, color: RGBColor | list): + if type(keys) == list: + assert len(color) == len(keys) + for i, key in enumerate(keys): + for led in device.leds: + try: + if qwertyToAzerty[led.name.lstrip("Key: ")] == key: + led.set_color(color if type(color) == RGBColor else color[i]) + continue + except KeyError: + if led.name.lstrip("Key: ") == key: + led.set_color(color if type(color) == RGBColor else color[i]) + continue + + +def keepAlive(): + keyboard.update() + + +def parseKeybinds(): + with open(Path(ED_BINDINGS_CUSTOM_PATH, "Custom.4.0.binds"), "r") as f: + readKeybinds = xmltodict.parse(f.read()) + keybindgs = readKeybinds["Root"] + + # extract keys for on foot keys + for k in ON_FOOT_KEYS: + if not k in keybindgs: + continue + keybind = keybindgs[k] + if "Primary" in keybind: + if keybind["Primary"]["@Device"] == "Keyboard": + key = keybind["Primary"]["@Key"].lstrip("Key_") + if key in KEYS_TR: + key = KEYS_TR[key] + configured_on_foot_keys[k] = key + print(f"{k} : {key}") + if "Secondary" in keybind: + if keybind["Secondary"]["@Device"] == "Keyboard": + key = keybind["Secondary"]["@Key"].lstrip("Key_") + if key in KEYS_TR: + key = KEYS_TR[key] + if k in configured_on_foot_keys: + print(f'Key "{k}" already found. Ignoring') + configured_on_foot_keys[k] = key + print(f"{k} : {key}") + + +class StatusHandler(FileSystemEventHandler): + lastOnFoot = False + + @after(keepAlive) + def on_modified(self, event): + try: + with open(ED_SAVE_PATH, "r") as f: + print("EDIT") + statusData = json.load(f) + except: + return + print(statusData) + if "Flags2" not in statusData: + return # game not running + print(StatusFlag(statusData["Flags"])) + print(StatusFlag2(statusData["Flags2"])) + if self.isOnFoot(statusData) and self.lastOnFoot == False: + keyboard.set_color(RGBColor(0, 0, 0)) + setKeysColor( + keyboard, + [v for k, v in configured_on_foot_keys.items()], + [c for k, c in ON_FOOT_KEYS.items() if k in configured_on_foot_keys], + ) + elif self.isOnFoot(statusData) == False and self.lastOnFoot == True: + keyboard.set_color(COLORS["ELITE_ORANGE"]) + + self.lastOnFoot = self.isOnFoot(statusData) + return super().on_modified(event) + + def isOnFoot(self, statusData): + return StatusFlag2.ON_FOOT in StatusFlag2(statusData["Flags2"]) + + +class KeybindHandler(FileSystemEventHandler): + + def on_modified(self, event): + parseKeybinds() + return super().on_modified(event) + + +if __name__ == "__main__": + + print("Parsing keybinds") + parseKeybinds() + + openrgbClient = OpenRGBClient(name=basename(__file__)) + keyboard = openrgbClient.get_devices_by_type(DeviceType.KEYBOARD)[0] + keyboard.set_mode("direct") + keyboard.set_color(COLORS["ELITE_ORANGE"]) + + observer = Observer() + statusHandler = StatusHandler() + keybindHandler = KeybindHandler() + observer.schedule(statusHandler, path=ED_SAVE_PATH, recursive=False) + observer.schedule( + keybindHandler, + path=Path(ED_BINDINGS_CUSTOM_PATH, "Custom.4.0.binds"), + recursive=False, + ) + observer.start() + + try: + # main loop + while observer.is_alive(): + observer.join(1) + finally: + observer.stop() + observer.join()