Jump to content
The simFlight Network Forums

StreamDeck Plugin for FSUIPC


pilotjohn

Recommended Posts

Hi,

Yes it looks to be very straightforward.

You'll need to add the DLL to the project via NuGet, then adapt the application to manage the connection to FSUIPC. There are templates available that show automatic connection handling (opening and detecting closing).

You will also need to be familiar with reading and writing offsets using the DLL. Everything you need can be found on the website:

http://fsuipc.paulhenty.com

For the virtual buttons you can use offsets 0x3340 and onwards directly. You can declare one 32-byte offset (as FsBitArray type) and have one large bitarray, or you could declare 9 4-byte bitarrays, and have one for each joystick.

Alternatively, offset 0x29F0 might be easier if you don't need to read or keep track of the virtual button states. Here you just supply the joystick and button number and the action (toggle, press, release).

If you opt for 0x29F0 you could either assemble the 4-byte integer value yourself, or declare 3 1-byte offsets (29F0, 29F1, 29F3). When you declare these it's important to have 29F0 declared last as it this address that will trigger the action.

This is a very broad overview. Let me know if need any more details.

Paul

Link to comment
Share on other sites

Brief questions...

1. I'm not sure if StreamDeck creates a separate instance for every panel or button (and how it actually instantiates the plugins). Is there are a large overhead for (potentially) creating lots of connections to FSUIPC? I assume Open() is at some global/singleton level per whatever process it's running in. So I can do IsOpen checks for each event, and just reconnect as needed.

2. Since I have to read 3340, is Process() synchronous? That is, can I do this in the StaremDeck events: Process() (to read), flip bits, Process() (to write)?

While 29F0 seems useful, I think I prefer to think of the virtual buttons as 288 independent items so I can group them by StreamDeck panel (I have 6 of them with 15 buttons each, and grouping each into a "device" wastes buttons). Anyway, not important. 🙂

Link to comment
Share on other sites

Quote

Is there are a large overhead for (potentially) creating lots of connections to FSUIPC? 

Not much. The Open() takes as much time as a Process(). Its usually in the region of 200ms.

Quote

 I assume Open() is at some global/singleton level per whatever process it's running in.

It is. The ideal scenario would be that your plugin is only instantiated once by the streamdeck. This will allow you to open the connection in the constructor and declare the offsets at the class level (once). Then every button press would just set the values of the the pre-declared offset(s) and call Process().

If there is one instance of the plugin per panel you'll have a separate FSUIPC connection for each device which isn't a problem.

If it's one instance per button then that will be a lot of open connections. I don't know if FSUIPC has a limit on how many simultaneous connections it will accept. You might have to keep opening and closing the connection for each button press. That would be inefficient, and may make the button press feel a bit sluggish, but it would probably be usable on modern PCs.

 

Quote

 Since I have to read 3340, is Process() synchronous? That is, can I do this in the StaremDeck events: Process() (to read), flip bits, Process() (to write)?

Yes the Process() call is synchronous. 

Paul

Link to comment
Share on other sites

Ok, so I have the plugin working, and FSUIPC connection succeeding (and failing when appropriate), but FSUIPC Button Assignment window doesn't seem to respond to button changes.

1. Are "Offset" instances registered globally by the client library during construction? How does Process() know to deal with them?

2. Is BitArray appropriate for offset 3340 (as I use it here)?

I have a Process() set/clear bit Process() as implemented here, but FSUIPC does not show a button press (even when I hard code 0 for the bit). Logs show things as expected (and so far experimentation reveals only 1 connection to FSUIPC per the one mobile device I'm using for testing).

Any thoughts about what I may be missing? Caveat: FSUIPC was not connected to MSFS during testing (since I was doing this on a VM).

Link to comment
Share on other sites

Quote

1. Are "Offset" instances registered globally by the client library during construction? How does Process() know to deal with them?

Yes they are registered globally when they are instantiated. They are processed whenever the group they are in is processed. Offsets are updated with new values from FSUIPC unless their value has been changed. In this case the new value is written to FSUIPC.

Quote

2. Is BitArray appropriate for offset 3340 (as I use it here)?

Yes, that's the easiest way to handle such offsets.

Quote

but FSUIPC does not show a button press

Any thoughts about what I may be missing? ... FSUIPC was not connected to MSFS

It might need to be connected.

I've tried your KeyPressed and KeyRelease code here (not via Stream Deck though as I don't have one) and it works fine.

