Skip to main content

krun_input/
rust_to_c.rs

1use crate::header::{
2    KRUN_INPUT_CONFIG_FEATURE_QUERY, KRUN_INPUT_EVENT_PROVIDER_FEATURE_QUEUE,
3    krun_input_config_vtable, krun_input_event_provider_vtable,
4};
5use crate::{
6    InputAbsInfo, InputBackendError, InputConfigBackend, InputDeviceIds, InputEvent,
7    InputEventProviderBackend,
8};
9use std::ffi::c_void;
10use std::marker::PhantomData;
11use std::os::fd::{AsRawFd, BorrowedFd};
12use std::ptr;
13use std::ptr::null;
14
15pub trait ObjectNew<T: Sync> {
16    fn new(userdata: Option<&T>) -> Self;
17}
18
19pub trait InputQueryConfig {
20    /// Query device name into provided buffer
21    fn query_device_name(&self, name_buf: &mut [u8]) -> Result<u8, InputBackendError>;
22
23    /// Query device name into provided buffer
24    fn query_serial_name(&self, name_buf: &mut [u8]) -> Result<u8, InputBackendError>;
25
26    /// Query device IDs into provided structure  
27    fn query_device_ids(&self, ids: &mut InputDeviceIds) -> Result<(), InputBackendError>;
28
29    /// Query event capabilities bitmap for specific event type into provided buffer
30    fn query_event_capabilities(
31        &self,
32        event_type: u8,
33        bitmap_buf: &mut [u8],
34    ) -> Result<u8, InputBackendError>;
35
36    /// Query absolute axis information into provided structure
37    fn query_abs_info(
38        &self,
39        abs_axis: u8,
40        abs_info: &mut InputAbsInfo,
41    ) -> Result<(), InputBackendError>;
42
43    /// Query device properties into provided u32
44    fn query_properties(&self, properties: &mut [u8]) -> Result<u8, InputBackendError>;
45}
46
47pub trait InputEventsImpl {
48    /// Get the file descriptor that becomes ready when input events are available
49    fn get_read_notify_fd(&self) -> Result<BorrowedFd<'_>, InputBackendError>;
50
51    /// Fetch the next available input event, returns None if no events are available
52    fn next_event(&mut self) -> Result<Option<InputEvent>, InputBackendError>;
53}
54
55pub trait IntoInputConfig<T: Sync> {
56    fn into_input_config(userdata: Option<&T>) -> InputConfigBackend<'_>;
57}
58
59impl<I, UserData: Send + Sync> IntoInputConfig<UserData> for I
60where
61    I: InputQueryConfig + ObjectNew<UserData>,
62{
63    fn into_input_config(userdata: Option<&UserData>) -> InputConfigBackend<'_> {
64        extern "C" fn create_config_fn<T: Sync, I: InputQueryConfig + ObjectNew<T>>(
65            instance: *mut *mut c_void,
66            userdata: *const c_void,
67            _reserved: *const c_void,
68        ) -> i32 {
69            let actual_userdata = if userdata.is_null() {
70                None
71            } else {
72                Some(unsafe { &*(userdata as *const T) })
73            };
74
75            let config_obj = I::new(actual_userdata);
76            let boxed_config = Box::into_raw(Box::new(config_obj));
77            unsafe { *instance = boxed_config as *mut c_void };
78            0
79        }
80
81        extern "C" fn config_destroy_fn<I>(instance: *mut c_void) -> i32 {
82            if instance.is_null() {
83                return 0;
84            }
85            let _ = unsafe { Box::from_raw(instance as *mut I) };
86            0
87        }
88
89        extern "C" fn query_device_name_fn<T: Sync, I: InputQueryConfig + ObjectNew<T>>(
90            instance: *mut c_void,
91            name_buf: *mut u8,
92            name_buf_len: usize,
93        ) -> i32 {
94            let config_obj = unsafe { &*(instance as *const I) };
95            let name_buf_slice = unsafe { std::slice::from_raw_parts_mut(name_buf, name_buf_len) };
96
97            match config_obj.query_device_name(name_buf_slice) {
98                Ok(len) => len as i32,
99                Err(e) => e as i32,
100            }
101        }
102
103        extern "C" fn query_serial_name_fn<T: Sync, I: InputQueryConfig + ObjectNew<T>>(
104            instance: *mut c_void,
105            name_buf: *mut u8,
106            name_buf_len: usize,
107        ) -> i32 {
108            let config_obj = unsafe { &*(instance as *const I) };
109            let name_buf_slice = unsafe { std::slice::from_raw_parts_mut(name_buf, name_buf_len) };
110
111            match config_obj.query_serial_name(name_buf_slice) {
112                Ok(len) => len as i32,
113                Err(e) => e as i32,
114            }
115        }
116
117        extern "C" fn query_device_ids_fn<T: Sync, I: InputQueryConfig + ObjectNew<T>>(
118            instance: *mut c_void,
119            ids: *mut InputDeviceIds,
120        ) -> i32 {
121            let config_obj = unsafe { &*(instance as *const I) };
122            let ids = unsafe { &mut *ids };
123
124            match config_obj.query_device_ids(ids) {
125                Ok(()) => 0,
126                Err(e) => e as i32,
127            }
128        }
129
130        extern "C" fn query_event_capabilities_fn<T: Sync, I: InputQueryConfig + ObjectNew<T>>(
131            instance: *mut c_void,
132            event_type: u8,
133            bitmap_buf: *mut u8,
134            bitmap_buf_len: usize,
135        ) -> i32 {
136            let config_obj = unsafe { &*(instance as *const I) };
137            let bitmap_buf_slice =
138                unsafe { std::slice::from_raw_parts_mut(bitmap_buf, bitmap_buf_len) };
139
140            match config_obj.query_event_capabilities(event_type, bitmap_buf_slice) {
141                Ok(len) => len as i32,
142                Err(e) => e as i32,
143            }
144        }
145
146        extern "C" fn query_abs_info_fn<T: Sync, I: InputQueryConfig + ObjectNew<T>>(
147            instance: *mut c_void,
148            abs_axis: u8,
149            abs_info: *mut InputAbsInfo,
150        ) -> i32 {
151            let config_obj = unsafe { &*(instance as *const I) };
152            let abs_info = unsafe { &mut *abs_info };
153
154            match config_obj.query_abs_info(abs_axis, abs_info) {
155                Ok(()) => 0,
156                Err(e) => e as i32,
157            }
158        }
159
160        extern "C" fn query_properties_fn<T: Sync, I: InputQueryConfig + ObjectNew<T>>(
161            instance: *mut c_void,
162            bitmap_buf: *mut u8,
163            bitmap_buf_len: usize,
164        ) -> i32 {
165            let config_obj = unsafe { &*(instance as *const I) };
166            let bitmap_buf_slice =
167                unsafe { std::slice::from_raw_parts_mut(bitmap_buf, bitmap_buf_len) };
168
169            match config_obj.query_properties(bitmap_buf_slice) {
170                Ok(len) => len as i32,
171                Err(e) => e as i32,
172            }
173        }
174
175        let x = userdata.map_or(null(), |t| ptr::from_ref(t) as *const c_void);
176
177        InputConfigBackend {
178            features: KRUN_INPUT_CONFIG_FEATURE_QUERY as u64,
179            create_userdata: x,
180            create_userdata_lifetime: PhantomData,
181            create_fn: Some(create_config_fn::<UserData, I>),
182            vtable: krun_input_config_vtable {
183                destroy: Some(config_destroy_fn::<I>),
184                query_device_name: Some(query_device_name_fn::<UserData, I>),
185                query_serial_name: Some(query_serial_name_fn::<UserData, I>),
186                query_device_ids: Some(query_device_ids_fn::<UserData, I>),
187                query_event_capabilities: Some(query_event_capabilities_fn::<UserData, I>),
188                query_abs_info: Some(query_abs_info_fn::<UserData, I>),
189                query_properties: Some(query_properties_fn::<UserData, I>),
190            },
191        }
192    }
193}
194
195pub trait IntoInputEvents<T: Sync> {
196    fn into_input_events(userdata: Option<&T>) -> InputEventProviderBackend<'_>;
197}
198
199impl<I, UserData: Send + Sync> IntoInputEvents<UserData> for I
200where
201    I: InputEventsImpl + ObjectNew<UserData>,
202{
203    fn into_input_events(userdata: Option<&UserData>) -> InputEventProviderBackend<'_> {
204        extern "C" fn create_events_fn<T: Sync, I: InputEventsImpl + ObjectNew<T>>(
205            instance: *mut *mut c_void,
206            userdata: *const c_void,
207            _reserved: *const c_void,
208        ) -> i32 {
209            let actual_userdata = if userdata.is_null() {
210                None
211            } else {
212                Some(unsafe { &*(userdata as *const T) })
213            };
214
215            let events_obj = I::new(actual_userdata);
216            let boxed_events = Box::into_raw(Box::new(events_obj));
217            unsafe { *instance = boxed_events as *mut c_void };
218            0
219        }
220
221        extern "C" fn events_destroy_fn<I>(instance: *mut c_void) -> i32 {
222            if instance.is_null() {
223                return 0;
224            }
225            let _ = unsafe { Box::from_raw(instance as *mut I) };
226            0
227        }
228
229        extern "C" fn get_ready_efd_fn<I: InputEventsImpl>(instance: *mut c_void) -> i32 {
230            let events_obj = unsafe { &*(instance as *const I) };
231            match events_obj.get_read_notify_fd() {
232                Ok(fd) => fd.as_raw_fd(),
233                Err(e) => e as i32,
234            }
235        }
236
237        extern "C" fn next_event_fn<I: InputEventsImpl>(
238            instance: *mut c_void,
239            out_event: *mut crate::InputEvent,
240        ) -> i32 {
241            let events_obj = unsafe { &mut *(instance as *mut I) };
242            let out_event = unsafe { &mut *out_event };
243
244            match events_obj.next_event() {
245                Ok(Some(event)) => {
246                    *out_event = event;
247                    1
248                }
249                Ok(None) => 0,
250                Err(e) => e as i32,
251            }
252        }
253        let x: *const c_void = userdata.map_or(null(), |t| ptr::from_ref(t) as *const c_void);
254        InputEventProviderBackend {
255            features: KRUN_INPUT_EVENT_PROVIDER_FEATURE_QUEUE as u64,
256            create_userdata: x,
257            create_userdata_lifetime: PhantomData,
258            create_fn: Some(create_events_fn::<UserData, I>),
259            vtable: krun_input_event_provider_vtable {
260                destroy: Some(events_destroy_fn::<I>),
261                get_ready_efd: Some(get_ready_efd_fn::<I>),
262                next_event: Some(next_event_fn::<I>),
263            },
264        }
265    }
266}