elgato_streamdeck/
util.rs1use std::str::{from_utf8, Utf8Error};
2use std::time::Duration;
3use hidapi::{HidDevice, HidError};
4use crate::{Kind, StreamDeckError, StreamDeckInput};
5
6pub fn get_feature_report(device: &HidDevice, report_id: u8, length: usize) -> Result<Vec<u8>, HidError> {
8 let mut buff = vec![0u8; length];
9
10 buff.insert(0, report_id);
12
13 device.get_feature_report(buff.as_mut_slice())?;
15
16 Ok(buff)
17}
18
19pub fn send_feature_report(device: &HidDevice, payload: &[u8]) -> Result<(), HidError> {
21 device.send_feature_report(payload)
22}
23
24pub fn read_data(device: &HidDevice, length: usize, timeout: Option<Duration>) -> Result<Vec<u8>, HidError> {
26 device.set_blocking_mode(timeout.is_some())?;
27
28 let mut buf = vec![0u8; length];
29
30 match timeout {
31 Some(timeout) => device.read_timeout(buf.as_mut_slice(), timeout.as_millis() as i32),
32 None => device.read(buf.as_mut_slice()),
33 }?;
34
35 Ok(buf)
36}
37
38pub fn write_data(device: &HidDevice, payload: &[u8]) -> Result<usize, HidError> {
40 device.write(payload)
41}
42
43pub fn extract_str(bytes: &[u8]) -> Result<String, Utf8Error> {
45 Ok(from_utf8(bytes)?.replace('\0', "").to_string())
46}
47
48pub fn flip_key_index(kind: &Kind, key: u8) -> u8 {
50 let col = key % kind.column_count();
51 (key - col) + ((kind.column_count() - 1) - col)
52}
53
54pub fn read_button_states(kind: &Kind, states: &[u8]) -> Vec<bool> {
56 if states[0] == 0 {
57 return vec![];
58 }
59
60 match kind {
61 Kind::Original => {
62 let mut bools = vec![];
63
64 for i in 0..kind.key_count() {
65 let flipped_i = flip_key_index(kind, i) as usize;
66
67 bools.push(states[flipped_i + 1] != 0);
68 }
69
70 bools
71 }
72
73 Kind::Mini | Kind::MiniMk2 | Kind::MiniDiscord | Kind::MiniMk2Module => states[1..].iter().map(|s| *s != 0).collect(),
74
75 _ => states[4..].iter().map(|s| *s != 0).collect(),
76 }
77}
78
79pub fn read_lcd_input(data: &[u8]) -> Result<StreamDeckInput, StreamDeckError> {
81 let start_x = u16::from_le_bytes([data[6], data[7]]);
82 let start_y = u16::from_le_bytes([data[8], data[9]]);
83
84 match &data[4] {
85 0x1 => Ok(StreamDeckInput::TouchScreenPress(start_x, start_y)),
86 0x2 => Ok(StreamDeckInput::TouchScreenLongPress(start_x, start_y)),
87
88 0x3 => {
89 let end_x = u16::from_le_bytes([data[10], data[11]]);
90 let end_y = u16::from_le_bytes([data[12], data[13]]);
91
92 Ok(StreamDeckInput::TouchScreenSwipe((start_x, start_y), (end_x, end_y)))
93 }
94
95 _ => Err(StreamDeckError::BadData),
96 }
97}
98
99pub fn read_encoder_input(kind: &Kind, data: &[u8]) -> Result<StreamDeckInput, StreamDeckError> {
101 match &data[4] {
102 0x0 => Ok(StreamDeckInput::EncoderStateChange(data[5..5 + kind.encoder_count() as usize].iter().map(|s| *s != 0).collect())),
103
104 0x1 => Ok(StreamDeckInput::EncoderTwist(
105 data[5..5 + kind.encoder_count() as usize].iter().map(|s| i8::from_le_bytes([*s])).collect(),
106 )),
107
108 _ => Err(StreamDeckError::BadData),
109 }
110}