I would try with FSUIPC connected. It might ignore IPC requests until its connected.

If it still doesn't work, check what is actually being sent to FSUIPC by enabling the "IPC Writes" logging in the Logging tab. Use the option to send the log to a console window to check in real time.

Have you considered adding the ability to send controls (events) directly to FSUIPC from the stream deck? e.g. 

            try
            {
                if (!FSUIPCConnection.IsOpen)
                {
                    Logger.Instance.LogMessage(TracingLevel.INFO, "Opening FSUIPC connection...");
                    FSUIPCConnection.Open();
                }

                Logger.Instance.LogMessage(TracingLevel.INFO, "Sending control " + (settings.ControlNumber).ToString());
                FSUIPCConnection.SendControlToFS(settings.ControlNumber, settings.Parameter);
            }
            catch (Exception ex)
            {
                Logger.Instance.LogMessage(TracingLevel.ERROR, ex.ToString());
            }

This would bypass the need to do any button mapping. 

e.g. sending control 66079 (with parameter 0) would raise the landing gear. 

Control numbers are listed in "The 2016 List of FSX and P3D Controls.pdf" in the FSUIPC Documents folder. Most controls don't need a parameter value so 0 is sent.

Paul

Link to comment
Share on other sites

1 hour ago, Paul Henty said:

Yes they are registered globally when they are instantiated. They are processed whenever the group they are in is processed. Offsets are updated with new values from FSUIPC unless their value has been changed. In this case the new value is written to FSUIPC.

Yes, that's the easiest way to handle such offsets.

It might need to be connected.

I've tried your KeyPressed and KeyRelease code here (not via Stream Deck though as I don't have one) and it works fine.

I would try with FSUIPC connected. It might ignore IPC requests until its connected.

Thanks, yeah connecting may be the issue... I'll have to test on my sim rig.

1 hour ago, Paul Henty said:

If it still doesn't work, check what is actually being sent to FSUIPC by enabling the "IPC Writes" logging in the Logging tab. Use the option to send the log to a console window to check in real time.

Have you considered adding the ability to send controls (events) directly to FSUIPC from the stream deck? e.g. 


            try
            {
                if (!FSUIPCConnection.IsOpen)
                {
                    Logger.Instance.LogMessage(TracingLevel.INFO, "Opening FSUIPC connection...");
                    FSUIPCConnection.Open();
                }

                Logger.Instance.LogMessage(TracingLevel.INFO, "Sending control " + (settings.ControlNumber).ToString());
                FSUIPCConnection.SendControlToFS(settings.ControlNumber, settings.Parameter);
            }
            catch (Exception ex)
            {
                Logger.Instance.LogMessage(TracingLevel.ERROR, ex.ToString());
            }

This would bypass the need to do any button mapping. 

e.g. sending control 66079 (with parameter 0) would raise the landing gear. 

Control numbers are listed in "The 2016 List of FSX and P3D Controls.pdf" in the FSUIPC Documents folder. Most controls don't need a parameter value so 0 is sent.

Paul

I did think about this and may do it. The immediate issue I'm trying to solve right now is to get rid of vJoy. If I start sending offsets directly, I loose the "UI" in FSUIPC so I was planning to just start with buttons. I also use some custom Lua for very non-standard things (like fuel selector, and ignition/magnetos), so I prefer to keep "config" for functionality in one place. If this works out, I'll add a generic "offset" plugin action, where you can just set the offset, size and value. I think Spad.Next is adding support for Stream Deck, and this would essentially provide that for FSUIPC.

