use {
crate::{
backend::{InputDeviceAccelProfile, InputDeviceCapability, InputDeviceClickMethod},
cli::{
GlobalArgs,
json::{JsonInputData, JsonInputDevice, JsonSeat, jsonl},
},
clientmem::ClientMem,
libinput::consts::{
ConfigClickMethod, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT, LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS,
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER, LIBINPUT_CONFIG_CLICK_METHOD_NONE,
},
object::Version,
tools::tool_client::{Handle, ToolClient, with_tool_client},
utils::{errorfmt::ErrorFmt, static_text::StaticText, string_ext::StringExt},
wire::{
JayCompositorId, JayInputId, JayKeymapBuilderId, jay_compositor, jay_input,
jay_keymap_builder,
},
},
clap::{Args, Subcommand, ValueEnum, ValueHint},
isnt::std_1::vec::IsntVecExt,
std::{
cell::RefCell,
io::{Read, Write, stdin, stdout},
mem,
ops::DerefMut,
rc::Rc,
},
uapi::{OwnedFd, c},
};
#[derive(Args, Debug)]
pub struct InputArgs {
#[clap(subcommand)]
pub command: Option<InputCmd>,
}
#[derive(Subcommand, Debug)]
pub enum InputCmd {
Show(ShowArgs),
Seat(SeatArgs),
Device(DeviceArgs),
}
impl Default for InputCmd {
fn default() -> Self {
Self::Show(Default::default())
}
}
#[derive(Args, Debug, Default)]
pub struct ShowArgs {
#[arg(short, long)]
pub verbose: bool,
}
#[derive(Args, Debug)]
pub struct SeatArgs {
pub seat: String,
#[clap(subcommand)]
pub command: Option<SeatCommand>,
}
#[derive(Args, Debug)]
pub struct DeviceArgs {
pub device: u32,
#[clap(subcommand)]
pub command: Option<DeviceCommand>,
}
#[derive(Subcommand, Debug, Clone)]
pub enum SeatCommand {
Show(SeatShowArgs),
SetRepeatRate(SetRepeatRateArgs),
SetKeymap(SetKeymapArgs),
SetKeymapFromNames(SetKeymapFromNamesArgs),
Keymap,
UseHardwareCursor(UseHardwareCursorArgs),
SetCursorSize(SetCursorSizeArgs),
SimpleIm(SimpleImArgs),
}
#[derive(Args, Debug, Clone)]
pub struct SimpleImArgs {
#[clap(subcommand)]
pub command: SimpleImCommand,
}
#[derive(Subcommand, Debug, Clone)]
pub enum SimpleImCommand {
Enable,
Disable,
Reload,
}
impl Default for SeatCommand {
fn default() -> Self {
Self::Show(SeatShowArgs::default())
}
}
#[derive(Args, Debug, Default, Clone)]
pub struct SeatShowArgs {
#[arg(short, long)]
pub verbose: bool,
}
#[derive(Subcommand, Debug, Clone, Default)]
pub enum DeviceCommand {
#[default]
Show,
SetAccelProfile(SetAccelProfileArgs),
SetAccelSpeed(SetAccelSpeedArgs),
SetTapEnabled(SetTapEnabledArgs),
SetTapDragEnabled(SetTapDragEnabledArgs),
SetTapDragLockEnabled(SetTapDragLockEnabledArgs),
SetLeftHanded(SetLeftHandedArgs),
SetNaturalScrolling(SetNaturalScrollingArgs),
SetPxPerWheelScroll(SetPxPerWheelScrollArgs),
SetPxScrollMultiplier(SetPxScrollMultiplierArgs),
SetTransformMatrix(SetTransformMatrixArgs),
SetKeymap(SetKeymapArgs),
SetKeymapFromNames(SetKeymapFromNamesArgs),
Keymap,
Attach(AttachArgs),
Detach,
MapToOutput(MapToOutputArgs),
RemoveMapping,
SetCalibrationMatrix(SetCalibrationMatrixArgs),
SetClickMethod(SetClickMethodArgs),
SetMiddleButtonEmulation(SetMiddleButtonEmulationArgs),
}
#[derive(ValueEnum, Debug, Clone)]
pub enum AccelProfile {
Flat,
Adaptive,
}
#[derive(Args, Debug, Clone)]
pub struct SetAccelProfileArgs {
pub profile: AccelProfile,
}
#[derive(Args, Debug, Clone)]
pub struct SetAccelSpeedArgs {
pub speed: f64,
}
#[derive(Args, Debug, Clone)]
pub struct SetTapEnabledArgs {
#[arg(action = clap::ArgAction::Set)]
pub enabled: bool,
}
#[derive(Args, Debug, Clone)]
pub struct SetTapDragEnabledArgs {
#[arg(action = clap::ArgAction::Set)]
pub enabled: bool,
}
#[derive(Args, Debug, Clone)]
pub struct SetTapDragLockEnabledArgs {
#[arg(action = clap::ArgAction::Set)]
pub enabled: bool,
}
#[derive(Args, Debug, Clone)]
pub struct SetLeftHandedArgs {
#[arg(action = clap::ArgAction::Set)]
pub left_handed: bool,
}
#[derive(Args, Debug, Clone)]
pub struct SetNaturalScrollingArgs {
#[arg(action = clap::ArgAction::Set)]
pub natural_scrolling: bool,
}
#[derive(Args, Debug, Clone)]
pub struct SetPxPerWheelScrollArgs {
pub px: f64,
}
#[derive(Args, Debug, Clone)]
pub struct SetPxScrollMultiplierArgs {
pub mul: 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 SetCalibrationMatrixArgs {
pub m00: f32,
pub m01: f32,
pub m02: f32,
pub m10: f32,
pub m11: f32,
pub m12: f32,
}
#[derive(ValueEnum, Debug, Clone)]
pub enum ClickMethod {
None,
ButtonAreas,
Clickfinger,
}
#[derive(Args, Debug, Clone)]
pub struct SetClickMethodArgs {
pub method: ClickMethod,
}
#[derive(Args, Debug, Clone)]
pub struct SetMiddleButtonEmulationArgs {
#[arg(action = clap::ArgAction::Set)]
pub middle_button_emulation: bool,
}
#[derive(Args, Debug, Clone)]
pub struct MapToOutputArgs {
pub output: String,
}
#[derive(Args, Debug, Clone)]
pub struct AttachArgs {
pub seat: String,
}
#[derive(Args, Debug, Clone)]
pub struct SetRepeatRateArgs {
pub rate: i32,
pub delay: i32,
}
#[derive(Args, Debug, Clone)]
pub struct SetCursorSizeArgs {
pub size: u32,
}
#[derive(Args, Debug, Clone)]
pub struct SetKeymapArgs {
#[clap(long)]
pub shortcuts_group: Option<u32>,
#[clap(value_hint = ValueHint::FilePath)]
pub file: Option<String>,
}
#[derive(Args, Debug, Clone)]
pub struct SetKeymapFromNamesArgs {
#[clap(long)]
pub shortcuts_group: Option<u32>,
#[clap(short, long)]
pub rules: Option<String>,
#[clap(short, long)]
pub model: Option<String>,
#[clap(short, long)]
pub layout: Option<String>,
#[clap(short, long)]
pub variant: Option<String>,
#[clap(short, long)]
pub options: Option<String>,
}
#[derive(Args, Debug, Clone)]
pub struct UseHardwareCursorArgs {
#[arg(action = clap::ArgAction::Set)]
pub enabled: bool,
}
pub fn main(global: GlobalArgs, args: InputArgs) {
with_tool_client(global.log_level, |tc| async move {
let comp = tc.jay_compositor().await;
let idle = Rc::new(Input {
tc: tc.clone(),
comp,
});
idle.run(&global, 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]>,
pub output: Option<String>,
pub calibration_matrix: Option<[[f32; 3]; 2]>,
pub click_method: Option<InputDeviceClickMethod>,
pub middle_button_emulation_enabled: Option<bool>,
}
#[derive(Clone, Debug, Default)]
struct Data {
seats: Vec<Seat>,
input_device: Vec<InputDevice>,
}
struct Input {
tc: Rc<ToolClient>,
comp: JayCompositorId,
}
const KEYMAP_BUILDER_SINCE: Version = Version(32);
impl Input {
async fn run(self: &Rc<Self>, global: &GlobalArgs, args: InputArgs) {
let tc = &self.tc;
let input = tc.id();
tc.send(jay_compositor::GetInput {
self_id: self.comp,
id: input,
});
match args.command.unwrap_or_default() {
InputCmd::Show(args) => self.show(global, input, args).await,
InputCmd::Seat(args) => self.seat(global, input, args).await,
InputCmd::Device(args) => self.device(global, 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);
});
}
fn prepare_keymap(&self, a: &SetKeymapArgs) -> (Rc<OwnedFd>, usize) {
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();
(Rc::new(memfd), map.len())
}
fn prepare_keymap_builder(
&self,
shortcuts_group: Option<u32>,
f: impl FnOnce(JayKeymapBuilderId),
) -> JayKeymapBuilderId {
let id = self.tc.id();
self.tc.send(jay_compositor::CreateKeymapBuilder {
self_id: self.comp,
id,
});
f(id);
if let Some(g) = shortcuts_group {
self.tc.send(jay_keymap_builder::SetShortcutsGroup {
self_id: id,
group: g,
});
}
id
}
fn prepare_keymap_builder_from_map(&self, a: &SetKeymapArgs) -> JayKeymapBuilderId {
self.prepare_keymap_builder(a.shortcuts_group, |id| {
let (keymap, keymap_len) = self.prepare_keymap(a);
self.tc.send(jay_keymap_builder::SetMap {
self_id: id,
keymap,
keymap_len: keymap_len as _,
});
})
}
fn prepare_keymap_builder_from_names(&self, a: &SetKeymapFromNamesArgs) -> JayKeymapBuilderId {
self.prepare_keymap_builder(a.shortcuts_group, |id| {
self.tc.send(jay_keymap_builder::SetNames {
self_id: id,
rules: a.rules.as_deref(),
model: a.model.as_deref(),
layout: a.layout.as_deref(),
variant: a.variant.as_deref(),
options: a.options.as_deref(),
});
})
}
async fn handle_keymap(&self, input: JayInputId) -> Vec<u8> {
let data = Rc::new(RefCell::new(Vec::new()));
jay_input::Keymap::handle(&self.tc, input, data.clone(), |d, map| {
let len = map.keymap_len as _;
let mem = Rc::new(ClientMem::new_private(&map.keymap, len, true, None, None).unwrap())
.offset(0, len);
mem.read(d.borrow_mut().deref_mut()).unwrap();
});
self.tc.round_trip().await;
data.take()
}
async fn seat(self: &Rc<Self>, global: &GlobalArgs, 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;
if global.json {
self.print_data_json(data);
} else {
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);
});
if self.tc.jay_compositor_version().await >= KEYMAP_BUILDER_SINCE {
tc.send(jay_input::SetKeymapFromBuilder {
self_id: input,
seat: &args.seat,
builder: self.prepare_keymap_builder_from_map(&a),
});
} else {
let (memfd, len) = self.prepare_keymap(&a);
tc.send(jay_input::SetKeymap {
self_id: input,
seat: &args.seat,
keymap: memfd,
keymap_len: 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);
});
tc.send(jay_input::GetKeymap {
self_id: input,
seat: &args.seat,
});
let map = self.handle_keymap(input).await;
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,
});
}
SeatCommand::SimpleIm(a) => match a.command {
SimpleImCommand::Enable | SimpleImCommand::Disable => {
self.handle_error(input, |e| {
eprintln!("Could not enable/disable the simple IM: {}", e);
});
tc.send(jay_input::SetSimpleImEnabled {
self_id: input,
seat: &args.seat,
enabled: matches!(a.command, SimpleImCommand::Enable) as _,
});
}
SimpleImCommand::Reload => {
self.handle_error(input, |e| {
eprintln!("Could not reload the simple IM: {}", e);
});
tc.send(jay_input::ReloadSimpleIm {
self_id: input,
seat: &args.seat,
});
}
},
SeatCommand::SetKeymapFromNames(a) => {
self.handle_error(input, |e| {
eprintln!("Could not set keymap: {}", e);
});
if tc.jay_compositor_version().await >= KEYMAP_BUILDER_SINCE {
tc.send(jay_input::SetKeymapFromBuilder {
self_id: input,
seat: &args.seat,
builder: self.prepare_keymap_builder_from_names(&a),
});
} else {
tc.send(jay_input::SetKeymapFromNames {
self_id: input,
seat: &args.seat,
rules: a.rules.as_deref(),
model: a.model.as_deref(),
layout: a.layout.as_deref(),
variant: a.variant.as_deref(),
options: a.options.as_deref(),
});
}
}
}
tc.round_trip().await;
}
async fn device(self: &Rc<Self>, global: &GlobalArgs, 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;
if global.json {
self.print_data_json(data);
} else {
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::SetPxScrollMultiplier(a) => {
self.handle_error(input, |e| {
eprintln!("Could not modify the px-scroll-multiplier setting: {}", e);
});
tc.send(jay_input::SetPxScrollMultiplier {
self_id: input,
id: args.device,
mul: a.mul,
});
}
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,
});
}
DeviceCommand::SetKeymap(a) => {
self.handle_error(input, |e| {
eprintln!("Could not set keymap: {}", e);
});
if self.tc.jay_compositor_version().await >= KEYMAP_BUILDER_SINCE {
tc.send(jay_input::SetDeviceKeymapFromBuilder {
self_id: input,
id: args.device,
builder: self.prepare_keymap_builder_from_map(&a),
});
} else {
let (memfd, len) = self.prepare_keymap(&a);
tc.send(jay_input::SetDeviceKeymap {
self_id: input,
id: args.device,
keymap: memfd,
keymap_len: len as _,
});
}
}
DeviceCommand::Keymap => {
self.handle_error(input, |e| {
eprintln!("Could not retrieve the keymap: {}", e);
});
tc.send(jay_input::GetDeviceKeymap {
self_id: input,
id: args.device,
});
let map = self.handle_keymap(input).await;
stdout().write_all(&map).unwrap();
}
DeviceCommand::MapToOutput(a) => {
self.handle_error(input, |e| {
eprintln!("Could not map the device to an output: {}", e);
});
tc.send(jay_input::MapToOutput {
self_id: input,
id: args.device,
output: Some(&a.output),
});
}
DeviceCommand::RemoveMapping => {
self.handle_error(input, |e| {
eprintln!("Could not remove the output mapping: {}", e);
});
tc.send(jay_input::MapToOutput {
self_id: input,
id: args.device,
output: None,
});
}
DeviceCommand::SetCalibrationMatrix(a) => {
self.handle_error(input, |e| {
eprintln!("Could not modify the calibration matrix: {}", e);
});
tc.send(jay_input::SetCalibrationMatrix {
self_id: input,
id: args.device,
m00: a.m00,
m01: a.m01,
m02: a.m02,
m10: a.m10,
m11: a.m11,
m12: a.m12,
});
}
DeviceCommand::SetClickMethod(a) => {
let method = match a.method {
ClickMethod::None => LIBINPUT_CONFIG_CLICK_METHOD_NONE.0,
ClickMethod::ButtonAreas => LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS.0,
ClickMethod::Clickfinger => LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER.0,
};
self.handle_error(input, |e| {
eprintln!("Could not set the click method: {}", e);
});
tc.send(jay_input::SetClickMethod {
self_id: input,
id: args.device,
method,
});
}
DeviceCommand::SetMiddleButtonEmulation(a) => {
self.handle_error(input, |e| {
eprintln!(
"Could not modify the middle-button-emulation setting: {}",
e
);
});
tc.send(jay_input::SetMiddleButtonEmulation {
self_id: input,
id: args.device,
enabled: a.middle_button_emulation as _,
});
}
DeviceCommand::SetKeymapFromNames(a) => {
self.handle_error(input, |e| {
eprintln!("Could not set keymap: {}", e);
});
if self.tc.jay_compositor_version().await >= KEYMAP_BUILDER_SINCE {
tc.send(jay_input::SetDeviceKeymapFromBuilder {
self_id: input,
id: args.device,
builder: self.prepare_keymap_builder_from_names(&a),
});
} else {
tc.send(jay_input::SetDeviceKeymapFromNames {
self_id: input,
id: args.device,
rules: a.rules.as_deref(),
model: a.model.as_deref(),
layout: a.layout.as_deref(),
variant: a.variant.as_deref(),
options: a.options.as_deref(),
});
}
}
}
tc.round_trip().await;
}
async fn show(self: &Rc<Self>, global: &GlobalArgs, input: JayInputId, args: ShowArgs) {
self.tc.send(jay_input::GetAll { self_id: input });
let data = self.get(input).await;
if global.json {
self.print_data_json(data);
} else {
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 = device.seat.as_deref().unwrap_or("<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 {
print!(" ");
if !mem::take(&mut first) {
print!("| ");
}
print!("{}", cap.text());
}
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);
}
if let Some(v) = &device.output {
println!("{prefix} mapped to output: {}", v);
}
if let Some(v) = &device.calibration_matrix {
println!("{prefix} calibration matrix: {:?}", v);
}
if let Some(v) = &device.click_method {
let name = match v {
InputDeviceClickMethod::None => "none",
InputDeviceClickMethod::ButtonAreas => "button-areas",
InputDeviceClickMethod::Clickfinger => "clickfinger",
};
println!("{prefix} click method: {}", name);
}
if let Some(v) = &device.middle_button_emulation_enabled {
println!("{prefix} middle button emulation: {}", v);
}
}
fn print_data_json(&self, mut data: Data) {
data.seats.sort_by(|l, r| l.name.cmp(&r.name));
data.input_device.sort_by_key(|l| l.id);
let mut seats = Vec::new();
for seat in &data.seats {
let devices = data
.input_device
.iter()
.filter(|c| c.seat.as_ref() == Some(&seat.name))
.map(make_json_device)
.collect();
seats.push(JsonSeat {
name: &seat.name,
repeat_rate: seat.repeat_rate,
repeat_delay: seat.repeat_delay,
hardware_cursor: seat.hardware_cursor,
devices,
});
}
let detached_devices = data
.input_device
.iter()
.filter(|c| c.seat.is_none())
.map(make_json_device)
.collect();
let json = JsonInputData {
seats,
detached_devices,
};
jsonl(&json);
}
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(),
output: None,
calibration_matrix: None,
click_method: None,
middle_button_emulation_enabled: None,
});
});
jay_input::InputDeviceOutput::handle(tc, input, data.clone(), |data, msg| {
let mut data = data.borrow_mut();
if let Some(last) = data.input_device.last_mut() {
last.output = Some(msg.output.to_string());
}
});
jay_input::CalibrationMatrix::handle(tc, input, data.clone(), |data, msg| {
let mut data = data.borrow_mut();
if let Some(last) = data.input_device.last_mut() {
last.calibration_matrix =
Some([[msg.m00, msg.m01, msg.m02], [msg.m10, msg.m11, msg.m12]]);
}
});
jay_input::ClickMethod::handle(tc, input, data.clone(), |data, msg| {
let click_method = match ConfigClickMethod(msg.click_method) {
LIBINPUT_CONFIG_CLICK_METHOD_NONE => Some(InputDeviceClickMethod::None),
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS => {
Some(InputDeviceClickMethod::ButtonAreas)
}
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER => {
Some(InputDeviceClickMethod::Clickfinger)
}
_ => None,
};
let mut data = data.borrow_mut();
if let Some(last) = data.input_device.last_mut() {
last.click_method = click_method;
}
});
jay_input::MiddleButtonEmulation::handle(tc, input, data.clone(), |data, msg| {
let mut data = data.borrow_mut();
if let Some(last) = data.input_device.last_mut() {
last.middle_button_emulation_enabled =
Some(msg.middle_button_emulation_enabled != 0);
}
});
tc.round_trip().await;
data.borrow_mut().clone()
}
}
fn make_json_device(device: &InputDevice) -> JsonInputDevice<'_> {
JsonInputDevice {
input_device_id: device.id,
name: &device.name,
seat: device.seat.as_deref(),
syspath: device.syspath.as_deref(),
devnode: device.devnode.as_deref(),
capabilities: device.capabilities.iter().map(|c| c.text()).collect(),
accel_profile: device.accel_profile.as_ref().map(|v| v.text()),
accel_speed: device.accel_speed,
tap_enabled: device.tap_enabled,
tap_drag_enabled: device.tap_drag_enabled,
tap_drag_lock_enabled: device.tap_drag_lock_enabled,
left_handed: device.left_handed,
natural_scrolling: device.natural_scrolling_enabled,
px_per_wheel_scroll: device.px_per_wheel_scroll,
transform_matrix: device.transform_matrix,
output: device.output.as_deref(),
calibration_matrix: device.calibration_matrix,
click_method: device.click_method.as_ref().map(|v| v.text()),
middle_button_emulation: device.middle_button_emulation_enabled,
}
}