Added support for MiraBox HSV293S (#22)

Co-authored-by: Zach Fine <zach@zachfine.com>
Co-authored-by: ninjadev64 <63245705+ninjadev64@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2024-12-26 22:19:12 +05:30
1 parent 7d59845a42
commit 81642c7138
6 files changed
+180 -207

No files matched your search

+24 -20
View File
@@ -1,55 +1,59 @@
SUBSYSTEM=="usb", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="0060", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="006d", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="0063", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="006c", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="008f", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="006d", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="0080", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="0090", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="0086", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="0084", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="0086", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="008f", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="0090", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="009a", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="5548", ATTR{idProduct}=="6674", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="5548", ATTR{idProduct}=="6670", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="5548", ATTR{idProduct}=="6672", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="5548", ATTR{idProduct}=="6674", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="0300", ATTR{idProduct}=="1010", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0060", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="006d", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0063", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="006c", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="008f", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="006d", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0080", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0090", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0086", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0084", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0086", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="008f", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0090", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="009a", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="5548", ATTRS{idProduct}=="6674", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="5548", ATTRS{idProduct}=="6670", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="5548", ATTRS{idProduct}=="6672", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="5548", ATTRS{idProduct}=="6674", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0300", ATTRS{idProduct}=="1010", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="0060", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="006d", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="0063", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="006c", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="008f", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="006d", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="0080", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="0090", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="0086", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="0084", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="0086", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="008f", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="0090", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="009a", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="5548", ATTR{idProduct}=="6674", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="5548", ATTR{idProduct}=="6670", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="5548", ATTR{idProduct}=="6672", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="5548", ATTR{idProduct}=="6674", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="0300", ATTR{idProduct}=="1010", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0060", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="006d", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0063", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="006c", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="008f", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="006d", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0080", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0090", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0086", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0084", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0086", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="008f", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0090", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="009a", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="5548", ATTRS{idProduct}=="6674", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="5548", ATTRS{idProduct}=="6670", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="5548", ATTRS{idProduct}=="6672", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="5548", ATTRS{idProduct}=="6674", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0300", ATTRS{idProduct}=="1010", MODE="0660", GROUP="plugdev"
+4 -3
View File
@@ -1,5 +1,5 @@
# elgato-streamdeck
Library for interacting with Elgato Stream Decks through [hidapi](https://crates.io/crates/hidapi).
Library for interacting with Elgato Stream Decks through [hidapi](https://crates.io/crates/hidapi).
Heavily based on [python-elgato-streamdeck](https://github.com/abcminiuser/python-elgato-streamdeck) and partially on
[streamdeck library for rust](https://github.com/ryankurte/rust-streamdeck).
@@ -19,7 +19,7 @@ sudo udevadm control --reload-rules
```
Unplugging and plugging back in the device should also help
You should also create group called "plugdev" and add yourself to it, so you get access to the devices.
You should also create group called "plugdev" and add yourself to it, so you get access to the devices.
You also need to restart the user session to let user group changes to kick in
## Example
@@ -62,7 +62,7 @@ if device.updated {
## Supported Devices
Support of the devices is the same as from libraries above, I personally tested Original v2 and Plus.
Support of the devices is the same as from libraries above, I personally tested Original v2 and Plus.
I'll just keep updating this library to match upstream libraries.
But as it stands, this library should support following devices:
@@ -79,3 +79,4 @@ But as it stands, this library should support following devices:
- Ajazz AKP153 (thanks to [@ZCube](https://github.com/ZCube))
- Ajazz AKP153E (thanks to [@teras](https://github.com/teras))
- Ajazz AKP815 (thanks to [@teras](https://github.com/teras))
- MiraBox HSV293S (thanks to [@czyz](https://github.com/czyz))
+2 -2
View File
@@ -113,7 +113,7 @@ impl AsyncStreamDeck {
Ok(block_in_place(move || device.write_image(key, image_data))?)
}
/// Writes image data to Stream Deck device's lcd strip/screen as region.
/// Writes image data to Stream Deck device's lcd strip/screen as region.
/// Only Stream Deck Plus supports writing LCD regions, for Stream Deck Neo use write_lcd_fill
pub async fn write_lcd(&self, x: u16, y: u16, rect: &ImageRect) -> Result<(), StreamDeckError> {
let device = self.device.lock().await;
@@ -222,7 +222,7 @@ impl AsyncDeviceStateReader {
StreamDeckInput::ButtonStateChange(buttons) => {
for (index, (their, mine)) in zip(buttons.iter(), my_states.buttons.iter()).enumerate() {
match self.device.kind {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => {
if *their {
updates.push(DeviceStateUpdate::ButtonDown(index as u8));
updates.push(DeviceStateUpdate::ButtonUp(index as u8));
+24 -21
View File
@@ -28,6 +28,9 @@ pub const AJAZZ_VENDOR_ID_1: u16 = 0x5548;
/// Product ID of Ajazz AKP153 Desk Controller
pub const PID_AJAZZ_AKP153: u16 = 0x6674;
/// Product ID of the "FHOOU" (front label) and "MiraBox HSV293S" (rear label). Seems just like an AKP153.
pub const PID_MIRABOX_HSV293S: u16 = 0x6670;
/// Product ID of Ajazz AKP815 Desk Controller
pub const PID_AJAZZ_AKP815: u16 = 0x6672;
@@ -37,18 +40,13 @@ pub const AJAZZ_VENDOR_ID_2: u16 = 0x0300;
/// Product ID of Ajazz AKP153E Desk Controller
pub const PID_AJAZZ_E_AKP153E: u16 = 0x1010;
const RECOGNIZED_VENDORS: &'static [u16] = &[
ELGATO_VENDOR_ID,
AJAZZ_VENDOR_ID_1,
AJAZZ_VENDOR_ID_2
];
const RECOGNIZED_VENDORS: &'static [u16] = &[ELGATO_VENDOR_ID, AJAZZ_VENDOR_ID_1, AJAZZ_VENDOR_ID_2];
/// Returns true for vendors IDs that are recognized by the library
pub fn is_vendor_familiar(vendor: &u16) -> bool {
RECOGNIZED_VENDORS.contains(vendor)
}
/// Enum describing kinds of Stream Decks out there
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum Kind {
@@ -76,8 +74,10 @@ pub enum Kind {
Akp153,
/// Ajazz AKP153E Desk Controller
Akp153E,
/// Ajazz Akl982 Desk Controller
/// Ajazz AKP815 Desk Controller
Akp815,
/// MiraBox HSV293S
MiraBoxHSV293S,
}
impl Kind {
@@ -95,17 +95,18 @@ impl Kind {
PID_STREAMDECK_NEO => Some(Kind::Neo),
PID_STREAMDECK_PEDAL => Some(Kind::Pedal),
PID_STREAMDECK_PLUS => Some(Kind::Plus),
_ => None
_ => None,
},
AJAZZ_VENDOR_ID_1 | AJAZZ_VENDOR_ID_2 => match pid {
PID_AJAZZ_AKP153 => Some(Kind::Akp153),
PID_AJAZZ_E_AKP153E => Some(Kind::Akp153E),
PID_AJAZZ_AKP815 => Some(Kind::Akp815),
_ => None
}
_ => None
PID_MIRABOX_HSV293S => Some(Kind::MiraBoxHSV293S),
_ => None,
},
_ => None,
}
}
@@ -125,6 +126,7 @@ impl Kind {
Kind::Akp153 => PID_AJAZZ_AKP153,
Kind::Akp815 => PID_AJAZZ_AKP815,
Kind::Akp153E => PID_AJAZZ_E_AKP153E,
Kind::MiraBoxHSV293S => PID_MIRABOX_HSV293S,
}
}
@@ -144,6 +146,7 @@ impl Kind {
Kind::Akp153 => AJAZZ_VENDOR_ID_1,
Kind::Akp815 => AJAZZ_VENDOR_ID_1,
Kind::Akp153E => AJAZZ_VENDOR_ID_2,
Kind::MiraBoxHSV293S => AJAZZ_VENDOR_ID_1,
}
}
@@ -155,7 +158,7 @@ impl Kind {
Kind::Xl | Kind::XlV2 => 32,
Kind::Pedal => 3,
Kind::Neo | Kind::Plus => 8,
Kind::Akp153 | Kind::Akp153E => 15 + 3,
Kind::Akp153 | Kind::Akp153E | Kind::MiraBoxHSV293S => 15 + 3,
Kind::Akp815 => 15,
}
}
@@ -168,8 +171,8 @@ impl Kind {
Kind::Xl | Kind::XlV2 => 4,
Kind::Pedal => 1,
Kind::Neo | Kind::Plus => 2,
Kind::Akp153 | Kind::Akp153E => 3,
Kind::Akp815 =>5,
Kind::Akp153 | Kind::Akp153E | Kind::MiraBoxHSV293S => 3,
Kind::Akp815 => 5,
}
}
@@ -181,7 +184,7 @@ impl Kind {
Kind::Xl | Kind::XlV2 => 8,
Kind::Pedal => 3,
Kind::Neo | Kind::Plus => 4,
Kind::Akp153 | Kind::Akp153E => 6,
Kind::Akp153 | Kind::Akp153E | Kind::MiraBoxHSV293S => 6,
Kind::Akp815 => 3,
}
}
@@ -207,7 +210,7 @@ impl Kind {
match self {
Kind::Plus => Some((800, 100)),
Kind::Neo => Some((248, 58)),
Kind::Akp153 | Kind::Akp153E => Some((854, 480)),
Kind::Akp153 | Kind::Akp153E | Kind::MiraBoxHSV293S => Some((854, 480)),
Kind::Akp815 => Some((800, 480)),
_ => None,
}
@@ -266,7 +269,7 @@ impl Kind {
Kind::Pedal => ImageFormat::default(),
Kind::Akp153 | Kind::Akp153E => ImageFormat {
Kind::Akp153 | Kind::Akp153E | Kind::MiraBoxHSV293S => ImageFormat {
mode: ImageMode::JPEG,
size: (85, 85),
rotation: ImageRotation::Rot90,
@@ -281,7 +284,7 @@ impl Kind {
},
}
}
/// Image format used by LCD screen, used for filling LCD
pub fn lcd_image_format(&self) -> Option<ImageFormat> {
match self {
@@ -297,7 +300,7 @@ impl Kind {
rotation: ImageRotation::Rot0,
mirror: ImageMirroring::None,
}),
_ => None
_ => None,
}
}
+124 -159
View File
@@ -22,7 +22,10 @@ use hidapi::{HidApi, HidDevice, HidError, HidResult};
use image::{DynamicImage, ImageError};
use crate::info::{is_vendor_familiar, Kind};
use crate::util::{ajazz153_to_elgato_input, elgato153_to_ajazz, extract_str, flip_key_index, get_feature_report, inverse_key_index, read_button_states, read_data, read_encoder_input, read_lcd_input, send_feature_report, write_data};
use crate::util::{
ajazz153_to_elgato_input, elgato_to_ajazz153, extract_str, flip_key_index, get_feature_report, inverse_key_index, read_button_states, read_data, read_encoder_input, read_lcd_input,
send_feature_report, write_data,
};
/// Various information about Stream Deck devices
pub mod info;
@@ -132,7 +135,12 @@ impl StreamDeck {
pub fn connect(hidapi: &HidApi, kind: Kind, serial: &str) -> Result<StreamDeck, StreamDeckError> {
let device = hidapi.open_serial(kind.vendor_id(), kind.product_id(), serial)?;
Ok(StreamDeck { kind, device, image_cache: RwLock::new(vec![]), initialized: false.into() })
Ok(StreamDeck {
kind,
device,
image_cache: RwLock::new(vec![]),
initialized: false.into(),
})
}
}
@@ -156,7 +164,7 @@ impl StreamDeck {
/// Returns serial number of the device
pub fn serial_number(&self) -> Result<String, StreamDeckError> {
match self.kind {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => {
let serial = self.device.get_serial_number_string()?;
match serial {
Some(serial) => {
@@ -184,7 +192,8 @@ impl StreamDeck {
let bytes = get_feature_report(&self.device, 0x06, 32)?;
Ok(extract_str(&bytes[2..])?)
}
}.map(|s| s.replace('\u{0001}', ""))
}
.map(|s| s.replace('\u{0001}', ""))
}
/// Returns firmware version of the StreamDeck
@@ -195,7 +204,7 @@ impl StreamDeck {
Ok(extract_str(&bytes[5..])?)
}
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => {
let bytes = get_feature_report(&self.device, 0x01, 20)?;
Ok(extract_str(&bytes[0..])?)
}
@@ -214,7 +223,7 @@ impl StreamDeck {
}
self.initialized.store(true, Ordering::Release);
match self.kind {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => {
let mut buf = vec![0x43, 0x52, 0x54, 0x00, 0x00, 0x44, 0x49, 0x53];
buf.extend(vec![0u8; 512 - buf.len()]);
write_data(&self.device, buf.as_slice())?;
@@ -224,8 +233,7 @@ impl StreamDeck {
write_data(&self.device, buf.as_slice())?;
}
_ => {
}
_ => {}
}
Ok(())
}
@@ -252,7 +260,7 @@ impl StreamDeck {
}
}
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => {
let data = match self.kind {
_ => read_data(&self.device, 512, timeout),
}?;
@@ -304,7 +312,7 @@ impl StreamDeck {
Ok(send_feature_report(&self.device, buf.as_slice())?)
}
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => Ok({
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => Ok({
self.set_brightness(100)?;
self.clear_button_image(0xff)?;
}),
@@ -333,7 +341,7 @@ impl StreamDeck {
Ok(send_feature_report(&self.device, buf.as_slice())?)
}
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => {
let mut buf = vec![0x43, 0x52, 0x54, 0x00, 0x00, 0x4c, 0x49, 0x47, 0x00, 0x00, percent];
buf.extend(vec![0u8; 512 - buf.len()]);
@@ -360,8 +368,8 @@ impl StreamDeck {
let key = if let Kind::Original = self.kind {
flip_key_index(&self.kind, key)
} else if let Kind::Akp153 | Kind::Akp153E = self.kind {
elgato153_to_ajazz(&self.kind, key)
} else if let Kind::Akp153 | Kind::Akp153E | Kind::MiraBoxHSV293S = self.kind {
elgato_to_ajazz153(&self.kind, key)
} else if let Kind::Akp815 = self.kind {
inverse_key_index(&self.kind, key)
} else {
@@ -373,7 +381,7 @@ impl StreamDeck {
}
match self.kind {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => {
let mut buf = vec![
0x43,
0x52,
@@ -397,64 +405,28 @@ impl StreamDeck {
_ => {}
}
self.write_image_data_reports(
image_data,
WriteImageParameters::for_key(self.kind, image_data.len()),
|page_number, this_length, last_package| {
match self.kind {
Kind::Original => vec![
0x02,
0x01,
(page_number + 1) as u8,
0,
if last_package { 1 } else { 0 },
key + 1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
],
Kind::Mini | Kind::MiniMk2 => vec![
0x02,
0x01,
page_number as u8,
0,
if last_package { 1 } else { 0 },
key + 1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
],
|page_number, this_length, last_package| match self.kind {
Kind::Original => vec![0x02, 0x01, (page_number + 1) as u8, 0, if last_package { 1 } else { 0 }, key + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => vec![],
Kind::Mini | Kind::MiniMk2 => vec![0x02, 0x01, page_number as u8, 0, if last_package { 1 } else { 0 }, key + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
_ => vec![
0x02,
0x07,
key,
if last_package { 1 } else { 0 },
(this_length & 0xff) as u8,
(this_length >> 8) as u8,
(page_number & 0xff) as u8,
(page_number >> 8) as u8,
],
}
}
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => vec![],
_ => vec![
0x02,
0x07,
key,
if last_package { 1 } else { 0 },
(this_length & 0xff) as u8,
(this_length >> 8) as u8,
(page_number & 0xff) as u8,
(page_number >> 8) as u8,
],
},
)?;
Ok(())
}
@@ -466,52 +438,52 @@ impl StreamDeck {
key,
image_data: image_data.to_vec(), // Convert &[u8] to Vec<u8>
};
self.image_cache.write()?.push(cache_entry);
Ok(())
}
/// Writes image data to Stream Deck device's lcd strip/screen as region.
/// Writes image data to Stream Deck device's lcd strip/screen as region.
/// Only Stream Deck Plus supports writing LCD regions, for Stream Deck Neo use write_lcd_fill
pub fn write_lcd(&self, x: u16, y: u16, rect: &ImageRect) -> Result<(), StreamDeckError> {
self.initialize()?;
match self.kind {
Kind::Plus => (),
_ => {
return Err(StreamDeckError::UnsupportedOperation)
}
_ => return Err(StreamDeckError::UnsupportedOperation),
}
self.write_image_data_reports(
rect.data.as_slice(),
WriteImageParameters {
image_report_length: 1024,
image_report_payload_length: 1024 - 16,
},
|page_number, this_length, last_package| vec![
0x02,
0x0c,
(x & 0xff) as u8,
(x >> 8) as u8,
(y & 0xff) as u8,
(y >> 8) as u8,
(rect.w & 0xff) as u8,
(rect.w >> 8) as u8,
(rect.h & 0xff) as u8,
(rect.h >> 8) as u8,
if last_package { 1 } else { 0 },
(page_number & 0xff) as u8,
(page_number >> 8) as u8,
(this_length & 0xff) as u8,
(this_length >> 8) as u8,
0,
]
|page_number, this_length, last_package| {
vec![
0x02,
0x0c,
(x & 0xff) as u8,
(x >> 8) as u8,
(y & 0xff) as u8,
(y >> 8) as u8,
(rect.w & 0xff) as u8,
(rect.w >> 8) as u8,
(rect.h & 0xff) as u8,
(rect.h >> 8) as u8,
if last_package { 1 } else { 0 },
(page_number & 0xff) as u8,
(page_number >> 8) as u8,
(this_length & 0xff) as u8,
(this_length >> 8) as u8,
0,
]
},
)
}
/// Writes image data to Stream Deck device's lcd strip/screen as full fill
///
///
/// You can convert your images into proper image_data like this:
/// ```
/// use elgato_streamdeck::images::convert_image_with_format;
@@ -521,14 +493,14 @@ impl StreamDeck {
pub fn write_lcd_fill(&self, image_data: &[u8]) -> Result<(), StreamDeckError> {
self.initialize()?;
match self.kind {
Kind::Neo => {
self.write_image_data_reports(
image_data,
WriteImageParameters {
image_report_length: 1024,
image_report_payload_length: 1024 - 8
},
|page_number, this_length, last_package| vec![
Kind::Neo => self.write_image_data_reports(
image_data,
WriteImageParameters {
image_report_length: 1024,
image_report_payload_length: 1024 - 8,
},
|page_number, this_length, last_package| {
vec![
0x02,
0x0b,
0,
@@ -538,9 +510,9 @@ impl StreamDeck {
(page_number & 0xff) as u8,
(page_number >> 8) as u8,
]
)
}
},
),
Kind::Plus => {
let (w, h) = self.kind.lcd_strip_size().unwrap();
@@ -550,28 +522,30 @@ impl StreamDeck {
image_report_length: 1024,
image_report_payload_length: 1024 - 16,
},
|page_number, this_length, last_package| vec![
0x02,
0x0c,
0,
0,
0,
0,
(w & 0xff) as u8,
(w >> 8) as u8,
(h & 0xff) as u8,
(h >> 8) as u8,
if last_package { 1 } else { 0 },
(page_number & 0xff) as u8,
(page_number >> 8) as u8,
(this_length & 0xff) as u8,
(this_length >> 8) as u8,
0,
]
|page_number, this_length, last_package| {
vec![
0x02,
0x0c,
0,
0,
0,
0,
(w & 0xff) as u8,
(w >> 8) as u8,
(h & 0xff) as u8,
(h >> 8) as u8,
if last_package { 1 } else { 0 },
(page_number & 0xff) as u8,
(page_number >> 8) as u8,
(this_length & 0xff) as u8,
(this_length >> 8) as u8,
0,
]
},
)
}
_ => Err(StreamDeckError::UnsupportedOperation)
_ => Err(StreamDeckError::UnsupportedOperation),
}
}
@@ -580,11 +554,11 @@ impl StreamDeck {
pub fn clear_button_image(&self, key: u8) -> Result<(), StreamDeckError> {
self.initialize()?;
match self.kind {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => {
let key = if self.kind == Kind::Akp815 {
inverse_key_index(&self.kind, key)
} else {
elgato153_to_ajazz(&self.kind, key)
elgato_to_ajazz153(&self.kind, key)
};
let mut buf = vec![0x43, 0x52, 0x54, 0x00, 0x00, 0x43, 0x4c, 0x45, 0x00, 0x00, 0x00, if key == 0xff { 0xff } else { key + 1 }];
@@ -605,15 +579,13 @@ impl StreamDeck {
pub fn clear_all_button_images(&self) -> Result<(), StreamDeckError> {
self.initialize()?;
match self.kind {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => {
self.clear_button_image(0xff)
}
_ => {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => self.clear_button_image(0xff),
_ => {
for i in 0..self.kind.key_count() {
self.clear_button_image(i)?
}
Ok(())
},
}
}
}
@@ -629,10 +601,8 @@ impl StreamDeck {
pub fn set_logo_image(&self, image: DynamicImage) -> Result<(), StreamDeckError> {
self.initialize()?;
match self.kind {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => (),
_ => {
return Err(StreamDeckError::UnsupportedOperation)
}
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => (),
_ => return Err(StreamDeckError::UnsupportedOperation),
}
if self.kind.lcd_strip_size().is_none() {
@@ -706,13 +676,13 @@ impl StreamDeck {
let image_report_length = match self.kind {
Kind::Original => 8191,
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => 512,
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => 512,
_ => 1024,
};
let image_report_header_length = match self.kind {
Kind::Original | Kind::Mini | Kind::MiniMk2 => 16,
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => 0,
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => 0,
_ => 8,
};
@@ -765,7 +735,7 @@ impl StreamDeck {
pub fn sleep(&self) -> Result<(), StreamDeckError> {
self.initialize()?;
match self.kind {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => {
let mut buf = vec![0x43, 0x52, 0x54, 0x00, 0x00, 0x48, 0x41, 0x4e];
buf.extend(vec![0u8; 512 - buf.len()]);
@@ -783,7 +753,7 @@ impl StreamDeck {
pub fn keep_alive(&self) -> Result<(), StreamDeckError> {
self.initialize()?;
match self.kind {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => {
let mut buf = vec![0x43, 0x52, 0x54, 0x00, 0x00, 0x43, 0x4F, 0x4E, 0x4E, 0x45, 0x43, 0x54];
buf.extend(vec![0u8; 512 - buf.len()]);
write_data(&self.device, buf.as_slice())?;
@@ -817,17 +787,17 @@ impl StreamDeck {
/// Flushes the button's image to the device
pub fn flush(&self) -> Result<(), StreamDeckError> {
self.initialize()?;
if self.image_cache.write()?.len() == 0 {
return Ok(());
}
for image in self.image_cache.read()?.iter() {
self.send_image(image.key, &image.image_data)?;
}
match self.kind {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => {
let mut buf = vec![0x43, 0x52, 0x54, 0x00, 0x00, 0x53, 0x54, 0x50];
buf.extend(vec![0u8; 512 - buf.len()]);
@@ -853,15 +823,10 @@ impl StreamDeck {
}),
})
}
fn write_image_data_reports<T>(
&self,
image_data: &[u8],
parameters: WriteImageParameters,
header_fn: T
) -> Result<(), StreamDeckError>
fn write_image_data_reports<T>(&self, image_data: &[u8], parameters: WriteImageParameters, header_fn: T) -> Result<(), StreamDeckError>
where
T: Fn(usize, usize, bool) -> Vec<u8>
T: Fn(usize, usize, bool) -> Vec<u8>,
{
let image_report_length = parameters.image_report_length;
let image_report_payload_length = parameters.image_report_payload_length;
@@ -886,28 +851,28 @@ impl StreamDeck {
bytes_remaining -= this_length;
page_number += 1;
}
Ok(())
}
}
#[derive(Clone, Copy)]
struct WriteImageParameters {
struct WriteImageParameters {
pub image_report_length: usize,
pub image_report_payload_length: usize
pub image_report_payload_length: usize,
}
impl WriteImageParameters {
pub fn for_key(kind: Kind, image_data_len: usize) -> Self {
let image_report_length = match kind {
Kind::Original => 8191,
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => 512,
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => 512,
_ => 1024,
};
let image_report_header_length = match kind {
Kind::Original | Kind::Mini | Kind::MiniMk2 => 16,
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => 0,
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => 0,
_ => 8,
};
@@ -915,12 +880,12 @@ impl WriteImageParameters {
Kind::Original => image_data_len / 2,
_ => image_report_length - image_report_header_length,
};
Self {
image_report_length,
image_report_payload_length
image_report_payload_length,
}
}
}
}
/// Errors that can occur while working with Stream Decks
@@ -1060,7 +1025,7 @@ impl DeviceStateReader {
StreamDeckInput::ButtonStateChange(buttons) => {
for (index, (their, mine)) in zip(buttons.iter(), my_states.buttons.iter()).enumerate() {
match self.device.kind {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => {
if *their {
updates.push(DeviceStateUpdate::ButtonDown(index as u8));
updates.push(DeviceStateUpdate::ButtonUp(index as u8));
+2 -2
View File
@@ -99,7 +99,7 @@ pub fn extract_str(bytes: &[u8]) -> Result<String, Utf8Error> {
*/
/// Converts Elgato key index to Ajazz key index
pub fn elgato153_to_ajazz(kind: &Kind, key: u8) -> u8 {
pub fn elgato_to_ajazz153(kind: &Kind, key: u8) -> u8 {
if key < kind.key_count() {
[12, 9, 6, 3, 0, 15, 13, 10, 7, 4, 1, 16, 14, 11, 8, 5, 2, 17][key as usize]
} else {
@@ -138,7 +138,7 @@ pub fn read_button_states(kind: &Kind, states: &Vec<u8>) -> Vec<bool> {
}
match kind {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 => {
Kind::Akp153 | Kind::Akp153E | Kind::Akp815 | Kind::MiraBoxHSV293S => {
let mut bools = vec![];
for i in 0..kind.key_count() {