diff options
| author | 1992414357@qq.com <1992414357@qq.com> | 2025-06-14 16:13:57 +0800 |
|---|---|---|
| committer | 1992414357@qq.com <1992414357@qq.com> | 2025-06-14 16:13:57 +0800 |
| commit | 70af7ac1dee88dee9197abc626982d6555aeb97a (patch) | |
| tree | 20db4c0da0fd86ac3dc9e984245561d7e2692d43 /core/bindings/lang/clang/src | |
| parent | 9d55a51782e811e8a71cda1a3d7872371ec54aeb (diff) | |
Add Controller Ffi Interface
Diffstat (limited to 'core/bindings/lang/clang/src')
| -rw-r--r-- | core/bindings/lang/clang/src/data/mod.rs | 3 | ||||
| -rw-r--r-- | core/bindings/lang/clang/src/data/ngpd_controller.rs | 309 |
2 files changed, 311 insertions, 1 deletions
diff --git a/core/bindings/lang/clang/src/data/mod.rs b/core/bindings/lang/clang/src/data/mod.rs index c93e7f0..ca432f9 100644 --- a/core/bindings/lang/clang/src/data/mod.rs +++ b/core/bindings/lang/clang/src/data/mod.rs @@ -1,3 +1,4 @@ pub mod ngpd_player; pub mod ngpd_message; -mod ngpd_game_info;
\ No newline at end of file +mod ngpd_game_info; +mod ngpd_controller;
\ No newline at end of file diff --git a/core/bindings/lang/clang/src/data/ngpd_controller.rs b/core/bindings/lang/clang/src/data/ngpd_controller.rs new file mode 100644 index 0000000..923218b --- /dev/null +++ b/core/bindings/lang/clang/src/data/ngpd_controller.rs @@ -0,0 +1,309 @@ +use crate::data::ngpd_message::{FfiControlMessage, FfiGameMessage}; +use crate::data::ngpd_player::FfiPlayer; +use nogamepads::entry_mutex; +use nogamepads_core::data::controller::controller_data::ControllerData; +use nogamepads_core::data::controller::controller_runtime::ControllerRuntime; +use nogamepads_core::data::message::message_enums::ControlMessage; +use nogamepads_core::data::player::player_data::Player; +use std::ffi::{c_char, c_double, c_void, CStr}; +use std::sync::{Arc, Mutex}; + +#[repr(C)] +pub struct FfiControllerData(*mut c_void); + +#[repr(C)] +pub struct FfiControllerRuntime { + inner: *mut c_void, + drop_fn: extern "C" fn(*mut c_void), +} + +impl FfiControllerData { + + /// Create controller data + #[unsafe(no_mangle)] + pub extern "C" fn controller_data_new() -> *mut FfiControllerData { + let controller_data = ControllerData::default(); + let raw = Box::into_raw(Box::new(FfiControllerData(Box::into_raw(Box::new(controller_data)) as *mut _))); + raw + } + + /// Bind player to controller + #[unsafe(no_mangle)] + #[allow(unsafe_op_in_unsafe_fn)] + pub unsafe extern "C" fn controller_data_bind_player( + controller: *mut FfiControllerData, + ffi_player: *mut FfiPlayer + ) { + assert!(!controller.is_null(), "ControllerData pointer is null"); + assert!(!ffi_player.is_null(), "FfiPlayer pointer is null"); + + let ffi_player_ref = unsafe { &*ffi_player }; + + // Convert FfiPlayer to Player + let player = Player::try_from(&*ffi_player_ref).unwrap_or_default(); + + // Get a mutable reference to the inner ControllerData + let controller_inner = unsafe { &mut *((*controller).0 as *mut ControllerData) }; + controller_inner.bind_player(player); + + // Release the FFI Player + drop(Box::from_raw(ffi_player)); + } + + /// Build runtime + #[unsafe(no_mangle)] + #[allow(unsafe_op_in_unsafe_fn)] + pub unsafe extern "C" fn controller_data_build_runtime( + controller: *mut FfiControllerData + ) -> *mut FfiControllerRuntime { + assert!(!controller.is_null(), "ControllerData pointer is null"); + + // Take ownership + let controller_box = unsafe { Box::from_raw(controller) }; + let raw_data = (*controller_box).0; + + // Convert ControllerData + let controller_data = unsafe { Box::from_raw(raw_data as *mut ControllerData) }; + let runtime = controller_data.runtime(); + + // Define custom drop function + extern "C" fn drop_runtime(raw: *mut c_void) { + unsafe { + let arc_ptr = raw as *const Arc<Mutex<ControllerRuntime>>; + drop(Arc::from_raw(arc_ptr)); + } + } + + // Convert to an FFI-safe structure + let arc_raw = Arc::into_raw(runtime.clone()) as *mut c_void; + + Box::into_raw(Box::new(FfiControllerRuntime { + inner: arc_raw, + drop_fn: drop_runtime, + })) + } + + /// Free ControllerData memory + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_data_free(controller: *mut FfiControllerData) { + if controller.is_null() { + return; + } + + let controller_box = unsafe { Box::from_raw(controller) }; + let raw_data = (*controller_box).0; + + if !raw_data.is_null() { + unsafe { + drop(Box::from_raw(raw_data as *mut ControllerData)); + } + } + } +} + +// ControllerRuntime implementation +impl FfiControllerRuntime { + + /// Close runtime and exit game + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_runtime_close( + runtime: *mut FfiControllerRuntime + ) { + if runtime.is_null() { + return; + } + + let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<ControllerRuntime>> }; + let arc_ref = unsafe { Arc::from_raw(arc_ptr) }; + + entry_mutex!(*arc_ref, |mutex_guard| { + mutex_guard.close(); + }); + + // Reconstruct Arc + let _ = Arc::into_raw(arc_ref); + } + + /// Send control message + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_runtime_send_message( + runtime: *mut FfiControllerRuntime, + control_message: *mut FfiControlMessage + ) { + if runtime.is_null() { + return; + } + + let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<ControllerRuntime>> }; + let arc_ref = unsafe { Arc::from_raw(arc_ptr) }; + let msg = unsafe { ControlMessage::from(control_message.read()) }; + + entry_mutex!(*arc_ref, |mutex_guard| { + mutex_guard.send_message(msg); + }); + + let _ = Arc::into_raw(arc_ref); + } + + /// Send text message + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_runtime_send_text_message( + runtime: *mut FfiControllerRuntime, + message_ptr: *const c_char + ) { + if runtime.is_null() || message_ptr.is_null() { + return; + } + + let c_str = unsafe { CStr::from_ptr(message_ptr) }; + let text = c_str.to_string_lossy().into_owned(); + let message = FfiControlMessage::from(ControlMessage::Msg(text)); + + unsafe { + Self::controller_runtime_send_message( + runtime, + Box::into_raw(Box::new(message)) + ) + } + } + + /// Press a button + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_runtime_press_a_button( + runtime: *mut FfiControllerRuntime, + key: u8 + ) { + if runtime.is_null() { + return; + } + + let message = FfiControlMessage::from( + ControlMessage::Pressed(key) + ); + + unsafe { + Self::controller_runtime_send_message( + runtime, + Box::into_raw(Box::new(message)) + ) + } + } + + /// Release a button + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_runtime_release_a_button( + runtime: *mut FfiControllerRuntime, + key: u8 + ) { + if runtime.is_null() { + return; + } + + let message = FfiControlMessage::from( + ControlMessage::Released(key) + ); + + unsafe { + Self::controller_runtime_send_message( + runtime, + Box::into_raw(Box::new(message)) + ) + } + } + + /// Change axis value + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_runtime_change_axis( + runtime: *mut FfiControllerRuntime, + key: u8, + axis: c_double + ) { + if runtime.is_null() { + return; + } + + let message = FfiControlMessage::from( + ControlMessage::Axis(key, axis) + ); + + unsafe { + Self::controller_runtime_send_message( + runtime, + Box::into_raw(Box::new(message)) + ) + } + } + + /// Change direction value + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_runtime_change_direction( + runtime: *mut FfiControllerRuntime, + key: u8, + x: c_double, + y: c_double + ) { + if runtime.is_null() { + return; + } + + let message = FfiControlMessage::from( + ControlMessage::Dir(key, (x, y)) + ); + + unsafe { + Self::controller_runtime_send_message( + runtime, + Box::into_raw(Box::new(message)) + ) + } + } + + /// Pop a message from the queue + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_runtime_pop( + runtime: *mut FfiControllerRuntime + ) -> *mut FfiGameMessage { + if runtime.is_null() { + return std::ptr::null_mut(); + } + + let arc_ptr = unsafe { (*runtime).inner as *const Arc<Mutex<ControllerRuntime>> }; + let arc_ref = unsafe { Arc::from_raw(arc_ptr) }; + + let result = { + let mut pop_result = None; + + entry_mutex!(*arc_ref, |mutex_guard| { + pop_result = mutex_guard.pop(); + }); + + pop_result + }; + + // Reconstruct Arc + let _ = Arc::into_raw(arc_ref); + + if let Some(msg) = result { + // Convert to FFI type + let ffi_msg = Box::new(FfiGameMessage::from(msg)); + Box::into_raw(ffi_msg) + } else { + std::ptr::null_mut() + } + } + + /// Free runtime memory + #[unsafe(no_mangle)] + pub unsafe extern "C" fn controller_runtime_free(runtime: *mut FfiControllerRuntime) { + if runtime.is_null() { + return; + } + + let runtime_box = unsafe { Box::from_raw(runtime) }; + let drop_fn = (*runtime_box).drop_fn; + let raw = (*runtime_box).inner; + + // Call custom drop function + drop_fn(raw); + } +}
\ No newline at end of file |
