WhiteMagic / JoystickGremlin

A tool for configuring and managing joystick devices.
http://whitemagic.github.io/JoystickGremlin/
GNU General Public License v3.0
313 stars 45 forks source link

Add builtin binding support #473

Open edwardwbarber opened 1 year ago

edwardwbarber commented 1 year ago

This pull request adds bindings: a new way to select VJoy outputs for remap containers. A binding string, when assigned to a VJoy output, becomes an alternative dropdown selection within the remap VJoy selector. I have a short write up of how this binding process compares to R13 here. The short version is, bindings can simplify profile management within Joystick Gremlin by displaying the intended link from physical inputs to sim buttons/axes directly, instead of only showing the VJoy intermediary.

For example, if the binding "pitch" is set to VJoy 1 Y Axis, then the user can choose to remap a physical axis to VJoy 1 Y Axis (as usual) OR select "pitch" from the binding dropdown. In either case, the unused selector(s) will automatically synchronize with the chosen binding/VJoy output: in the end the remap will show the usual VJoy 1 / Y Axis dropdowns and, now, the "pitch" binding selection. The binding selection does not remove the existing method - it is simply an alternative option if the user wishes to use it.

Since most profiles can use large numbers of bindings, new Binding Exporter and Binding Importer tools are also included in this pull request. These allow VJoy-binding pairs both to be exported to, and imported from, sim configuration files. Sample scripts are provided for XPlane 11 and IL-2 Cliffs of Dover. An importer is also provided for CSV files, which can be convenient for importing from a generic command list. Custom scripts can also be added by users as needed. Guides for writing custom exporters and importers are included in exporter_plugins/README.md and importer_plugins/README.md.

To make all this work under the hood, this pull request introduces a new BoundVJoy class to track all VJoy InputItems which correspond to a specific binding over all Modes. Additional logic is added within the Profile class to allow for binding-based look-ups and to handle when conflicting bindings are added. A profile conversion is included to update old profiles (version 9 and lower) to include blank "binding" attributes in the profile XML file. However, since the output used by Remap is the same, all existing profile functionality is preserved.

In the UI, there are four main changes: (1) output VJoy device tabs now display a binding input box, similar to the existing description input box; (2) VJoy buttons are shown on VJoy device tabs, along with their bindings; (3) remap VJoy selectors now have a third dropdown menu for binding selection; (4) Binding Export and Binding Import dialogs are now available under Tools. Examples of these are included below.

New UI Example Change Description
new_vjoy_tab VJoy tab with buttons, binding entry box, and binding text display
new_remap Remap includes binding dropdown
new_toolsbinding_importbinding_export Binding import and export tools

For this pull request, I've combined much of the work into a few "feature-complete" commits, to help better identify which sets of changes go together. The commits themselves should lend more detail on the reasons for the specific changes added. Hopefully this makes it easier to see where the main changes / additions to the existing code are and why.

As a final note, I am well aware this does not fit into the scheme for the R14 release. Nonetheless, it is a feature I wanted for myself, so I went ahead and made it. On my own develop fork, I've included this work and a few R13 bugfixes (unrelated to this pull request) - if you want to give a working version a spin my that would be a good place to start. I've personally been using this setup for configuring new profiles over the past month or so. Finally, I added a conda environment file to make the build process a little easier, but that's the topic of another pull request... cheers!

WhiteMagic commented 1 year ago

Nice, and quite a lot of work, as I'm preventing myself from touching R13 I can't really integrate it in but anyone that's keen on trying this out should definitely give your repo a spin.

As for how it relates to R14. Well all of the UI and profile related aspects are not reusable as that changed (some is still changing). There won't be something as elaborate as you have done here but it will have the option to assign existing, lets call them "action trees", i.e. what currently is a container , to an input rather than specifying it from scratch. The main purpose of this is to copy things around and speed up minor modifications. Though that opens the door to have a "library" of such "action trees" that perform specific mappings and have a name.

The other bit that I'm trying to work out at the moment is how to get rid of the need to have vJoy tabs. The only reason they exist is that merge axis lives outside the normal input -> action realm and thus can't benefit from response curves etc. The currently plan is to make it so every action lives on physical inputs. However, that then requires an "intermediate output" layer that can be mapped to vJoy devices and have all kinds of other operations applied to it.

Another upside of R14 is that it shouldn't be too hard to add an action that has your remap logic in it. How to feed it with data is a bit of a different story but probably not impossible to figure out either. The other bit that goes along with that is that Gremlin should also be able to load actions not shipped with Gremlin directly by telling it where to look for them. Technically that was possible in R13 and before ... the code just never got told to do so.

edwardwbarber commented 1 year ago

Thanks for the kind words. I respect wanting to focus your effort on R14. I'm not sure I completely follow what you have in mind for "action trees" in R14 but I'm eager to see those changes when they are ready. Happy to adapt features of what I have here to the new release too, if applicable (I'm quite pleased with how the import/export functions worked out, for example).

WhiteMagic commented 1 year ago

They are a bit weird to explain in just words but effectively they are just a unit of stuff to do that are stored in a central library (per profile) and then can be assigned to the individual inputs. They can still be created on the fly as normal but once created it's possible to reuse them. Them being stored in a library means it's possible to import entire collection of them into a profile.

artesim commented 1 year ago

Hi, just wanted to drop a big "thank you", because this pull request is exactly what I need, I'll definitely check it out. Yesterday I was writing a little script to generate an Elite Dangerous config file where every single possible binding is assigned its own vjoy button, and extracted a map of "ED action" => "vjoy button" from all that. And my next step was supposed to be checking out Gremlin's code and see if I could implement exactly that... So yes, you're not alone, there's a real need for what you did here, great job ! :)

edwardwbarber commented 1 year ago

@artesim thanks for the kind words. I hope this suits your needs - if you have any questions, feel free to ping me on the gremlin discord channel. I don't have an importer/exporter written for Elite Dangerous, but it's probably not too hard to write one. If you do decide to, I'd be interested to see what you come up with. Cheers!