Wechselnde Joystick-IDs: Versuch einer Lösung...

  • Problemstellung:


    Bei der Belegung der Eingabegeräte hält sich Star Citizen nicht an Windows-Vorgaben sondern würfelt sich seine IDs selbst zusammen, so dass alle Tastenzuordnungen nicht mehr stimmen, wenn sich aus irgendeinem Grund die Reihenfolge der Eingabegeräte ändert. CIG selbst bietet zwar mit "pp_resortdevices" einen Konsolenbefehl an, mit dem man Joystick-IDs ändern kann - nur hat das zumindest bei mir noch nie funktioniert. Mary Lene Drake hat hier Wechselnde Joystick-IDs verhindern - Reihenfolge festlegen - Fragen rund um Crash & Star Citizen, technische Probleme etc. - C.R.A.S.H CORPS (crashcorps.space) eine Lösung vorgestellt, die durch EAC (EasyAntiCheat) allerdings nicht mehr verwendet werden kann. Tools wie HidHide, vJoy und Joystick Gremlin funktionieren bei mir zwar, sind aber recht aufwendig zu konfigurieren und zu pflegen.


    Die meisten Lösungen, von denen ich bisher diesbezüglich weiß, sind in der Regel hardwarebasiert: Die Joysticks sind z.B. an einen Hub mit einzeln schaltbaren Ports angeschlossen und müssen in einer bestimmten Reihenfolge wieder aktiviert werden, nachdem die jeweiligen Treiber deinstalliert worden sind.

    Ich wollte eine Software-Lösung haben, damit ich nicht unter meinem Tisch herumkriechen muss. Bisher hatte ich die Datei mit der Joystickbelegung manuell editiert, aber das ist mir im Lauf der Zeit auf die Nerven gegangen... Ich wollte auch mit Windows-Bordmitteln arbeiten, ohne zusätzliche Toos und dergleichen, daher habe ich versucht über die Powershell eine Lösung zu finden. Ausserdem bin ich programmiertechnisch ein Lauch und wollte mir einfach ein paar Powershell-Kenntnisse aneignen, das funktioniert bei mir immer besser anhand eines konkreten Problems statt durch irgendwelche synthetischen Aufgabestellungen in einer Laborumgebung.


    Disclaimer 1: Ich bin KEIN Programmierer, sondern hab nur etwas mit der Powershell herumgespielt hat. Ich bin mir sicher, dass ich teilweise sehr "seltsam" vorgegangen bin: Falls sich jemand damit beschäftigen will, bin ich gerne bereit dazuzulernen und bin für entsprechende Hinweise dankbar. Falls es nicht funktioniert, schickt mir bitte Eure Original-Datei wie im Lösungsansatz, Schritt 1 beschrieben und ich sehe mir das mal an...


    Disclaimer 2: Das folgende Script funktioniert NICHT bei HOSAS-Konfigurationen mit zwei oder mehreren identischen Devices: Ich frage die IDs der Geräte ab und wenn jemand z.B. zwei Thrustmaster T.16000 verwendet, dann sind die IDs identisch. Ich habe keine Lösung dafür gefunden die nicht ausgeufert wäre und vor allem: Ich kann das nicht testen, weil ich selbst nicht so ein Setup verwende...


    Disclaimer 3: Es funktioniert NUR, wenn sich an der Anzahl und den verwendeten Joysticks inzwischen nichts geändert hat!


    Disclaimer 4: Ich habe das folgende so gründlich wie möglich getestet - seid trotzdem vorsichtig, wenn Ihr es testet und erstellt Euch auf jeden Fall ein Backup der Konfigurationsdatei wie in Schritt 1 meines Lösungsansatzes beschrieben!


    Disclaimer 5: Das ganze ist erstmal nur für den "internen Dienstgebrauch" - ich habe mal vor, das auf Spectrum zu veröffentlichen, aber dazu muss es vorher noch etwas poliert werden. Wenn es Probleme gibt, bin ich hier einfach im TS zu erreichen und Ihr kennt mich - in Spectrum muss ich mich unter Umständen mit Leuten herumschlagen, die das ganze ernst nehmen - und dies hier ist nur ein Hobby-Projekt ....


    Mein Lösungsansatz:


    1. Nachdem man einmal die gewünschte Joystickbelegung gefunden hat, erstellt man sich gemäß https://support.robertsspacein…nd-import-custom-profiles eine "Originaldatei" indem indem man im Spiel unter "Options" im Reiter "Keybindings" auf "Advanced Controls Customization" klickt und dann im Menü "Control Profiles" den Punkt "Save Controls Settings" auswählt. Im anschliessenden Fenster vergibt mal als Dateinamen "original" und speichert mit "Save".




    Bilderquellen: ALLE (auch die nachfolgenden) Bilder sind eigene Screeshots!


    Dies erstellt im Star Citizen-Verzeichnes des Users (bei mir z.B. "D:\Roberts Space Industries\StarCitizen\LIVE\USER\Client\0\Controls\Mappings") eine Datei


    "layout_original_exported.xml"


    Diese Datei fasst man nun nicht mehr an - es sei denn man stellt fest, dass einem eine andere Belegung der Joysticktasten besser behagt. Dann erstellt man wie beschrieben eine neue Originaldatei (die alte Datei sicherheitshalber vorher löschen oder umbenennen!).




    2. Stellt man fest, das Star Citizen die Joysticks durcheinandergewürfelt hat, erstellt man eine Delta-Datei mit den Änderungen und nennt sie "changed".


    Man erhält im Verzeichnis eine Datei


    "layout_changed_exported.xml"



    3. Nun öffnet man eine Powershell (Windows-Startbutton und "Powershell" eintippen)...



    ...und kopiert dort die folgenden Zeilen hinein:


    ## EingabeVariablen deklarieren

    $SCPath = Read-Host -Prompt 'Input Location to Star Citizen-Mappings'

    $OriginalFile = "$SCPath"+'\layout_original_exported.xml'

    $ChangedFile = "$SCPath"+'\layout_changed_exported.xml'

    $ResultFile = "$SCPath"+'\RESULT.xml'


    ## Arrays für Joystickbezeichnungen deklarieren

    [System.Collections.ArrayList]$ProductOriginalArray = @()

    [System.Collections.ArrayList]$ProductChangedArray = @()

    [System.Collections.ArrayList]$ProductResultArray = @()


    ## Arrays für Joystick-IDs deklarieren

    [System.Collections.ArrayList]$InstancesOriginalArray = @()

    [System.Collections.ArrayList]$InstancesChangedArray = @()

    [System.Collections.ArrayList]$InstancesResultArray = @()


    ## Arrays für Joystick-Identifier aus Typ, ID und Bezeichnung

    [System.Collections.ArrayList]$OptionTypesOriginalArray = @()

    [System.Collections.ArrayList]$OptionTypesChangedArray = @()

    [System.Collections.ArrayList]$OptionTypesResultArray = @()


    ## Originaldatei einlesen

    [xml]$xmlElm = Get-Content -Path $OriginalFile

    [xml]$xmlAttr = Get-Content -Path $OriginalFile


    ## Ursprüngliche Joystickbelegungen umbenennen um Probleme beim späteren ändern zu vermeiden

    $OriginaljsRenamed = Get-Content $OriginalFile -RAW | ForEach-Object {

    $_ -replace 'js(\d{1})_', 'jsORIGINAL$1_'

    }


    ## Ursprüngliche Joystickbezeichnungen einlesen (Tastatur wird ignoriert)

    $ProductOriginalArray = $xmlAttr.ActionMaps.options | Where type -EQ 'joystick' | Select-Object -ExpandProperty 'product'


    ## Den ursprüngliche Joystickbezeichnungen zugeordnete IDs identifizieren

    foreach ($i in $ProductOriginalArray){

    $InstancesOriginalArray += $xmlAttr.ActionMaps.options |

    Where product -eq $i |

    Select-Object -ExpandProperty instance

    }


    ## Datei mit den Änderungen einlesen

    [xml]$xmlElm = Get-Content -Path $ChangedFile

    [xml]$xmlAttr = Get-Content -Path $ChangedFile


    ## geänderte Joystickbezeichnungen einlesen (wird nicht verwendet: Joystick-Anzahl und Typ müssen identisch sein)

    $ProductChangedArray = $xmlAttr.ActionMaps.options | Where type -EQ 'joystick' | Select-Object -ExpandProperty 'product'


    ## Die geänderten IDs werden gesucht

    foreach ($i in $ProductOriginalArray){

    $InstancesChangedArray += $xmlAttr.ActionMaps.options |

    Where product -eq $i |

    Select-Object -ExpandProperty instance

    }


    ## Die Joystick-Identifier der Orginaldatei werden nachgebaut

    for($i=0;$i-lt $ProductOriginalArray.count;$i++){

    $OptionTypesOriginalArray += -join("<options type=`"joystick`" instance=`"",$InstancesOriginalArray[$i],"`" Product=`"",$ProductOriginalArray[$i],"")

    }


    ## Die Joystick-Identifier der geänderten Datei werden nachgebaut

    for($i=0;$i-lt $ProductOriginalArray.count;$i++){

    $OptionTypesChangedArray += -join("<options type=`"joystick`" instance=`"",$InstancesChangedArray[$i],"`" Product=`"",$ProductOriginalArray[$i],"")

    }


    ## Das Ergebnis der umbenannten ursprüngliche Joystickbelegungen wird in ein Array geschrieben

    $InstancesResultArray = @($OriginaljsRenamed)


    ## Entsprechend der Anzahl der Joysticks werden die umbenannten Joystickbelegungen in die neuen Belegungen geändert

    for($i=0;$i-lt $ProductOriginalArray.count;$i++){

    $InstancesResultArray += ForEach-Object {

    $InstancesResultArray[$i] -replace -join("jsORIGINAL",$InstancesOriginalArray[$i]), -join("js",$InstancesChangedArray[$i])

    }

    }


    ## Der letzte Durchlauf der Joystickbelegungen wird in ein Array geschrieben

    $ProductResultArray = @($InstancesResultArray[$i])


    ## Die originalen Joystick-Identifier mit der alten ID werden durch die Identifier mit der neuen ID ersetzt

    for($i=0;$i-lt $ProductOriginalArray.count;$i++){

    $ProductResultArray += ForEach-Object {

    $ProductResultArray[$i] -replace [Regex]::Escape($OptionTypesOriginalArray[$i]),$OptionTypesChangedArray[$i]

    }

    }


    ## Die Ausgabedatei wird erstellt

    $ProductResultArray[$i] > $ResultFile


    Nach dem Ausführen wird man zunächst nach dem Pfad der Mapping-Datei im Starcitizen-Verzeichnisses gefragt (also z.B. bei mir "D:\Roberts Space Industries\StarCitizen\LIVE\USER\Client\0\Controls\Mappings") - es wird davon ausgegangen, dass dort sowohl eine Datei "layout_original_exported.xml" als auch eine Datei "layout_changed_exported.xml" vorhanden sind.



    Anschliessend findet man in diesem Pfad eine Datei "RESULT.xml" vor.

    Die Powershell kann geschlossen werden, nachdem man sich vergewissert hat, dass eine Datei "RESULT.xml" im Star Citizen Mappings-Verzeichnis erstellt wurde.



    4. Die erstellte Datei liest man in Star Citizen in der Konsole ein, indem innerhalb des Spiels die Konsole geöffnet wird (auf Deutschen Tastaturen ist das defaultmäßig das Caret "^", auf der Taste links neben der "1") und dann folgendes eingibt:


    pp_RebindKeys


    sowie


    pp_RebindKeys RESULT.xml


    Es ist nicht nötig, Star Citizen oder gar den PC neu zu starten.



    5. Enjoy!




    Nachsatz: Mir ist völlig klar, dass man noch verschiedene Mechanismen für die Fehlerbehandlung einbauen und dass man es für Anwender noch etwas freundlicher gestalten kann, mir kam es jetzt aber primär darauf an, den eigentlichen Algorithmus vorzustellen und weniger darauf, ein fertig poliertes Produkt zu präsentieren (Hey, wir spielen Star Citizen, wir sind Alpha-Builds gewohnt!)...

    Bilder

    57-b2b2b6d1-large.png?id=4a530b41
    56-cd1994f6-large.png

    ======= Capt "Athena Promachos" ==================================================

    ======== αἰὲν ἀριστεύειν καὶ ὑπείροχον ἔμμεναι ἄλλων =========================================

    ======== 80% Explorer | 80% Achiever | 40% Socialiser | 0% Killer ================================

  • Ja, das funktioniert noch: Ich habe damit die Joystickbelegung vom PU ins PTU transferiert. Man muss dort natürlich beachten, dass sich dort etwas ändern kann bzw. wird (Salvage gab es ja vorher noch nicht), aber zumindest die Grundlegenden Kommandos hat man dann erst mal.

    Du darfst das Skript gerne jederzeit anpassen - ich bitte sogar sehr darum. Mir kam es darauf an, eben gerade nicht mit Tools von Drittherstellern arbeiten zu müssen, damit es prinzipiell jeder verwenden kann, aber wenn Du ein PlugIn daraus machen möchtest: Nur zu! 8)

    57-b2b2b6d1-large.png?id=4a530b41
    56-cd1994f6-large.png

    ======= Capt "Athena Promachos" ==================================================

    ======== αἰὲν ἀριστεύειν καὶ ὑπείροχον ἔμμεναι ἄλλων =========================================

    ======== 80% Explorer | 80% Achiever | 40% Socialiser | 0% Killer ================================

  • Mille S'Abor

    Du musst mir nochmnal nachhelfen. Punkt 2 ist für mich nicht ganz klar. DIe changend XML

    Die Änderungen welche du ansprichst, ist ja die Reihenfolge oder?

    Zb: ich hab den VPC Stick von der 5 zur 3 gemacht

    Orginal

    Code
    1. <options type="keyboard" instance="1" Product="Tastatur {6F1D2B61-D5A0-11CF-BFC7-444553540000}"/>
    2. <options type="gamepad" instance="1" Product="Controller (Gamepad)"/>
    3. <options type="joystick" instance="1" Product="vJoy Device {12C820E0-8E65-11ED-8003-444553540000}"/>
    4. <options type="joystick" instance="2" Product="Joystick - HOTAS Warthog {E241FD50-8E65-11ED-8003-444553540000}"/>
    5. <options type="joystick" instance="4" Product="Throttle - HOTAS Warthog {ED0EF470-997F-11ED-8003-444553540000}"/>
    6. <options type="joystick" instance="3" Product="Saitek Pro Flight Rudder Pedals {EBB44670-997F-11ED-8002-444553540000}"/>
    7. <options type="joystick" instance="5" Product="L-VPC Stick MT-50CM2 {812F3344-0000-0000-0000-504944564944}"/>
    8. <options type="joystick" instance="6" Product="DSD 32 Button Controller - EST {8A3D04D8-0000-0000-0000-504944564944}"/>

    Changed:

    Code
    1. <options type="keyboard" instance="1" Product="Tastatur {6F1D2B61-D5A0-11CF-BFC7-444553540000}"/>
    2. <options type="gamepad" instance="1" Product="Controller (Gamepad)"/>
    3. <options type="joystick" instance="1" Product="vJoy Device {12C820E0-8E65-11ED-8003-444553540000}"/>
    4. <options type="joystick" instance="2" Product="Joystick - HOTAS Warthog {E241FD50-8E65-11ED-8003-444553540000}"/>
    5. <options type="joystick" instance="4" Product="Throttle - HOTAS Warthog {ED0EF470-997F-11ED-8003-444553540000}"/>
    6. <options type="joystick" instance="5" Product="Saitek Pro Flight Rudder Pedals {EBB44670-997F-11ED-8002-444553540000}"/>
    7. <options type="joystick" instance="3" Product="L-VPC Stick MT-50CM2 {812F3344-0000-0000-0000-504944564944}"/>
    8. <options type="joystick" instance="6" Product="DSD 32 Button Controller - EST {8A3D04D8-0000-0000-0000-504944564944}"/>

    Result: das gleiche wie Changed:

    Code
    1. <options type="keyboard" instance="1" Product="Tastatur {6F1D2B61-D5A0-11CF-BFC7-444553540000}"/>
    2. <options type="gamepad" instance="1" Product="Controller (Gamepad)"/>
    3. <options type="joystick" instance="1" Product="vJoy Device {12C820E0-8E65-11ED-8003-444553540000}"/>
    4. <options type="joystick" instance="2" Product="Joystick - HOTAS Warthog {E241FD50-8E65-11ED-8003-444553540000}"/>
    5. <options type="joystick" instance="4" Product="Throttle - HOTAS Warthog {ED0EF470-997F-11ED-8003-444553540000}"/>
    6. <options type="joystick" instance="5" Product="Saitek Pro Flight Rudder Pedals {EBB44670-997F-11ED-8002-444553540000}"/>
    7. <options type="joystick" instance="3" Product="L-VPC Stick MT-50CM2 {812F3344-0000-0000-0000-504944564944}"/>
    8. <options type="joystick" instance="6" Product="DSD 32 Button Controller - EST {8A3D04D8-0000-0000-0000-504944564944}"/>

    Wieso wählst du diesen Weg? Kann man nicht die orginal Datei editieren und dann

    pp_RebindKeys

    pp_RebindKeys layout_original_exported.xml


    Weil du vielleicht nicht in der orginal Datei rumschreiben willst?

    Wenn ja wieso schreibst du eine RESULT.xml?Wäre es nicht möglich die Kopie changed dann mit pp_RebindKeys layout_changed_exported.xml einzulesen?


    Ich frag, da ich in meinem Test keinerlei Unterschied zwischen changed und result erkennen kann.

    Muss aber zugeben, dass ich den Ablauf noch nicht ganz nachvollziehen kann.

    die "instance" ist meiner Einschätzung nach die Reihenfolge der Inputs oder ist es die reale Reihenfolge in der xml?



    Ahh hab etwas gefunden, dass muss ich später probieren. Das könnte meine Frage erklären. Muss aber erstmal im Tierpark spazieren :P

  • Vielen Dank für die Nachfrage und Dein Interesse Die Originaldatei wollte ich nicht anfassen - die dient einfach als Backup und als "Golden Master", falls irgendwas schiefgeht, kann man immer noch darauf zurückgreifen (ich bin da etwas paranoid). Die "Changed"-Datei habe ich z.B. im PTU erstellt - ohne irgendwelche Keybindings zu ändern. Damit hatte ich mit minimalem Aufwand eine Delta-Datei, in der NUR die Joysticks drinstehen.

    Beantwortet das Deine Frage? ich geb zu, es ginge einfacher, aber ich wollte flexibel bleiben...


    Die "instance" ist tatsächlich die Reihenfolge der Inputs - also die kann wild durcheinandergewürfelt sein. Bei Jan'D sieht sie z.B. so aus:



    Und hier mal im Vergleich "Original" bei mir:


    und "changed" bei mir:


    Code
    1. <options type="keyboard" instance="1" Product="Keyboard {6F1D2B61-D5A0-11CF-BFC7-444553540000}"/>
    2. <options type="joystick" instance="1" Product="WINWING JOYSTICK BASE1 + F18 GRIP {BE114098-0000-0000-0000-504944564944}"/>
    3. <options type="joystick" instance="2" Product="WINWING THROTTLE BASE1 + F18 HANDLE {BE224098-0000-0000-0000-504944564944}"/>
    4. <options type="joystick" instance="3" Product="T-Pendular-Rudder {B68F044F-0000-0000-0000-504944564944}"/>
    5. <options type="joystick" instance="4" Product="WINWING F18 STARTUP PANEL {BE034098-0000-0000-0000-504944564944}"/>
    6. <options type="joystick" instance="5" Product="WINWING F18 COMBAT READY PANEL {BE054098-0000-0000-0000-504944564944}"/>
    7. <options type="joystick" instance="6" Product="WINWING F18 TAKEOFF PANEL {BE044098-0000-0000-0000-504944564944}"/>
    8. <options type="joystick" instance="7" Product="F16 MFD 1 {B351044F-0000-0000-0000-504944564944}"/>
    9. <options type="joystick" instance="8" Product="F16 MFD 2 {B352044F-0000-0000-0000-504944564944}"/>

    57-b2b2b6d1-large.png?id=4a530b41
    56-cd1994f6-large.png

    ======= Capt "Athena Promachos" ==================================================

    ======== αἰὲν ἀριστεύειν καὶ ὑπείροχον ἔμμεναι ἄλλων =========================================

    ======== 80% Explorer | 80% Achiever | 40% Socialiser | 0% Killer ================================

    Einmal editiert, zuletzt von Mille S'Abor ()

  • Ich hab mal ein bissel rumgeschrieben!

    Bin aber noch nicht fertig! Dauert doch länger als gewollt :P

    Dachte ich mach das mal schnell..

    [eigener Screenshot]


    Ich muss das Speichern noch etwas verbessern. Aber soweit ist das Interface schonmal fast.....vorzeigbar.


    Ich hab heute bereits viel Zeit und Gehirnschmalz damit verbraucht, daraus eine brauchbare exe Datei zu machen.

    Auf dem Plan steht auch, dass man das in Zukunft aus JoystickGremlin aus Konfigurieren und Starten kann.

    Die Wunschliste wurde immer länger...


    Habt ihr Wünsche dazu? Deswegen eigentlich der Post hier

  • Ich überlege gerade ob man da einen Gegencheck der UUID mit durchführen sollte.

    Ich persönlich spiel ja immer mit Joystick Gremlin. Da ist das implimentiert. Habt ihr da Fehlererfahrungen?Müsst ihr die UUID anpassen?

    Code
    1. "Throttle - HOTAS Warthog": {
    2. "uuid": "{ED0EF470-997F-11ED-8003-444553540000}",
    3. "old_instance_nr": 2,
    4. "new_instance_nr": 2
    5. },