Jump to content
The simFlight Network Forums

StreamDeck Plugin for FSUIPC


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 post
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 post
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 post
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 post
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 post
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 post
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 post
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 post
Share on other sites

Uhm ... okay?! 🤔

Thank you for your Insight on your Use-Case. I now know that it has to be this Approach because of completely different Premises.
It would have been completely fine to just write "Thanks, but this doesn't suite my needs!"

 

Link to post
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 post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • 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.