Thanks for you help.

 

Link to comment
Share on other sites

  • 1 month later...

Hey @pilotjohn,

I'm currently working on a StreamDeck Plugin myself. It's on Github, you can try it if you want here .
It doesn't present / create any virtual Joystick Buttons that would be assignable in the Sim - the Assignment is done directly in the StreamDeck Plugin ("this StreamDeck Key fires Offset/Lua/Control/Macro/Script XY in the Sim").

Don't if that fits your use-case, but maybe it is a more straight-forward way? 🙂

 

Link to comment
Share on other sites

51 minutes ago, Fragtality said:

Hey @pilotjohn,

I'm currently working on a StreamDeck Plugin myself. It's on Github, you can try it if you want here .
It doesn't present / create any virtual Joystick Buttons that would be assignable in the Sim - the Assignment is done directly in the StreamDeck Plugin ("this StreamDeck Key fires Offset/Lua/Control/Macro/Script XY in the Sim").

Don't if that fits your use-case, but maybe it is a more straight-forward way? 🙂

 

Cool, I've thought about this, but it didn't make sense for my use case. I just needed vJoy off my system.

But generally in my view it's less advantageous to do this, and here's my reasoning:

  • 1. FSUIPC already has a very reach UI (list drop downs for all events, params etc.)
  • 2. FSUIPC already has a rich configuration language when the UI is not enough (e.g. advanced options like multi-actions etc.)
  • 3. FSUIPC has profile specific actions
  • 4. All of this is centralized in one place

What was missing is a way to trigger them from non-joystick devices, which you could solve by:

  • vJoy (problematic on my system and MSFS - I was using this)
  • FSUIPC's virtual joystick facility (removes a layer of abstraction)

If I solve this via the FSUIPC joystick facility, the value add of the plugin is something FSUIPC doesn't currently provide:

  • Triggering of these already-existing facilities from something that is not a joystick
  • The ability to expand to something FSUIPC does not currently do like long-press and double-press (when/if I need it) for which the UI can be relatively clean

