Skip to main content

simconnect_sdk/domain/
system_event.rs

1use std::os::raw::c_char;
2
3use crate::{bindings, fixed_c_str_to_string, SimConnectError};
4
5/// SimConnect System Event Request.
6#[derive(Debug, Copy, Clone, PartialEq, Eq, num_enum::TryFromPrimitive)]
7#[repr(u32)]
8#[non_exhaustive]
9pub enum SystemEventRequest {
10    /// Request a notification every second.
11    OneSecond = 0,
12    /// Request a notification every four seconds.
13    FourSeconds,
14    /// Request notifications six times per second. This is the same rate that joystick movement events are transmitted.
15    SixTimesPerSecond,
16    /// Request a notification when the aircraft flight dynamics file is changed. These files have a .AIR extension. The filename is returned.
17    AircraftLoaded,
18    /// Request a notification if the user aircraft crashes.
19    Crashed,
20    /// Request a notification when the crash cut-scene has completed.
21    CrashReset,
22    /// Request a notification when a flight is loaded. Note that when a flight is ended, a default flight is typically loaded, so these events will occur when flights and missions are started and finished. The filename of the flight loaded is returned.
23    FlightLoaded,
24    /// Request a notification when a flight is saved correctly. The filename of the flight saved is returned.
25    FlightSaved,
26    /// Request a notification when a new flight plan is activated. The filename of the activated flight plan is returned.
27    FlightPlanActivated,
28    /// Request a notification when the active flight plan is de-activated.
29    FlightPlanDeactivated,
30    /// Request notifications every visual frame.
31    Frame,
32    /// Request notifications when the scenario is paused or unpaused, and also immediately returns the current pause state.
33    Pause,
34    /// Request a notification when the scenario is paused.
35    Paused,
36    /// Request notifications for every visual frame that the simulation is paused.
37    PauseFrame,
38    /// Request a notification when the user changes the position of their aircraft through a dialog.
39    PositionChanged,
40    /// Request notifications when the scenario is running or not, and also immediately returns the current state.
41    Sim,
42    /// The simulator is running. Typically the user is actively controlling the vehicle which is on the ground, underwater or in the air.
43    SimStart,
44    /// The simulator is not running. Typically the user is loading a scenario, navigating the user interface or in a dialog.
45    SimStop,
46    /// Requests a notification when the master sound switch is changed. This request will also return the current state of the master sound switch immediately.
47    Sound,
48    /// Request a notification when the flight is un-paused.
49    Unpaused,
50    /// Requests a notification when the user aircraft view is changed. This request will also return the current view immediately.
51    View,
52}
53
54impl SystemEventRequest {
55    pub(crate) fn into_c_char(self) -> *const c_char {
56        match self {
57            SystemEventRequest::OneSecond => c"1sec".as_ptr() as *const c_char,
58            SystemEventRequest::FourSeconds => c"4sec".as_ptr() as *const c_char,
59            SystemEventRequest::SixTimesPerSecond => c"6Hz".as_ptr() as *const c_char,
60            SystemEventRequest::AircraftLoaded => c"AircraftLoaded".as_ptr() as *const c_char,
61            SystemEventRequest::Crashed => c"Crashed".as_ptr() as *const c_char,
62            SystemEventRequest::CrashReset => c"CrashReset".as_ptr() as *const c_char,
63            SystemEventRequest::FlightLoaded => c"FlightLoaded".as_ptr() as *const c_char,
64            SystemEventRequest::FlightSaved => c"FlightSaved".as_ptr() as *const c_char,
65            SystemEventRequest::FlightPlanActivated => {
66                c"FlightPlanActivated".as_ptr() as *const c_char
67            }
68            SystemEventRequest::FlightPlanDeactivated => {
69                c"FlightPlanDeactivated".as_ptr() as *const c_char
70            }
71            SystemEventRequest::Frame => c"Frame".as_ptr() as *const c_char,
72            SystemEventRequest::Pause => c"Pause".as_ptr() as *const c_char,
73            SystemEventRequest::Paused => c"Paused".as_ptr() as *const c_char,
74            SystemEventRequest::PauseFrame => c"PauseFrame".as_ptr() as *const c_char,
75            SystemEventRequest::PositionChanged => c"PositionChanged".as_ptr() as *const c_char,
76            SystemEventRequest::Sim => c"Sim".as_ptr() as *const c_char,
77            SystemEventRequest::SimStart => c"SimStart".as_ptr() as *const c_char,
78            SystemEventRequest::SimStop => c"SimStop".as_ptr() as *const c_char,
79            SystemEventRequest::Sound => c"Sound".as_ptr() as *const c_char,
80            SystemEventRequest::Unpaused => c"Unpaused".as_ptr() as *const c_char,
81            SystemEventRequest::View => c"View".as_ptr() as *const c_char,
82        }
83    }
84}
85
86/// Cockpit view type.
87#[derive(Debug, Copy, Clone, PartialEq, Eq, num_enum::TryFromPrimitive)]
88#[repr(u32)]
89pub enum ViewType {
90    /// No cockpit view.
91    None = 0,
92    /// 2D Panels in cockpit view.
93    Cockpit2D = bindings::SIMCONNECT_VIEW_SYSTEM_EVENT_DATA_COCKPIT_2D,
94    /// Virtual (3D) panels in cockpit view.
95    CockpitVirtual = bindings::SIMCONNECT_VIEW_SYSTEM_EVENT_DATA_COCKPIT_VIRTUAL,
96    /// Orthogonal (map) view.
97    Orthogonal = bindings::SIMCONNECT_VIEW_SYSTEM_EVENT_DATA_ORTHOGONAL,
98}
99
100/// SimConnect System Event Notification.
101#[derive(Debug, Clone, PartialEq)]
102#[non_exhaustive]
103pub enum SystemEvent {
104    /// A notification every second.
105    OneSecond,
106    /// A notification every four seconds.
107    FourSeconds,
108    /// A notification six times per second. This is the same rate that joystick movement events are transmitted.
109    SixTimesPerSecond,
110    /// A notification when the aircraft flight dynamics file is changed. These files have a .AIR extension. The filename is returned.
111    AircraftLoaded {
112        /// The returned filename.
113        file_name: String,
114    },
115    /// A notification if the user aircraft crashes.
116    Crashed,
117    /// A notification when the crash cut-scene has completed.
118    CrashReset,
119    /// A notification when a flight is loaded. Note that when a flight is ended, a default flight is typically loaded, so these events will occur when flights and missions are started and finished. The filename of the flight loaded is returned.
120    FlightLoaded {
121        /// The returned filename.
122        file_name: String,
123    },
124    /// A notification when a flight is saved correctly. The filename of the flight saved is returned.
125    FlightSaved {
126        /// The returned filename.
127        file_name: String,
128    },
129    /// A notification when a new flight plan is activated. The filename of the activated flight plan is returned.
130    FlightPlanActivated {
131        /// The returned filename.
132        file_name: String,
133    },
134    /// A notification when the active flight plan is de-activated.
135    FlightPlanDeactivated,
136    /// Notifications every visual frame.
137    Frame {
138        /// The visual frame rate in frames per second.
139        frame_rate: f32,
140        /// The simulation rate. For example if the simulation is running at four times normal speed -- 4X -- then `4.0` will be returned.
141        sim_speed: f32,
142    },
143    /// Notifications when the scenario is paused or unpaused, and also immediately returns the current pause state.
144    Pause {
145        /// The current pause state (`true` = paused or `false` = unpaused).
146        state: bool,
147    },
148    /// A notification when the scenario is paused.
149    Paused,
150    /// Notifications for every visual frame that the simulation is paused.
151    PauseFrame {
152        /// The visual frame rate in frames per second.
153        frame_rate: f32,
154        /// The simulation rate. For example if the simulation is running at four times normal speed -- 4X -- then 4.0 will be returned.
155        sim_speed: f32,
156    },
157    /// A notification when the user changes the position of their aircraft through a dialog.
158    PositionChanged,
159    /// Notifications when the scenario is running or not, and also immediately returns the current state.
160    Sim {
161        /// The current state (`true` = running or `false` = not running).
162        state: bool,
163    },
164    /// The simulator is running. Typically the user is actively controlling the vehicle which is on the ground, underwater or in the air.
165    SimStart,
166    /// The simulator is not running. Typically the user is loading a scenario, navigating the user interface or in a dialog.
167    SimStop,
168    /// A notification when the master sound switch is changed. This request will also return the current state of the master sound switch immediately.
169    Sound {
170        /// The current state of the master sound switch. `false` if the switch is off, `true` if the switch is on.
171        state: bool,
172    },
173    /// A notification when the flight is un-paused.
174    Unpaused,
175    /// A notification when the user aircraft view is changed. This request will also return the current view immediately.
176    View {
177        /// The current cockpit view type.
178        view: ViewType,
179    },
180}
181
182impl TryFrom<&bindings::SIMCONNECT_RECV_EVENT> for SystemEvent {
183    type Error = SimConnectError;
184
185    fn try_from(event: &bindings::SIMCONNECT_RECV_EVENT) -> Result<Self, Self::Error> {
186        let request = SystemEventRequest::try_from(event.uEventID)
187            .map_err(|_| SimConnectError::UnimplementedEventType(event.uEventID))?;
188
189        match request {
190            SystemEventRequest::OneSecond => Ok(SystemEvent::OneSecond),
191            SystemEventRequest::FourSeconds => Ok(SystemEvent::FourSeconds),
192            SystemEventRequest::SixTimesPerSecond => Ok(SystemEvent::SixTimesPerSecond),
193            SystemEventRequest::Crashed => Ok(SystemEvent::Crashed),
194            SystemEventRequest::CrashReset => Ok(SystemEvent::CrashReset),
195            SystemEventRequest::FlightPlanDeactivated => Ok(SystemEvent::FlightPlanDeactivated),
196            SystemEventRequest::Pause => Ok(SystemEvent::Pause {
197                state: event.dwData == 1,
198            }),
199            SystemEventRequest::Paused => Ok(SystemEvent::Paused),
200            SystemEventRequest::PositionChanged => Ok(SystemEvent::PositionChanged),
201            SystemEventRequest::Sim => Ok(SystemEvent::Sim {
202                state: event.dwData == 1,
203            }),
204            SystemEventRequest::SimStart => Ok(SystemEvent::SimStart),
205            SystemEventRequest::SimStop => Ok(SystemEvent::SimStop),
206            SystemEventRequest::Sound => Ok(SystemEvent::Sound {
207                state: event.dwData == bindings::SIMCONNECT_SOUND_SYSTEM_EVENT_DATA_MASTER,
208            }),
209            SystemEventRequest::Unpaused => Ok(SystemEvent::Unpaused),
210            SystemEventRequest::View => Ok(SystemEvent::View {
211                view: ViewType::try_from(event.dwData).unwrap_or(ViewType::None),
212            }),
213            _ => Err(SimConnectError::UnimplementedEventType(event.uEventID)),
214        }
215    }
216}
217
218impl TryFrom<&bindings::SIMCONNECT_RECV_EVENT_FILENAME> for SystemEvent {
219    type Error = SimConnectError;
220
221    fn try_from(event: &bindings::SIMCONNECT_RECV_EVENT_FILENAME) -> Result<Self, Self::Error> {
222        let request = SystemEventRequest::try_from(event._base.uEventID)
223            .map_err(|_| SimConnectError::UnimplementedEventType(event._base.uEventID))?;
224
225        match request {
226            SystemEventRequest::AircraftLoaded => {
227                let file_name = fixed_c_str_to_string(&event.szFileName);
228                Ok(SystemEvent::AircraftLoaded { file_name })
229            }
230            SystemEventRequest::FlightLoaded => {
231                let file_name = fixed_c_str_to_string(&event.szFileName);
232                Ok(SystemEvent::FlightLoaded { file_name })
233            }
234            SystemEventRequest::FlightSaved => {
235                let file_name = fixed_c_str_to_string(&event.szFileName);
236                Ok(SystemEvent::FlightSaved { file_name })
237            }
238            SystemEventRequest::FlightPlanActivated => {
239                let file_name = fixed_c_str_to_string(&event.szFileName);
240                Ok(SystemEvent::FlightPlanActivated { file_name })
241            }
242            _ => Err(SimConnectError::UnimplementedEventType(
243                event._base.uEventID,
244            )),
245        }
246    }
247}
248
249impl TryFrom<&bindings::SIMCONNECT_RECV_EVENT_FRAME> for SystemEvent {
250    type Error = SimConnectError;
251
252    fn try_from(event: &bindings::SIMCONNECT_RECV_EVENT_FRAME) -> Result<Self, Self::Error> {
253        let request = SystemEventRequest::try_from(event._base.uEventID)
254            .map_err(|_| SimConnectError::UnimplementedEventType(event._base.uEventID))?;
255
256        match request {
257            SystemEventRequest::Frame => Ok(SystemEvent::Frame {
258                frame_rate: event.fFrameRate,
259                sim_speed: event.fSimSpeed,
260            }),
261            SystemEventRequest::PauseFrame => Ok(SystemEvent::PauseFrame {
262                frame_rate: event.fFrameRate,
263                sim_speed: event.fSimSpeed,
264            }),
265            _ => Err(SimConnectError::UnimplementedEventType(
266                event._base.uEventID,
267            )),
268        }
269    }
270}