Skip to main content

pybevy_input/
gamepad_events.rs

1use bevy::input::gamepad::{
2    GamepadAxisChangedEvent as GamepadAxisChanged,
3    GamepadButtonChangedEvent as GamepadButtonChanged, GamepadButtonStateChangedEvent,
4    GamepadConnection, GamepadConnectionEvent,
5};
6pub use pybevy_core::PyMessage;
7use pybevy_macros::message_bridge;
8use pyo3::prelude::*;
9
10use crate::{
11    button_state::PyButtonState, gamepad_axis::PyGamepadAxis, gamepad_button::PyGamepadButton,
12};
13
14// ============================================================================
15// GamepadButtonChanged
16// ============================================================================
17
18#[pyclass(name = "GamepadButtonChanged", extends = PyMessage)]
19#[derive(Debug, Clone)]
20pub struct PyGamepadButtonChanged {
21    pub button: PyGamepadButton,
22    pub value: f32,
23}
24
25impl PyGamepadButtonChanged {
26    pub fn from_bevy(event: &GamepadButtonChanged) -> (Self, PyMessage) {
27        (
28            PyGamepadButtonChanged {
29                button: event.button.into(),
30                value: event.value,
31            },
32            PyMessage,
33        )
34    }
35}
36
37impl From<&GamepadButtonChanged> for PyGamepadButtonChanged {
38    fn from(event: &GamepadButtonChanged) -> Self {
39        PyGamepadButtonChanged {
40            button: event.button.into(),
41            value: event.value,
42        }
43    }
44}
45
46#[pymethods]
47impl PyGamepadButtonChanged {
48    #[new]
49    fn new(button: PyGamepadButton, value: f32) -> (Self, PyMessage) {
50        (PyGamepadButtonChanged { button, value }, PyMessage)
51    }
52
53    #[getter]
54    fn button(&self) -> PyGamepadButton {
55        self.button
56    }
57
58    #[getter]
59    fn value(&self) -> f32 {
60        self.value
61    }
62
63    fn __repr__(&self) -> String {
64        format!(
65            "GamepadButtonChanged(button={:?}, value={})",
66            self.button, self.value
67        )
68    }
69}
70
71// ============================================================================
72// GamepadAxisChanged
73// ============================================================================
74
75#[pyclass(name = "GamepadAxisChanged", extends = PyMessage)]
76#[derive(Debug, Clone)]
77pub struct PyGamepadAxisChanged {
78    pub axis: PyGamepadAxis,
79    pub value: f32,
80}
81
82impl PyGamepadAxisChanged {
83    pub fn from_bevy(event: &GamepadAxisChanged) -> (Self, PyMessage) {
84        (
85            PyGamepadAxisChanged {
86                axis: event.axis.into(),
87                value: event.value,
88            },
89            PyMessage,
90        )
91    }
92}
93
94impl From<&GamepadAxisChanged> for PyGamepadAxisChanged {
95    fn from(event: &GamepadAxisChanged) -> Self {
96        PyGamepadAxisChanged {
97            axis: event.axis.into(),
98            value: event.value,
99        }
100    }
101}
102
103#[pymethods]
104impl PyGamepadAxisChanged {
105    #[new]
106    fn new(axis: PyGamepadAxis, value: f32) -> (Self, PyMessage) {
107        (PyGamepadAxisChanged { axis, value }, PyMessage)
108    }
109
110    #[getter]
111    fn axis(&self) -> PyGamepadAxis {
112        self.axis
113    }
114
115    #[getter]
116    fn value(&self) -> f32 {
117        self.value
118    }
119
120    fn __repr__(&self) -> String {
121        format!(
122            "GamepadAxisChanged(axis={:?}, value={})",
123            self.axis, self.value
124        )
125    }
126}
127
128// ============================================================================
129// GamepadConnection
130// ============================================================================
131
132#[pyclass(name = "GamepadConnection", extends = PyMessage, eq)]
133#[derive(Debug, Clone, PartialEq)]
134pub struct PyGamepadConnection {
135    pub connected: bool,
136    pub name: Option<String>,
137    pub vendor_id: Option<u16>,
138    pub product_id: Option<u16>,
139}
140
141impl PyGamepadConnection {
142    pub fn from_bevy(event: &GamepadConnectionEvent) -> (Self, PyMessage) {
143        let (connected, name, vendor_id, product_id) = match &event.connection {
144            GamepadConnection::Connected {
145                name,
146                vendor_id,
147                product_id,
148            } => (true, Some(name.clone()), *vendor_id, *product_id),
149            GamepadConnection::Disconnected => (false, None, None, None),
150        };
151
152        (
153            PyGamepadConnection {
154                connected,
155                name,
156                vendor_id,
157                product_id,
158            },
159            PyMessage,
160        )
161    }
162}
163
164impl From<&GamepadConnectionEvent> for PyGamepadConnection {
165    fn from(event: &GamepadConnectionEvent) -> Self {
166        let (connected, name, vendor_id, product_id) = match &event.connection {
167            GamepadConnection::Connected {
168                name,
169                vendor_id,
170                product_id,
171            } => (true, Some(name.clone()), *vendor_id, *product_id),
172            GamepadConnection::Disconnected => (false, None, None, None),
173        };
174
175        PyGamepadConnection {
176            connected,
177            name,
178            vendor_id,
179            product_id,
180        }
181    }
182}
183
184#[pymethods]
185impl PyGamepadConnection {
186    #[new]
187    #[pyo3(signature = (connected, name=None, vendor_id=None, product_id=None))]
188    fn new(
189        connected: bool,
190        name: Option<String>,
191        vendor_id: Option<u16>,
192        product_id: Option<u16>,
193    ) -> (Self, PyMessage) {
194        (
195            PyGamepadConnection {
196                connected,
197                name,
198                vendor_id,
199                product_id,
200            },
201            PyMessage,
202        )
203    }
204
205    #[getter]
206    fn connected(&self) -> bool {
207        self.connected
208    }
209
210    #[getter]
211    fn name(&self) -> Option<String> {
212        self.name.clone()
213    }
214
215    #[getter]
216    fn vendor_id(&self) -> Option<u16> {
217        self.vendor_id
218    }
219
220    #[getter]
221    fn product_id(&self) -> Option<u16> {
222        self.product_id
223    }
224
225    fn __repr__(&self) -> String {
226        if self.connected {
227            let name_str = match &self.name {
228                Some(n) => n.as_str(),
229                None => "Unknown",
230            };
231            let vendor_str = match self.vendor_id {
232                Some(v) => format!("0x{:04X}", v),
233                None => "None".to_string(),
234            };
235            let product_str = match self.product_id {
236                Some(p) => format!("0x{:04X}", p),
237                None => "None".to_string(),
238            };
239            format!(
240                "GamepadConnection(connected=True, name=\"{}\", vendor_id={}, product_id={})",
241                name_str, vendor_str, product_str
242            )
243        } else {
244            "GamepadConnection(connected=False)".to_string()
245        }
246    }
247}
248
249// ============================================================================
250// GamepadButtonStateChanged
251// ============================================================================
252
253#[pyclass(name = "GamepadButtonStateChanged", extends = PyMessage, eq)]
254#[derive(Debug, Clone, PartialEq)]
255pub struct PyGamepadButtonStateChanged {
256    pub button: PyGamepadButton,
257    pub state: PyButtonState,
258}
259
260impl PyGamepadButtonStateChanged {
261    pub fn from_bevy(event: &GamepadButtonStateChangedEvent) -> (Self, PyMessage) {
262        (
263            PyGamepadButtonStateChanged {
264                button: event.button.into(),
265                state: event.state.into(),
266            },
267            PyMessage,
268        )
269    }
270}
271
272impl From<&GamepadButtonStateChangedEvent> for PyGamepadButtonStateChanged {
273    fn from(event: &GamepadButtonStateChangedEvent) -> Self {
274        PyGamepadButtonStateChanged {
275            button: event.button.into(),
276            state: event.state.into(),
277        }
278    }
279}
280
281#[pymethods]
282impl PyGamepadButtonStateChanged {
283    #[new]
284    fn new(button: PyGamepadButton, state: PyButtonState) -> (Self, PyMessage) {
285        (PyGamepadButtonStateChanged { button, state }, PyMessage)
286    }
287
288    #[getter]
289    fn button(&self) -> PyGamepadButton {
290        self.button
291    }
292
293    #[getter]
294    fn state(&self) -> PyButtonState {
295        self.state
296    }
297
298    fn __repr__(&self) -> String {
299        format!(
300            "GamepadButtonStateChanged(button={:?}, state={:?})",
301            self.button, self.state
302        )
303    }
304}
305
306// Note: PyGamepadEvent remains in main crate (src/input/events.rs) as it uses PyGamepad
307// which has ComponentStorage that can't easily implement Debug/Clone in feature crate
308
309// Message bridges
310message_bridge!(GamepadButtonChanged, PyGamepadButtonChanged);
311message_bridge!(GamepadAxisChanged, PyGamepadAxisChanged);
312message_bridge!(
313    GamepadConnectionEvent,
314    PyGamepadConnection,
315    "GamepadConnection"
316);
317message_bridge!(GamepadButtonStateChangedEvent, PyGamepadButtonStateChanged);