mirror of
https://github.com/OpenActionAPI/rust-elgato-streamdeck.git
synced 2026-10-28 09:44:56 +00:00
feat: add support for the Stream Deck Plus XL (#54)
This commit is contained in:
1 parent
86f18a3a21
commit
8975fa08f4
7 files changed
+61
-16
No files matched your search
@@ -13,6 +13,7 @@ SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="00a5", MODE="0660"
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="00b8", MODE="0660", TAG+="uaccess"
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="00b9", MODE="0660", TAG+="uaccess"
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="00ba", MODE="0660", TAG+="uaccess"
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="00c6", MODE="0660", TAG+="uaccess"
|
||||
|
||||
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0060", MODE="0660", TAG+="uaccess"
|
||||
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0063", MODE="0660", TAG+="uaccess"
|
||||
@@ -29,3 +30,4 @@ KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct
|
||||
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="00b8", MODE="0660", TAG+="uaccess"
|
||||
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="00b9", MODE="0660", TAG+="uaccess"
|
||||
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="00ba", MODE="0660", TAG+="uaccess"
|
||||
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="00c6", MODE="0660", TAG+="uaccess"
|
||||
@@ -73,6 +73,7 @@ As it stands, this library should support the following devices.
|
||||
- Stream Deck Mk2
|
||||
- Stream Deck Pedal
|
||||
- Stream Deck Plus (thanks to [node-elgato-stream-deck](https://github.com/Julusian/node-elgato-stream-deck))
|
||||
- Stream Deck Plus XL (thanks to [@Jerry260102](https://github.com/Jerry260102))
|
||||
- Stream Deck Neo (thanks to [@ejiektpobehuk](https://github.com/ejiektpobehuk), [@AkechiShiro](https://github.com/AkechiShiro) and [node-elgato-stream-deck](https://github.com/Julusian/node-elgato-stream-deck))
|
||||
|
||||
Support for non-Elgato (Mirabox/Ajazz) devices has been removed in v0.11. If you wish to use these devices, please use the `mirajazz` crate, or use v0.10.2 of this crate.
|
||||
+13
-4
@@ -4,6 +4,7 @@ compile_error!("The `async` feature must be enabled to compile this example.");
|
||||
use std::time::Duration;
|
||||
use image::open;
|
||||
|
||||
use elgato_streamdeck::info::{ImageFormat};
|
||||
use elgato_streamdeck::{DeviceStateUpdate, list_devices, new_hidapi, AsyncStreamDeck};
|
||||
use elgato_streamdeck::images::{convert_image_with_format, ImageRect};
|
||||
use tokio::time::sleep;
|
||||
@@ -41,16 +42,24 @@ async fn main() {
|
||||
}
|
||||
|
||||
if let Some(format) = device.kind().lcd_image_format() {
|
||||
let scaled_image = image.clone().resize_to_fill(format.size.0 as u32, format.size.1 as u32, image::imageops::FilterType::Nearest);
|
||||
let converted_image = convert_image_with_format(format, scaled_image).unwrap();
|
||||
let converted_image = convert_image_with_format(format, image.clone()).unwrap();
|
||||
let _ = device.write_lcd_fill(&converted_image).await;
|
||||
}
|
||||
|
||||
let small = match device.kind().lcd_strip_size() {
|
||||
Some((w, h)) => {
|
||||
let min = w.min(h) as u32;
|
||||
let scaled_image = image.clone().resize_to_fill(min, min, image::imageops::Nearest);
|
||||
Some(ImageRect::from_image(scaled_image).unwrap())
|
||||
let converted_image = convert_image_with_format(
|
||||
ImageFormat {
|
||||
mode: device.kind().lcd_image_format().unwrap().mode,
|
||||
size: (min.try_into().unwrap(), min.try_into().unwrap()),
|
||||
rotation: device.kind().lcd_image_format().unwrap().rotation,
|
||||
mirror: device.kind().lcd_image_format().unwrap().mirror,
|
||||
},
|
||||
image.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
Some(ImageRect::from_image(image::load_from_memory(&converted_image).unwrap()).unwrap())
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
+13
-4
@@ -3,6 +3,7 @@ use std::time::Duration;
|
||||
|
||||
use image::open;
|
||||
|
||||
use elgato_streamdeck::info::{ImageFormat};
|
||||
use elgato_streamdeck::{DeviceStateUpdate, list_devices, new_hidapi, StreamDeck};
|
||||
use elgato_streamdeck::images::{convert_image_with_format, ImageRect};
|
||||
|
||||
@@ -36,16 +37,24 @@ fn main() {
|
||||
}
|
||||
|
||||
if let Some(format) = device.kind().lcd_image_format() {
|
||||
let scaled_image = image.clone().resize_to_fill(format.size.0 as u32, format.size.1 as u32, image::imageops::FilterType::Nearest);
|
||||
let converted_image = convert_image_with_format(format, scaled_image).unwrap();
|
||||
let converted_image = convert_image_with_format(format, image.clone()).unwrap();
|
||||
let _ = device.write_lcd_fill(&converted_image);
|
||||
}
|
||||
|
||||
let small = match device.kind().lcd_strip_size() {
|
||||
Some((w, h)) => {
|
||||
let min = w.min(h) as u32;
|
||||
let scaled_image = image.clone().resize_to_fill(min, min, image::imageops::Nearest);
|
||||
Some(ImageRect::from_image(scaled_image).unwrap())
|
||||
let converted_image = convert_image_with_format(
|
||||
ImageFormat {
|
||||
mode: device.kind().lcd_image_format().unwrap().mode,
|
||||
size: (min.try_into().unwrap(), min.try_into().unwrap()),
|
||||
rotation: device.kind().lcd_image_format().unwrap().rotation,
|
||||
mirror: device.kind().lcd_image_format().unwrap().mirror,
|
||||
},
|
||||
image.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
Some(ImageRect::from_image(image::load_from_memory(&converted_image).unwrap()).unwrap())
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
+2
-2
@@ -18,8 +18,6 @@ pub fn convert_image_with_format(image_format: ImageFormat, image: DynamicImage)
|
||||
// Ensuring size of the image
|
||||
let (ws, hs) = image_format.size;
|
||||
|
||||
let image = image.resize_exact(ws as u32, hs as u32, FilterType::Nearest);
|
||||
|
||||
// Applying rotation
|
||||
let image = match image_format.rotation {
|
||||
ImageRotation::Rot0 => image,
|
||||
@@ -28,6 +26,8 @@ pub fn convert_image_with_format(image_format: ImageFormat, image: DynamicImage)
|
||||
ImageRotation::Rot270 => image.rotate270(),
|
||||
};
|
||||
|
||||
let image = image.resize_exact(ws as u32, hs as u32, FilterType::Nearest);
|
||||
|
||||
// Applying mirroring
|
||||
let image = match image_format.mirror {
|
||||
ImageMirroring::None => image,
|
||||
|
||||
+26
-2
@@ -28,6 +28,8 @@ pub const PID_STREAMDECK_NEO: u16 = 0x009a;
|
||||
pub const PID_STREAMDECK_PEDAL: u16 = 0x0086;
|
||||
/// Product ID of Stream Deck Plus
|
||||
pub const PID_STREAMDECK_PLUS: u16 = 0x0084;
|
||||
/// Product ID of Stream Deck Plus XL
|
||||
pub const PID_STREAMDECK_PLUS_XL: u16 = 0x00c6;
|
||||
/// Product ID of Stream Deck Mini Mk2 Module
|
||||
pub const PID_STREAMDECK_MINI_MK2_MODULE: u16 = 0x00b8;
|
||||
/// Product ID of Stream Deck Mk2 Module
|
||||
@@ -70,6 +72,8 @@ pub enum Kind {
|
||||
Pedal,
|
||||
/// Stream Deck Plus
|
||||
Plus,
|
||||
/// Stream Deck Plus XL
|
||||
PlusXl,
|
||||
/// Stream Deck Mini Mk2 Module
|
||||
MiniMk2Module,
|
||||
/// Stream Deck Mk2 Module
|
||||
@@ -95,6 +99,7 @@ impl Kind {
|
||||
PID_STREAMDECK_NEO => Some(Kind::Neo),
|
||||
PID_STREAMDECK_PEDAL => Some(Kind::Pedal),
|
||||
PID_STREAMDECK_PLUS => Some(Kind::Plus),
|
||||
PID_STREAMDECK_PLUS_XL => Some(Kind::PlusXl),
|
||||
PID_STREAMDECK_MINI_MK2_MODULE => Some(Kind::MiniMk2Module),
|
||||
PID_STREAMDECK_MK2_MODULE => Some(Kind::Mk2Module),
|
||||
PID_STREAMDECK_XL_V2_MODULE => Some(Kind::XlV2Module),
|
||||
@@ -119,6 +124,7 @@ impl Kind {
|
||||
Kind::Neo => PID_STREAMDECK_NEO,
|
||||
Kind::Pedal => PID_STREAMDECK_PEDAL,
|
||||
Kind::Plus => PID_STREAMDECK_PLUS,
|
||||
Kind::PlusXl => PID_STREAMDECK_PLUS_XL,
|
||||
Kind::MiniMk2Module => PID_STREAMDECK_MINI_MK2_MODULE,
|
||||
Kind::Mk2Module => PID_STREAMDECK_MK2_MODULE,
|
||||
Kind::XlV2Module => PID_STREAMDECK_XL_V2_MODULE,
|
||||
@@ -140,6 +146,7 @@ impl Kind {
|
||||
Kind::Neo => ELGATO_VENDOR_ID,
|
||||
Kind::Pedal => ELGATO_VENDOR_ID,
|
||||
Kind::Plus => ELGATO_VENDOR_ID,
|
||||
Kind::PlusXl => ELGATO_VENDOR_ID,
|
||||
Kind::MiniMk2Module => ELGATO_VENDOR_ID,
|
||||
Kind::Mk2Module => ELGATO_VENDOR_ID,
|
||||
Kind::XlV2Module => ELGATO_VENDOR_ID,
|
||||
@@ -152,6 +159,7 @@ impl Kind {
|
||||
Kind::Original | Kind::OriginalV2 | Kind::Mk2 | Kind::Mk2Scissor | Kind::Mk2Module => 15,
|
||||
Kind::Mini | Kind::MiniMk2 | Kind::MiniDiscord | Kind::MiniMk2Module => 6,
|
||||
Kind::Xl | Kind::XlV2 | Kind::XlV2Module => 32,
|
||||
Kind::PlusXl => 36,
|
||||
Kind::Pedal => 3,
|
||||
Kind::Neo | Kind::Plus => 8,
|
||||
}
|
||||
@@ -162,7 +170,7 @@ impl Kind {
|
||||
match self {
|
||||
Kind::Original | Kind::OriginalV2 | Kind::Mk2 | Kind::Mk2Scissor | Kind::Mk2Module => 3,
|
||||
Kind::Mini | Kind::MiniMk2 | Kind::MiniDiscord | Kind::MiniMk2Module => 2,
|
||||
Kind::Xl | Kind::XlV2 | Kind::XlV2Module => 4,
|
||||
Kind::Xl | Kind::XlV2 | Kind::XlV2Module | Kind::PlusXl => 4,
|
||||
Kind::Pedal => 1,
|
||||
Kind::Neo | Kind::Plus => 2,
|
||||
}
|
||||
@@ -174,6 +182,7 @@ impl Kind {
|
||||
Kind::Original | Kind::OriginalV2 | Kind::Mk2 | Kind::Mk2Scissor | Kind::Mk2Module => 5,
|
||||
Kind::Mini | Kind::MiniMk2 | Kind::MiniDiscord | Kind::MiniMk2Module => 3,
|
||||
Kind::Xl | Kind::XlV2 | Kind::XlV2Module => 8,
|
||||
Kind::PlusXl => 9,
|
||||
Kind::Pedal => 3,
|
||||
Kind::Neo | Kind::Plus => 4,
|
||||
}
|
||||
@@ -183,6 +192,7 @@ impl Kind {
|
||||
pub fn encoder_count(&self) -> u8 {
|
||||
match self {
|
||||
Kind::Plus => 4,
|
||||
Kind::PlusXl => 6,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
@@ -199,6 +209,7 @@ impl Kind {
|
||||
pub fn lcd_strip_size(&self) -> Option<(usize, usize)> {
|
||||
match self {
|
||||
Kind::Plus => Some((800, 100)),
|
||||
Kind::PlusXl => Some((100, 1200)),
|
||||
Kind::Neo => Some((248, 58)),
|
||||
_ => None,
|
||||
}
|
||||
@@ -252,6 +263,13 @@ impl Kind {
|
||||
mirror: ImageMirroring::None,
|
||||
},
|
||||
|
||||
Kind::PlusXl => ImageFormat {
|
||||
mode: ImageMode::JPEG,
|
||||
size: (120, 120),
|
||||
rotation: ImageRotation::Rot270,
|
||||
mirror: ImageMirroring::None,
|
||||
},
|
||||
|
||||
Kind::Pedal => ImageFormat::default(),
|
||||
}
|
||||
}
|
||||
@@ -271,6 +289,12 @@ impl Kind {
|
||||
rotation: ImageRotation::Rot0,
|
||||
mirror: ImageMirroring::None,
|
||||
}),
|
||||
Kind::PlusXl => Some(ImageFormat {
|
||||
mode: ImageMode::JPEG,
|
||||
size: (100, 1200),
|
||||
rotation: ImageRotation::Rot270,
|
||||
mirror: ImageMirroring::None,
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -348,7 +372,7 @@ impl Kind {
|
||||
0x28, 0xa0, 0x02, 0x8a, 0x28, 0xa0, 0x02, 0x8a, 0x28, 0xa0, 0x02, 0x8a, 0x28, 0xa0, 0x02, 0x8a, 0x28, 0xa0, 0x0f, 0xff, 0xd9,
|
||||
],
|
||||
|
||||
Kind::Plus => vec![
|
||||
Kind::Plus | Kind::PlusXl => vec![
|
||||
0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0x78, 0x00, 0x78, 0x03,
|
||||
0x01, 0x11, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x03, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x05, 0x08,
|
||||
0x05, 0x05, 0x04, 0x04, 0x05, 0x0a, 0x07, 0x07, 0x06, 0x08, 0x0c, 0x0a, 0x0c, 0x0c, 0x0b, 0x0a, 0x0b, 0x0b, 0x0d, 0x0e, 0x12, 0x10, 0x0d, 0x0e, 0x11, 0x0e, 0x0b, 0x0b, 0x10, 0x16,
|
||||
|
||||
+4
-4
@@ -194,8 +194,8 @@ impl StreamDeck {
|
||||
/// Reads all possible input from Stream Deck device
|
||||
pub fn read_input(&self, timeout: Option<Duration>) -> Result<StreamDeckInput, StreamDeckError> {
|
||||
match &self.kind {
|
||||
Kind::Plus => {
|
||||
let data = read_data(&self.device, 14.max(5 + self.kind.encoder_count() as usize), timeout)?;
|
||||
Kind::Plus | Kind::PlusXl => {
|
||||
let data = read_data(&self.device, (6 + self.kind.key_count()).max(5 + self.kind.encoder_count()) as usize, timeout)?;
|
||||
|
||||
if data[0] == 0 {
|
||||
return Ok(StreamDeckInput::NoData);
|
||||
@@ -319,7 +319,7 @@ impl StreamDeck {
|
||||
/// 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> {
|
||||
match self.kind {
|
||||
Kind::Plus => (),
|
||||
Kind::Plus | Kind::PlusXl => (),
|
||||
_ => return Err(StreamDeckError::UnsupportedOperation),
|
||||
}
|
||||
|
||||
@@ -382,7 +382,7 @@ impl StreamDeck {
|
||||
},
|
||||
),
|
||||
|
||||
Kind::Plus => {
|
||||
Kind::Plus | Kind::PlusXl => {
|
||||
let (w, h) = self.kind.lcd_strip_size().unwrap();
|
||||
|
||||
self.write_image_data_reports(
|
||||
|
||||
Reference in new issue
Block a user