Inject tablet/pen events into a dedicated uinput device

This commit is contained in:
cyber-sushi 2024-11-02 19:43:01 +01:00
parent dfd1e88543
commit 2a342ee056
3 changed files with 143 additions and 33 deletions

View file

@ -52,6 +52,7 @@ pub struct EventReader {
impl EventReader {
pub fn new(
config: Vec<Config>,
virt_dev: Arc<Mutex<VirtualDevices>>,
stream: Arc<Mutex<EventStream>>,
modifiers: Arc<Mutex<Vec<Event>>>,
modifier_was_activated: Arc<Mutex<bool>>,
@ -72,7 +73,6 @@ impl EventReader {
.unwrap()
.clone(),
));
let virt_dev = Arc::new(Mutex::new(VirtualDevices::new()));
let lstick_function = config
.iter()
.find(|&x| x.associations == Associations::default())
@ -264,6 +264,11 @@ impl EventReader {
) = ((0, 0), (0, 0), (0, 0), (0, 0), 0);
let switcher: Key = self.settings.layout_switcher;
let mut stream = self.stream.lock().await;
let mut pen_events: Vec<InputEvent> = Vec::new();
let is_tablet: bool =
stream.device().properties().contains(evdev::PropType::POINTER)
&& stream.device().supported_keys()
.unwrap_or(&evdev::AttributeSet::new()).contains(evdev::Key::BTN_TOOL_PEN);
let mut max_abs_wheel = 0;
if let Ok(abs_state) = stream.device().get_abs_state() {
for state in abs_state {
@ -277,9 +282,18 @@ impl EventReader {
event.event_type(),
RelativeAxisType(event.code()),
AbsoluteAxisType(event.code()),
is_tablet,
) {
(EventType::KEY, _, _) => match Key(event.code()) {
(EventType::KEY, _, _, _) => match Key(event.code()) {
Key::BTN_TL2 | Key::BTN_TR2 => {}
Key::BTN_TOOL_PEN
| Key::BTN_TOOL_RUBBER
| Key::BTN_TOOL_BRUSH
| Key::BTN_TOOL_PENCIL
| Key::BTN_TOOL_AIRBRUSH
| Key::BTN_TOOL_MOUSE
| Key::BTN_TOOL_LENS
if is_tablet => pen_events.push(event),
key if key == switcher && event.value() == 1 => {
self.change_active_layout().await
}
@ -297,6 +311,7 @@ impl EventReader {
EventType::RELATIVE,
RelativeAxisType::REL_WHEEL | RelativeAxisType::REL_WHEEL_HI_RES,
_,
_,
) => match event.value() {
-1 => {
self.convert_event(event, Event::Axis(Axis::SCROLL_WHEEL_DOWN), 1, true)
@ -308,7 +323,35 @@ impl EventReader {
}
_ => {}
},
(_, _, AbsoluteAxisType::ABS_HAT0X) => {
(EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_WHEEL, _) => {
let value = event.value();
if value != 0 && abs_wheel_position != 0 {
let gap = value - abs_wheel_position;
if gap < -max_abs_wheel / 2 {
self.convert_event(event, Event::Axis(Axis::ABS_WHEEL_CW), 1, true)
.await;
} else if gap > max_abs_wheel / 2 {
self.convert_event(event, Event::Axis(Axis::ABS_WHEEL_CCW), 1, true)
.await;
} else if value > abs_wheel_position {
self.convert_event(event, Event::Axis(Axis::ABS_WHEEL_CW), 1, true)
.await;
} else if value < abs_wheel_position {
self.convert_event(event, Event::Axis(Axis::ABS_WHEEL_CCW), 1, true)
.await;
}
}
abs_wheel_position = value;
}
(EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_MISC, false) => {
if event.value() == 0 {
abs_wheel_position = 0
}
}
(EventType::ABSOLUTE, _, _, true) => {
pen_events.push(event)
}
(_, _, AbsoluteAxisType::ABS_HAT0X, _) => {
match event.value() {
-1 => {
self.convert_event(event, Event::Axis(Axis::BTN_DPAD_LEFT), 1, false)
@ -347,7 +390,7 @@ impl EventReader {
_ => {}
};
}
(_, _, AbsoluteAxisType::ABS_HAT0Y) => {
(_, _, AbsoluteAxisType::ABS_HAT0Y, _) => {
match event.value() {
-1 => {
self.convert_event(event, Event::Axis(Axis::BTN_DPAD_UP), 1, false)
@ -386,7 +429,12 @@ impl EventReader {
_ => {}
};
}
(EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_X | AbsoluteAxisType::ABS_Y) => {
(
EventType::ABSOLUTE,
_,
AbsoluteAxisType::ABS_X | AbsoluteAxisType::ABS_Y,
false
) => {
match self.settings.lstick.function.as_str() {
"cursor" | "scroll" => {
let axis_value = self
@ -513,7 +561,12 @@ impl EventReader {
_ => {}
}
}
(EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_RX | AbsoluteAxisType::ABS_RY) => {
(
EventType::ABSOLUTE,
_,
AbsoluteAxisType::ABS_RX | AbsoluteAxisType::ABS_RY,
false
) => {
match self.settings.rstick.function.as_str() {
"cursor" | "scroll" => {
let axis_value = self
@ -644,7 +697,7 @@ impl EventReader {
_ => {}
}
}
(EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_Z) => {
(EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_Z, false) => {
match (event.value(), triggers_values.0) {
(0, 1) => {
self.convert_event(event, Event::Axis(Axis::BTN_TL2), 0, false)
@ -659,7 +712,7 @@ impl EventReader {
_ => {}
}
}
(EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_RZ) => {
(EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_RZ, false) => {
match (event.value(), triggers_values.1) {
(0, 1) => {
self.convert_event(event, Event::Axis(Axis::BTN_TR2), 0, false)
@ -674,30 +727,15 @@ impl EventReader {
_ => {}
}
}
(EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_WHEEL) => {
let value = event.value();
if value != 0 && abs_wheel_position != 0 {
let gap = value - abs_wheel_position;
if gap < -max_abs_wheel / 2 {
self.convert_event(event, Event::Axis(Axis::ABS_WHEEL_CW), 1, true)
.await;
} else if gap > max_abs_wheel / 2 {
self.convert_event(event, Event::Axis(Axis::ABS_WHEEL_CCW), 1, true)
.await;
} else if value > abs_wheel_position {
self.convert_event(event, Event::Axis(Axis::ABS_WHEEL_CW), 1, true)
.await;
} else if value < abs_wheel_position {
self.convert_event(event, Event::Axis(Axis::ABS_WHEEL_CCW), 1, true)
.await;
}
(EventType::MISC, _, _, true) => {
if !stream.device().properties().contains(evdev::PropType::POINTER) {
self.emit_default_event(event).await;
} else if evdev::MiscType(event.code()) == evdev::MiscType::MSC_SERIAL {
pen_events.push(event);
let mut virt_dev = self.virt_dev.lock().await;
virt_dev.abs.emit(&pen_events).unwrap();
pen_events.clear()
}
abs_wheel_position = value;
}
(EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_MISC) => {
if event.value() == 0 {
abs_wheel_position = 0
};
}
_ => self.emit_default_event(event).await,
}
@ -877,6 +915,13 @@ impl EventReader {
EventType::RELATIVE => {
virt_dev.axis.emit(&[default_event]).unwrap();
}
EventType::ABSOLUTE => {
virt_dev.abs.emit(&[default_event]).unwrap();
}
EventType::MISC => {
let mut virt_dev = self.virt_dev.lock().await;
virt_dev.abs.emit(&[default_event]).unwrap();
}
_ => {}
}
}
@ -892,6 +937,14 @@ impl EventReader {
let mut virt_dev = self.virt_dev.lock().await;
virt_dev.axis.emit(&[event]).unwrap();
}
EventType::ABSOLUTE => {
let mut virt_dev = self.virt_dev.lock().await;
virt_dev.abs.emit(&[event]).unwrap();
}
EventType::MISC => {
let mut virt_dev = self.virt_dev.lock().await;
virt_dev.abs.emit(&[event]).unwrap();
}
_ => {}
}
}

View file

@ -1,6 +1,7 @@
use crate::config::{Associations, Event};
use crate::event_reader::EventReader;
use crate::Config;
use crate::virtual_devices::VirtualDevices;
use evdev::{Device, EventStream};
use std::{env, path::Path, process::Command, sync::Arc};
use tokio::sync::Mutex;
@ -138,8 +139,10 @@ pub fn launch_tasks(
Path::new(&event_device),
config_list.clone(),
)));
let virt_dev = Arc::new(Mutex::new(VirtualDevices::new(device.1)));
let reader = EventReader::new(
config_list.clone(),
virt_dev,
stream,
modifiers.clone(),
modifier_was_activated.clone(),
@ -213,7 +216,7 @@ fn set_environment() -> Environment {
}
(Ok(session), Ok(desktop)) if session == wayland => {
println!("Warning: unsupported compositor: {}, won't be able to change bindings according to the active window.\n\
Currently supported desktops: Hyprland, Sway, Plasma/KWin, X11.\n", desktop);
Currently supported desktops: Hyprland, Sway, Niri, Plasma/KWin, X11.\n", desktop);
Server::Unsupported
}
(Ok(session), _) if session == x11 => {

View file

@ -6,10 +6,11 @@ use evdev::{
pub struct VirtualDevices {
pub keys: VirtualDevice,
pub axis: VirtualDevice,
pub abs: VirtualDevice,
}
impl VirtualDevices {
pub fn new() -> Self {
pub fn new(device: evdev::Device) -> Self {
let mut key_capabilities = evdev::AttributeSet::new();
for i in 1..334 {
key_capabilities.insert(Key(i));
@ -18,6 +19,46 @@ impl VirtualDevices {
for i in 0..13 {
axis_capabilities.insert(evdev::RelativeAxisType(i));
}
let mut tablet_abs_capabilities: Vec<evdev::UinputAbsSetup> = Vec::new();
if let Ok(absinfo) = device.get_abs_state() {
for (axis_type, info) in absinfo.iter().enumerate() {
if [0, 1, 2, 5, 6, 8, 24, 25, 26, 27].contains(&axis_type) {
let new_absinfo = evdev::AbsInfo::new(
info.value,
info.minimum,
info.maximum,
info.fuzz,
info.flat,
info.resolution
);
tablet_abs_capabilities.push(
evdev::UinputAbsSetup::new(
evdev::AbsoluteAxisType(axis_type.try_into().unwrap()),
new_absinfo
)
)
}
}
}
let mut tablet_capabilities = evdev::AttributeSet::new();
for i in 272..277 {
tablet_capabilities.insert(evdev::Key(i));
}
for i in 320..325 {
tablet_capabilities.insert(evdev::Key(i));
}
for i in 326..328 {
tablet_capabilities.insert(evdev::Key(i));
}
for i in 330..333 {
tablet_capabilities.insert(evdev::Key(i));
}
let mut tab_rel = evdev::AttributeSet::new();
tab_rel.insert(evdev::RelativeAxisType(8));
let mut tab_msc = evdev::AttributeSet::new();
tab_msc.insert(evdev::MiscType(0));
let mut pointer_prop = evdev::AttributeSet::new();
pointer_prop.insert(evdev::PropType::POINTER);
let keys_builder = VirtualDeviceBuilder::new()
.expect("Unable to create virtual device through uinput. Take a look at the Troubleshooting section for more info.")
.name("Makima Virtual Keyboard/Mouse")
@ -26,11 +67,24 @@ impl VirtualDevices {
.expect("Unable to create virtual device through uinput. Take a look at the Troubleshooting section for more info.")
.name("Makima Virtual Pointer")
.with_relative_axes(&axis_capabilities).unwrap();
let mut abs_builder = VirtualDeviceBuilder::new()
.expect("Unable to create virtual device through uinput. Take a look at the Troubleshooting section for more info.")
.name("Makima Virtual Pen/Tablet")
.with_properties(&pointer_prop).unwrap()
.with_msc(&tab_msc).unwrap()
.with_relative_axes(&tab_rel).unwrap()
.with_keys(&tablet_capabilities).unwrap()
.input_id(device.input_id());
for abs_setup in tablet_abs_capabilities {
abs_builder = abs_builder.with_absolute_axis(&abs_setup).unwrap();
};
let virtual_device_keys = keys_builder.build().unwrap();
let virtual_device_axis = axis_builder.build().unwrap();
let virtual_device_abs = abs_builder.build().unwrap();
Self {
keys: virtual_device_keys,
axis: virtual_device_axis,
abs: virtual_device_abs,
}
}
}