Rework events and add proper support for client events
Added - Client events are now implemented through `SimConnect::subscribe_to_client_event`, `SimConnect::unsubscribe_from_client_event` and `SimConnect::unsubscribe_from_all_client_events`. - `subscribe_to_client_events.rs` example has been added. - `SimConnectError::EventAlreadySubscribedTo` and `SimConnectError::EventNotSubscribedTo` error variants have been added. Changed - A second call to `SimConnect::subscribe_to_system_event` for the same event will now return an error of type `SimConnectError::EventAlreadySubscribedTo` instead of `SimConnectError::SimConnectException`. - The call to `SimConnect::unsubscribe_from_system_event` is now a NOOP when the system event is not subscribed to. - `SimConnectError::UnimplementedMessageType` has been renamed to `SimConnectError::UnimplementedNotification`. Removed - `SimConnect::register_event` has been replaced by the new client event functions. - `NotificationGroup` has been removed in favor of an internally managed notification group.
This commit is contained in:
@@ -25,10 +25,12 @@ fn main() {
|
||||
.allowlist_function("SimConnect_AddToDataDefinition")
|
||||
.allowlist_function("SimConnect_CallDispatch")
|
||||
.allowlist_function("SimConnect_ClearDataDefinition")
|
||||
.allowlist_function("SimConnect_ClearNotificationGroup")
|
||||
.allowlist_function("SimConnect_Close")
|
||||
.allowlist_function("SimConnect_GetNextDispatch")
|
||||
.allowlist_function("SimConnect_MapClientEventToSimEvent")
|
||||
.allowlist_function("SimConnect_Open")
|
||||
.allowlist_function("SimConnect_RemoveClientEvent")
|
||||
.allowlist_function("SimConnect_RequestDataOnSimObject")
|
||||
.allowlist_function("SimConnect_RequestFacilitiesList")
|
||||
.allowlist_function("SimConnect_SetNotificationGroupPriority")
|
||||
@@ -52,6 +54,11 @@ fn main() {
|
||||
.allowlist_type("SIMCONNECT_RECV_WAYPOINT_LIST")
|
||||
.allowlist_type("SIMCONNECT_RECV")
|
||||
.allowlist_var("SIMCONNECT_DATA_REQUEST_FLAG_CHANGED")
|
||||
.allowlist_var("SIMCONNECT_GROUP_PRIORITY_DEFAULT")
|
||||
.allowlist_var("SIMCONNECT_GROUP_PRIORITY_HIGHEST_MASKABLE")
|
||||
.allowlist_var("SIMCONNECT_GROUP_PRIORITY_HIGHEST")
|
||||
.allowlist_var("SIMCONNECT_GROUP_PRIORITY_LOWEST")
|
||||
.allowlist_var("SIMCONNECT_GROUP_PRIORITY_STANDARD")
|
||||
.allowlist_var("SIMCONNECT_OBJECT_ID_USER")
|
||||
.allowlist_var("SIMCONNECT_RECV_ID_VOR_LIST_HAS_DME")
|
||||
.allowlist_var("SIMCONNECT_RECV_ID_VOR_LIST_HAS_GLIDE_SLOPE")
|
||||
|
194
simconnect-sdk/src/domain/client_event.rs
Normal file
194
simconnect-sdk/src/domain/client_event.rs
Normal file
@@ -0,0 +1,194 @@
|
||||
use std::os::raw::c_char;
|
||||
|
||||
use crate::{bindings, SimConnectError};
|
||||
|
||||
// System Events start from 0 so we have to stagger the values to avoid collisions.
|
||||
pub(crate) const CLIENT_EVENT_DISCRIMINANT_START: u32 = 1024;
|
||||
|
||||
/// SimConnect Client Event Request.
|
||||
///
|
||||
/// Defined by <https://www.prepar3d.com/SDKv5/sdk/references/variables/event_ids.html>.
|
||||
/// Extended by <https://docs.flightsimulator.com/html/Programming_Tools/Event_IDs/Event_IDs.htm>.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, num_enum::TryFromPrimitive)]
|
||||
#[repr(u32)]
|
||||
#[non_exhaustive]
|
||||
pub enum ClientEventRequest {
|
||||
// ---------------
|
||||
// Aircraft Engine
|
||||
// ---------------
|
||||
/// Set throttle 1 exactly (0 to 16383).
|
||||
Throttle1Set = CLIENT_EVENT_DISCRIMINANT_START,
|
||||
/// Set throttle 2 exactly (0 to 16383).
|
||||
Throttle2Set,
|
||||
/// Set throttle 3 exactly (0 to 16383).
|
||||
Throttle3Set,
|
||||
/// Set throttle 4 exactly (0 to 16383).
|
||||
Throttle4Set,
|
||||
// ---------------
|
||||
// Aircraft Flight Controls
|
||||
// ---------------
|
||||
/// Sets elevator position (-16383 - +16383).
|
||||
AxisElevatorSet,
|
||||
// ---------------
|
||||
// Aircraft Miscellaneous Systems
|
||||
// ---------------
|
||||
/// Increment brake pressure. Note: These are simulated spring-loaded toe brakes, which will bleed back to zero over time.
|
||||
Brakes,
|
||||
/// Increments left brake pressure. Note: This is a simulated spring-loaded toe brake, which will bleed back to zero over time.
|
||||
BrakesLeft,
|
||||
/// Increments right brake pressure. Note: This is a simulated spring-loaded toe brake, which will bleed back to zero over time.
|
||||
BrakesRight,
|
||||
/// Sets left brake position from axis controller (e.g. joystick). -16383 (0 brakes) to +16383 (max brakes).
|
||||
AxisLeftBrakeSet,
|
||||
/// Sets right brake position from axis controller (e.g. joystick). -16383 (0 brakes) to +16383 (max brakes).
|
||||
AxisRightBrakeSet,
|
||||
/// Toggles parking brake on/off.
|
||||
ParkingBrakes,
|
||||
}
|
||||
|
||||
impl ClientEventRequest {
|
||||
pub(crate) fn into_c_char(self) -> *const c_char {
|
||||
match self {
|
||||
// Aircraft Engine
|
||||
Self::Throttle1Set => "THROTTLE1_SET\0".as_ptr() as *const c_char,
|
||||
Self::Throttle2Set => "THROTTLE2_SET\0".as_ptr() as *const c_char,
|
||||
Self::Throttle3Set => "THROTTLE3_SET\0".as_ptr() as *const c_char,
|
||||
Self::Throttle4Set => "THROTTLE4_SET\0".as_ptr() as *const c_char,
|
||||
// Aircraft Flight Controls
|
||||
Self::AxisElevatorSet => "AXIS_ELEVATOR_SET\0".as_ptr() as *const c_char,
|
||||
// Aircraft Miscellaneous Systems
|
||||
Self::Brakes => "BRAKES\0".as_ptr() as *const c_char,
|
||||
Self::BrakesLeft => "BRAKES_LEFT\0".as_ptr() as *const c_char,
|
||||
Self::BrakesRight => "BRAKES_RIGHT\0".as_ptr() as *const c_char,
|
||||
Self::AxisLeftBrakeSet => "AXIS_LEFT_BRAKE_SET\0".as_ptr() as *const c_char,
|
||||
Self::AxisRightBrakeSet => "AXIS_RIGHT_BRAKE_SET\0".as_ptr() as *const c_char,
|
||||
Self::ParkingBrakes => "PARKING_BRAKES\0".as_ptr() as *const c_char,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// SimConnect Client Event.
|
||||
///
|
||||
/// Defined by <https://www.prepar3d.com/SDKv5/sdk/references/variables/event_ids.html>.
|
||||
/// Extended by <https://docs.flightsimulator.com/html/Programming_Tools/Event_IDs/Event_IDs.htm>.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
pub enum ClientEvent {
|
||||
// ---------------
|
||||
// Aircraft Engine
|
||||
// ---------------
|
||||
/// Set throttle 1 exactly (0 to 16383).
|
||||
Throttle1Set {
|
||||
/// -16383 (0 throttle) to +16383 (max throttle).
|
||||
value: i32,
|
||||
},
|
||||
/// Set throttle 2 exactly (0 to 16383).
|
||||
Throttle2Set {
|
||||
/// -16383 (0 throttle) to +16383 (max throttle).
|
||||
value: i32,
|
||||
},
|
||||
/// Set throttle 3 exactly (0 to 16383).
|
||||
Throttle3Set {
|
||||
/// -16383 (0 throttle) to +16383 (max throttle).
|
||||
value: i32,
|
||||
},
|
||||
/// Set throttle 4 exactly (0 to 16383).
|
||||
Throttle4Set {
|
||||
/// -16383 (0 throttle) to +16383 (max throttle).
|
||||
value: i32,
|
||||
},
|
||||
// ---------------
|
||||
// Aircraft Flight Controls
|
||||
// ---------------
|
||||
/// Sets elevator position (-16383 - +16383).
|
||||
AxisElevatorSet {
|
||||
/// -16383 (full down) to +16383 (full up).
|
||||
value: i32,
|
||||
},
|
||||
// ---------------
|
||||
// Aircraft Miscellaneous Systems
|
||||
// ---------------
|
||||
/// Increment brake pressure. Note: These are simulated spring-loaded toe brakes, which will bleed back to zero over time.
|
||||
Brakes,
|
||||
/// Increments left brake pressure. Note: This is a simulated spring-loaded toe brake, which will bleed back to zero over time.
|
||||
BrakesLeft,
|
||||
/// Increments right brake pressure. Note: This is a simulated spring-loaded toe brake, which will bleed back to zero over time.
|
||||
BrakesRight,
|
||||
/// Sets left brake position from axis controller (e.g. joystick). -16383 (0 brakes) to +16383 (max brakes).
|
||||
AxisLeftBrakeSet {
|
||||
/// -16383 (0 brakes) to +16383 (max brakes).
|
||||
value: i32,
|
||||
},
|
||||
/// Sets right brake position from axis controller (e.g. joystick). -16383 (0 brakes) to +16383 (max brakes).
|
||||
AxisRightBrakeSet {
|
||||
/// -16383 (0 brakes) to +16383 (max brakes).
|
||||
value: i32,
|
||||
},
|
||||
/// Toggles parking brake on/off.
|
||||
ParkingBrakes,
|
||||
}
|
||||
|
||||
impl TryFrom<&bindings::SIMCONNECT_RECV_EVENT> for ClientEvent {
|
||||
type Error = SimConnectError;
|
||||
|
||||
fn try_from(event: &bindings::SIMCONNECT_RECV_EVENT) -> Result<Self, Self::Error> {
|
||||
let request = ClientEventRequest::try_from(event.uEventID)
|
||||
.map_err(|_| SimConnectError::UnimplementedEventType(event.uEventID))?;
|
||||
|
||||
match request {
|
||||
// Aircraft Engine
|
||||
ClientEventRequest::Throttle1Set => Ok(Self::Throttle1Set {
|
||||
value: event.dwData as i32,
|
||||
}),
|
||||
ClientEventRequest::Throttle2Set => Ok(Self::Throttle2Set {
|
||||
value: event.dwData as i32,
|
||||
}),
|
||||
ClientEventRequest::Throttle3Set => Ok(Self::Throttle3Set {
|
||||
value: event.dwData as i32,
|
||||
}),
|
||||
ClientEventRequest::Throttle4Set => Ok(Self::Throttle4Set {
|
||||
value: event.dwData as i32,
|
||||
}),
|
||||
// Aircraft Flight Controls
|
||||
ClientEventRequest::AxisElevatorSet => Ok(Self::AxisElevatorSet {
|
||||
value: event.dwData as i32,
|
||||
}),
|
||||
// Aircraft Miscellaneous Systems
|
||||
ClientEventRequest::Brakes => Ok(Self::Brakes),
|
||||
ClientEventRequest::BrakesLeft => Ok(Self::BrakesLeft),
|
||||
ClientEventRequest::BrakesRight => Ok(Self::BrakesRight),
|
||||
ClientEventRequest::AxisLeftBrakeSet => Ok(Self::AxisLeftBrakeSet {
|
||||
value: event.dwData as i32,
|
||||
}),
|
||||
ClientEventRequest::AxisRightBrakeSet => Ok(Self::AxisRightBrakeSet {
|
||||
value: event.dwData as i32,
|
||||
}),
|
||||
ClientEventRequest::ParkingBrakes => Ok(Self::ParkingBrakes),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ClientEvent> for (ClientEventRequest, i32) {
|
||||
fn from(event: ClientEvent) -> Self {
|
||||
match event {
|
||||
// Aircraft Engine
|
||||
ClientEvent::Throttle1Set { value } => (ClientEventRequest::Throttle1Set, value),
|
||||
ClientEvent::Throttle2Set { value } => (ClientEventRequest::Throttle2Set, value),
|
||||
ClientEvent::Throttle3Set { value } => (ClientEventRequest::Throttle3Set, value),
|
||||
ClientEvent::Throttle4Set { value } => (ClientEventRequest::Throttle4Set, value),
|
||||
// Aircraft Flight Controls
|
||||
ClientEvent::AxisElevatorSet { value } => (ClientEventRequest::AxisElevatorSet, value),
|
||||
// Aircraft Miscellaneous Systems
|
||||
ClientEvent::Brakes => (ClientEventRequest::Brakes, 0),
|
||||
ClientEvent::BrakesLeft => (ClientEventRequest::BrakesLeft, 0),
|
||||
ClientEvent::BrakesRight => (ClientEventRequest::BrakesRight, 0),
|
||||
ClientEvent::AxisLeftBrakeSet { value } => {
|
||||
(ClientEventRequest::AxisLeftBrakeSet, value)
|
||||
}
|
||||
ClientEvent::AxisRightBrakeSet { value } => {
|
||||
(ClientEventRequest::AxisRightBrakeSet, value)
|
||||
}
|
||||
ClientEvent::ParkingBrakes => (ClientEventRequest::ParkingBrakes, 0),
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,15 +1,15 @@
|
||||
mod client_event;
|
||||
mod condition;
|
||||
mod data_type;
|
||||
mod events;
|
||||
mod facilities;
|
||||
mod notification;
|
||||
mod notification_group;
|
||||
mod period;
|
||||
mod system_event;
|
||||
|
||||
pub use client_event::*;
|
||||
pub use condition::*;
|
||||
pub use data_type::*;
|
||||
pub use events::*;
|
||||
pub use facilities::*;
|
||||
pub use notification::*;
|
||||
pub use notification_group::*;
|
||||
pub use period::*;
|
||||
pub use system_event::*;
|
||||
|
@@ -1,6 +0,0 @@
|
||||
/// SimConnect event notification group.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[repr(u32)]
|
||||
pub enum NotificationGroup {
|
||||
Group0,
|
||||
}
|
@@ -268,38 +268,3 @@ impl TryFrom<&bindings::SIMCONNECT_RECV_EVENT_FRAME> for SystemEvent {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const CLIENT_EVENT_START: u32 = 128;
|
||||
|
||||
/// SimConnect Client Event.
|
||||
///
|
||||
/// WIP. As defined by <https://www.prepar3d.com/SDKv5/sdk/references/variables/event_ids.html>.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, num_enum::TryFromPrimitive)]
|
||||
#[repr(u32)]
|
||||
#[non_exhaustive]
|
||||
pub enum ClientEvent {
|
||||
// Aircraft Engine
|
||||
/// Set throttles max.
|
||||
ThrottleFull = CLIENT_EVENT_START,
|
||||
// ---------------
|
||||
// Aircraft Miscellaneous Systems
|
||||
/// Increment brake pressure. Note: These are simulated spring-loaded toe brakes, which will bleed back to zero over time.
|
||||
Brakes,
|
||||
/// Increments left brake pressure. Note: This is a simulated spring-loaded toe brake, which will bleed back to zero over time.
|
||||
BrakesLeft,
|
||||
/// Sets left brake position from axis controller (e.g. joystick). -16383 (0 brakes) to +16383 (max brakes).
|
||||
AxisLeftBrakeSet,
|
||||
}
|
||||
|
||||
impl ClientEvent {
|
||||
pub(crate) fn into_c_char(self) -> *const c_char {
|
||||
match self {
|
||||
// Aircraft Engine
|
||||
ClientEvent::ThrottleFull => "THROTTLE_FULL\0".as_ptr() as *const c_char,
|
||||
// Aircraft Miscellaneous Systems
|
||||
ClientEvent::Brakes => "BRAKES\0".as_ptr() as *const c_char,
|
||||
ClientEvent::BrakesLeft => "BRAKES_LEFT\0".as_ptr() as *const c_char,
|
||||
ClientEvent::AxisLeftBrakeSet => "AXIS_LEFT_BRAKE_SET\0".as_ptr() as *const c_char,
|
||||
}
|
||||
}
|
||||
}
|
@@ -13,15 +13,19 @@ pub enum SimConnectError {
|
||||
/// An unimplemented event type has been received by the SDK.
|
||||
#[error("Unimplemented event in the SDK: {0}")]
|
||||
UnimplementedEventType(u32),
|
||||
/// An unimplemented message type has been received by the SDK.
|
||||
/// An unimplemented notification has been received by the SDK.
|
||||
#[error("Unimplemented notification in the SDK: {0}")]
|
||||
UnimplementedMessageType(i32),
|
||||
UnimplementedNotification(i32),
|
||||
/// Object already registered with the client instance.
|
||||
#[error("Object `{0}` has already been registered")]
|
||||
ObjectAlreadyRegistered(String),
|
||||
/// Object already registered with the client instance.
|
||||
#[error("Object `{0}` has not been registered")]
|
||||
ObjectNotRegistered(String),
|
||||
#[error("Event `{0}` has already been subscribed to")]
|
||||
EventAlreadySubscribedTo(String),
|
||||
#[error("Event `{0}` has not been subscribed to")]
|
||||
EventNotSubscribedTo(String),
|
||||
/// Object mismatch.
|
||||
#[error("Tried to convert object of type {actual} to {expected}")]
|
||||
ObjectMismatch { actual: String, expected: String },
|
||||
|
@@ -2,11 +2,13 @@ use std::{collections::HashMap, ffi::c_void};
|
||||
|
||||
use tracing::{error, span, trace, warn, Level};
|
||||
|
||||
use crate::{
|
||||
as_c_string, bindings, helpers::fixed_c_str_to_string, ok_if_fail, success, Airport,
|
||||
ClientEvent, Notification, Object, SimConnectError, SystemEvent, Waypoint, CLIENT_EVENT_START,
|
||||
NDB, VOR,
|
||||
use crate::domain::{
|
||||
Airport, ClientEvent, ClientEventRequest, Notification, Object, SystemEvent,
|
||||
SystemEventRequest, Waypoint, CLIENT_EVENT_DISCRIMINANT_START, NDB, VOR,
|
||||
};
|
||||
use crate::helpers::fixed_c_str_to_string;
|
||||
use crate::simconnect::EventRegister;
|
||||
use crate::{as_c_string, bindings, ok_if_fail, success, SimConnectError};
|
||||
|
||||
/// SimConnect SDK Client.
|
||||
///
|
||||
@@ -83,20 +85,22 @@ use crate::{
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct SimConnect {
|
||||
pub(super) handle: std::ptr::NonNull<c_void>,
|
||||
pub(super) next_request_id: u32,
|
||||
pub(super) registered_objects: HashMap<String, RegisteredObject>,
|
||||
pub(crate) handle: std::ptr::NonNull<c_void>,
|
||||
pub(crate) next_request_id: u32,
|
||||
pub(crate) registered_objects: HashMap<String, RegisteredObject>,
|
||||
pub(crate) system_event_register: EventRegister<SystemEventRequest>,
|
||||
pub(crate) client_event_register: EventRegister<ClientEventRequest>,
|
||||
}
|
||||
|
||||
/// A struct that represents a registered object.
|
||||
#[derive(Debug)]
|
||||
pub(super) struct RegisteredObject {
|
||||
pub(crate) struct RegisteredObject {
|
||||
pub id: u32,
|
||||
pub transient: bool,
|
||||
}
|
||||
|
||||
impl RegisteredObject {
|
||||
pub(super) fn new(id: u32, transient: bool) -> Self {
|
||||
pub(crate) fn new(id: u32, transient: bool) -> Self {
|
||||
Self { id, transient }
|
||||
}
|
||||
}
|
||||
@@ -126,6 +130,8 @@ impl SimConnect {
|
||||
})?,
|
||||
next_request_id: 0,
|
||||
registered_objects: HashMap::new(),
|
||||
system_event_register: EventRegister::new(),
|
||||
client_event_register: EventRegister::new(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -172,9 +178,8 @@ impl SimConnect {
|
||||
let event: &bindings::SIMCONNECT_RECV_EVENT =
|
||||
unsafe { &*(data_buf as *const bindings::SIMCONNECT_RECV_EVENT) };
|
||||
|
||||
if event.uEventID >= CLIENT_EVENT_START {
|
||||
let event = ClientEvent::try_from(event.uEventID)
|
||||
.map_err(|_| SimConnectError::UnimplementedEventType(event.uEventID))?;
|
||||
if event.uEventID >= CLIENT_EVENT_DISCRIMINANT_START {
|
||||
let event = ClientEvent::try_from(event)?;
|
||||
|
||||
Ok(Some(Notification::ClientEvent(event)))
|
||||
} else {
|
||||
@@ -393,7 +398,7 @@ impl SimConnect {
|
||||
bindings::SIMCONNECT_RECV_ID_SIMCONNECT_RECV_ID_NULL => Ok(None),
|
||||
id => {
|
||||
error!("Received unhandled notification ID: {}", id);
|
||||
Err(SimConnectError::UnimplementedMessageType(id))
|
||||
Err(SimConnectError::UnimplementedNotification(id))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -401,7 +406,7 @@ impl SimConnect {
|
||||
|
||||
/// Register a Request ID in the internal state so that the user doesn't have to manually manage Request IDs.
|
||||
#[tracing::instrument(name = "SimConnect::new_request_id", level = "trace", skip(self))]
|
||||
pub(super) fn new_request_id(
|
||||
pub(crate) fn new_request_id(
|
||||
&mut self,
|
||||
type_name: String,
|
||||
transient: bool,
|
||||
@@ -436,7 +441,7 @@ impl SimConnect {
|
||||
level = "trace",
|
||||
skip(self)
|
||||
)]
|
||||
pub(super) fn unregister_request_id_by_type_name(&mut self, type_name: &str) -> Option<u32> {
|
||||
pub(crate) fn unregister_request_id_by_type_name(&mut self, type_name: &str) -> Option<u32> {
|
||||
self.registered_objects.remove(type_name).map(|obj| obj.id)
|
||||
}
|
||||
|
||||
@@ -446,7 +451,7 @@ impl SimConnect {
|
||||
level = "trace",
|
||||
skip(self)
|
||||
)]
|
||||
pub(super) fn get_type_name_by_request_id(&self, request_id: u32) -> Option<String> {
|
||||
pub(crate) fn get_type_name_by_request_id(&self, request_id: u32) -> Option<String> {
|
||||
self.registered_objects
|
||||
.iter()
|
||||
.find(|(_, v)| v.id == request_id)
|
||||
@@ -455,7 +460,7 @@ impl SimConnect {
|
||||
|
||||
/// Get the Type Name of a Request ID.
|
||||
#[tracing::instrument(name = "SimConnect::is_transient_request", level = "trace", skip(self))]
|
||||
pub(super) fn is_transient_request(&self, request_id: u32) -> Option<bool> {
|
||||
pub(crate) fn is_transient_request(&self, request_id: u32) -> Option<bool> {
|
||||
self.registered_objects
|
||||
.iter()
|
||||
.find(|(_, v)| v.id == request_id)
|
||||
@@ -472,7 +477,7 @@ impl SimConnect {
|
||||
fields(type_name, transient),
|
||||
skip(self)
|
||||
)]
|
||||
pub(super) fn unregister_potential_transient_request(
|
||||
pub(crate) fn unregister_potential_transient_request(
|
||||
&mut self,
|
||||
entry_number: u32,
|
||||
out_of: u32,
|
||||
|
48
simconnect-sdk/src/simconnect/event_register.rs
Normal file
48
simconnect-sdk/src/simconnect/event_register.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
use crate::SimConnectError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct EventRegister<T>
|
||||
where
|
||||
T: std::fmt::Debug + std::cmp::PartialEq,
|
||||
{
|
||||
items: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T> EventRegister<T>
|
||||
where
|
||||
T: std::fmt::Debug + std::cmp::PartialEq,
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
Self { items: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn is_registered(&self, item: T) -> bool {
|
||||
self.items.contains(&item)
|
||||
}
|
||||
|
||||
pub fn register(&mut self, item: T) -> Result<(), SimConnectError> {
|
||||
if self.items.contains(&item) {
|
||||
return Err(SimConnectError::EventAlreadySubscribedTo(format!(
|
||||
"{item:?}"
|
||||
)));
|
||||
}
|
||||
|
||||
self.items.push(item);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn unregister(&mut self, item: T) -> Result<(), SimConnectError> {
|
||||
if !self.items.contains(&item) {
|
||||
return Err(SimConnectError::EventNotSubscribedTo(format!("{item:?}")));
|
||||
}
|
||||
|
||||
self.items.retain(|i| *i != item);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.items.clear();
|
||||
}
|
||||
}
|
@@ -1,18 +1,68 @@
|
||||
use crate::{
|
||||
bindings, success, ClientEvent, NotificationGroup, SimConnect, SimConnectError,
|
||||
SystemEventRequest,
|
||||
bindings, success, ClientEventRequest, SimConnect, SimConnectError, SystemEventRequest,
|
||||
};
|
||||
|
||||
// In order to simplify the usage we're using a single notification group for all client events.
|
||||
const NOTIFICATION_GROUP_ID: u32 = 0;
|
||||
|
||||
impl SimConnect {
|
||||
/// Associates a client defined event with a Microsoft Flight Simulator event name.
|
||||
///
|
||||
/// WIP
|
||||
#[tracing::instrument(name = "SimConnect::register_event", level = "debug", skip(self))]
|
||||
pub fn register_event(
|
||||
&self,
|
||||
event: ClientEvent,
|
||||
notification_group: NotificationGroup,
|
||||
/// Request that a specific system event is notified.
|
||||
#[tracing::instrument(
|
||||
name = "SimConnect::subscribe_to_system_event",
|
||||
level = "debug",
|
||||
skip(self)
|
||||
)]
|
||||
pub fn subscribe_to_system_event(
|
||||
&mut self,
|
||||
event: SystemEventRequest,
|
||||
) -> Result<(), SimConnectError> {
|
||||
self.system_event_register.register(event)?;
|
||||
|
||||
success!(unsafe {
|
||||
bindings::SimConnect_SubscribeToSystemEvent(
|
||||
self.handle.as_ptr(),
|
||||
event as u32,
|
||||
event.into_c_char(),
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Request that notifications are no longer received for the specified system event.
|
||||
/// If the system event is not subscribed to, this function does nothing.
|
||||
#[tracing::instrument(
|
||||
name = "SimConnect::unsubscribe_from_system_event",
|
||||
level = "debug",
|
||||
skip(self)
|
||||
)]
|
||||
pub fn unsubscribe_from_system_event(
|
||||
&mut self,
|
||||
event: SystemEventRequest,
|
||||
) -> Result<(), SimConnectError> {
|
||||
if self.system_event_register.is_registered(event) {
|
||||
success!(unsafe {
|
||||
bindings::SimConnect_UnsubscribeFromSystemEvent(self.handle.as_ptr(), event as u32)
|
||||
})?;
|
||||
|
||||
self.system_event_register.clear();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Request that a specific client event is notified.
|
||||
#[tracing::instrument(
|
||||
name = "SimConnect::subscribe_to_client_event",
|
||||
level = "debug",
|
||||
skip(self)
|
||||
)]
|
||||
pub fn subscribe_to_client_event(
|
||||
&mut self,
|
||||
event: ClientEventRequest,
|
||||
) -> Result<(), SimConnectError> {
|
||||
self.client_event_register.register(event)?;
|
||||
|
||||
success!(unsafe {
|
||||
bindings::SimConnect_MapClientEventToSimEvent(
|
||||
self.handle.as_ptr(),
|
||||
@@ -24,7 +74,7 @@ impl SimConnect {
|
||||
success!(unsafe {
|
||||
bindings::SimConnect_AddClientEventToNotificationGroup(
|
||||
self.handle.as_ptr(),
|
||||
notification_group as u32,
|
||||
NOTIFICATION_GROUP_ID,
|
||||
event as u32,
|
||||
0,
|
||||
)
|
||||
@@ -33,43 +83,53 @@ impl SimConnect {
|
||||
success!(unsafe {
|
||||
bindings::SimConnect_SetNotificationGroupPriority(
|
||||
self.handle.as_ptr(),
|
||||
notification_group as u32,
|
||||
1,
|
||||
NOTIFICATION_GROUP_ID,
|
||||
bindings::SIMCONNECT_GROUP_PRIORITY_HIGHEST,
|
||||
)
|
||||
})
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Request that a specific system event is notified to the client.
|
||||
/// Request that notifications are no longer received for the specified client event.
|
||||
/// If the client event is not subscribed to, this function does nothing.
|
||||
#[tracing::instrument(
|
||||
name = "SimConnect::subscribe_to_system_event",
|
||||
name = "SimConnect::unsubscribe_from_client_event",
|
||||
level = "debug",
|
||||
skip(self)
|
||||
)]
|
||||
pub fn subscribe_to_system_event(
|
||||
pub fn unsubscribe_from_client_event(
|
||||
&mut self,
|
||||
event: SystemEventRequest,
|
||||
event: ClientEventRequest,
|
||||
) -> Result<(), SimConnectError> {
|
||||
success!(unsafe {
|
||||
bindings::SimConnect_SubscribeToSystemEvent(
|
||||
self.handle.as_ptr(),
|
||||
event as u32,
|
||||
event.into_c_char(),
|
||||
)
|
||||
})
|
||||
if self.client_event_register.is_registered(event) {
|
||||
success!(unsafe {
|
||||
bindings::SimConnect_RemoveClientEvent(
|
||||
self.handle.as_ptr(),
|
||||
NOTIFICATION_GROUP_ID,
|
||||
event as u32,
|
||||
)
|
||||
})?;
|
||||
|
||||
self.client_event_register.unregister(event)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Request that notifications are no longer received for the specified system event.
|
||||
/// Request that notifications are no longer received for any client event.
|
||||
#[tracing::instrument(
|
||||
name = "SimConnect::unsubscribe_from_system_event",
|
||||
name = "SimConnect::unsubscribe_from_all_client_events",
|
||||
level = "debug",
|
||||
skip(self)
|
||||
)]
|
||||
pub fn unsubscribe_from_system_event(
|
||||
&mut self,
|
||||
event: SystemEventRequest,
|
||||
) -> Result<(), SimConnectError> {
|
||||
pub fn unsubscribe_from_all_client_events(&mut self) -> Result<(), SimConnectError> {
|
||||
success!(unsafe {
|
||||
bindings::SimConnect_UnsubscribeFromSystemEvent(self.handle.as_ptr(), event as u32)
|
||||
})
|
||||
bindings::SimConnect_ClearNotificationGroup(self.handle.as_ptr(), NOTIFICATION_GROUP_ID)
|
||||
})?;
|
||||
|
||||
self.client_event_register.clear();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,11 @@
|
||||
mod base;
|
||||
mod event_register;
|
||||
mod events;
|
||||
mod facilities;
|
||||
mod objects;
|
||||
|
||||
pub(crate) use event_register::*;
|
||||
|
||||
pub use base::*;
|
||||
pub use events::*;
|
||||
pub use facilities::*;
|
||||
|
Reference in New Issue
Block a user