Locate the MobiFlight firmware source
mainhttps://github.com/MobiFlight/MobiFlight-FirmwareSource.repository·main·Indexed 43 days ago
https://github.com/mobiflight/mobiflight-connectorAn open-source Windows application that bridges flight simulators (MSFS, X-Plane, FSX, P3D) with custom hardware such as Arduino, MIDI, and USB HID. It provides a graphical user interface for creating peripherals without programming, includes a WebSocket API for CDU displays, and supports custom device integration and aircraft-specific configuration profiles.
https://github.com/MobiFlight/MobiFlight-FirmwareSource.When debugging virtual button events, the logs and the UI RawValue follow specific rules:
PRESS and RELEASE are logged as real hardware transitions.HOLD, REPEAT, and LONG_RELEASE are logged with their configured threshold. For example, a log might show ButtonName:300ms to indicate that the 300ms HoldDelay threshold was the trigger.PRESS or RELEASE always updates the RawValue in the UI, even if no configuration is currently bound to that specific event. This confirms the hardware is communicating.HOLD or REPEAT events only update the RawValue if there is a configuration specifically defining an onHold action. This prevents the UI from showing synthetic states that the user has no active control over.MobiFlight uses a synthetic button event generator to handle complex button behaviors like holding and repeating. Instead of tracking state within individual configuration items (which could lead to duplicate timers for the same physical button), the state is managed at the controller layer (MobiFlightCache, JoystickManager, or MidiBoardManager).
HoldDelay.RepeatDelay while the button remains pressed. Note that REPEAT events resolve to the same onHold action as HOLD, but are distinguished in logs/UI to show they are part of a repeat cycle.LongReleaseDelay has elapsed.The system uses a chain of three processing shapes:
HOLD and REPEAT events based on elapsed time.LEFT_FAST encoder event).Encoder event).MobiFlight Connector supports synthetic button events derived from physical button presses. This allows a single physical button to trigger different actions based on how long it is held.
HoldDelay and subsequently repeats at a RepeatDelay interval.RELEASE event that is reclassified as a LONG_RELEASE if the button was held longer than the configured LongReleaseDelay.onHold after 300ms, while another triggers an onHold after 1000ms. The system resolves these independently.LONG_RELEASE is not a separate hardware event; it is a decision made by each individual configuration during the dispatch phase. The hardware only ever sends a RELEASE, and each config checks if the HeldDurationMs exceeds its own LongReleaseDelay to decide whether to execute its onLongRelease action or its standard onRelease action.Messages sent between the Frontend and Backend use a Message<T> envelope. This structure ensures that the receiver can identify the type of payload before full deserialization occurs.
Envelope Structure:
key: A string representing the message type. By default, this is the name of the payload type (payload.GetType().Name).payload: The actual data object of type T.Serialization Details:
JsonConvert.SerializeObject.[JsonConverter] attributes on the model types themselves (e.g., Incoming/Converter/InputActionConverter.cs).Message<object> to extract the key, then looking up the registered Type for that key to deserialize the payload into its concrete type. Unknown keys are logged as warnings and dropped.{
"key": "string",
"payload": {}
}Some joystick hardware reports rotary encoders as two separate momentary buttons (e.g., an INC pulse and a DEC pulse). MobiFlight handles this via an Aggregate stage within the JoystickManager.
Encoder device output.onHold or onRelease triggers from encoder pulses.After aggregation, a Reclassify stage can detect rapid movements. For example, if 5 consecutive turns occur in under 1 second, the event is relabeled as a LEFT_FAST or RIGHT_FAST event.
MobiFlight Connector supports 'virtual' button events that are synthesized by the software rather than reported directly by physical hardware. These events allow you to trigger actions based on how a button is interacted with over time.
RELEASE).These events are managed by the SyntheticButtonEventGenerator and are integrated into the MobiFlightCache, JoystickManager, and MidiBoardManager. They are designed to follow the same execution pipeline as real PRESS and RELEASE events, ensuring that Preconditions, Modifiers, Status reporting, and UI updates behave consistently regardless of whether the event was physical or virtual.
The MobiFlight Connector uses a symmetric, non-blocking messaging architecture to communicate between the .NET WinForms application (backend) and the React frontend (browser/WebView2).
Instead of using the WebView2 postMessage bridge for all traffic, the .NET app hosts an in-process WebSocket server built using the BCL (System.Net.Sockets.TcpListener and System.Net.WebSockets.WebSocket.CreateFromStream). This allows for a scalable design where the frontend is one of potentially many clients (e.g., future mobile companion apps).
MessageExchange.Publish<T> to send messages. An IMessagePublisher (specifically WebSocketServerPublisher) broadcasts messages to all connected WebSocket sessions.messageClient that maps message keys to handlers. It communicates via a MessageTransport layer, which abstracts whether the underlying transport is WebSocketTransport or PostMessageTransport (used for E2E testing).{ key, payload } structure (defined in MobiFlight/BrowserMessages/Message.cs). .NET (WinForms) Browser (WebView2 / dev browser)
--------------- --------------------------------
producers ──► MessageExchange.Publish<T> components ──► publish(CommandMessage)
│ │
▼ ▼
IMessagePublisher messageClient
(WebSocketServerPublisher) (key→handlers map, single dispatch)
│ │
▼ ▼
MessageServer (BCL) ◄══ ws://127.0.0.1:PORT ══► MessageTransport
broadcast to all sessions (WebSocketTransport | PostMessageTransport)
│ ▲
▼ │
MessageExchange.PublishReceivedMessage useAppMessage(key, cb)MobiFlight is a hybrid application consisting of a C# backend and a React/TypeScript frontend:
PostMessage to send messages, which the C# side processes via handlers in BrowserMessages.While Hold, Repeat, and LongRelease are implemented, certain advanced features related to button state are currently deferred:
InputEventArgs for Button, Encoder, and Analog events. While this works for most consumers, it means the system does not yet have strictly typed delegates for each specific input type.WinCtrl CDU scripts mirror a simulated aircraft's CDU (Control Display Unit) screen to physical WinCtrl CDU hardware.
When MobiFlight detects a WinCTRL CDU device, it performs the following workflow:
ScriptMappings.json to find a matching AircraftMatchPattern.ScriptName).Matching Logic:
aircraft.cfg.sim/aircraft/view/acf_ui_name dataref.{
"VendorId": "0x4098",
"ProductIds": [ "WinwingCDUs" ],
"AircraftMatchPattern": "pmdg 737",
"ScriptName": "pmdg_737_winwing_cdu.py"
}The UserAuthenticationWebView is a deliberate exception to the WebSocket architecture. Because it navigates to foreign origins (Identity Providers) during the login process, it cannot use the local WebSocket server due to origin security restrictions.
window.chrome.webview.postMessage to send commands (e.g., CommandUserAuthentication{state:'cancelled'}) back to the app.FrontendPanel does not inject the WebSocket URL into this WebView. Instead, WebViewMessageReceiver provides a receive-only bridge that routes messages into MessageExchange.PublishReceivedMessage.