1use lazy_static::lazy_static;
2use libspnav_bindings as libspnav;
3use std::convert::{From, Into, TryFrom};
4use std::sync::Mutex;
5
6#[derive(Debug, Clone, Copy)]
7pub enum EventType {
8 Any,
9 Motion,
10 Button,
11}
12
13const SPNAV_EVENT_ANY: i32 = 0;
14const SPNAV_EVENT_MOTION: i32 = 1;
15const SPNAV_EVENT_BUTTON: i32 = 2;
16
17impl Into<i32> for EventType {
18 fn into(self) -> i32 {
19 match self {
20 EventType::Any => SPNAV_EVENT_ANY,
21 EventType::Motion => SPNAV_EVENT_MOTION,
22 EventType::Button => SPNAV_EVENT_BUTTON,
23 }
24 }
25}
26
27#[derive(Debug, Clone)]
28pub enum Event {
29 Motion(MotionEvent),
30 Button(ButtonEvent),
31}
32
33#[derive(Debug, Clone)]
34pub struct MotionEvent {
35 pub x: i32,
36 pub y: i32,
37 pub z: i32,
38 pub rx: i32,
39 pub ry: i32,
40 pub rz: i32,
41 pub period: u32,
42 }
44
45impl MotionEvent {
46 pub fn t(&self) -> (i32, i32, i32) {
48 (self.x, self.y, self.z)
49 }
50 pub fn r(&self) -> (i32, i32, i32) {
52 (self.rx, self.ry, self.rz)
53 }
54}
55
56impl From<libspnav::spnav_event_motion> for MotionEvent {
57 fn from(event: libspnav::spnav_event_motion) -> Self {
58 MotionEvent {
59 x: event.x,
60 y: event.y,
61 z: event.z,
62 rx: event.rx,
63 ry: event.ry,
64 rz: event.rz,
65 period: event.period,
66 }
67 }
68}
69
70#[derive(Debug, Clone)]
71pub struct ButtonEvent {
72 pub press: bool,
73 pub bnum: i32,
74}
75
76impl From<libspnav::spnav_event_button> for ButtonEvent {
77 fn from(event: libspnav::spnav_event_button) -> Self {
78 ButtonEvent {
79 press: event.press != 0,
80 bnum: event.bnum,
81 }
82 }
83}
84
85impl TryFrom<libspnav::spnav_event> for Event {
86 type Error = ();
87 fn try_from(event: libspnav::spnav_event) -> Result<Self, Self::Error> {
88 unsafe {
89 match event {
90 libspnav::spnav_event {
91 type_: SPNAV_EVENT_MOTION,
92 } => Ok(Event::Motion(event.motion.into())),
93 libspnav::spnav_event {
94 type_: SPNAV_EVENT_BUTTON,
95 } => Ok(Event::Button(event.button.into())),
96 _ => Err(()),
97 }
98 }
99 }
100}
101
102#[derive(Debug)]
103pub struct Connection {
104 pub fd: i32,
105}
106
107lazy_static! {
108 static ref CONN_COUNT: Mutex<usize> = Mutex::new(0);
109}
110
111impl Connection {
112 pub fn new() -> Result<Connection, ()> {
113 let mut count = CONN_COUNT.lock().expect("to lock");
114 if *count > 0 {
115 *count += 1;
116 Ok(Connection {
117 fd: lib::spnav_fd()?,
118 })
119 } else {
120 *count = 1;
121 lib::spnav_open()?;
122 Ok(Connection {
123 fd: lib::spnav_fd()?,
124 })
125 }
126 }
127 pub fn poll(&self) -> Option<Event> {
128 lib::spnav_poll_event()
129 }
130 pub fn wait(&self) -> Result<Event, ()> {
131 lib::spnav_wait_event()
132 }
133}
134
135impl Drop for Connection {
136 fn drop(&mut self) {
137 let mut count = CONN_COUNT.lock().expect("to lock");
138 if *count == 1 {
139 *count = 0;
140 lib::spnav_close().expect("to close");
141 } else {
142 *count -= 1;
143 }
144 }
145}
146
147pub mod lib {
148 use super::*;
149
150 pub fn spnav_open() -> Result<(), ()> {
156 unsafe {
157 if libspnav::spnav_open() == -1 {
158 Err(())
159 } else {
160 Ok(())
161 }
162 }
163 }
164
165 pub fn spnav_close() -> Result<(), ()> {
170 unsafe {
171 if libspnav::spnav_close() == -1 {
172 Err(())
173 } else {
174 Ok(())
175 }
176 }
177 }
178
179 pub fn spnav_fd() -> Result<i32, ()> {
188 unsafe {
189 let fd = libspnav::spnav_fd();
190 if fd == -1 {
191 Err(())
192 } else {
193 Ok(fd)
194 }
195 }
196 }
197
198 pub fn spnav_sensitivity(sens: f64) -> Result<i32, ()> {
201 unsafe {
202 let v = libspnav::spnav_sensitivity(sens);
203 if v == -1 {
204 Err(())
205 } else {
206 Ok(v)
207 }
208 }
209 }
210
211 pub fn spnav_wait_event() -> Result<Event, ()> {
214 let mut event = libspnav::spnav_event {
215 type_: SPNAV_EVENT_ANY,
216 };
217 let t = unsafe { libspnav::spnav_wait_event(&mut event) };
218 if t == 0 {
219 Err(())
220 } else {
221 event.try_into()
222 }
223 }
224
225 pub fn spnav_poll_event() -> Option<Event> {
230 let mut event = libspnav::spnav_event {
231 type_: SPNAV_EVENT_ANY,
232 };
233 let t = unsafe { libspnav::spnav_poll_event(&mut event) };
234 if t == 0 {
235 None
236 } else {
237 event.try_into().ok()
238 }
239 }
240
241 pub fn spnav_remove_events(t: EventType) -> i32 {
247 unsafe { libspnav::spnav_remove_events(t.into()) }
248 }
249}
250
251#[cfg(test)]
252mod test {
253 use super::*;
254
255 #[test]
256 fn basic() -> Result<(), ()> {
257 let c = Connection::new()?;
258 println!("{:?}", c);
259 println!("{:?}", c.wait());
260 Ok(())
261 }
262}