use std::sync::Arc;
use hidpp::{
channel::HidppChannel,
feature::{CreatableFeature, reprog_controls as hidpp_reprog},
protocol::v20::Hidpp20Error,
};
mod event;
pub use event::{RawControlEvent, decode_event};
pub use hidpp_reprog::{
AnalyticsKeyEvent, CidFlags, CidInfo, CidReporting, CidReportingChange, CidReportingChangeEcho,
ControlId, GroupMask, RawWheelResolution, ReprogControlsCapabilities, ReprogControlsEvent,
TaskId, decode_event as decode_full_event,
};
pub use hidpp_reprog::{control_ids, task_ids};
pub const FEATURE_ID: u16 = 0x1b04;
pub const GESTURE_BUTTON_CID: u16 = 0x00c3;
pub const HAPTIC_PANEL_CID: u16 = control_ids::HAPTIC_PANEL.0;
pub const DPI_MODE_SHIFT_CIDS: [u16; 3] = [0x00c4, 0x00ed, 0x00fd];
pub const BACK_CIDS: [u16; 4] = [0x0053, 0x00BD, 0x00CE, 0x00DB];
pub const FORWARD_CIDS: [u16; 2] = [0x0056, 0x00CF];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CtrlIdInfo {
pub cid: u16,
pub task_id: u16,
pub flags: u16,
}
impl CtrlIdInfo {
#[must_use]
pub fn typed_flags(self) -> CidFlags {
CidFlags::from_bits_retain(self.flags)
}
#[must_use]
pub fn is_divertable(self) -> bool {
self.typed_flags().is_divertable()
}
#[must_use]
pub fn supports_raw_xy(self) -> bool {
self.typed_flags().supports_raw_xy()
}
#[must_use]
pub fn supports_force_raw_xy(self) -> bool {
self.typed_flags().supports_force_raw_xy()
}
#[must_use]
pub fn supports_analytics_events(self) -> bool {
self.typed_flags().supports_analytics_key_events()
}
#[must_use]
pub fn supports_raw_wheel(self) -> bool {
self.typed_flags().supports_raw_wheel()
}
}
impl From<CidInfo> for CtrlIdInfo {
fn from(info: CidInfo) -> Self {
Self {
cid: info.cid.into(),
task_id: info.task_id.0,
flags: info.flags.raw(),
}
}
}
#[derive(Clone)]
pub struct ReprogControlsV4 {
inner: Arc<hidpp_reprog::ReprogControlsFeature>,
device_index: u8,
feature_index: u8,
}
impl ReprogControlsV4 {
#[must_use]
pub fn new(chan: Arc<HidppChannel>, device_index: u8, feature_index: u8) -> Self {
Self {
inner: Arc::new(hidpp_reprog::ReprogControlsFeature::new(
chan,
device_index,
feature_index,
)),
device_index,
feature_index,
}
}
#[must_use]
pub fn feature_index(&self) -> u8 {
self.feature_index
}
#[must_use]
pub fn device_index(&self) -> u8 {
self.device_index
}
pub async fn get_count(&self) -> Result<u8, Hidpp20Error> {
self.inner.get_count().await
}
pub async fn get_cid_info(&self, index: u8) -> Result<CidInfo, Hidpp20Error> {
self.inner.get_cid_info(index).await
}
pub async fn get_ctrl_id_info(&self, index: u8) -> Result<CtrlIdInfo, Hidpp20Error> {
Ok(self.get_cid_info(index).await?.into())
}
pub async fn find_cid_info(&self, cid: ControlId) -> Result<Option<CidInfo>, Hidpp20Error> {
let count = self.get_count().await?;
for index in 0..count {
let info = self.get_cid_info(index).await?;
if info.cid == cid {
return Ok(Some(info));
}
}
Ok(None)
}
pub async fn find_control(&self, cid: u16) -> Result<Option<CtrlIdInfo>, Hidpp20Error> {
Ok(self.find_cid_info(ControlId(cid)).await?.map(Into::into))
}
pub async fn get_cid_reporting(&self, cid: u16) -> Result<CidReporting, Hidpp20Error> {
self.inner.get_cid_reporting(ControlId(cid)).await
}
pub async fn set_cid_reporting_full(
&self,
cid: u16,
change: CidReportingChange,
) -> Result<CidReportingChangeEcho, Hidpp20Error> {
self.inner.set_cid_reporting(ControlId(cid), change).await
}
pub async fn get_capabilities(&self) -> Result<ReprogControlsCapabilities, Hidpp20Error> {
self.inner.get_capabilities().await
}
pub async fn reset_all_cid_report_settings(&self) -> Result<(), Hidpp20Error> {
self.inner.reset_all_cid_report_settings().await
}
pub async fn set_cid_reporting(
&self,
cid: u16,
diverted: bool,
raw_xy: bool,
) -> Result<(), Hidpp20Error> {
self.set_cid_reporting_full(
cid,
hidpp_reprog::CidReportingChange::temporary_diversion(diverted, raw_xy),
)
.await?;
Ok(())
}
}