Merge pull request #130 from mahkoh/jorth/input-cli
cli: add an input subcommand
This commit is contained in:
commit
7fcfe35c87
30 changed files with 1734 additions and 163 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
|
@ -1042,9 +1042,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uapi"
|
name = "uapi"
|
||||||
version = "0.2.12"
|
version = "0.2.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "651f13cef1d1988a4c73d215c39fec385fc1be4c7eb6daf89822d5021f7029f8"
|
checksum = "3bf073840d1b16485bfe28b4e752eccee38d9ac53f152adf869708e3136561e6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ panic = "abort"
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
uapi = "0.2.12"
|
uapi = "0.2.13"
|
||||||
thiserror = "1.0.56"
|
thiserror = "1.0.56"
|
||||||
ahash = "0.8.7"
|
ahash = "0.8.7"
|
||||||
log = { version = "0.4.20", features = ["std"] }
|
log = { version = "0.4.20", features = ["std"] }
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use {
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
gfx_api::GfxFramebuffer,
|
gfx_api::GfxFramebuffer,
|
||||||
ifs::wl_seat::wl_pointer::{CONTINUOUS, FINGER, HORIZONTAL_SCROLL, VERTICAL_SCROLL, WHEEL},
|
ifs::wl_seat::wl_pointer::{CONTINUOUS, FINGER, HORIZONTAL_SCROLL, VERTICAL_SCROLL, WHEEL},
|
||||||
|
libinput::consts::DeviceCapability,
|
||||||
video::drm::{ConnectorType, DrmError, DrmVersion},
|
video::drm::{ConnectorType, DrmError, DrmVersion},
|
||||||
},
|
},
|
||||||
jay_config::video::GfxApi,
|
jay_config::video::GfxApi,
|
||||||
|
|
@ -118,14 +119,41 @@ pub trait InputDevice {
|
||||||
fn on_change(&self, cb: Rc<dyn Fn()>);
|
fn on_change(&self, cb: Rc<dyn Fn()>);
|
||||||
fn grab(&self, grab: bool);
|
fn grab(&self, grab: bool);
|
||||||
fn has_capability(&self, cap: InputDeviceCapability) -> bool;
|
fn has_capability(&self, cap: InputDeviceCapability) -> bool;
|
||||||
|
fn left_handed(&self) -> Option<bool> {
|
||||||
|
None
|
||||||
|
}
|
||||||
fn set_left_handed(&self, left_handed: bool);
|
fn set_left_handed(&self, left_handed: bool);
|
||||||
|
fn accel_profile(&self) -> Option<InputDeviceAccelProfile> {
|
||||||
|
None
|
||||||
|
}
|
||||||
fn set_accel_profile(&self, profile: InputDeviceAccelProfile);
|
fn set_accel_profile(&self, profile: InputDeviceAccelProfile);
|
||||||
|
fn accel_speed(&self) -> Option<f64> {
|
||||||
|
None
|
||||||
|
}
|
||||||
fn set_accel_speed(&self, speed: f64);
|
fn set_accel_speed(&self, speed: f64);
|
||||||
|
fn transform_matrix(&self) -> Option<TransformMatrix> {
|
||||||
|
None
|
||||||
|
}
|
||||||
fn set_transform_matrix(&self, matrix: TransformMatrix);
|
fn set_transform_matrix(&self, matrix: TransformMatrix);
|
||||||
fn name(&self) -> Rc<String>;
|
fn name(&self) -> Rc<String>;
|
||||||
|
fn dev_t(&self) -> Option<c::dev_t> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn tap_enabled(&self) -> Option<bool> {
|
||||||
|
None
|
||||||
|
}
|
||||||
fn set_tap_enabled(&self, enabled: bool);
|
fn set_tap_enabled(&self, enabled: bool);
|
||||||
|
fn drag_enabled(&self) -> Option<bool> {
|
||||||
|
None
|
||||||
|
}
|
||||||
fn set_drag_enabled(&self, enabled: bool);
|
fn set_drag_enabled(&self, enabled: bool);
|
||||||
|
fn drag_lock_enabled(&self) -> Option<bool> {
|
||||||
|
None
|
||||||
|
}
|
||||||
fn set_drag_lock_enabled(&self, enabled: bool);
|
fn set_drag_lock_enabled(&self, enabled: bool);
|
||||||
|
fn natural_scrolling_enabled(&self) -> Option<bool> {
|
||||||
|
None
|
||||||
|
}
|
||||||
fn set_natural_scrolling_enabled(&self, enabled: bool);
|
fn set_natural_scrolling_enabled(&self, enabled: bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -140,6 +168,21 @@ pub enum InputDeviceCapability {
|
||||||
Switch,
|
Switch,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl InputDeviceCapability {
|
||||||
|
pub fn to_libinput(self) -> DeviceCapability {
|
||||||
|
use crate::libinput::consts::*;
|
||||||
|
match self {
|
||||||
|
InputDeviceCapability::Keyboard => LIBINPUT_DEVICE_CAP_KEYBOARD,
|
||||||
|
InputDeviceCapability::Pointer => LIBINPUT_DEVICE_CAP_POINTER,
|
||||||
|
InputDeviceCapability::Touch => LIBINPUT_DEVICE_CAP_TOUCH,
|
||||||
|
InputDeviceCapability::TabletTool => LIBINPUT_DEVICE_CAP_TABLET_TOOL,
|
||||||
|
InputDeviceCapability::TabletPad => LIBINPUT_DEVICE_CAP_TABLET_PAD,
|
||||||
|
InputDeviceCapability::Gesture => LIBINPUT_DEVICE_CAP_GESTURE,
|
||||||
|
InputDeviceCapability::Switch => LIBINPUT_DEVICE_CAP_SWITCH,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum InputDeviceAccelProfile {
|
pub enum InputDeviceAccelProfile {
|
||||||
Flat,
|
Flat,
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,7 @@ use {
|
||||||
libinput::{
|
libinput::{
|
||||||
consts::{
|
consts::{
|
||||||
AccelProfile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
|
AccelProfile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
|
||||||
LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT, LIBINPUT_DEVICE_CAP_GESTURE,
|
LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT,
|
||||||
LIBINPUT_DEVICE_CAP_KEYBOARD, LIBINPUT_DEVICE_CAP_POINTER,
|
|
||||||
LIBINPUT_DEVICE_CAP_SWITCH, LIBINPUT_DEVICE_CAP_TABLET_PAD,
|
|
||||||
LIBINPUT_DEVICE_CAP_TABLET_TOOL, LIBINPUT_DEVICE_CAP_TOUCH,
|
|
||||||
},
|
},
|
||||||
device::RegisteredDevice,
|
device::RegisteredDevice,
|
||||||
LibInput, LibInputAdapter, LibInputError,
|
LibInput, LibInputAdapter, LibInputError,
|
||||||
|
|
@ -281,7 +278,7 @@ pub async fn create(state: &Rc<State>) -> Result<Rc<MetalBackend>, MetalError> {
|
||||||
struct MetalInputDevice {
|
struct MetalInputDevice {
|
||||||
slot: usize,
|
slot: usize,
|
||||||
id: InputDeviceId,
|
id: InputDeviceId,
|
||||||
_devnum: c::dev_t,
|
devnum: c::dev_t,
|
||||||
fd: CloneCell<Option<Rc<OwnedFd>>>,
|
fd: CloneCell<Option<Rc<OwnedFd>>>,
|
||||||
inputdev: CloneCell<Option<Rc<RegisteredDevice>>>,
|
inputdev: CloneCell<Option<Rc<RegisteredDevice>>>,
|
||||||
devnode: CString,
|
devnode: CString,
|
||||||
|
|
@ -290,17 +287,22 @@ struct MetalInputDevice {
|
||||||
events: SyncQueue<InputEvent>,
|
events: SyncQueue<InputEvent>,
|
||||||
cb: CloneCell<Option<Rc<dyn Fn()>>>,
|
cb: CloneCell<Option<Rc<dyn Fn()>>>,
|
||||||
name: CloneCell<Rc<String>>,
|
name: CloneCell<Rc<String>>,
|
||||||
natural_scrolling: Cell<bool>,
|
transform_matrix: Cell<Option<TransformMatrix>>,
|
||||||
|
|
||||||
// state
|
// state
|
||||||
pressed_keys: SmallMap<u32, (), 5>,
|
pressed_keys: SmallMap<u32, (), 5>,
|
||||||
pressed_buttons: SmallMap<u32, (), 2>,
|
pressed_buttons: SmallMap<u32, (), 2>,
|
||||||
|
|
||||||
// config
|
// config
|
||||||
|
desired: InputDeviceProperties,
|
||||||
|
effective: InputDeviceProperties,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct InputDeviceProperties {
|
||||||
left_handed: Cell<Option<bool>>,
|
left_handed: Cell<Option<bool>>,
|
||||||
accel_profile: Cell<Option<AccelProfile>>,
|
accel_profile: Cell<Option<AccelProfile>>,
|
||||||
accel_speed: Cell<Option<f64>>,
|
accel_speed: Cell<Option<f64>>,
|
||||||
transform_matrix: Cell<Option<TransformMatrix>>,
|
|
||||||
tap_enabled: Cell<Option<bool>>,
|
tap_enabled: Cell<Option<bool>>,
|
||||||
drag_enabled: Cell<Option<bool>>,
|
drag_enabled: Cell<Option<bool>>,
|
||||||
drag_lock_enabled: Cell<Option<bool>>,
|
drag_lock_enabled: Cell<Option<bool>>,
|
||||||
|
|
@ -341,30 +343,58 @@ impl LibInputAdapter for DeviceHolder {
|
||||||
|
|
||||||
impl MetalInputDevice {
|
impl MetalInputDevice {
|
||||||
fn apply_config(&self) {
|
fn apply_config(&self) {
|
||||||
let dev = match self.inputdev.get() {
|
if self.inputdev.is_none() {
|
||||||
Some(dev) => dev,
|
return;
|
||||||
_ => return,
|
}
|
||||||
|
if let Some(lh) = self.desired.left_handed.get() {
|
||||||
|
self.set_left_handed(lh);
|
||||||
|
}
|
||||||
|
if let Some(profile) = self.desired.accel_profile.get() {
|
||||||
|
self.set_accel_profile_(profile);
|
||||||
|
}
|
||||||
|
if let Some(speed) = self.desired.accel_speed.get() {
|
||||||
|
self.set_accel_speed(speed);
|
||||||
|
}
|
||||||
|
if let Some(enabled) = self.desired.tap_enabled.get() {
|
||||||
|
self.set_tap_enabled(enabled);
|
||||||
|
}
|
||||||
|
if let Some(enabled) = self.desired.drag_enabled.get() {
|
||||||
|
self.set_drag_enabled(enabled);
|
||||||
|
}
|
||||||
|
if let Some(enabled) = self.desired.drag_lock_enabled.get() {
|
||||||
|
self.set_drag_lock_enabled(enabled);
|
||||||
|
}
|
||||||
|
if let Some(enabled) = self.desired.natural_scrolling_enabled.get() {
|
||||||
|
self.set_natural_scrolling_enabled(enabled);
|
||||||
|
}
|
||||||
|
self.fetch_effective();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fetch_effective(&self) {
|
||||||
|
let Some(dev) = self.inputdev.get() else {
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
if let Some(lh) = self.left_handed.get() {
|
let device = dev.device();
|
||||||
dev.device().set_left_handed(lh);
|
if device.left_handed_available() {
|
||||||
|
self.effective.left_handed.set(Some(device.left_handed()));
|
||||||
}
|
}
|
||||||
if let Some(profile) = self.accel_profile.get() {
|
if device.accel_available() {
|
||||||
dev.device().set_accel_profile(profile);
|
self.effective
|
||||||
|
.accel_profile
|
||||||
|
.set(Some(device.accel_profile()));
|
||||||
|
self.effective.accel_speed.set(Some(device.accel_speed()));
|
||||||
}
|
}
|
||||||
if let Some(speed) = self.accel_speed.get() {
|
if device.tap_available() {
|
||||||
dev.device().set_accel_speed(speed);
|
self.effective.tap_enabled.set(Some(device.tap_enabled()));
|
||||||
|
self.effective.drag_enabled.set(Some(device.drag_enabled()));
|
||||||
|
self.effective
|
||||||
|
.drag_lock_enabled
|
||||||
|
.set(Some(device.drag_lock_enabled()));
|
||||||
}
|
}
|
||||||
if let Some(enabled) = self.tap_enabled.get() {
|
if device.has_natural_scrolling() {
|
||||||
dev.device().set_tap_enabled(enabled);
|
self.effective
|
||||||
}
|
.natural_scrolling_enabled
|
||||||
if let Some(enabled) = self.drag_enabled.get() {
|
.set(Some(device.natural_scrolling_enabled()));
|
||||||
dev.device().set_drag_enabled(enabled);
|
|
||||||
}
|
|
||||||
if let Some(enabled) = self.drag_lock_enabled.get() {
|
|
||||||
dev.device().set_drag_lock_enabled(enabled);
|
|
||||||
}
|
|
||||||
if let Some(enabled) = self.natural_scrolling_enabled.get() {
|
|
||||||
self.do_set_natural_scrolling_enabled(&dev, enabled);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -386,10 +416,16 @@ impl MetalInputDevice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_set_natural_scrolling_enabled(&self, dev: &RegisteredDevice, enabled: bool) {
|
fn set_accel_profile_(&self, profile: AccelProfile) {
|
||||||
dev.device().set_natural_scrolling_enabled(enabled);
|
self.desired.accel_profile.set(Some(profile));
|
||||||
self.natural_scrolling
|
if let Some(dev) = self.inputdev.get() {
|
||||||
.set(dev.device().natural_scrolling_enabled());
|
if dev.device().accel_available() {
|
||||||
|
dev.device().set_accel_profile(profile);
|
||||||
|
self.effective
|
||||||
|
.accel_profile
|
||||||
|
.set(Some(dev.device().accel_profile()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -415,15 +451,7 @@ impl InputDevice for MetalInputDevice {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_capability(&self, cap: InputDeviceCapability) -> bool {
|
fn has_capability(&self, cap: InputDeviceCapability) -> bool {
|
||||||
let li = match cap {
|
let li = cap.to_libinput();
|
||||||
InputDeviceCapability::Keyboard => LIBINPUT_DEVICE_CAP_KEYBOARD,
|
|
||||||
InputDeviceCapability::Pointer => LIBINPUT_DEVICE_CAP_POINTER,
|
|
||||||
InputDeviceCapability::Touch => LIBINPUT_DEVICE_CAP_TOUCH,
|
|
||||||
InputDeviceCapability::TabletTool => LIBINPUT_DEVICE_CAP_TABLET_TOOL,
|
|
||||||
InputDeviceCapability::TabletPad => LIBINPUT_DEVICE_CAP_TABLET_PAD,
|
|
||||||
InputDeviceCapability::Gesture => LIBINPUT_DEVICE_CAP_GESTURE,
|
|
||||||
InputDeviceCapability::Switch => LIBINPUT_DEVICE_CAP_SWITCH,
|
|
||||||
};
|
|
||||||
match self.inputdev.get() {
|
match self.inputdev.get() {
|
||||||
Some(dev) => dev.device().has_cap(li),
|
Some(dev) => dev.device().has_cap(li),
|
||||||
_ => false,
|
_ => false,
|
||||||
|
|
@ -431,9 +459,14 @@ impl InputDevice for MetalInputDevice {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_left_handed(&self, left_handed: bool) {
|
fn set_left_handed(&self, left_handed: bool) {
|
||||||
self.left_handed.set(Some(left_handed));
|
self.desired.left_handed.set(Some(left_handed));
|
||||||
if let Some(dev) = self.inputdev.get() {
|
if let Some(dev) = self.inputdev.get() {
|
||||||
dev.device().set_left_handed(left_handed);
|
if dev.device().left_handed_available() {
|
||||||
|
dev.device().set_left_handed(left_handed);
|
||||||
|
self.effective
|
||||||
|
.left_handed
|
||||||
|
.set(Some(dev.device().left_handed()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -442,16 +475,18 @@ impl InputDevice for MetalInputDevice {
|
||||||
InputDeviceAccelProfile::Flat => LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT,
|
InputDeviceAccelProfile::Flat => LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT,
|
||||||
InputDeviceAccelProfile::Adaptive => LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
|
InputDeviceAccelProfile::Adaptive => LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
|
||||||
};
|
};
|
||||||
self.accel_profile.set(Some(profile));
|
self.set_accel_profile_(profile);
|
||||||
if let Some(dev) = self.inputdev.get() {
|
|
||||||
dev.device().set_accel_profile(profile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_accel_speed(&self, speed: f64) {
|
fn set_accel_speed(&self, speed: f64) {
|
||||||
self.accel_speed.set(Some(speed));
|
self.desired.accel_speed.set(Some(speed));
|
||||||
if let Some(dev) = self.inputdev.get() {
|
if let Some(dev) = self.inputdev.get() {
|
||||||
dev.device().set_accel_speed(speed);
|
if dev.device().accel_available() {
|
||||||
|
dev.device().set_accel_speed(speed);
|
||||||
|
self.effective
|
||||||
|
.accel_speed
|
||||||
|
.set(Some(dev.device().accel_speed()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -463,33 +498,95 @@ impl InputDevice for MetalInputDevice {
|
||||||
self.name.get()
|
self.name.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn dev_t(&self) -> Option<c::dev_t> {
|
||||||
|
Some(self.devnum)
|
||||||
|
}
|
||||||
|
|
||||||
fn set_tap_enabled(&self, enabled: bool) {
|
fn set_tap_enabled(&self, enabled: bool) {
|
||||||
self.tap_enabled.set(Some(enabled));
|
self.desired.tap_enabled.set(Some(enabled));
|
||||||
if let Some(dev) = self.inputdev.get() {
|
if let Some(dev) = self.inputdev.get() {
|
||||||
dev.device().set_tap_enabled(enabled);
|
if dev.device().tap_available() {
|
||||||
|
dev.device().set_tap_enabled(enabled);
|
||||||
|
self.effective
|
||||||
|
.tap_enabled
|
||||||
|
.set(Some(dev.device().tap_enabled()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_drag_enabled(&self, enabled: bool) {
|
fn set_drag_enabled(&self, enabled: bool) {
|
||||||
self.drag_enabled.set(Some(enabled));
|
self.desired.drag_enabled.set(Some(enabled));
|
||||||
if let Some(dev) = self.inputdev.get() {
|
if let Some(dev) = self.inputdev.get() {
|
||||||
dev.device().set_drag_enabled(enabled);
|
if dev.device().tap_available() {
|
||||||
|
dev.device().set_drag_enabled(enabled);
|
||||||
|
self.effective
|
||||||
|
.drag_enabled
|
||||||
|
.set(Some(dev.device().drag_enabled()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_drag_lock_enabled(&self, enabled: bool) {
|
fn set_drag_lock_enabled(&self, enabled: bool) {
|
||||||
self.drag_lock_enabled.set(Some(enabled));
|
self.desired.drag_lock_enabled.set(Some(enabled));
|
||||||
if let Some(dev) = self.inputdev.get() {
|
if let Some(dev) = self.inputdev.get() {
|
||||||
dev.device().set_drag_lock_enabled(enabled);
|
if dev.device().tap_available() {
|
||||||
|
dev.device().set_drag_lock_enabled(enabled);
|
||||||
|
self.effective
|
||||||
|
.drag_lock_enabled
|
||||||
|
.set(Some(dev.device().drag_lock_enabled()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_natural_scrolling_enabled(&self, enabled: bool) {
|
fn set_natural_scrolling_enabled(&self, enabled: bool) {
|
||||||
self.natural_scrolling_enabled.set(Some(enabled));
|
self.desired.natural_scrolling_enabled.set(Some(enabled));
|
||||||
if let Some(dev) = self.inputdev.get() {
|
if let Some(dev) = self.inputdev.get() {
|
||||||
self.do_set_natural_scrolling_enabled(&dev, enabled);
|
if dev.device().has_natural_scrolling() {
|
||||||
|
dev.device().set_natural_scrolling_enabled(enabled);
|
||||||
|
self.effective
|
||||||
|
.natural_scrolling_enabled
|
||||||
|
.set(Some(dev.device().natural_scrolling_enabled()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn left_handed(&self) -> Option<bool> {
|
||||||
|
self.effective.left_handed.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accel_profile(&self) -> Option<InputDeviceAccelProfile> {
|
||||||
|
let p = self.effective.accel_profile.get()?;
|
||||||
|
let p = match p {
|
||||||
|
LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT => InputDeviceAccelProfile::Flat,
|
||||||
|
LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE => InputDeviceAccelProfile::Adaptive,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
Some(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accel_speed(&self) -> Option<f64> {
|
||||||
|
self.effective.accel_speed.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transform_matrix(&self) -> Option<TransformMatrix> {
|
||||||
|
self.transform_matrix.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tap_enabled(&self) -> Option<bool> {
|
||||||
|
self.effective.tap_enabled.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drag_enabled(&self) -> Option<bool> {
|
||||||
|
self.effective.drag_enabled.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drag_lock_enabled(&self) -> Option<bool> {
|
||||||
|
self.effective.drag_lock_enabled.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn natural_scrolling_enabled(&self) -> Option<bool> {
|
||||||
|
self.effective.natural_scrolling_enabled.get()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MetalInputDevice {
|
impl MetalInputDevice {
|
||||||
|
|
|
||||||
|
|
@ -149,13 +149,21 @@ impl MetalBackend {
|
||||||
InputEvent::Axis120 {
|
InputEvent::Axis120 {
|
||||||
dist: scroll as _,
|
dist: scroll as _,
|
||||||
axis,
|
axis,
|
||||||
inverted: dev.natural_scrolling.get(),
|
inverted: dev
|
||||||
|
.effective
|
||||||
|
.natural_scrolling_enabled
|
||||||
|
.get()
|
||||||
|
.unwrap_or_default(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
InputEvent::AxisPx {
|
InputEvent::AxisPx {
|
||||||
dist: Fixed::from_f64(scroll),
|
dist: Fixed::from_f64(scroll),
|
||||||
axis,
|
axis,
|
||||||
inverted: dev.natural_scrolling.get(),
|
inverted: dev
|
||||||
|
.effective
|
||||||
|
.natural_scrolling_enabled
|
||||||
|
.get()
|
||||||
|
.unwrap_or_default(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
dev.event(ie);
|
dev.event(ie);
|
||||||
|
|
@ -192,10 +200,14 @@ impl MetalBackend {
|
||||||
let mut dx_unaccelerated = event.dx_unaccelerated();
|
let mut dx_unaccelerated = event.dx_unaccelerated();
|
||||||
let mut dy_unaccelerated = event.dy_unaccelerated();
|
let mut dy_unaccelerated = event.dy_unaccelerated();
|
||||||
if let Some(matrix) = dev.transform_matrix.get() {
|
if let Some(matrix) = dev.transform_matrix.get() {
|
||||||
dx = matrix[0][0] * dx + matrix[0][1] * dy;
|
(dx, dy) = (
|
||||||
dy = matrix[1][0] * dx + matrix[1][1] * dy;
|
matrix[0][0] * dx + matrix[0][1] * dy,
|
||||||
dx_unaccelerated = matrix[0][0] * dx_unaccelerated + matrix[0][1] * dy_unaccelerated;
|
matrix[1][0] * dx + matrix[1][1] * dy,
|
||||||
dy_unaccelerated = matrix[1][0] * dx_unaccelerated + matrix[1][1] * dy_unaccelerated;
|
);
|
||||||
|
(dx_unaccelerated, dy_unaccelerated) = (
|
||||||
|
matrix[0][0] * dx_unaccelerated + matrix[0][1] * dy_unaccelerated,
|
||||||
|
matrix[1][0] * dx_unaccelerated + matrix[1][1] * dy_unaccelerated,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
dev.event(InputEvent::Motion {
|
dev.event(InputEvent::Motion {
|
||||||
time_usec: event.time_usec(),
|
time_usec: event.time_usec(),
|
||||||
|
|
|
||||||
|
|
@ -278,7 +278,7 @@ impl MetalBackend {
|
||||||
let dev = Rc::new(MetalInputDevice {
|
let dev = Rc::new(MetalInputDevice {
|
||||||
slot,
|
slot,
|
||||||
id: device_id,
|
id: device_id,
|
||||||
_devnum: devnum,
|
devnum,
|
||||||
fd: Default::default(),
|
fd: Default::default(),
|
||||||
inputdev: Default::default(),
|
inputdev: Default::default(),
|
||||||
devnode: devnode.to_owned(),
|
devnode: devnode.to_owned(),
|
||||||
|
|
@ -287,17 +287,11 @@ impl MetalBackend {
|
||||||
events: Default::default(),
|
events: Default::default(),
|
||||||
cb: Default::default(),
|
cb: Default::default(),
|
||||||
name: Default::default(),
|
name: Default::default(),
|
||||||
natural_scrolling: Default::default(),
|
|
||||||
pressed_keys: Default::default(),
|
pressed_keys: Default::default(),
|
||||||
pressed_buttons: Default::default(),
|
pressed_buttons: Default::default(),
|
||||||
left_handed: Default::default(),
|
desired: Default::default(),
|
||||||
accel_profile: Default::default(),
|
|
||||||
accel_speed: Default::default(),
|
|
||||||
transform_matrix: Default::default(),
|
transform_matrix: Default::default(),
|
||||||
tap_enabled: Default::default(),
|
effective: Default::default(),
|
||||||
drag_enabled: Default::default(),
|
|
||||||
drag_lock_enabled: Default::default(),
|
|
||||||
natural_scrolling_enabled: Default::default(),
|
|
||||||
});
|
});
|
||||||
slots[slot] = Some(dev.clone());
|
slots[slot] = Some(dev.clone());
|
||||||
self.device_holder
|
self.device_holder
|
||||||
|
|
@ -337,8 +331,6 @@ impl MetalBackend {
|
||||||
};
|
};
|
||||||
inputdev.device().set_slot(slot);
|
inputdev.device().set_slot(slot);
|
||||||
dev.name.set(Rc::new(inputdev.device().name()));
|
dev.name.set(Rc::new(inputdev.device().name()));
|
||||||
dev.natural_scrolling
|
|
||||||
.set(inputdev.device().natural_scrolling_enabled());
|
|
||||||
dev.inputdev.set(Some(inputdev));
|
dev.inputdev.set(Some(inputdev));
|
||||||
dev.apply_config();
|
dev.apply_config();
|
||||||
slf.state
|
slf.state
|
||||||
|
|
|
||||||
|
|
@ -1177,6 +1177,10 @@ impl InputDevice for XSeatKeyboard {
|
||||||
self.0.kb_name.clone()
|
self.0.kb_name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn dev_t(&self) -> Option<dev_t> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn set_tap_enabled(&self, enabled: bool) {
|
fn set_tap_enabled(&self, enabled: bool) {
|
||||||
let _ = enabled;
|
let _ = enabled;
|
||||||
}
|
}
|
||||||
|
|
@ -1242,6 +1246,10 @@ impl InputDevice for XSeatMouse {
|
||||||
self.0.mouse_name.clone()
|
self.0.mouse_name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn dev_t(&self) -> Option<dev_t> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn set_tap_enabled(&self, enabled: bool) {
|
fn set_tap_enabled(&self, enabled: bool) {
|
||||||
let _ = enabled;
|
let _ = enabled;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
src/cli.rs
10
src/cli.rs
|
|
@ -1,5 +1,6 @@
|
||||||
mod generate;
|
mod generate;
|
||||||
mod idle;
|
mod idle;
|
||||||
|
mod input;
|
||||||
mod log;
|
mod log;
|
||||||
mod quit;
|
mod quit;
|
||||||
mod randr;
|
mod randr;
|
||||||
|
|
@ -10,7 +11,11 @@ mod set_log_level;
|
||||||
mod unlock;
|
mod unlock;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{cli::randr::RandrArgs, compositor::start_compositor, portal},
|
crate::{
|
||||||
|
cli::{input::InputArgs, randr::RandrArgs},
|
||||||
|
compositor::start_compositor,
|
||||||
|
portal,
|
||||||
|
},
|
||||||
::log::Level,
|
::log::Level,
|
||||||
clap::{Args, Parser, Subcommand, ValueEnum},
|
clap::{Args, Parser, Subcommand, ValueEnum},
|
||||||
clap_complete::Shell,
|
clap_complete::Shell,
|
||||||
|
|
@ -58,6 +63,8 @@ pub enum Cmd {
|
||||||
Portal,
|
Portal,
|
||||||
/// Inspect/modify graphics card and connector settings.
|
/// Inspect/modify graphics card and connector settings.
|
||||||
Randr(RandrArgs),
|
Randr(RandrArgs),
|
||||||
|
/// Inspect/modify input settings.
|
||||||
|
Input(InputArgs),
|
||||||
#[cfg(feature = "it")]
|
#[cfg(feature = "it")]
|
||||||
RunTests,
|
RunTests,
|
||||||
}
|
}
|
||||||
|
|
@ -221,6 +228,7 @@ pub fn main() {
|
||||||
Cmd::SeatTest(a) => seat_test::main(cli.global, a),
|
Cmd::SeatTest(a) => seat_test::main(cli.global, a),
|
||||||
Cmd::Portal => portal::run(cli.global),
|
Cmd::Portal => portal::run(cli.global),
|
||||||
Cmd::Randr(a) => randr::main(cli.global, a),
|
Cmd::Randr(a) => randr::main(cli.global, a),
|
||||||
|
Cmd::Input(a) => input::main(cli.global, a),
|
||||||
#[cfg(feature = "it")]
|
#[cfg(feature = "it")]
|
||||||
Cmd::RunTests => crate::it::run_tests(),
|
Cmd::RunTests => crate::it::run_tests(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
732
src/cli/input.rs
Normal file
732
src/cli/input.rs
Normal file
|
|
@ -0,0 +1,732 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
backend::{InputDeviceAccelProfile, InputDeviceCapability},
|
||||||
|
cli::GlobalArgs,
|
||||||
|
clientmem::ClientMem,
|
||||||
|
libinput::consts::{
|
||||||
|
LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE, LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT,
|
||||||
|
},
|
||||||
|
tools::tool_client::{with_tool_client, Handle, ToolClient},
|
||||||
|
utils::{errorfmt::ErrorFmt, string_ext::StringExt},
|
||||||
|
wire::{jay_compositor, jay_input, JayInputId},
|
||||||
|
},
|
||||||
|
clap::{Args, Subcommand, ValueEnum},
|
||||||
|
isnt::std_1::vec::IsntVecExt,
|
||||||
|
std::{
|
||||||
|
cell::RefCell,
|
||||||
|
io::{stdin, stdout, Read, Write},
|
||||||
|
mem,
|
||||||
|
ops::DerefMut,
|
||||||
|
rc::Rc,
|
||||||
|
},
|
||||||
|
uapi::c,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Args, Debug)]
|
||||||
|
pub struct InputArgs {
|
||||||
|
#[clap(subcommand)]
|
||||||
|
pub command: Option<InputCmd>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand, Debug)]
|
||||||
|
pub enum InputCmd {
|
||||||
|
/// Show the current settings.
|
||||||
|
Show(ShowArgs),
|
||||||
|
/// Modify the settings of a seat.
|
||||||
|
Seat(SeatArgs),
|
||||||
|
/// Modify the settings of a device.
|
||||||
|
Device(DeviceArgs),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for InputCmd {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Show(Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Default)]
|
||||||
|
pub struct ShowArgs {
|
||||||
|
/// Print more information about devices.
|
||||||
|
#[arg(short, long)]
|
||||||
|
pub verbose: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug)]
|
||||||
|
pub struct SeatArgs {
|
||||||
|
/// The seat to modify, e.g. default.
|
||||||
|
pub seat: String,
|
||||||
|
#[clap(subcommand)]
|
||||||
|
pub command: Option<SeatCommand>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug)]
|
||||||
|
pub struct DeviceArgs {
|
||||||
|
/// The ID of the device to modify.
|
||||||
|
pub device: u32,
|
||||||
|
#[clap(subcommand)]
|
||||||
|
pub command: Option<DeviceCommand>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand, Debug, Clone)]
|
||||||
|
pub enum SeatCommand {
|
||||||
|
/// Show information about this seat.
|
||||||
|
Show(SeatShowArgs),
|
||||||
|
/// Set the repeat rate of the keyboard.
|
||||||
|
SetRepeatRate(SetRepeatRateArgs),
|
||||||
|
/// Set the keymap.
|
||||||
|
SetKeymap(SetKeymapArgs),
|
||||||
|
/// Retrieve the keymap.
|
||||||
|
Keymap,
|
||||||
|
/// Configure whether this seat uses the hardware cursor.
|
||||||
|
UseHardwareCursor(UseHardwareCursorArgs),
|
||||||
|
/// Set the size of the cursor.
|
||||||
|
SetCursorSize(SetCursorSizeArgs),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SeatCommand {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Show(SeatShowArgs::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Default, Clone)]
|
||||||
|
pub struct SeatShowArgs {
|
||||||
|
/// Print more information about devices.
|
||||||
|
#[arg(short, long)]
|
||||||
|
pub verbose: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand, Debug, Clone, Default)]
|
||||||
|
pub enum DeviceCommand {
|
||||||
|
/// Show information about this device.
|
||||||
|
#[default]
|
||||||
|
Show,
|
||||||
|
/// Set the acceleration profile.
|
||||||
|
SetAccelProfile(SetAccelProfileArgs),
|
||||||
|
/// Set the acceleration speed.
|
||||||
|
SetAccelSpeed(SetAccelSpeedArgs),
|
||||||
|
/// Set whether tap is enabled.
|
||||||
|
SetTapEnabled(SetTapDragEnabledArgs),
|
||||||
|
/// Set whether tap-drag is enabled.
|
||||||
|
SetTapDragEnabled(SetTapDragEnabledArgs),
|
||||||
|
/// Set whether tap-drag-lock is enabled.
|
||||||
|
SetTapDragLockEnabled(SetTapDragLockEnabledArgs),
|
||||||
|
/// Set whether the device is left-handed.
|
||||||
|
SetLeftHanded(SetLeftHandedArgs),
|
||||||
|
/// Set whether the device uses natural scrolling.
|
||||||
|
SetNaturalScrolling(SetNaturalScrollingArgs),
|
||||||
|
/// Set the pixels to scroll per scroll-wheel dedent.
|
||||||
|
SetPxPerWheelScroll(SetPxPerWheelScrollArgs),
|
||||||
|
/// Set the transformation matrix.
|
||||||
|
SetTransformMatrix(SetTransformMatrixArgs),
|
||||||
|
/// Attach the device to a seat.
|
||||||
|
Attach(AttachArgs),
|
||||||
|
/// Detach the device from its seat.
|
||||||
|
Detach,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(ValueEnum, Debug, Clone)]
|
||||||
|
pub enum AccelProfile {
|
||||||
|
Flat,
|
||||||
|
Adaptive,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Clone)]
|
||||||
|
pub struct SetAccelProfileArgs {
|
||||||
|
/// The profile.
|
||||||
|
pub profile: AccelProfile,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Clone)]
|
||||||
|
pub struct SetAccelSpeedArgs {
|
||||||
|
/// The speed. Must be in the range \[-1, 1].
|
||||||
|
pub speed: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Clone)]
|
||||||
|
pub struct SetTapEnabledArgs {
|
||||||
|
/// Whether tap is enabled.
|
||||||
|
#[arg(action = clap::ArgAction::Set)]
|
||||||
|
pub enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Clone)]
|
||||||
|
pub struct SetTapDragEnabledArgs {
|
||||||
|
/// Whether tap-drag is enabled.
|
||||||
|
#[arg(action = clap::ArgAction::Set)]
|
||||||
|
pub enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Clone)]
|
||||||
|
pub struct SetTapDragLockEnabledArgs {
|
||||||
|
/// Whether tap-drag-lock is enabled.
|
||||||
|
#[arg(action = clap::ArgAction::Set)]
|
||||||
|
pub enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Clone)]
|
||||||
|
pub struct SetLeftHandedArgs {
|
||||||
|
/// Whether the device is left handed.
|
||||||
|
#[arg(action = clap::ArgAction::Set)]
|
||||||
|
pub left_handed: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Clone)]
|
||||||
|
pub struct SetNaturalScrollingArgs {
|
||||||
|
/// Whether natural scrolling is enabled.
|
||||||
|
#[arg(action = clap::ArgAction::Set)]
|
||||||
|
pub natural_scrolling: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Clone)]
|
||||||
|
pub struct SetPxPerWheelScrollArgs {
|
||||||
|
/// The number of pixels to scroll.
|
||||||
|
pub px: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Clone)]
|
||||||
|
pub struct SetTransformMatrixArgs {
|
||||||
|
pub m11: f64,
|
||||||
|
pub m12: f64,
|
||||||
|
pub m21: f64,
|
||||||
|
pub m22: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Clone)]
|
||||||
|
pub struct AttachArgs {
|
||||||
|
/// The seat to attach to.
|
||||||
|
pub seat: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Clone)]
|
||||||
|
pub struct SetRepeatRateArgs {
|
||||||
|
/// The number of repeats per second.
|
||||||
|
pub rate: i32,
|
||||||
|
/// The delay before the first repeat in milliseconds.
|
||||||
|
pub delay: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Clone)]
|
||||||
|
pub struct SetCursorSizeArgs {
|
||||||
|
/// The size of the cursor.
|
||||||
|
pub size: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Clone)]
|
||||||
|
pub struct SetKeymapArgs {
|
||||||
|
/// The file to read the keymap from. Omit for stdin.
|
||||||
|
pub file: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Args, Debug, Clone)]
|
||||||
|
pub struct UseHardwareCursorArgs {
|
||||||
|
/// Whether the seat uses the hardware cursor.
|
||||||
|
#[arg(action = clap::ArgAction::Set)]
|
||||||
|
pub enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main(global: GlobalArgs, args: InputArgs) {
|
||||||
|
with_tool_client(global.log_level.into(), |tc| async move {
|
||||||
|
let idle = Rc::new(Input { tc: tc.clone() });
|
||||||
|
idle.run(args).await;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct Seat {
|
||||||
|
pub name: String,
|
||||||
|
pub repeat_rate: i32,
|
||||||
|
pub repeat_delay: i32,
|
||||||
|
pub hardware_cursor: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct InputDevice {
|
||||||
|
pub id: u32,
|
||||||
|
pub name: String,
|
||||||
|
pub seat: Option<String>,
|
||||||
|
pub syspath: Option<String>,
|
||||||
|
pub devnode: Option<String>,
|
||||||
|
pub capabilities: Vec<InputDeviceCapability>,
|
||||||
|
pub accel_profile: Option<InputDeviceAccelProfile>,
|
||||||
|
pub accel_speed: Option<f64>,
|
||||||
|
pub tap_enabled: Option<bool>,
|
||||||
|
pub tap_drag_enabled: Option<bool>,
|
||||||
|
pub tap_drag_lock_enabled: Option<bool>,
|
||||||
|
pub left_handed: Option<bool>,
|
||||||
|
pub natural_scrolling_enabled: Option<bool>,
|
||||||
|
pub px_per_wheel_scroll: Option<f64>,
|
||||||
|
pub transform_matrix: Option<[[f64; 2]; 2]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
struct Data {
|
||||||
|
seats: Vec<Seat>,
|
||||||
|
input_device: Vec<InputDevice>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Input {
|
||||||
|
tc: Rc<ToolClient>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Input {
|
||||||
|
async fn run(self: &Rc<Self>, args: InputArgs) {
|
||||||
|
let tc = &self.tc;
|
||||||
|
let comp = tc.jay_compositor().await;
|
||||||
|
let input = tc.id();
|
||||||
|
tc.send(jay_compositor::GetInput {
|
||||||
|
self_id: comp,
|
||||||
|
id: input,
|
||||||
|
});
|
||||||
|
match args.command.unwrap_or_default() {
|
||||||
|
InputCmd::Show(args) => self.show(input, args).await,
|
||||||
|
InputCmd::Seat(args) => self.seat(input, args).await,
|
||||||
|
InputCmd::Device(args) => self.device(input, args).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_error<F: Fn(&str) + 'static>(&self, input: JayInputId, f: F) {
|
||||||
|
jay_input::Error::handle(&self.tc, input, (), move |_, msg| {
|
||||||
|
f(msg.msg);
|
||||||
|
std::process::exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn seat(self: &Rc<Self>, input: JayInputId, args: SeatArgs) {
|
||||||
|
let tc = &self.tc;
|
||||||
|
match args.command.unwrap_or_default() {
|
||||||
|
SeatCommand::Show(a) => {
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not retrieve seat data: {}", e);
|
||||||
|
});
|
||||||
|
tc.send(jay_input::GetSeat {
|
||||||
|
self_id: input,
|
||||||
|
name: &args.seat,
|
||||||
|
});
|
||||||
|
let data = self.get(input).await;
|
||||||
|
self.print_data(data, a.verbose);
|
||||||
|
}
|
||||||
|
SeatCommand::SetRepeatRate(a) => {
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not set repeat rate: {}", e);
|
||||||
|
});
|
||||||
|
tc.send(jay_input::SetRepeatRate {
|
||||||
|
self_id: input,
|
||||||
|
seat: &args.seat,
|
||||||
|
repeat_rate: a.rate,
|
||||||
|
repeat_delay: a.delay,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
SeatCommand::SetKeymap(a) => {
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not set keymap: {}", e);
|
||||||
|
});
|
||||||
|
let map = match &a.file {
|
||||||
|
None => {
|
||||||
|
let mut map = vec![];
|
||||||
|
if let Err(e) = stdin().read_to_end(&mut map) {
|
||||||
|
eprintln!("Could not read from stdin: {}", ErrorFmt(e));
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
map
|
||||||
|
}
|
||||||
|
Some(f) => match std::fs::read(f) {
|
||||||
|
Ok(m) => m,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Could not read {}: {}", f, ErrorFmt(e));
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let mut memfd =
|
||||||
|
uapi::memfd_create("keymap", c::MFD_CLOEXEC | c::MFD_ALLOW_SEALING).unwrap();
|
||||||
|
memfd.write_all(&map).unwrap();
|
||||||
|
uapi::lseek(memfd.raw(), 0, c::SEEK_SET).unwrap();
|
||||||
|
uapi::fcntl_add_seals(
|
||||||
|
memfd.raw(),
|
||||||
|
c::F_SEAL_SEAL | c::F_SEAL_GROW | c::F_SEAL_SHRINK | c::F_SEAL_WRITE,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
tc.send(jay_input::SetKeymap {
|
||||||
|
self_id: input,
|
||||||
|
seat: &args.seat,
|
||||||
|
keymap: Rc::new(memfd),
|
||||||
|
keymap_len: map.len() as _,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
SeatCommand::UseHardwareCursor(a) => {
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not set hardware cursor: {}", e);
|
||||||
|
});
|
||||||
|
tc.send(jay_input::UseHardwareCursor {
|
||||||
|
self_id: input,
|
||||||
|
seat: &args.seat,
|
||||||
|
use_hardware_cursor: a.enabled as _,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
SeatCommand::Keymap => {
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not retrieve the keymap: {}", e);
|
||||||
|
});
|
||||||
|
let data = Rc::new(RefCell::new(Vec::new()));
|
||||||
|
jay_input::Keymap::handle(tc, input, data.clone(), |d, map| {
|
||||||
|
let mem = Rc::new(
|
||||||
|
ClientMem::new(map.keymap.raw(), map.keymap_len as _, true).unwrap(),
|
||||||
|
)
|
||||||
|
.offset(0);
|
||||||
|
mem.read(d.borrow_mut().deref_mut()).unwrap();
|
||||||
|
});
|
||||||
|
tc.send(jay_input::GetKeymap {
|
||||||
|
self_id: input,
|
||||||
|
seat: &args.seat,
|
||||||
|
});
|
||||||
|
tc.round_trip().await;
|
||||||
|
let map = data.take();
|
||||||
|
stdout().write_all(&map).unwrap();
|
||||||
|
}
|
||||||
|
SeatCommand::SetCursorSize(a) => {
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not set cursor size: {}", e);
|
||||||
|
});
|
||||||
|
tc.send(jay_input::SetCursorSize {
|
||||||
|
self_id: input,
|
||||||
|
seat: &args.seat,
|
||||||
|
size: a.size,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tc.round_trip().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn device(self: &Rc<Self>, input: JayInputId, args: DeviceArgs) {
|
||||||
|
let tc = &self.tc;
|
||||||
|
match args.command.unwrap_or_default() {
|
||||||
|
DeviceCommand::Show => {
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not retrieve device data: {}", e);
|
||||||
|
});
|
||||||
|
tc.send(jay_input::GetDevice {
|
||||||
|
self_id: input,
|
||||||
|
id: args.device,
|
||||||
|
});
|
||||||
|
let data = self.get(input).await;
|
||||||
|
for device in &data.input_device {
|
||||||
|
self.print_device("", true, device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DeviceCommand::SetAccelProfile(a) => {
|
||||||
|
let profile = match a.profile {
|
||||||
|
AccelProfile::Flat => LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT.0,
|
||||||
|
AccelProfile::Adaptive => LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE.0,
|
||||||
|
};
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not set the acceleration profile: {}", e);
|
||||||
|
});
|
||||||
|
tc.send(jay_input::SetAccelProfile {
|
||||||
|
self_id: input,
|
||||||
|
id: args.device,
|
||||||
|
profile,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
DeviceCommand::SetAccelSpeed(a) => {
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not set the acceleration speed: {}", e);
|
||||||
|
});
|
||||||
|
tc.send(jay_input::SetAccelSpeed {
|
||||||
|
self_id: input,
|
||||||
|
id: args.device,
|
||||||
|
speed: a.speed,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
DeviceCommand::SetTapEnabled(a) => {
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not modify the tap-enabled setting: {}", e);
|
||||||
|
});
|
||||||
|
tc.send(jay_input::SetTapEnabled {
|
||||||
|
self_id: input,
|
||||||
|
id: args.device,
|
||||||
|
enabled: a.enabled as _,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
DeviceCommand::SetTapDragEnabled(a) => {
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not modify the tap-drag-enabled setting: {}", e);
|
||||||
|
});
|
||||||
|
tc.send(jay_input::SetTapDragEnabled {
|
||||||
|
self_id: input,
|
||||||
|
id: args.device,
|
||||||
|
enabled: a.enabled as _,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
DeviceCommand::SetTapDragLockEnabled(a) => {
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not modify the tap-drag-lock-enabled setting: {}", e);
|
||||||
|
});
|
||||||
|
tc.send(jay_input::SetTapDragLockEnabled {
|
||||||
|
self_id: input,
|
||||||
|
id: args.device,
|
||||||
|
enabled: a.enabled as _,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
DeviceCommand::SetLeftHanded(a) => {
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not modify the left-handed setting: {}", e);
|
||||||
|
});
|
||||||
|
tc.send(jay_input::SetLeftHanded {
|
||||||
|
self_id: input,
|
||||||
|
id: args.device,
|
||||||
|
enabled: a.left_handed as _,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
DeviceCommand::SetNaturalScrolling(a) => {
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not modify the natural-scrolling setting: {}", e);
|
||||||
|
});
|
||||||
|
tc.send(jay_input::SetNaturalScrolling {
|
||||||
|
self_id: input,
|
||||||
|
id: args.device,
|
||||||
|
enabled: a.natural_scrolling as _,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
DeviceCommand::SetPxPerWheelScroll(a) => {
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not modify the px-per-wheel-scroll setting: {}", e);
|
||||||
|
});
|
||||||
|
tc.send(jay_input::SetPxPerWheelScroll {
|
||||||
|
self_id: input,
|
||||||
|
id: args.device,
|
||||||
|
px: a.px,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
DeviceCommand::SetTransformMatrix(a) => {
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not modify the transform matrix: {}", e);
|
||||||
|
});
|
||||||
|
tc.send(jay_input::SetTransformMatrix {
|
||||||
|
self_id: input,
|
||||||
|
id: args.device,
|
||||||
|
m11: a.m11,
|
||||||
|
m12: a.m12,
|
||||||
|
m21: a.m21,
|
||||||
|
m22: a.m22,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
DeviceCommand::Attach(a) => {
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not attach the device: {}", e);
|
||||||
|
});
|
||||||
|
tc.send(jay_input::Attach {
|
||||||
|
self_id: input,
|
||||||
|
id: args.device,
|
||||||
|
seat: &a.seat,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
DeviceCommand::Detach => {
|
||||||
|
self.handle_error(input, |e| {
|
||||||
|
eprintln!("Could not detach the device: {}", e);
|
||||||
|
});
|
||||||
|
tc.send(jay_input::Detach {
|
||||||
|
self_id: input,
|
||||||
|
id: args.device,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tc.round_trip().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn show(self: &Rc<Self>, input: JayInputId, args: ShowArgs) {
|
||||||
|
self.tc.send(jay_input::GetAll { self_id: input });
|
||||||
|
let data = self.get(input).await;
|
||||||
|
self.print_data(data, args.verbose);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_data(self: &Rc<Self>, mut data: Data, verbose: bool) {
|
||||||
|
data.seats.sort_by(|l, r| l.name.cmp(&r.name));
|
||||||
|
data.input_device.sort_by_key(|l| l.id);
|
||||||
|
let mut first = true;
|
||||||
|
let print_devices = |d: &[&InputDevice]| {
|
||||||
|
for device in d {
|
||||||
|
if verbose {
|
||||||
|
self.print_device(" ", false, device);
|
||||||
|
} else {
|
||||||
|
println!(" {}: {}", device.id, device.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for seat in &data.seats {
|
||||||
|
if !mem::take(&mut first) {
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
self.print_seat(seat);
|
||||||
|
let input_devices: Vec<_> = data
|
||||||
|
.input_device
|
||||||
|
.iter()
|
||||||
|
.filter(|c| c.seat.as_ref() == Some(&seat.name))
|
||||||
|
.collect();
|
||||||
|
if input_devices.is_not_empty() {
|
||||||
|
println!(" devices:");
|
||||||
|
}
|
||||||
|
print_devices(&input_devices);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let input_devices: Vec<_> = data
|
||||||
|
.input_device
|
||||||
|
.iter()
|
||||||
|
.filter(|c| c.seat.is_none())
|
||||||
|
.collect();
|
||||||
|
if input_devices.is_not_empty() {
|
||||||
|
if !mem::take(&mut first) {
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
println!("Detached devices:");
|
||||||
|
print_devices(&input_devices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_seat(&self, seat: &Seat) {
|
||||||
|
println!("Seat {}:", seat.name);
|
||||||
|
println!(" repeat rate: {}", seat.repeat_rate);
|
||||||
|
println!(" repeat delay: {}", seat.repeat_delay);
|
||||||
|
if !seat.hardware_cursor {
|
||||||
|
println!(" hardware cursor disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_device(&self, prefix: &str, print_seat: bool, device: &InputDevice) {
|
||||||
|
println!("{prefix}{}:", device.id);
|
||||||
|
println!("{prefix} name: {}", device.name);
|
||||||
|
if print_seat {
|
||||||
|
let seat = match device.seat.as_deref() {
|
||||||
|
Some(s) => s,
|
||||||
|
_ => "<detached>",
|
||||||
|
};
|
||||||
|
println!("{prefix} seat: {}", seat);
|
||||||
|
}
|
||||||
|
if let Some(v) = &device.syspath {
|
||||||
|
println!("{prefix} syspath: {}", v);
|
||||||
|
}
|
||||||
|
if let Some(v) = &device.devnode {
|
||||||
|
println!("{prefix} devnode: {}", v);
|
||||||
|
}
|
||||||
|
print!("{prefix} capabilities:");
|
||||||
|
let mut first = true;
|
||||||
|
for cap in &device.capabilities {
|
||||||
|
use InputDeviceCapability::*;
|
||||||
|
print!(" ");
|
||||||
|
if !mem::take(&mut first) {
|
||||||
|
print!("| ");
|
||||||
|
}
|
||||||
|
let name = match cap {
|
||||||
|
Keyboard => "keyboard",
|
||||||
|
Pointer => "pointer",
|
||||||
|
Touch => "touch",
|
||||||
|
TabletTool => "tablet tool",
|
||||||
|
TabletPad => "tablet pad",
|
||||||
|
Gesture => "gesture",
|
||||||
|
Switch => "switch",
|
||||||
|
};
|
||||||
|
print!("{}", name);
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
if let Some(v) = &device.accel_profile {
|
||||||
|
let name = match v {
|
||||||
|
InputDeviceAccelProfile::Flat => "flat",
|
||||||
|
InputDeviceAccelProfile::Adaptive => "adaptive",
|
||||||
|
};
|
||||||
|
println!("{prefix} accel profile: {}", name);
|
||||||
|
}
|
||||||
|
if let Some(v) = &device.accel_speed {
|
||||||
|
println!("{prefix} accel speed: {}", v);
|
||||||
|
}
|
||||||
|
if let Some(v) = &device.tap_enabled {
|
||||||
|
println!("{prefix} tap enabled: {}", v);
|
||||||
|
}
|
||||||
|
if let Some(v) = &device.tap_drag_enabled {
|
||||||
|
println!("{prefix} tap drag enabled: {}", v);
|
||||||
|
}
|
||||||
|
if let Some(v) = &device.tap_drag_lock_enabled {
|
||||||
|
println!("{prefix} tap drag lock enabled: {}", v);
|
||||||
|
}
|
||||||
|
if let Some(v) = &device.left_handed {
|
||||||
|
println!("{prefix} left handed: {}", v);
|
||||||
|
}
|
||||||
|
if let Some(v) = &device.natural_scrolling_enabled {
|
||||||
|
println!("{prefix} natural scrolling: {}", v);
|
||||||
|
}
|
||||||
|
if let Some(v) = &device.px_per_wheel_scroll {
|
||||||
|
println!("{prefix} px per wheel scroll: {}", v);
|
||||||
|
}
|
||||||
|
if let Some(v) = &device.transform_matrix {
|
||||||
|
println!("{prefix} transform matrix: {:?}", v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get(self: &Rc<Self>, input: JayInputId) -> Data {
|
||||||
|
let tc = &self.tc;
|
||||||
|
let data = Rc::new(RefCell::new(Data::default()));
|
||||||
|
jay_input::Seat::handle(tc, input, data.clone(), |data, msg| {
|
||||||
|
data.borrow_mut().seats.push(Seat {
|
||||||
|
name: msg.name.to_string(),
|
||||||
|
repeat_rate: msg.repeat_rate,
|
||||||
|
repeat_delay: msg.repeat_delay,
|
||||||
|
hardware_cursor: msg.hardware_cursor != 0,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
jay_input::InputDevice::handle(tc, input, data.clone(), |data, msg| {
|
||||||
|
use crate::{backend::InputDeviceCapability::*, libinput::consts::*};
|
||||||
|
let mut capabilities = vec![];
|
||||||
|
let mut is_pointer = false;
|
||||||
|
for cap in msg.capabilities {
|
||||||
|
let cap = match DeviceCapability(*cap) {
|
||||||
|
LIBINPUT_DEVICE_CAP_KEYBOARD => Keyboard,
|
||||||
|
LIBINPUT_DEVICE_CAP_POINTER => {
|
||||||
|
is_pointer = true;
|
||||||
|
Pointer
|
||||||
|
}
|
||||||
|
LIBINPUT_DEVICE_CAP_TOUCH => Touch,
|
||||||
|
LIBINPUT_DEVICE_CAP_TABLET_TOOL => TabletTool,
|
||||||
|
LIBINPUT_DEVICE_CAP_TABLET_PAD => TabletPad,
|
||||||
|
LIBINPUT_DEVICE_CAP_GESTURE => Gesture,
|
||||||
|
LIBINPUT_DEVICE_CAP_SWITCH => InputDeviceCapability::Switch,
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
capabilities.push(cap);
|
||||||
|
}
|
||||||
|
let accel_available = msg.accel_available != 0;
|
||||||
|
let tap_available = msg.tap_available != 0;
|
||||||
|
let left_handed_available = msg.left_handed_available != 0;
|
||||||
|
let natural_scrolling_available = msg.natural_scrolling_available != 0;
|
||||||
|
let mut accel_profile = match AccelProfile(msg.accel_profile) {
|
||||||
|
LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT => Some(InputDeviceAccelProfile::Flat),
|
||||||
|
LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE => Some(InputDeviceAccelProfile::Adaptive),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
if !accel_available {
|
||||||
|
accel_profile = None;
|
||||||
|
}
|
||||||
|
let mut data = data.borrow_mut();
|
||||||
|
data.input_device.push(InputDevice {
|
||||||
|
id: msg.id,
|
||||||
|
name: msg.name.to_string(),
|
||||||
|
seat: msg.seat.to_string_if_not_empty(),
|
||||||
|
syspath: msg.syspath.to_string_if_not_empty(),
|
||||||
|
devnode: msg.devnode.to_string_if_not_empty(),
|
||||||
|
capabilities,
|
||||||
|
accel_profile,
|
||||||
|
accel_speed: accel_available.then_some(msg.accel_speed),
|
||||||
|
tap_enabled: tap_available.then_some(msg.tap_enabled != 0),
|
||||||
|
tap_drag_enabled: tap_available.then_some(msg.tap_drag_enabled != 0),
|
||||||
|
tap_drag_lock_enabled: tap_available.then_some(msg.tap_drag_lock_enabled != 0),
|
||||||
|
left_handed: left_handed_available.then_some(msg.left_handed != 0),
|
||||||
|
natural_scrolling_enabled: natural_scrolling_available
|
||||||
|
.then_some(msg.natural_scrolling_enabled != 0),
|
||||||
|
px_per_wheel_scroll: is_pointer.then_some(msg.px_per_wheel_scroll),
|
||||||
|
transform_matrix: uapi::pod_read(msg.transform_matrix).ok(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
tc.round_trip().await;
|
||||||
|
let x = data.borrow_mut().clone();
|
||||||
|
x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use {
|
use {
|
||||||
|
crate::utils::vec_ext::VecExt,
|
||||||
std::{
|
std::{
|
||||||
cell::Cell,
|
cell::Cell,
|
||||||
mem::MaybeUninit,
|
mem::MaybeUninit,
|
||||||
|
|
@ -33,7 +34,7 @@ pub struct ClientMemOffset {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientMem {
|
impl ClientMem {
|
||||||
pub fn new(fd: i32, len: usize) -> Result<Self, ClientMemError> {
|
pub fn new(fd: i32, len: usize, read_only: bool) -> Result<Self, ClientMemError> {
|
||||||
let mut sigbus_impossible = false;
|
let mut sigbus_impossible = false;
|
||||||
if let Ok(seals) = uapi::fcntl_get_seals(fd) {
|
if let Ok(seals) = uapi::fcntl_get_seals(fd) {
|
||||||
if seals & c::F_SEAL_SHRINK != 0 {
|
if seals & c::F_SEAL_SHRINK != 0 {
|
||||||
|
|
@ -45,15 +46,12 @@ impl ClientMem {
|
||||||
let data = if len == 0 {
|
let data = if len == 0 {
|
||||||
&mut [][..]
|
&mut [][..]
|
||||||
} else {
|
} else {
|
||||||
|
let prot = match read_only {
|
||||||
|
true => c::PROT_READ,
|
||||||
|
false => c::PROT_READ | c::PROT_WRITE,
|
||||||
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
let data = c::mmap64(
|
let data = c::mmap64(ptr::null_mut(), len, prot, c::MAP_SHARED, fd, 0);
|
||||||
ptr::null_mut(),
|
|
||||||
len,
|
|
||||||
c::PROT_READ | c::PROT_WRITE,
|
|
||||||
c::MAP_SHARED,
|
|
||||||
fd,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
if data == c::MAP_FAILED {
|
if data == c::MAP_FAILED {
|
||||||
return Err(ClientMemError::MmapFailed(uapi::Errno::default().into()));
|
return Err(ClientMemError::MmapFailed(uapi::Errno::default().into()));
|
||||||
}
|
}
|
||||||
|
|
@ -101,6 +99,17 @@ impl ClientMemOffset {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read(&self, dst: &mut Vec<u8>) -> Result<(), ClientMemError> {
|
||||||
|
self.access(|v| {
|
||||||
|
dst.reserve(v.len());
|
||||||
|
let (_, unused) = dst.split_at_spare_mut_ext();
|
||||||
|
unused[..v.len()].copy_from_slice(uapi::as_maybe_uninit_bytes(v));
|
||||||
|
unsafe {
|
||||||
|
dst.set_len(dst.len() + v.len());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for ClientMem {
|
impl Drop for ClientMem {
|
||||||
|
|
|
||||||
|
|
@ -656,6 +656,7 @@ fn parser_cursor_file<R: BufRead + Seek>(
|
||||||
size: u32,
|
size: u32,
|
||||||
scale: Scale,
|
scale: Scale,
|
||||||
best_fit: i64,
|
best_fit: i64,
|
||||||
|
best_fit_size: u32,
|
||||||
}
|
}
|
||||||
let mut targets = Vec::new();
|
let mut targets = Vec::new();
|
||||||
for scale in scales {
|
for scale in scales {
|
||||||
|
|
@ -668,6 +669,7 @@ fn parser_cursor_file<R: BufRead + Seek>(
|
||||||
size: *size,
|
size: *size,
|
||||||
scale: *scale,
|
scale: *scale,
|
||||||
best_fit: i64::MAX,
|
best_fit: i64::MAX,
|
||||||
|
best_fit_size: 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -682,9 +684,10 @@ fn parser_cursor_file<R: BufRead + Seek>(
|
||||||
let fit = (size as i64 - target.effective_size as i64).abs();
|
let fit = (size as i64 - target.effective_size as i64).abs();
|
||||||
if fit < target.best_fit {
|
if fit < target.best_fit {
|
||||||
target.best_fit = fit;
|
target.best_fit = fit;
|
||||||
|
target.best_fit_size = size;
|
||||||
target.positions.clear();
|
target.positions.clear();
|
||||||
}
|
}
|
||||||
if fit == target.best_fit {
|
if size == target.best_fit_size {
|
||||||
target.positions.push(position);
|
target.positions.push(position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ pub mod ext_session_lock_v1;
|
||||||
pub mod ipc;
|
pub mod ipc;
|
||||||
pub mod jay_compositor;
|
pub mod jay_compositor;
|
||||||
pub mod jay_idle;
|
pub mod jay_idle;
|
||||||
|
pub mod jay_input;
|
||||||
pub mod jay_log_file;
|
pub mod jay_log_file;
|
||||||
pub mod jay_output;
|
pub mod jay_output;
|
||||||
pub mod jay_pointer;
|
pub mod jay_pointer;
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,11 @@ use {
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientError},
|
||||||
globals::{Global, GlobalName},
|
globals::{Global, GlobalName},
|
||||||
ifs::{
|
ifs::{
|
||||||
jay_idle::JayIdle, jay_log_file::JayLogFile, jay_output::JayOutput,
|
jay_idle::JayIdle, jay_input::JayInput, jay_log_file::JayLogFile,
|
||||||
jay_pointer::JayPointer, jay_randr::JayRandr, jay_render_ctx::JayRenderCtx,
|
jay_output::JayOutput, jay_pointer::JayPointer, jay_randr::JayRandr,
|
||||||
jay_screencast::JayScreencast, jay_screenshot::JayScreenshot,
|
jay_render_ctx::JayRenderCtx, jay_screencast::JayScreencast,
|
||||||
jay_seat_events::JaySeatEvents, jay_workspace_watcher::JayWorkspaceWatcher,
|
jay_screenshot::JayScreenshot, jay_seat_events::JaySeatEvents,
|
||||||
|
jay_workspace_watcher::JayWorkspaceWatcher,
|
||||||
},
|
},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::Object,
|
object::Object,
|
||||||
|
|
@ -316,6 +317,14 @@ impl JayCompositor {
|
||||||
self.client.add_client_obj(&sc)?;
|
self.client.add_client_obj(&sc)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_input(&self, parser: MsgParser<'_, '_>) -> Result<(), JayCompositorError> {
|
||||||
|
let req: GetInput = self.client.parse(self, parser)?;
|
||||||
|
let sc = Rc::new(JayInput::new(req.id, &self.client));
|
||||||
|
track!(self.client, sc);
|
||||||
|
self.client.add_client_obj(&sc)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object_base! {
|
object_base! {
|
||||||
|
|
@ -338,6 +347,7 @@ object_base! {
|
||||||
WATCH_WORKSPACES => watch_workspaces,
|
WATCH_WORKSPACES => watch_workspaces,
|
||||||
CREATE_SCREENCAST => create_screencast,
|
CREATE_SCREENCAST => create_screencast,
|
||||||
GET_RANDR => get_randr,
|
GET_RANDR => get_randr,
|
||||||
|
GET_INPUT => get_input,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Object for JayCompositor {}
|
impl Object for JayCompositor {}
|
||||||
|
|
|
||||||
411
src/ifs/jay_input.rs
Normal file
411
src/ifs/jay_input.rs
Normal file
|
|
@ -0,0 +1,411 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
backend::{self, InputDeviceAccelProfile, InputDeviceId},
|
||||||
|
client::{Client, ClientError},
|
||||||
|
clientmem::{ClientMem, ClientMemError},
|
||||||
|
ifs::wl_seat::WlSeatGlobal,
|
||||||
|
leaks::Tracker,
|
||||||
|
libinput::consts::{
|
||||||
|
AccelProfile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
|
||||||
|
LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT,
|
||||||
|
},
|
||||||
|
object::Object,
|
||||||
|
state::{DeviceHandlerData, InputDeviceData},
|
||||||
|
utils::{
|
||||||
|
buffd::{MsgParser, MsgParserError},
|
||||||
|
errorfmt::ErrorFmt,
|
||||||
|
},
|
||||||
|
wire::{jay_input::*, JayInputId},
|
||||||
|
xkbcommon::XkbCommonError,
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
thiserror::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct JayInput {
|
||||||
|
pub id: JayInputId,
|
||||||
|
pub client: Rc<Client>,
|
||||||
|
pub tracker: Tracker<Self>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JayInput {
|
||||||
|
pub fn new(id: JayInputId, client: &Rc<Client>) -> Self {
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
client: client.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let _req: Destroy = self.client.parse(self, parser)?;
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_all(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let _req: GetAll = self.client.parse(self, parser)?;
|
||||||
|
let state = &self.client.state;
|
||||||
|
for seat in state.globals.seats.lock().values() {
|
||||||
|
self.send_seat(seat);
|
||||||
|
}
|
||||||
|
for dev in state.input_device_handlers.borrow().values() {
|
||||||
|
self.send_input_device(dev);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_seat(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let req: GetSeat = self.client.parse(self, parser)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
let seat = self.seat(req.name)?;
|
||||||
|
self.send_seat(&seat);
|
||||||
|
for dev in self.client.state.input_device_handlers.borrow().values() {
|
||||||
|
if let Some(attached) = dev.data.seat.get() {
|
||||||
|
if attached.id() == seat.id() {
|
||||||
|
self.send_input_device(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_device(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let req: GetDevice = self.client.parse(self, parser)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
match self
|
||||||
|
.client
|
||||||
|
.state
|
||||||
|
.input_device_handlers
|
||||||
|
.borrow()
|
||||||
|
.get(&InputDeviceId::from_raw(req.id))
|
||||||
|
{
|
||||||
|
None => Err(JayInputError::DeviceDoesNotExist(req.id)),
|
||||||
|
Some(d) => {
|
||||||
|
self.send_input_device(d);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn seat(&self, name: &str) -> Result<Rc<WlSeatGlobal>, JayInputError> {
|
||||||
|
for seat in self.client.state.globals.seats.lock().values() {
|
||||||
|
if seat.seat_name() == name {
|
||||||
|
return Ok(seat.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(JayInputError::SeatDoesNotExist(name.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn or_error(&self, f: impl FnOnce() -> Result<(), JayInputError>) -> Result<(), JayInputError> {
|
||||||
|
if let Err(e) = f() {
|
||||||
|
self.send_error(&ErrorFmt(e).to_string());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_repeat_rate(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let req: SetRepeatRate = self.client.parse(self, parser)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
if req.repeat_rate < 0 {
|
||||||
|
return Err(JayInputError::NegativeRepeatRate);
|
||||||
|
}
|
||||||
|
if req.repeat_delay < 0 {
|
||||||
|
return Err(JayInputError::NegativeRepeatDelay);
|
||||||
|
}
|
||||||
|
let seat = self.seat(req.seat)?;
|
||||||
|
seat.set_rate(req.repeat_rate, req.repeat_delay);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_keymap(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let req: SetKeymap = self.client.parse(self, parser)?;
|
||||||
|
let cm = Rc::new(ClientMem::new(req.keymap.raw(), req.keymap_len as _, true)?).offset(0);
|
||||||
|
let mut map = vec![];
|
||||||
|
cm.read(&mut map)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
let map = self.client.state.xkb_ctx.keymap_from_str(&map)?;
|
||||||
|
let seat = self.seat(req.seat)?;
|
||||||
|
seat.set_keymap(&map);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_keymap(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let req: GetKeymap = self.client.parse(self, parser)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
let seat = self.seat(req.seat)?;
|
||||||
|
self.send_keymap(&seat);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn use_hardware_cursor(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let req: UseHardwareCursor = self.client.parse(self, parser)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
let seat = self.seat(req.seat)?;
|
||||||
|
seat.set_hardware_cursor(req.use_hardware_cursor != 0);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_seat(&self, data: &WlSeatGlobal) {
|
||||||
|
self.client.event(Seat {
|
||||||
|
self_id: self.id,
|
||||||
|
name: data.seat_name(),
|
||||||
|
repeat_rate: data.get_rate().0,
|
||||||
|
repeat_delay: data.get_rate().1,
|
||||||
|
hardware_cursor: data.hardware_cursor() as _,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_error(&self, error: &str) {
|
||||||
|
self.client.event(Error {
|
||||||
|
self_id: self.id,
|
||||||
|
msg: error,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_keymap(&self, data: &WlSeatGlobal) {
|
||||||
|
let map = data.keymap();
|
||||||
|
self.client.event(Keymap {
|
||||||
|
self_id: self.id,
|
||||||
|
keymap: map.map.clone(),
|
||||||
|
keymap_len: (map.map_len - 1) as _,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_input_device(&self, data: &InputDeviceData) {
|
||||||
|
use backend::InputDeviceCapability::*;
|
||||||
|
let mut caps = vec![];
|
||||||
|
for cap in [
|
||||||
|
Keyboard, Pointer, Touch, TabletTool, TabletPad, Gesture, Switch,
|
||||||
|
] {
|
||||||
|
if data.data.device.has_capability(cap) {
|
||||||
|
caps.push(cap.to_libinput().raw());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let dev = &data.data.device;
|
||||||
|
let accel_profile = dev.accel_profile();
|
||||||
|
let left_handed = dev.left_handed();
|
||||||
|
let natural_scrolling = dev.natural_scrolling_enabled();
|
||||||
|
let tap_enabled = dev.tap_enabled();
|
||||||
|
let transform_matrix = dev.transform_matrix();
|
||||||
|
self.client.event(InputDevice {
|
||||||
|
self_id: self.id,
|
||||||
|
seat: data
|
||||||
|
.data
|
||||||
|
.seat
|
||||||
|
.get()
|
||||||
|
.as_deref()
|
||||||
|
.map(|s| s.seat_name())
|
||||||
|
.unwrap_or_default(),
|
||||||
|
id: data.id.raw(),
|
||||||
|
syspath: data.syspath.as_deref().unwrap_or_default(),
|
||||||
|
devnode: data.devnode.as_deref().unwrap_or_default(),
|
||||||
|
name: dev.name().as_str(),
|
||||||
|
capabilities: &caps,
|
||||||
|
accel_available: accel_profile.is_some() as _,
|
||||||
|
accel_profile: match accel_profile {
|
||||||
|
None => 0,
|
||||||
|
Some(p) => match p {
|
||||||
|
InputDeviceAccelProfile::Flat => LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT.0,
|
||||||
|
InputDeviceAccelProfile::Adaptive => LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE.0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
accel_speed: dev.accel_speed().unwrap_or_default(),
|
||||||
|
left_handed_available: left_handed.is_some() as _,
|
||||||
|
left_handed: left_handed.unwrap_or_default() as _,
|
||||||
|
natural_scrolling_available: natural_scrolling.is_some() as _,
|
||||||
|
natural_scrolling_enabled: natural_scrolling.unwrap_or_default() as _,
|
||||||
|
px_per_wheel_scroll: data.data.px_per_scroll_wheel.get(),
|
||||||
|
tap_available: tap_enabled.is_some() as _,
|
||||||
|
tap_enabled: tap_enabled.unwrap_or_default() as _,
|
||||||
|
tap_drag_enabled: dev.drag_enabled().unwrap_or_default() as _,
|
||||||
|
tap_drag_lock_enabled: dev.drag_lock_enabled().unwrap_or_default() as _,
|
||||||
|
transform_matrix: transform_matrix
|
||||||
|
.as_ref()
|
||||||
|
.map(uapi::as_bytes)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn device(&self, id: u32) -> Result<Rc<DeviceHandlerData>, JayInputError> {
|
||||||
|
let idh = self.client.state.input_device_handlers.borrow_mut();
|
||||||
|
match idh.get(&InputDeviceId::from_raw(id)) {
|
||||||
|
None => Err(JayInputError::DeviceDoesNotExist(id)),
|
||||||
|
Some(d) => Ok(d.data.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_accel_profile(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let req: SetAccelProfile = self.client.parse(self, parser)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
let dev = self.device(req.id)?;
|
||||||
|
let profile = match AccelProfile(req.profile) {
|
||||||
|
LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT => InputDeviceAccelProfile::Flat,
|
||||||
|
LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE => InputDeviceAccelProfile::Adaptive,
|
||||||
|
_ => return Err(JayInputError::UnknownAccelerationProfile(req.profile)),
|
||||||
|
};
|
||||||
|
dev.device.set_accel_profile(profile);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_accel_speed(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let req: SetAccelSpeed = self.client.parse(self, parser)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
let dev = self.device(req.id)?;
|
||||||
|
dev.device.set_accel_speed(req.speed);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_tap_enabled(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let req: SetTapEnabled = self.client.parse(self, parser)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
let dev = self.device(req.id)?;
|
||||||
|
dev.device.set_tap_enabled(req.enabled != 0);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_tap_drag_enabled(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let req: SetTapDragEnabled = self.client.parse(self, parser)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
let dev = self.device(req.id)?;
|
||||||
|
dev.device.set_drag_enabled(req.enabled != 0);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_tap_drag_lock_enabled(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let req: SetTapDragEnabled = self.client.parse(self, parser)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
let dev = self.device(req.id)?;
|
||||||
|
dev.device.set_drag_lock_enabled(req.enabled != 0);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_left_handed(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let req: SetLeftHanded = self.client.parse(self, parser)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
let dev = self.device(req.id)?;
|
||||||
|
dev.device.set_left_handed(req.enabled != 0);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_natural_scrolling(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let req: SetNaturalScrolling = self.client.parse(self, parser)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
let dev = self.device(req.id)?;
|
||||||
|
dev.device.set_natural_scrolling_enabled(req.enabled != 0);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_px_per_wheel_scroll(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let req: SetPxPerWheelScroll = self.client.parse(self, parser)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
let dev = self.device(req.id)?;
|
||||||
|
dev.px_per_scroll_wheel.set(req.px);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_transform_matrix(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let req: SetTransformMatrix = self.client.parse(self, parser)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
let dev = self.device(req.id)?;
|
||||||
|
dev.device
|
||||||
|
.set_transform_matrix([[req.m11, req.m12], [req.m21, req.m22]]);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_cursor_size(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let req: SetCursorSize = self.client.parse(self, parser)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
let seat = self.seat(req.seat)?;
|
||||||
|
seat.set_cursor_size(req.size);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn attach(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let req: Attach = self.client.parse(self, parser)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
let seat = self.seat(req.seat)?;
|
||||||
|
let dev = self.device(req.id)?;
|
||||||
|
dev.seat.set(Some(seat));
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn detach(&self, parser: MsgParser<'_, '_>) -> Result<(), JayInputError> {
|
||||||
|
let req: Detach = self.client.parse(self, parser)?;
|
||||||
|
self.or_error(|| {
|
||||||
|
let dev = self.device(req.id)?;
|
||||||
|
dev.seat.set(None);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_base! {
|
||||||
|
self = JayInput;
|
||||||
|
|
||||||
|
DESTROY => destroy,
|
||||||
|
GET_ALL => get_all,
|
||||||
|
SET_REPEAT_RATE => set_repeat_rate,
|
||||||
|
SET_KEYMAP => set_keymap,
|
||||||
|
USE_HARDWARE_CURSOR => use_hardware_cursor,
|
||||||
|
GET_KEYMAP => get_keymap,
|
||||||
|
SET_ACCEL_PROFILE => set_accel_profile,
|
||||||
|
SET_ACCEL_SPEED => set_accel_speed,
|
||||||
|
SET_TAP_ENABLED => set_tap_enabled,
|
||||||
|
SET_TAP_DRAG_ENABLED => set_tap_drag_enabled,
|
||||||
|
SET_TAP_DRAG_LOCK_ENABLED => set_tap_drag_lock_enabled,
|
||||||
|
SET_LEFT_HANDED => set_left_handed,
|
||||||
|
SET_NATURAL_SCROLLING => set_natural_scrolling,
|
||||||
|
SET_PX_PER_WHEEL_SCROLL => set_px_per_wheel_scroll,
|
||||||
|
SET_TRANSFORM_MATRIX => set_transform_matrix,
|
||||||
|
SET_CURSOR_SIZE => set_cursor_size,
|
||||||
|
ATTACH => attach,
|
||||||
|
DETACH => detach,
|
||||||
|
GET_SEAT => get_seat,
|
||||||
|
GET_DEVICE => get_device,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for JayInput {}
|
||||||
|
|
||||||
|
simple_add_obj!(JayInput);
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum JayInputError {
|
||||||
|
#[error("Parsing failed")]
|
||||||
|
MsgParserError(Box<MsgParserError>),
|
||||||
|
#[error(transparent)]
|
||||||
|
ClientError(Box<ClientError>),
|
||||||
|
#[error("There is no seat called {0}")]
|
||||||
|
SeatDoesNotExist(String),
|
||||||
|
#[error("There is no device with id {0}")]
|
||||||
|
DeviceDoesNotExist(u32),
|
||||||
|
#[error("There is no acceleration profile with id {0}")]
|
||||||
|
UnknownAccelerationProfile(i32),
|
||||||
|
#[error("Repeat rate must not be negative")]
|
||||||
|
NegativeRepeatRate,
|
||||||
|
#[error("Repeat delay must not be negative")]
|
||||||
|
NegativeRepeatDelay,
|
||||||
|
#[error("Could not access client memory")]
|
||||||
|
ClientMemError(#[from] ClientMemError),
|
||||||
|
#[error("Could not parse keymap")]
|
||||||
|
XkbCommonError(#[from] XkbCommonError),
|
||||||
|
}
|
||||||
|
efrom!(JayInputError, MsgParserError);
|
||||||
|
efrom!(JayInputError, ClientError);
|
||||||
|
|
@ -231,6 +231,10 @@ impl WlSeatGlobal {
|
||||||
slf
|
slf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn keymap(&self) -> Rc<XkbKeymap> {
|
||||||
|
self.kb_map.get()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn toplevel_drag(&self) -> Option<Rc<XdgToplevelDragV1>> {
|
pub fn toplevel_drag(&self) -> Option<Rc<XdgToplevelDragV1>> {
|
||||||
self.pointer_owner.toplevel_drag()
|
self.pointer_owner.toplevel_drag()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ impl WlShmPool {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
id,
|
id,
|
||||||
client: client.clone(),
|
client: client.clone(),
|
||||||
mem: CloneCell::new(Rc::new(ClientMem::new(fd.raw(), len)?)),
|
mem: CloneCell::new(Rc::new(ClientMem::new(fd.raw(), len, false)?)),
|
||||||
fd,
|
fd,
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
})
|
})
|
||||||
|
|
@ -80,8 +80,11 @@ impl WlShmPool {
|
||||||
if (req.size as usize) < self.mem.get().len() {
|
if (req.size as usize) < self.mem.get().len() {
|
||||||
return Err(WlShmPoolError::CannotShrink);
|
return Err(WlShmPoolError::CannotShrink);
|
||||||
}
|
}
|
||||||
self.mem
|
self.mem.set(Rc::new(ClientMem::new(
|
||||||
.set(Rc::new(ClientMem::new(self.fd.raw(), req.size as usize)?));
|
self.fd.raw(),
|
||||||
|
req.size as usize,
|
||||||
|
false,
|
||||||
|
)?));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -492,6 +492,10 @@ impl<T: TestInputDevice> InputDevice for T {
|
||||||
self.common().name.clone()
|
self.common().name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn dev_t(&self) -> Option<c::dev_t> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn set_tap_enabled(&self, enabled: bool) {
|
fn set_tap_enabled(&self, enabled: bool) {
|
||||||
<Self as TestInputDevice>::set_tap_enabled(self, enabled)
|
<Self as TestInputDevice>::set_tap_enabled(self, enabled)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,19 @@ use {
|
||||||
LIBINPUT_CONFIG_TAP_DISABLED, LIBINPUT_CONFIG_TAP_ENABLED,
|
LIBINPUT_CONFIG_TAP_DISABLED, LIBINPUT_CONFIG_TAP_ENABLED,
|
||||||
},
|
},
|
||||||
sys::{
|
sys::{
|
||||||
libinput_device, libinput_device_config_accel_set_profile,
|
libinput_device, libinput_device_config_accel_get_profile,
|
||||||
libinput_device_config_accel_set_speed, libinput_device_config_left_handed_set,
|
libinput_device_config_accel_get_speed, libinput_device_config_accel_is_available,
|
||||||
|
libinput_device_config_accel_set_profile, libinput_device_config_accel_set_speed,
|
||||||
|
libinput_device_config_left_handed_get,
|
||||||
|
libinput_device_config_left_handed_is_available,
|
||||||
|
libinput_device_config_left_handed_set,
|
||||||
libinput_device_config_scroll_get_natural_scroll_enabled,
|
libinput_device_config_scroll_get_natural_scroll_enabled,
|
||||||
|
libinput_device_config_scroll_has_natural_scroll,
|
||||||
libinput_device_config_scroll_set_natural_scroll_enabled,
|
libinput_device_config_scroll_set_natural_scroll_enabled,
|
||||||
libinput_device_config_tap_get_drag_enabled,
|
libinput_device_config_tap_get_drag_enabled,
|
||||||
libinput_device_config_tap_get_drag_lock_enabled,
|
libinput_device_config_tap_get_drag_lock_enabled,
|
||||||
libinput_device_config_tap_get_enabled, libinput_device_config_tap_set_drag_enabled,
|
libinput_device_config_tap_get_enabled, libinput_device_config_tap_get_finger_count,
|
||||||
|
libinput_device_config_tap_set_drag_enabled,
|
||||||
libinput_device_config_tap_set_drag_lock_enabled,
|
libinput_device_config_tap_set_drag_lock_enabled,
|
||||||
libinput_device_config_tap_set_enabled, libinput_device_get_name,
|
libinput_device_config_tap_set_enabled, libinput_device_get_name,
|
||||||
libinput_device_get_user_data, libinput_device_has_capability,
|
libinput_device_get_user_data, libinput_device_has_capability,
|
||||||
|
|
@ -64,12 +70,32 @@ impl<'a> LibInputDevice<'a> {
|
||||||
res != 0
|
res != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn left_handed_available(&self) -> bool {
|
||||||
|
unsafe { libinput_device_config_left_handed_is_available(self.dev) != 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn left_handed(&self) -> bool {
|
||||||
|
unsafe { libinput_device_config_left_handed_get(self.dev) != 0 }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_left_handed(&self, left_handed: bool) {
|
pub fn set_left_handed(&self, left_handed: bool) {
|
||||||
unsafe {
|
unsafe {
|
||||||
libinput_device_config_left_handed_set(self.dev, left_handed as _);
|
libinput_device_config_left_handed_set(self.dev, left_handed as _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn accel_available(&self) -> bool {
|
||||||
|
unsafe { libinput_device_config_accel_is_available(self.dev) != 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn accel_profile(&self) -> AccelProfile {
|
||||||
|
unsafe { AccelProfile(libinput_device_config_accel_get_profile(self.dev)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn accel_speed(&self) -> f64 {
|
||||||
|
unsafe { libinput_device_config_accel_get_speed(self.dev) }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_accel_profile(&self, profile: AccelProfile) {
|
pub fn set_accel_profile(&self, profile: AccelProfile) {
|
||||||
unsafe {
|
unsafe {
|
||||||
libinput_device_config_accel_set_profile(self.dev, profile.raw() as _);
|
libinput_device_config_accel_set_profile(self.dev, profile.raw() as _);
|
||||||
|
|
@ -99,7 +125,10 @@ impl<'a> LibInputDevice<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
pub fn tap_available(&self) -> bool {
|
||||||
|
unsafe { libinput_device_config_tap_get_finger_count(self.dev) != 0 }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn tap_enabled(&self) -> bool {
|
pub fn tap_enabled(&self) -> bool {
|
||||||
let enabled = unsafe { ConfigTapState(libinput_device_config_tap_get_enabled(self.dev)) };
|
let enabled = unsafe { ConfigTapState(libinput_device_config_tap_get_enabled(self.dev)) };
|
||||||
match enabled {
|
match enabled {
|
||||||
|
|
@ -158,6 +187,10 @@ impl<'a> LibInputDevice<'a> {
|
||||||
pub fn natural_scrolling_enabled(&self) -> bool {
|
pub fn natural_scrolling_enabled(&self) -> bool {
|
||||||
unsafe { libinput_device_config_scroll_get_natural_scroll_enabled(self.dev) != 0 }
|
unsafe { libinput_device_config_scroll_get_natural_scroll_enabled(self.dev) != 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn has_natural_scrolling(&self) -> bool {
|
||||||
|
unsafe { libinput_device_config_scroll_has_natural_scroll(self.dev) != 0 }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegisteredDevice {
|
impl RegisteredDevice {
|
||||||
|
|
|
||||||
|
|
@ -41,19 +41,29 @@ extern "C" {
|
||||||
device: *mut libinput_device,
|
device: *mut libinput_device,
|
||||||
cap: libinput_device_capability,
|
cap: libinput_device_capability,
|
||||||
) -> c::c_int;
|
) -> c::c_int;
|
||||||
|
pub fn libinput_device_config_left_handed_is_available(
|
||||||
|
device: *mut libinput_device,
|
||||||
|
) -> c::c_int;
|
||||||
|
pub fn libinput_device_config_left_handed_get(device: *mut libinput_device) -> c::c_int;
|
||||||
pub fn libinput_device_config_left_handed_set(
|
pub fn libinput_device_config_left_handed_set(
|
||||||
device: *mut libinput_device,
|
device: *mut libinput_device,
|
||||||
left_handed: c::c_int,
|
left_handed: c::c_int,
|
||||||
) -> libinput_config_status;
|
) -> libinput_config_status;
|
||||||
|
pub fn libinput_device_config_accel_is_available(device: *mut libinput_device) -> c::c_int;
|
||||||
|
pub fn libinput_device_config_accel_get_profile(
|
||||||
|
device: *mut libinput_device,
|
||||||
|
) -> libinput_config_accel_profile;
|
||||||
pub fn libinput_device_config_accel_set_profile(
|
pub fn libinput_device_config_accel_set_profile(
|
||||||
device: *mut libinput_device,
|
device: *mut libinput_device,
|
||||||
profile: libinput_config_accel_profile,
|
profile: libinput_config_accel_profile,
|
||||||
) -> libinput_config_status;
|
) -> libinput_config_status;
|
||||||
|
pub fn libinput_device_config_accel_get_speed(device: *mut libinput_device) -> f64;
|
||||||
pub fn libinput_device_config_accel_set_speed(
|
pub fn libinput_device_config_accel_set_speed(
|
||||||
device: *mut libinput_device,
|
device: *mut libinput_device,
|
||||||
speed: f64,
|
speed: f64,
|
||||||
) -> libinput_config_status;
|
) -> libinput_config_status;
|
||||||
pub fn libinput_device_get_name(device: *mut libinput_device) -> *const c::c_char;
|
pub fn libinput_device_get_name(device: *mut libinput_device) -> *const c::c_char;
|
||||||
|
pub fn libinput_device_config_tap_get_finger_count(device: *mut libinput_device) -> c::c_int;
|
||||||
pub fn libinput_device_config_tap_set_enabled(
|
pub fn libinput_device_config_tap_set_enabled(
|
||||||
device: *mut libinput_device,
|
device: *mut libinput_device,
|
||||||
enable: libinput_config_tap_state,
|
enable: libinput_config_tap_state,
|
||||||
|
|
@ -82,6 +92,9 @@ extern "C" {
|
||||||
pub fn libinput_device_config_scroll_get_natural_scroll_enabled(
|
pub fn libinput_device_config_scroll_get_natural_scroll_enabled(
|
||||||
device: *mut libinput_device,
|
device: *mut libinput_device,
|
||||||
) -> c::c_int;
|
) -> c::c_int;
|
||||||
|
pub fn libinput_device_config_scroll_has_natural_scroll(
|
||||||
|
device: *mut libinput_device,
|
||||||
|
) -> c::c_int;
|
||||||
|
|
||||||
pub fn libinput_event_destroy(event: *mut libinput_event);
|
pub fn libinput_event_destroy(event: *mut libinput_event);
|
||||||
pub fn libinput_event_get_type(event: *mut libinput_event) -> libinput_event_type;
|
pub fn libinput_event_get_type(event: *mut libinput_event) -> libinput_event_type;
|
||||||
|
|
|
||||||
|
|
@ -257,7 +257,7 @@ macro_rules! linear_ids {
|
||||||
macro_rules! cenum {
|
macro_rules! cenum {
|
||||||
($name:ident, $uc:ident; $($name2:ident = $val:expr,)*) => {
|
($name:ident, $uc:ident; $($name2:ident = $val:expr,)*) => {
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct $name(pub(super) i32);
|
pub struct $name(pub i32);
|
||||||
|
|
||||||
impl $name {
|
impl $name {
|
||||||
pub fn raw(self) -> i32 {
|
pub fn raw(self) -> i32 {
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,8 @@ pub struct InputDeviceData {
|
||||||
pub id: InputDeviceId,
|
pub id: InputDeviceId,
|
||||||
pub data: Rc<DeviceHandlerData>,
|
pub data: Rc<DeviceHandlerData>,
|
||||||
pub async_event: Rc<AsyncEvent>,
|
pub async_event: Rc<AsyncEvent>,
|
||||||
|
pub syspath: Option<String>,
|
||||||
|
pub devnode: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DeviceHandlerData {
|
pub struct DeviceHandlerData {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ mod hardware_cursor;
|
||||||
mod idle;
|
mod idle;
|
||||||
mod input_device;
|
mod input_device;
|
||||||
mod slow_clients;
|
mod slow_clients;
|
||||||
|
mod udev_utils;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
|
|
||||||
|
|
@ -2,78 +2,24 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
backend::{BackendDrmDevice, DrmDeviceId, DrmEvent},
|
backend::{BackendDrmDevice, DrmDeviceId, DrmEvent},
|
||||||
state::{DrmDevData, State},
|
state::{DrmDevData, State},
|
||||||
udev::{Udev, UdevDeviceType},
|
tasks::udev_utils::udev_props,
|
||||||
utils::{asyncevent::AsyncEvent, errorfmt::ErrorFmt},
|
utils::asyncevent::AsyncEvent,
|
||||||
},
|
},
|
||||||
jay_config::PciId,
|
|
||||||
std::{cell::Cell, rc::Rc},
|
std::{cell::Cell, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn handle(state: &Rc<State>, dev: Rc<dyn BackendDrmDevice>) {
|
pub fn handle(state: &Rc<State>, dev: Rc<dyn BackendDrmDevice>) {
|
||||||
let id = dev.id();
|
let id = dev.id();
|
||||||
let mut syspath = None;
|
let props = udev_props(dev.dev_t(), 1);
|
||||||
let mut devnode = None;
|
|
||||||
let mut vendor = None;
|
|
||||||
let mut model = None;
|
|
||||||
let mut pci_id = None;
|
|
||||||
'properties: {
|
|
||||||
let udev = match Udev::new() {
|
|
||||||
Ok(udev) => Rc::new(udev),
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Could not create a udev instance: {}", e);
|
|
||||||
break 'properties;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let odev = match udev.create_device_from_devnum(UdevDeviceType::Character, dev.dev_t()) {
|
|
||||||
Ok(dev) => dev,
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("{}", ErrorFmt(e));
|
|
||||||
break 'properties;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let dev = match odev.parent() {
|
|
||||||
Ok(dev) => dev,
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("{}", ErrorFmt(e));
|
|
||||||
break 'properties;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
syspath = dev.syspath().map(|s| s.to_string_lossy().into_owned());
|
|
||||||
vendor = dev.vendor().map(|s| s.to_string_lossy().into_owned());
|
|
||||||
model = dev.model().map(|s| s.to_string_lossy().into_owned());
|
|
||||||
devnode = odev.devnode().map(|s| s.to_string_lossy().into_owned());
|
|
||||||
'get_pci_id: {
|
|
||||||
let id = match dev.pci_id() {
|
|
||||||
Some(id) => id,
|
|
||||||
_ => break 'get_pci_id,
|
|
||||||
};
|
|
||||||
let id = id.to_string_lossy();
|
|
||||||
let colon = match id.find(':') {
|
|
||||||
Some(pos) => pos,
|
|
||||||
_ => break 'get_pci_id,
|
|
||||||
};
|
|
||||||
let vendor = &id[..colon];
|
|
||||||
let model = &id[colon + 1..];
|
|
||||||
let vendor = match u32::from_str_radix(vendor, 16) {
|
|
||||||
Ok(v) => v,
|
|
||||||
_ => break 'get_pci_id,
|
|
||||||
};
|
|
||||||
let model = match u32::from_str_radix(model, 16) {
|
|
||||||
Ok(v) => v,
|
|
||||||
_ => break 'get_pci_id,
|
|
||||||
};
|
|
||||||
pci_id = Some(PciId { vendor, model });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let data = Rc::new(DrmDevData {
|
let data = Rc::new(DrmDevData {
|
||||||
dev: dev.clone(),
|
dev: dev.clone(),
|
||||||
handler: Cell::new(None),
|
handler: Cell::new(None),
|
||||||
connectors: Default::default(),
|
connectors: Default::default(),
|
||||||
syspath,
|
syspath: props.syspath,
|
||||||
devnode,
|
devnode: props.devnode,
|
||||||
vendor,
|
vendor: props.vendor,
|
||||||
model,
|
model: props.model,
|
||||||
pci_id,
|
pci_id: props.pci_id,
|
||||||
});
|
});
|
||||||
let oh = DrvDevHandler {
|
let oh = DrvDevHandler {
|
||||||
id,
|
id,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use {
|
||||||
backend::InputDevice,
|
backend::InputDevice,
|
||||||
ifs::wl_seat::PX_PER_SCROLL,
|
ifs::wl_seat::PX_PER_SCROLL,
|
||||||
state::{DeviceHandlerData, InputDeviceData, State},
|
state::{DeviceHandlerData, InputDeviceData, State},
|
||||||
|
tasks::udev_utils::{udev_props, UdevProps},
|
||||||
utils::asyncevent::AsyncEvent,
|
utils::asyncevent::AsyncEvent,
|
||||||
},
|
},
|
||||||
std::{cell::Cell, rc::Rc},
|
std::{cell::Cell, rc::Rc},
|
||||||
|
|
@ -22,6 +23,10 @@ pub fn handle(state: &Rc<State>, dev: Rc<dyn InputDevice>) {
|
||||||
ae: ae.clone(),
|
ae: ae.clone(),
|
||||||
};
|
};
|
||||||
let handler = state.eng.spawn(oh.handle());
|
let handler = state.eng.spawn(oh.handle());
|
||||||
|
let props = match dev.dev_t() {
|
||||||
|
None => UdevProps::default(),
|
||||||
|
Some(dev_t) => udev_props(dev_t, 3),
|
||||||
|
};
|
||||||
state.input_device_handlers.borrow_mut().insert(
|
state.input_device_handlers.borrow_mut().insert(
|
||||||
dev.id(),
|
dev.id(),
|
||||||
InputDeviceData {
|
InputDeviceData {
|
||||||
|
|
@ -29,6 +34,8 @@ pub fn handle(state: &Rc<State>, dev: Rc<dyn InputDevice>) {
|
||||||
id: dev.id(),
|
id: dev.id(),
|
||||||
data,
|
data,
|
||||||
async_event: ae,
|
async_event: ae,
|
||||||
|
syspath: props.syspath,
|
||||||
|
devnode: props.devnode,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
72
src/tasks/udev_utils.rs
Normal file
72
src/tasks/udev_utils.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
udev::{Udev, UdevDeviceType},
|
||||||
|
utils::errorfmt::ErrorFmt,
|
||||||
|
},
|
||||||
|
jay_config::PciId,
|
||||||
|
std::rc::Rc,
|
||||||
|
uapi::c,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct UdevProps {
|
||||||
|
pub syspath: Option<String>,
|
||||||
|
pub devnode: Option<String>,
|
||||||
|
pub vendor: Option<String>,
|
||||||
|
pub model: Option<String>,
|
||||||
|
pub pci_id: Option<PciId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn udev_props(dev_t: c::dev_t, depth: usize) -> UdevProps {
|
||||||
|
let mut res = UdevProps::default();
|
||||||
|
let udev = match Udev::new() {
|
||||||
|
Ok(udev) => Rc::new(udev),
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Could not create a udev instance: {}", e);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut dev = match udev.create_device_from_devnum(UdevDeviceType::Character, dev_t) {
|
||||||
|
Ok(dev) => dev,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{}", ErrorFmt(e));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
res.devnode = dev.devnode().map(|s| s.to_string_lossy().into_owned());
|
||||||
|
for _ in 0..depth {
|
||||||
|
dev = match dev.parent() {
|
||||||
|
Ok(dev) => dev,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{}", ErrorFmt(e));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.syspath = dev.syspath().map(|s| s.to_string_lossy().into_owned());
|
||||||
|
res.vendor = dev.vendor().map(|s| s.to_string_lossy().into_owned());
|
||||||
|
res.model = dev.model().map(|s| s.to_string_lossy().into_owned());
|
||||||
|
{
|
||||||
|
let id = match dev.pci_id() {
|
||||||
|
Some(id) => id,
|
||||||
|
_ => return res,
|
||||||
|
};
|
||||||
|
let id = id.to_string_lossy();
|
||||||
|
let colon = match id.find(':') {
|
||||||
|
Some(pos) => pos,
|
||||||
|
_ => return res,
|
||||||
|
};
|
||||||
|
let vendor = &id[..colon];
|
||||||
|
let model = &id[colon + 1..];
|
||||||
|
let vendor = match u32::from_str_radix(vendor, 16) {
|
||||||
|
Ok(v) => v,
|
||||||
|
_ => return res,
|
||||||
|
};
|
||||||
|
let model = match u32::from_str_radix(model, 16) {
|
||||||
|
Ok(v) => v,
|
||||||
|
_ => return res,
|
||||||
|
};
|
||||||
|
res.pci_id = Some(PciId { vendor, model });
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
@ -35,6 +35,7 @@ pub mod run_toplevel;
|
||||||
pub mod scroller;
|
pub mod scroller;
|
||||||
pub mod smallmap;
|
pub mod smallmap;
|
||||||
pub mod stack;
|
pub mod stack;
|
||||||
|
pub mod string_ext;
|
||||||
pub mod syncqueue;
|
pub mod syncqueue;
|
||||||
pub mod threshold_counter;
|
pub mod threshold_counter;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
|
|
|
||||||
11
src/utils/string_ext.rs
Normal file
11
src/utils/string_ext.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
use isnt::std_1::primitive::IsntStrExt;
|
||||||
|
|
||||||
|
pub trait StringExt {
|
||||||
|
fn to_string_if_not_empty(&self) -> Option<String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StringExt for str {
|
||||||
|
fn to_string_if_not_empty(&self) -> Option<String> {
|
||||||
|
self.is_not_empty().then(|| self.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -148,11 +148,15 @@ impl XkbContext {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keymap_from_str(&self, s: &str) -> Result<Rc<XkbKeymap>, XkbCommonError> {
|
pub fn keymap_from_str<S>(&self, s: &S) -> Result<Rc<XkbKeymap>, XkbCommonError>
|
||||||
|
where
|
||||||
|
S: AsRef<[u8]> + ?Sized,
|
||||||
|
{
|
||||||
|
let s = s.as_ref();
|
||||||
unsafe {
|
unsafe {
|
||||||
let keymap = xkb_keymap_new_from_buffer(
|
let keymap = xkb_keymap_new_from_buffer(
|
||||||
self.context,
|
self.context,
|
||||||
s.as_bytes().as_ptr(),
|
s.as_ptr(),
|
||||||
s.len(),
|
s.len(),
|
||||||
XKB_KEYMAP_FORMAT_TEXT_V1.raw(),
|
XKB_KEYMAP_FORMAT_TEXT_V1.raw(),
|
||||||
0,
|
0,
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,10 @@ msg get_randr = 16 {
|
||||||
id: id(jay_randr),
|
id: id(jay_randr),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
msg get_input = 17 {
|
||||||
|
id: id(jay_input),
|
||||||
|
}
|
||||||
|
|
||||||
# events
|
# events
|
||||||
|
|
||||||
msg client_id = 0 {
|
msg client_id = 0 {
|
||||||
|
|
|
||||||
140
wire/jay_input.txt
Normal file
140
wire/jay_input.txt
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
# requests
|
||||||
|
|
||||||
|
msg destroy = 0 {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
msg get_all = 1 {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
msg set_repeat_rate = 2 {
|
||||||
|
seat: str,
|
||||||
|
repeat_rate: i32,
|
||||||
|
repeat_delay: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg set_keymap = 3 {
|
||||||
|
seat: str,
|
||||||
|
keymap: fd,
|
||||||
|
keymap_len: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg use_hardware_cursor = 4 {
|
||||||
|
seat: str,
|
||||||
|
use_hardware_cursor: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg get_keymap = 5 {
|
||||||
|
seat: str,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg set_accel_profile = 6 {
|
||||||
|
id: u32,
|
||||||
|
profile: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg set_accel_speed = 7 {
|
||||||
|
id: u32,
|
||||||
|
speed: pod(f64),
|
||||||
|
}
|
||||||
|
|
||||||
|
msg set_tap_enabled = 8 {
|
||||||
|
id: u32,
|
||||||
|
enabled: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg set_tap_drag_enabled = 9 {
|
||||||
|
id: u32,
|
||||||
|
enabled: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg set_tap_drag_lock_enabled = 10 {
|
||||||
|
id: u32,
|
||||||
|
enabled: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg set_left_handed = 11 {
|
||||||
|
id: u32,
|
||||||
|
enabled: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg set_natural_scrolling = 12 {
|
||||||
|
id: u32,
|
||||||
|
enabled: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg set_px_per_wheel_scroll = 13 {
|
||||||
|
id: u32,
|
||||||
|
px: pod(f64),
|
||||||
|
}
|
||||||
|
|
||||||
|
msg set_transform_matrix = 14 {
|
||||||
|
id: u32,
|
||||||
|
m11: pod(f64),
|
||||||
|
m12: pod(f64),
|
||||||
|
m21: pod(f64),
|
||||||
|
m22: pod(f64),
|
||||||
|
}
|
||||||
|
|
||||||
|
msg set_cursor_size = 15 {
|
||||||
|
seat: str,
|
||||||
|
size: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg attach = 16 {
|
||||||
|
id: u32,
|
||||||
|
seat: str,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg detach = 17 {
|
||||||
|
id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg get_seat = 18 {
|
||||||
|
name: str,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg get_device = 19 {
|
||||||
|
id: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
# events
|
||||||
|
|
||||||
|
msg seat = 0 {
|
||||||
|
name: str,
|
||||||
|
repeat_rate: i32,
|
||||||
|
repeat_delay: i32,
|
||||||
|
hardware_cursor: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg input_device = 1 {
|
||||||
|
id: u32,
|
||||||
|
name: str,
|
||||||
|
seat: str,
|
||||||
|
syspath: str,
|
||||||
|
devnode: str,
|
||||||
|
capabilities: array(pod(i32)),
|
||||||
|
accel_available: u32,
|
||||||
|
accel_profile: i32,
|
||||||
|
accel_speed: pod(f64),
|
||||||
|
tap_available: u32,
|
||||||
|
tap_enabled: u32,
|
||||||
|
tap_drag_enabled: u32,
|
||||||
|
tap_drag_lock_enabled: u32,
|
||||||
|
left_handed_available: u32,
|
||||||
|
left_handed: u32,
|
||||||
|
natural_scrolling_available: u32,
|
||||||
|
natural_scrolling_enabled: u32,
|
||||||
|
px_per_wheel_scroll: pod(f64),
|
||||||
|
transform_matrix: array(pod(u8)),
|
||||||
|
}
|
||||||
|
|
||||||
|
msg error = 2 {
|
||||||
|
msg: str,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg keymap = 3 {
|
||||||
|
keymap: fd,
|
||||||
|
keymap_len: u32,
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue