comparison src/main.rs @ 0:816237b684ea

Hello world!
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Wed, 07 Oct 2020 04:10:33 +0200
parents
children 6dbe2bbeef70
comparison
equal deleted inserted replaced
-1:000000000000 0:816237b684ea
1 use gio::prelude::*;
2 use gtk::prelude::*;
3
4 use std::env::args;
5 use std::fs::{File, OpenOptions};
6 use std::io::ErrorKind;
7 use std::sync::{Arc, Mutex};
8
9 use input_linux::{
10 sys::input_event, sys::timeval, AbsoluteAxis, AbsoluteInfo, AbsoluteInfoSetup, EventKind,
11 InputId, InputProperty, Key, MiscKind, UInputHandle,
12 };
13
14 const WIDTH: i32 = 320;
15 const HEIGHT: i32 = 180;
16
17 const MAX_X: i32 = 69920;
18 const MAX_Y: i32 = 39980;
19
20 fn create_uinput_device() -> std::io::Result<UInputHandle<File>> {
21 let file = OpenOptions::new().write(true).open("/dev/uinput")?;
22 let dev = UInputHandle::new(file);
23
24 dev.set_evbit(EventKind::Synchronize)?;
25 dev.set_evbit(EventKind::Key)?;
26 dev.set_evbit(EventKind::Absolute)?;
27 dev.set_evbit(EventKind::Misc)?;
28 dev.set_keybit(Key::ButtonToolPen)?;
29 dev.set_keybit(Key::ButtonToolRubber)?;
30 dev.set_keybit(Key::ButtonToolBrush)?;
31 dev.set_keybit(Key::ButtonToolPencil)?;
32 dev.set_keybit(Key::ButtonToolAirbrush)?;
33 dev.set_keybit(Key::ButtonTouch)?;
34 dev.set_keybit(Key::ButtonStylus)?;
35 dev.set_keybit(Key::ButtonStylus2)?;
36 dev.set_keybit(Key::ButtonStylus3)?;
37 dev.set_mscbit(MiscKind::Serial)?;
38 dev.set_propbit(InputProperty::Direct)?;
39
40 dev.set_absbit(AbsoluteAxis::X)?;
41 dev.set_absbit(AbsoluteAxis::Y)?;
42 dev.set_absbit(AbsoluteAxis::Z)?;
43 dev.set_absbit(AbsoluteAxis::Wheel)?;
44 dev.set_absbit(AbsoluteAxis::Pressure)?;
45 dev.set_absbit(AbsoluteAxis::Distance)?;
46 dev.set_absbit(AbsoluteAxis::TiltX)?;
47 dev.set_absbit(AbsoluteAxis::TiltY)?;
48 dev.set_absbit(AbsoluteAxis::Misc)?;
49
50 let id = InputId {
51 bustype: 3,
52 vendor: 0x56a,
53 product: 0x350,
54 version: 0xb,
55 };
56
57 let x = AbsoluteInfoSetup {
58 axis: AbsoluteAxis::X,
59 info: AbsoluteInfo {
60 value: 0,
61 minimum: 0,
62 maximum: MAX_X,
63 fuzz: 0,
64 flat: 0,
65 resolution: 200,
66 },
67 };
68 let y = AbsoluteInfoSetup {
69 axis: AbsoluteAxis::Y,
70 info: AbsoluteInfo {
71 value: 0,
72 minimum: 0,
73 maximum: MAX_Y,
74 fuzz: 0,
75 flat: 0,
76 resolution: 200,
77 },
78 };
79 let z = AbsoluteInfoSetup {
80 axis: AbsoluteAxis::Z,
81 info: AbsoluteInfo {
82 value: 0,
83 minimum: -900,
84 maximum: 899,
85 fuzz: 0,
86 flat: 0,
87 resolution: 287,
88 },
89 };
90 let wheel = AbsoluteInfoSetup {
91 axis: AbsoluteAxis::Wheel,
92 info: AbsoluteInfo {
93 value: 0,
94 minimum: 0,
95 maximum: 2047,
96 fuzz: 0,
97 flat: 0,
98 resolution: 0,
99 },
100 };
101 let pressure = AbsoluteInfoSetup {
102 axis: AbsoluteAxis::Pressure,
103 info: AbsoluteInfo {
104 value: 0,
105 minimum: 0,
106 maximum: 8196,
107 fuzz: 0,
108 flat: 0,
109 resolution: 0,
110 },
111 };
112 let distance = AbsoluteInfoSetup {
113 axis: AbsoluteAxis::Distance,
114 info: AbsoluteInfo {
115 value: 0,
116 minimum: 0,
117 maximum: 63,
118 fuzz: 0,
119 flat: 0,
120 resolution: 0,
121 },
122 };
123 let tilt_x = AbsoluteInfoSetup {
124 axis: AbsoluteAxis::TiltX,
125 info: AbsoluteInfo {
126 value: 0,
127 minimum: -64,
128 maximum: 63,
129 fuzz: 0,
130 flat: 0,
131 resolution: 57,
132 },
133 };
134 let tilt_y = AbsoluteInfoSetup {
135 axis: AbsoluteAxis::TiltY,
136 info: AbsoluteInfo {
137 value: 0,
138 minimum: -64,
139 maximum: 63,
140 fuzz: 0,
141 flat: 0,
142 resolution: 57,
143 },
144 };
145 let misc = AbsoluteInfoSetup {
146 axis: AbsoluteAxis::Misc,
147 info: AbsoluteInfo {
148 value: 0,
149 minimum: 0,
150 maximum: 0,
151 fuzz: 0,
152 flat: 0,
153 resolution: 0,
154 },
155 };
156
157 dev.create(
158 &id,
159 b"TabletEmu",
160 0,
161 &[x, y, z, wheel, pressure, distance, tilt_x, tilt_y, misc],
162 )?;
163 Ok(dev)
164 }
165
166 fn input_event_new(type_: EventKind, code: AbsoluteAxis, value: i32) -> input_event {
167 input_event {
168 time: timeval {
169 tv_sec: 0,
170 tv_usec: 0,
171 },
172 type_: type_ as u16,
173 code: code as u16,
174 value,
175 }
176 }
177
178 fn build_ui(application: &gtk::Application) {
179 let dev = match create_uinput_device() {
180 Ok(dev) => Arc::new(dev),
181 Err(err) => {
182 match err.kind() {
183 ErrorKind::NotFound => {
184 eprintln!("Couldn’t find /dev/uinput: {}", err);
185 eprintln!("Maybe you forgot to `modprobe uinput`?");
186 }
187 ErrorKind::PermissionDenied => {
188 eprintln!("Couldn’t open /dev/uinput for writing: {}", err);
189 eprintln!("Maybe you aren’t allowed to create input devices?");
190 }
191 _ => eprintln!("Couldn’t open /dev/uinput for writing: {}", err),
192 }
193 return;
194 }
195 };
196 println!(
197 "New device at {:?} ({:?})",
198 dev.evdev_path().unwrap(),
199 dev.sys_path().unwrap()
200 );
201
202 let window = gtk::ApplicationWindow::new(application);
203
204 window.set_title("tablet-emu");
205 window.set_position(gtk::WindowPosition::Center);
206
207 let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0);
208 let tools_box = gtk::Box::new(gtk::Orientation::Vertical, 0);
209
210 let tool_name = Arc::new(Mutex::new(String::from("Pen")));
211 let tool1 = gtk::Button::with_label("Pen");
212 let tool2 = gtk::Button::with_label("Rubber");
213 let tool3 = gtk::Button::with_label("Brush");
214 let tool4 = gtk::Button::with_label("Pencil");
215 let tool5 = gtk::Button::with_label("Airbrush");
216
217 macro_rules! impl_tool_signal {
218 ($tool:ident) => {
219 let tool_name_weak = Arc::downgrade(&tool_name);
220 $tool.connect_clicked(move |b| {
221 let tool_name = tool_name_weak.upgrade().unwrap();
222 let mut tool_name = tool_name.lock().unwrap();
223 *tool_name = b.get_label().unwrap().to_string();
224 });
225 };
226 };
227 impl_tool_signal!(tool1);
228 impl_tool_signal!(tool2);
229 impl_tool_signal!(tool3);
230 impl_tool_signal!(tool4);
231 impl_tool_signal!(tool5);
232
233 tools_box.add(&tool1);
234 tools_box.add(&tool2);
235 tools_box.add(&tool3);
236 tools_box.add(&tool4);
237 tools_box.add(&tool5);
238
239 let current_size = Arc::new(Mutex::new((WIDTH as f64, HEIGHT as f64)));
240 let pressed = Arc::new(Mutex::new(false));
241
242 let drawing_area = gtk::DrawingArea::new();
243 drawing_area.set_size_request(WIDTH, HEIGHT);
244 drawing_area.set_hexpand(true);
245 drawing_area.set_events(
246 gdk::EventMask::BUTTON_PRESS_MASK
247 | gdk::EventMask::BUTTON_RELEASE_MASK
248 | gdk::EventMask::POINTER_MOTION_MASK,
249 );
250 let current_size_weak = Arc::downgrade(&current_size);
251 drawing_area.connect_configure_event(move |_, event| {
252 let current_size = current_size_weak.upgrade().unwrap();
253 let mut current_size = current_size.lock().unwrap();
254 *current_size = match event.get_size() {
255 (width, height) => (width as f64, height as f64),
256 };
257 true
258 });
259 let dev_weak = Arc::downgrade(&dev);
260 let current_size_weak = Arc::downgrade(&current_size);
261 let pressed_weak = Arc::downgrade(&pressed);
262 drawing_area.connect_button_press_event(move |_, event| {
263 if event.get_button() != 1 {
264 return Inhibit(false);
265 }
266
267 let dev = dev_weak.upgrade().unwrap();
268 let pressed = pressed_weak.upgrade().unwrap();
269 let mut pressed = pressed.lock().unwrap();
270 *pressed = true;
271 let (x, y) = event.get_position();
272 println!("press tool {} at {}, {}", tool_name.lock().unwrap(), x, y);
273 let current_size = current_size_weak.upgrade().unwrap();
274 let current_size = current_size.lock().unwrap();
275 let (width, height) = *current_size;
276 dev.write(&[
277 input_event_new(
278 EventKind::Absolute,
279 AbsoluteAxis::X,
280 (x * MAX_X as f64 / width) as i32,
281 ),
282 input_event_new(
283 EventKind::Absolute,
284 AbsoluteAxis::Y,
285 (y * MAX_Y as f64 / height) as i32,
286 ),
287 input_event_new(EventKind::Absolute, AbsoluteAxis::Z, 0),
288 input_event_new(EventKind::Absolute, AbsoluteAxis::Wheel, 0),
289 input_event_new(EventKind::Absolute, AbsoluteAxis::Pressure, 1024),
290 input_event_new(EventKind::Absolute, AbsoluteAxis::Distance, 0),
291 input_event_new(EventKind::Absolute, AbsoluteAxis::TiltX, 16),
292 input_event_new(EventKind::Absolute, AbsoluteAxis::TiltY, 0),
293 // TODO: Change the type of the second parameter here.
294 input_event_new(EventKind::Misc, AbsoluteAxis::X, 0),
295 input_event_new(EventKind::Synchronize, AbsoluteAxis::X, 0),
296 ])
297 .unwrap();
298 Inhibit(false)
299 });
300 let dev_weak = Arc::downgrade(&dev);
301 let current_size_weak = Arc::downgrade(&current_size);
302 let pressed_weak = Arc::downgrade(&pressed);
303 drawing_area.connect_button_release_event(move |_, event| {
304 if event.get_button() != 1 {
305 return Inhibit(false);
306 }
307
308 let dev = dev_weak.upgrade().unwrap();
309 let (x, y) = event.get_position();
310 let pressed = pressed_weak.upgrade().unwrap();
311 let mut pressed = pressed.lock().unwrap();
312 *pressed = false;
313 //println!("release {}, {}", x, y);
314 let current_size = current_size_weak.upgrade().unwrap();
315 let current_size = current_size.lock().unwrap();
316 let (width, height) = *current_size;
317 dev.write(&[
318 input_event_new(
319 EventKind::Absolute,
320 AbsoluteAxis::X,
321 (x * MAX_X as f64 / width) as i32,
322 ),
323 input_event_new(
324 EventKind::Absolute,
325 AbsoluteAxis::Y,
326 (y * MAX_Y as f64 / height) as i32,
327 ),
328 input_event_new(EventKind::Absolute, AbsoluteAxis::Z, 0),
329 input_event_new(EventKind::Absolute, AbsoluteAxis::Wheel, 0),
330 input_event_new(EventKind::Absolute, AbsoluteAxis::Pressure, 0),
331 input_event_new(EventKind::Absolute, AbsoluteAxis::Distance, 16),
332 input_event_new(EventKind::Absolute, AbsoluteAxis::TiltX, 16),
333 input_event_new(EventKind::Absolute, AbsoluteAxis::TiltY, 0),
334 // TODO: Change the type of the second parameter here.
335 input_event_new(EventKind::Misc, AbsoluteAxis::X, 0),
336 input_event_new(EventKind::Synchronize, AbsoluteAxis::X, 0),
337 ])
338 .unwrap();
339 Inhibit(false)
340 });
341 drawing_area.connect_motion_notify_event(move |_, event| {
342 let (x, y) = event.get_position();
343 let pressed = pressed.lock().unwrap();
344 //println!("motion {}, {}", x, y);
345 let current_size = current_size.lock().unwrap();
346 let (width, height) = *current_size;
347 dev.write(&[
348 input_event_new(
349 EventKind::Absolute,
350 AbsoluteAxis::X,
351 (x * MAX_X as f64 / width) as i32,
352 ),
353 input_event_new(
354 EventKind::Absolute,
355 AbsoluteAxis::Y,
356 (y * MAX_Y as f64 / height) as i32,
357 ),
358 input_event_new(EventKind::Absolute, AbsoluteAxis::Z, 0),
359 input_event_new(EventKind::Absolute, AbsoluteAxis::Wheel, 0),
360 input_event_new(
361 EventKind::Absolute,
362 AbsoluteAxis::Pressure,
363 if *pressed { 2048 } else { 0 },
364 ),
365 input_event_new(
366 EventKind::Absolute,
367 AbsoluteAxis::Distance,
368 if *pressed { 0 } else { 32 },
369 ),
370 input_event_new(EventKind::Absolute, AbsoluteAxis::TiltX, 16),
371 input_event_new(EventKind::Absolute, AbsoluteAxis::TiltY, 0),
372 // TODO: Change the type of the second parameter here.
373 input_event_new(EventKind::Misc, AbsoluteAxis::X, 0),
374 input_event_new(EventKind::Synchronize, AbsoluteAxis::X, 0),
375 ])
376 .unwrap();
377 Inhibit(false)
378 });
379 drawing_area.connect_draw(move |_, ctx| {
380 //println!("drawing {}", drawing_area);
381 ctx.set_source_rgb(1., 0., 0.);
382 ctx.set_operator(cairo::Operator::Screen);
383 ctx.paint();
384 Inhibit(false)
385 });
386
387 hbox.add(&tools_box);
388 hbox.add(&drawing_area);
389
390 window.add(&hbox);
391
392 window.show_all();
393 }
394
395 fn main() {
396 let application = gtk::Application::new(
397 Some("fr.linkmauve.TabletEmu"),
398 gio::ApplicationFlags::empty(),
399 )
400 .expect("Initialisation failed…");
401 application.connect_activate(build_ui);
402 application.run(&args().collect::<Vec<_>>());
403 }