Skip to content

Commit

Permalink
Fix input devices management
Browse files Browse the repository at this point in the history
  • Loading branch information
katyo committed Jan 6, 2024
1 parent 75e160f commit d3b259e
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 87 deletions.
22 changes: 16 additions & 6 deletions agent/src/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,11 @@ impl Agent {
// On/off devices
if let Some(xclient) = &self.state.xclient {
// in tablet mode
for (id, action) in devices_to_switch {
xclient.switch_input_device(id, action).await?;
for (id, on) in devices_to_switch {
tracing::info!("Turn {} input device {id}", if on { "on" } else { "off" });
if let Err(error) = xclient.set_input_device_state(id, on).await {
tracing::error!("Error while switching input device {id}: {error}");
}
}
}

Expand All @@ -373,14 +376,17 @@ impl Agent {
Ok(())
}

pub async fn update_input_device_state(&self, id: u32, enable: bool, is_tablet_mode: bool) -> Result<()> {
pub async fn update_input_device_state(&self, id: u32, on: bool, is_tablet_mode: bool) -> Result<()> {
let tablet_mode = {
let mode = self.state.tablet_mode.read().await;
*mode
};
if is_tablet_mode == tablet_mode {
if let Some(xclient) = &self.state.xclient {
xclient.switch_input_device(id, enable).await?;
tracing::info!("Turn {} input device {id}", if on { "on" } else { "off" });
if let Err(error) = xclient.set_input_device_state(id, on).await {
tracing::error!("Error while switching input device {id}: {error}");
}
}
}
Ok(())
Expand All @@ -394,7 +400,10 @@ impl Agent {
Default::default()
};
if let Some(xclient) = &self.state.xclient {
xclient.set_input_device_orientation(id, orientation).await?;
tracing::info!("Rotate input device {id} to {orientation}");
if let Err(error) = xclient.set_input_device_orientation(id, orientation).await {
tracing::error!("Error while rotating input device {id}: {error}");
}
}
Ok(())
}
Expand Down Expand Up @@ -478,8 +487,9 @@ impl Agent {
}

for id in devices_to_rotate {
tracing::info!("Rotate input device {id} to {orientation}");
if let Err(error) = xclient.set_input_device_orientation(id, orientation).await {
tracing::error!("Error while rotating input device: {error}");
tracing::error!("Error while rotating input device {id}: {error}");
}
}
}
Expand Down
184 changes: 103 additions & 81 deletions agent/src/xclient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ pub struct XClient {
device_type_map: RwLock<HashMap<u32, String>>,
device_enabled_prop: Atom,
coord_trans_mat_prop: Atom,
enable_disable_val: [ChangeDevicePropertyAux; 2],
coord_trans_mat_val: [ChangeDevicePropertyAux; 4],
}

impl XClient {
Expand Down Expand Up @@ -108,13 +110,27 @@ impl XClient {
let device_enabled_prop = Self::atom(&conn, "Device Enabled").await?;
let coord_trans_mat_prop = Self::atom(&conn, "Coordinate Transformation Matrix").await?;

let enable_disable_val = [
state_to_propval(true),
state_to_propval(false),
];

let coord_trans_mat_val = [
orientation_to_propval(Orientation::TopUp),
orientation_to_propval(Orientation::LeftUp),
orientation_to_propval(Orientation::RightUp),
orientation_to_propval(Orientation::BottomUp),
];

Ok(Self {
task,
conn,
screen,
device_type_map,
device_enabled_prop,
coord_trans_mat_prop,
enable_disable_val,
coord_trans_mat_val,
})
}

Expand Down Expand Up @@ -165,7 +181,7 @@ impl XClient {
}

/*
pub async fn input_device_status(&self, device: &DeviceId) -> Result<bool> {
pub async fn input_device_state(&self, device: &DeviceId) -> Result<bool> {
let reply = self
.conn
.xinput_get_device_property(self.device_enabled_prop, ANY_PROPERTY_TYPE, 0, 1, device.id as _, false)
Expand All @@ -181,45 +197,47 @@ impl XClient {
}
*/

pub async fn switch_input_device(&self, device: u32, enable: bool) -> Result<()> {
let reply = self
.conn
.xinput_get_device_property(
self.device_enabled_prop,
ANY_PROPERTY_TYPE,
0,
1,
device as _,
false,
)
.await?
.reply()
.await?;

let type_ = reply.type_;
let enabled = reply
.items
.as_data8()
.map(|data| if data.is_empty() { false } else { data[0] == 1 })
.unwrap_or_default();
pub async fn set_input_device_state(&self, device: u32, enable: bool) -> Result<()> {
for _ in 0..4 {
let reply = self
.conn
.xinput_get_device_property(
self.device_enabled_prop,
ANY_PROPERTY_TYPE,
0,
1,
device as _,
false,
)
.await?
.reply()
.await?;

let type_ = reply.type_;
let enabled = reply
.items
.as_data8()
.and_then(|data| data.get(0).map(|val| *val != 0))
.unwrap_or_default();

if enable == enabled {
break;
}

if enable == enabled {
return Ok(());
let value = &self.enable_disable_val[if enable { 0 } else { 1 }];

self.conn
.xinput_change_device_property(
self.device_enabled_prop,
type_,
device as _,
PropMode::REPLACE,
1,
value,
)
.await?;
}

let value = ChangeDevicePropertyAux::Data8(vec![if enable { 1 } else { 0 }]);

self.conn
.xinput_change_device_property(
self.device_enabled_prop,
type_,
device as _,
PropMode::REPLACE,
1,
&value,
)
.await?;

Ok(())
}

Expand All @@ -228,57 +246,55 @@ impl XClient {
device: u32,
orientation: Orientation,
) -> Result<()> {
let reply = self
.conn
.xinput_get_device_property(
self.coord_trans_mat_prop,
ANY_PROPERTY_TYPE,
0,
core::mem::size_of::<f32>() as u32 * 9,
device as _,
false,
)
.await?
.reply()
.await?;

let type_ = reply.type_;
let had_matrix = reply
.items
.as_data32()
.and_then(|data| {
let mat: &[u32; 9] = data.as_slice().try_into().ok()?;
let mat: &[f32; 9] = unsafe { &*(mat as *const _ as *const _) };
Some(mat)
})
.ok_or_else(|| XError::NotFound("coord transform matrix"))?;

let matrix = orientation_to_matrix(orientation);
for _ in 0..4 {
let reply = self
.conn
.xinput_get_device_property(
self.coord_trans_mat_prop,
ANY_PROPERTY_TYPE,
0,
core::mem::size_of::<f32>() as u32 * 9,
device as _,
false,
)
.await?
.reply()
.await?;

let type_ = reply.type_;

let value = &self.coord_trans_mat_val[orientation as usize];

let had_value = reply
.items
.as_data32()
.ok_or_else(|| XError::NotFound("coord transform matrix"))?;

if had_value == value.as_data32().unwrap() {
break;
}

if had_matrix == matrix {
return Ok(());
self.conn
.xinput_change_device_property(
self.coord_trans_mat_prop,
type_,
device as _,
PropMode::REPLACE,
9,
value,
)
.await?;
}

let value = ChangeDevicePropertyAux::Data32({
let mat: &[u32; 9] = unsafe { &*(matrix as *const _ as *const _) };
(&mat[..]).into()
});

self.conn
.xinput_change_device_property(
self.coord_trans_mat_prop,
type_,
device as _,
PropMode::REPLACE,
9,
&value,
)
.await?;

Ok(())
}
}

fn state_to_propval(state: bool) -> ChangeDevicePropertyAux {
let val = if state { 1 } else { 0 };
ChangeDevicePropertyAux::Data8(vec![val])
}

fn orientation_to_matrix(orientation: Orientation) -> &'static [f32; 9] {
match orientation {
Orientation::TopUp => &[
Expand All @@ -304,6 +320,12 @@ fn orientation_to_matrix(orientation: Orientation) -> &'static [f32; 9] {
}
}

fn orientation_to_propval(orientation: Orientation) -> ChangeDevicePropertyAux {
let mat = orientation_to_matrix(orientation);
let mat: &[u32; 9] = unsafe { &*(mat as *const _ as *const _) };
ChangeDevicePropertyAux::Data32(mat.as_slice().into())
}

impl XClient {
async fn get_screen_resources(&self, window: u32) -> Result<(ScreenResources, u32, u32)> {
tracing::debug!("Request get screen 0x{window:x?} resources");
Expand Down

0 comments on commit d3b259e

Please sign in to comment.