Moving the configuration to the plugin actually has disadvantages in my view:

  • First, it's a lot of boilerplate UI re-implementation (which is going to be worse than FSUIPCs due to limitation)
  • The advanced logic (which doesn't have a UI in FSUIPC) will be hard to do in the limited UI space of Stream Deck
  • Add profile specific use cases and now you're also reimplementing conditionals
  • It would split my config (and if I want to move a button from Stream Deck to a joystick, I have to reconfigure instead of just re-assign)

The only limitation I see is the number of virtual buttons available in FSUIPC. I have 6 panels and may run out if I add long/double press (but hopefully Pete and/or John are willing to expand - they're very responsive and helpful in general)

Lastly, if I were to go down this path despite all the above, I would likely just skip the FSUIPC layer and use SimConnect. But, there's already several projects for this.

Of course your mileage may vary and maybe I missed a value proposition. I tend to be very pragmatic.

I'm not against it, just don't have a need. What I will likely implement, as mentioned, is different triggers based on long press and double press.

 

Link to comment
Share on other sites

It was simply my view, and you suggested maybe moving UI was a more straightforward way. I responded with my analysis (and why I chose what I did). I didn't say it's right, it was simply a design choice and reasoning of pros/cons. There can be many implementations. I'm sure there are benefits to you approach I missed (my use case is specific). I also pointed out an even further simplification that's possible (e.g. direct SimConnect), for which a UI is actually necessary. Take it or leave it.

"Thanks, but this doesn't suite my needs!" is not a collaborative process. If you understand my reasoning maybe you can help me see something I didn't (and vice versa). I certainly know my approach may be too minimal as suggested before.

 

Link to comment
Share on other sites

I just realized how "ignorant" your analysis was.
To be fair, I myself was also ignorant. At least I don't go ahead and write lengthy posts on things I didn't bother with.
You say this was "collaborative" - I can't judge if it was generally. But personally: it is not a style I'm compatible to. It didn't encourage me in any way to bother with your problem any longer, I just stumbled on the realization by accident (was looking for something else in the Offset Document).

The thing is:
Would I have spent some more minutes on your Code, especially on what FSUIPC Facility you're using there, I could have come to the conclusion, that basically you need/want to write a specific Value to a a specific Offset.
Would you have spent some more minutes (time at all?) to look into the Readme, you could have come to the conclusion, that my Plugin does allow to write any value to any offset.

So this virtual Joystick Facility is/was only a subset of my Plugin's capabilities all the time. I just need it to make it usable within the FSUIPC UI (does not send any Command while Sim is not ready) and if and how I can combine the keyDown/Up Mechanic (Set/Clear the Button) with my already built-in Long-Press Mechanic. Already made a quick test without that ready check - works straight away!

Don't know what it is worth for ... although there where some requests to have "something" for the StreamDeck, People seem to don't care anymore.
But at least I adhere to my "Design Goal" of the Plugin being a flexible and customizable tool a potential user can use it their way - although the two Users that are indeed using the Plugin and love it for its capabilities don't need this Facility.

Link to comment
Share on other sites

On 2/27/2021 at 8:50 PM, Fragtality said:

Should be ready in the next 2-3 days, want to add/improve some other things 😉 (crispier display on the XL, profile switching when multiple decks are connected, easier way to change the sim - I can't test but could eventually run with XP/2020).

Waiting for all this ;D would be nice!

Edited by LiamAllan
Link to comment
Share on other sites

Unfortunately the Workload in my normal Job is pretty high this Week, just came out of the last Session for today. So I'm slower than I wanted to be 😕 (But hey, it pays the Bills^^)

Depending on how big the urgency is: the "PilotsDeck-latest.zip" I just uploaded has most of it included already! Besides some further Optimizing/Testing/Polishing the only thing left is to add the Images with the "native" Resolution for the XL. (And obviously document all that in the Readme^^)

So if you wish, you can start with that! When the Release-Version includes these Images, there is nothing to reconfigure. The Plugin automatically loads the right Image for the specific StreamDeck (so Actions can easily move between different Decks and adapt automatically).

The vJoy Syntax is: <joystick>:<button> (numbers as documented in FSUIPC). You can add a ":t" after that for a toggle-type Button, without it the vJoystick's Button will be set as soon as the StreamDeck Button is pressed and will be cleared when it is released. But only with the ":t" you can have a Second Command ("Long Press") for that Button. Couldn't find another way to safely differentiate if user wants to press the vJoy Button as long as he wants or if he want's to fire the "Long Press" Command 😉  (It uses the 29F0 Offset for the technically intrigued)

The Profile Switching is more or less the same as currently documented. The Difference is now, that "Use Default" and "Default Profile" are per connected StreamDeck, the Profile Switching can also be enabled/disabled when the Button of the Profile Switcher is pushed on the Deck and the Profile reinstallation does not require to leave the PI anymore.

I've added all Executables to Plugin-Manifest (XP, 2020, FSX, FS9, P3D - hopefully spelled right). The other Setting (in the .config) does not exist anymore. So it should theoretically "just connect" without fiddling with the Configuration. I'd recommend to only have one Sim opened 😄 

Link to comment
Share on other sites

  • 1 year later...

@pilotjohn 

I would like to thank you for sharing the Streamdeck FSUIPC plugin.
I'm very interested in using it, but I don't understand how to add the two parameters requested when creating a new button:

Virtual Joystick:
Button Number:

I would like to assign simple shortcuts like turning the landing lights on and off.
Could you give me the documentation path to use it, or better, give me an example of how to fill in these fields?

I have access to the B738 PMDG SDK file and I can assign these shortcuts through FSUIPC.

Thank you very much.
I hope you can help me! Just to let you know I'm inexperienced with programming, but I've studied a lot on the subject.

I tried to do it this way and it didn't work:

https://prnt.sc/mq2Fkt5QE0KB

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use. Guidelines Privacy Policy We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.