Inject tablet/pen events into a dedicated uinput device
This commit is contained in:
parent
dfd1e88543
commit
2a342ee056
3 changed files with 143 additions and 33 deletions
|
@ -52,6 +52,7 @@ pub struct EventReader {
|
||||||
impl EventReader {
|
impl EventReader {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
config: Vec<Config>,
|
config: Vec<Config>,
|
||||||
|
virt_dev: Arc<Mutex<VirtualDevices>>,
|
||||||
stream: Arc<Mutex<EventStream>>,
|
stream: Arc<Mutex<EventStream>>,
|
||||||
modifiers: Arc<Mutex<Vec<Event>>>,
|
modifiers: Arc<Mutex<Vec<Event>>>,
|
||||||
modifier_was_activated: Arc<Mutex<bool>>,
|
modifier_was_activated: Arc<Mutex<bool>>,
|
||||||
|
@ -72,7 +73,6 @@ impl EventReader {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.clone(),
|
.clone(),
|
||||||
));
|
));
|
||||||
let virt_dev = Arc::new(Mutex::new(VirtualDevices::new()));
|
|
||||||
let lstick_function = config
|
let lstick_function = config
|
||||||
.iter()
|
.iter()
|
||||||
.find(|&x| x.associations == Associations::default())
|
.find(|&x| x.associations == Associations::default())
|
||||||
|
@ -264,6 +264,11 @@ impl EventReader {
|
||||||
) = ((0, 0), (0, 0), (0, 0), (0, 0), 0);
|
) = ((0, 0), (0, 0), (0, 0), (0, 0), 0);
|
||||||
let switcher: Key = self.settings.layout_switcher;
|
let switcher: Key = self.settings.layout_switcher;
|
||||||
let mut stream = self.stream.lock().await;
|
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;
|
let mut max_abs_wheel = 0;
|
||||||
if let Ok(abs_state) = stream.device().get_abs_state() {
|
if let Ok(abs_state) = stream.device().get_abs_state() {
|
||||||
for state in abs_state {
|
for state in abs_state {
|
||||||
|
@ -277,9 +282,18 @@ impl EventReader {
|
||||||
event.event_type(),
|
event.event_type(),
|
||||||
RelativeAxisType(event.code()),
|
RelativeAxisType(event.code()),
|
||||||
AbsoluteAxisType(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_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 => {
|
key if key == switcher && event.value() == 1 => {
|
||||||
self.change_active_layout().await
|
self.change_active_layout().await
|
||||||
}
|
}
|
||||||
|
@ -297,6 +311,7 @@ impl EventReader {
|
||||||
EventType::RELATIVE,
|
EventType::RELATIVE,
|
||||||
RelativeAxisType::REL_WHEEL | RelativeAxisType::REL_WHEEL_HI_RES,
|
RelativeAxisType::REL_WHEEL | RelativeAxisType::REL_WHEEL_HI_RES,
|
||||||
_,
|
_,
|
||||||
|
_,
|
||||||
) => match event.value() {
|
) => match event.value() {
|
||||||
-1 => {
|
-1 => {
|
||||||
self.convert_event(event, Event::Axis(Axis::SCROLL_WHEEL_DOWN), 1, true)
|
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() {
|
match event.value() {
|
||||||
-1 => {
|
-1 => {
|
||||||
self.convert_event(event, Event::Axis(Axis::BTN_DPAD_LEFT), 1, false)
|
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() {
|
match event.value() {
|
||||||
-1 => {
|
-1 => {
|
||||||
self.convert_event(event, Event::Axis(Axis::BTN_DPAD_UP), 1, false)
|
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() {
|
match self.settings.lstick.function.as_str() {
|
||||||
"cursor" | "scroll" => {
|
"cursor" | "scroll" => {
|
||||||
let axis_value = self
|
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() {
|
match self.settings.rstick.function.as_str() {
|
||||||
"cursor" | "scroll" => {
|
"cursor" | "scroll" => {
|
||||||
let axis_value = self
|
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) {
|
match (event.value(), triggers_values.0) {
|
||||||
(0, 1) => {
|
(0, 1) => {
|
||||||
self.convert_event(event, Event::Axis(Axis::BTN_TL2), 0, false)
|
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) {
|
match (event.value(), triggers_values.1) {
|
||||||
(0, 1) => {
|
(0, 1) => {
|
||||||
self.convert_event(event, Event::Axis(Axis::BTN_TR2), 0, false)
|
self.convert_event(event, Event::Axis(Axis::BTN_TR2), 0, false)
|
||||||
|
@ -674,31 +727,16 @@ impl EventReader {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(EventType::ABSOLUTE, _, AbsoluteAxisType::ABS_WHEEL) => {
|
(EventType::MISC, _, _, true) => {
|
||||||
let value = event.value();
|
if !stream.device().properties().contains(evdev::PropType::POINTER) {
|
||||||
if value != 0 && abs_wheel_position != 0 {
|
self.emit_default_event(event).await;
|
||||||
let gap = value - abs_wheel_position;
|
} else if evdev::MiscType(event.code()) == evdev::MiscType::MSC_SERIAL {
|
||||||
if gap < -max_abs_wheel / 2 {
|
pen_events.push(event);
|
||||||
self.convert_event(event, Event::Axis(Axis::ABS_WHEEL_CW), 1, true)
|
let mut virt_dev = self.virt_dev.lock().await;
|
||||||
.await;
|
virt_dev.abs.emit(&pen_events).unwrap();
|
||||||
} else if gap > max_abs_wheel / 2 {
|
pen_events.clear()
|
||||||
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) => {
|
|
||||||
if event.value() == 0 {
|
|
||||||
abs_wheel_position = 0
|
|
||||||
};
|
|
||||||
}
|
|
||||||
_ => self.emit_default_event(event).await,
|
_ => self.emit_default_event(event).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -877,6 +915,13 @@ impl EventReader {
|
||||||
EventType::RELATIVE => {
|
EventType::RELATIVE => {
|
||||||
virt_dev.axis.emit(&[default_event]).unwrap();
|
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;
|
let mut virt_dev = self.virt_dev.lock().await;
|
||||||
virt_dev.axis.emit(&[event]).unwrap();
|
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();
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::config::{Associations, Event};
|
use crate::config::{Associations, Event};
|
||||||
use crate::event_reader::EventReader;
|
use crate::event_reader::EventReader;
|
||||||
use crate::Config;
|
use crate::Config;
|
||||||
|
use crate::virtual_devices::VirtualDevices;
|
||||||
use evdev::{Device, EventStream};
|
use evdev::{Device, EventStream};
|
||||||
use std::{env, path::Path, process::Command, sync::Arc};
|
use std::{env, path::Path, process::Command, sync::Arc};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
@ -138,8 +139,10 @@ pub fn launch_tasks(
|
||||||
Path::new(&event_device),
|
Path::new(&event_device),
|
||||||
config_list.clone(),
|
config_list.clone(),
|
||||||
)));
|
)));
|
||||||
|
let virt_dev = Arc::new(Mutex::new(VirtualDevices::new(device.1)));
|
||||||
let reader = EventReader::new(
|
let reader = EventReader::new(
|
||||||
config_list.clone(),
|
config_list.clone(),
|
||||||
|
virt_dev,
|
||||||
stream,
|
stream,
|
||||||
modifiers.clone(),
|
modifiers.clone(),
|
||||||
modifier_was_activated.clone(),
|
modifier_was_activated.clone(),
|
||||||
|
@ -213,7 +216,7 @@ fn set_environment() -> Environment {
|
||||||
}
|
}
|
||||||
(Ok(session), Ok(desktop)) if session == wayland => {
|
(Ok(session), Ok(desktop)) if session == wayland => {
|
||||||
println!("Warning: unsupported compositor: {}, won't be able to change bindings according to the active window.\n\
|
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
|
Server::Unsupported
|
||||||
}
|
}
|
||||||
(Ok(session), _) if session == x11 => {
|
(Ok(session), _) if session == x11 => {
|
||||||
|
|
|
@ -6,10 +6,11 @@ use evdev::{
|
||||||
pub struct VirtualDevices {
|
pub struct VirtualDevices {
|
||||||
pub keys: VirtualDevice,
|
pub keys: VirtualDevice,
|
||||||
pub axis: VirtualDevice,
|
pub axis: VirtualDevice,
|
||||||
|
pub abs: VirtualDevice,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VirtualDevices {
|
impl VirtualDevices {
|
||||||
pub fn new() -> Self {
|
pub fn new(device: evdev::Device) -> Self {
|
||||||
let mut key_capabilities = evdev::AttributeSet::new();
|
let mut key_capabilities = evdev::AttributeSet::new();
|
||||||
for i in 1..334 {
|
for i in 1..334 {
|
||||||
key_capabilities.insert(Key(i));
|
key_capabilities.insert(Key(i));
|
||||||
|
@ -18,6 +19,46 @@ impl VirtualDevices {
|
||||||
for i in 0..13 {
|
for i in 0..13 {
|
||||||
axis_capabilities.insert(evdev::RelativeAxisType(i));
|
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()
|
let keys_builder = VirtualDeviceBuilder::new()
|
||||||
.expect("Unable to create virtual device through uinput. Take a look at the Troubleshooting section for more info.")
|
.expect("Unable to create virtual device through uinput. Take a look at the Troubleshooting section for more info.")
|
||||||
.name("Makima Virtual Keyboard/Mouse")
|
.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.")
|
.expect("Unable to create virtual device through uinput. Take a look at the Troubleshooting section for more info.")
|
||||||
.name("Makima Virtual Pointer")
|
.name("Makima Virtual Pointer")
|
||||||
.with_relative_axes(&axis_capabilities).unwrap();
|
.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_keys = keys_builder.build().unwrap();
|
||||||
let virtual_device_axis = axis_builder.build().unwrap();
|
let virtual_device_axis = axis_builder.build().unwrap();
|
||||||
|
let virtual_device_abs = abs_builder.build().unwrap();
|
||||||
Self {
|
Self {
|
||||||
keys: virtual_device_keys,
|
keys: virtual_device_keys,
|
||||||
axis: virtual_device_axis,
|
axis: virtual_device_axis,
|
||||||
|
abs: virtual_device_abs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue