312 lines
9.6 KiB
Python
Executable File
312 lines
9.6 KiB
Python
Executable File
#!/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()
|