ninjadev64 / OpenDeck

OpenDeck is a cross-platform desktop application that provides functionality for stream controller devices.
https://discord.gg/26Nf8rHvaj
GNU General Public License v3.0
185 stars 8 forks source link

Unable to locate my device Streamdeck Mini on Arch Linux #24

Closed teras closed 1 month ago

teras commented 2 months ago

Hello and thank you for your work.

Unfortunately the system can't recognize my device. I don't believe it is a permission problem, since the rules are there and the other two apps, streamdeck-ui and StreamController do recognize it and I am able to use it. Only one reason I can think of: the serial number is "Invalid SN! " and this is a hardware property, not able to change. Any hints?

ninjadev64 commented 2 months ago

Hmm, the invalid serial number could be causing problems. Could you try quitting and then running OpenDeck from the terminal with /usr/bin/opendeck and seeing if there are any meaningful logs?

teras commented 2 months ago

Unfortunately it's a hardware (?) issue and something that plagues me since the beginning. I have the same problem even on windows. I double checked it and it's what the device reports (i.e. when I am looking at dmesg). I don't think there's anything to be done, even on driver level.

Since I picked it up now, I even emailed elgato about it, but I don't have high hopes. What's optimistic is that, the other tools don't mind about this crazy sn.

ninjadev64 commented 2 months ago

Huh. I'll try to remember to get a fix for this in for 2.1.0, it should be relatively straightforward.

teras commented 2 months ago

Thank you, I'll wait for your update!

ninjadev64 commented 2 months ago

Thank you, I'll wait for your update!

No worries. The 2.1.0 update won't be out until Tauri v2 is out, though.

ninjadev64 commented 1 month ago

@teras There's hopefully a fix for this in 5b43efd6d2a9d63676f0cdd5ad8b22d1d1faa1ed / v2.1.0.

teras commented 1 month ago

Hello

I tried the latest (released) version and still same issue. It is not recognized. How can I provide more debug information?

Here are the logs:

Gtk-Message: 22:10:03.239: Failed to load module "xapp-gtk3-module"
Gtk-Message: 22:10:03.239: Failed to load module "appmenu-gtk-module"
Gtk-Message: 22:10:03.521: Failed to load module "xapp-gtk3-module"
Gtk-Message: 22:10:03.522: Failed to load module "appmenu-gtk-module"
[2024-10-03][19:10:03][tiny_http][DEBUG] Server listening on 0.0.0.0:57118
[2024-10-03][19:10:03][tiny_http][DEBUG] Running accept thread
[2024-10-03][19:10:03][opendeck::events][DEBUG] Registered plugin com.amansprojects.starterpack.sdPlugin
[2024-10-03][19:10:04][opendeck::events][DEBUG] Registered plugin com.elgato.cpu.sdPlugin

PS: With all respect, please let the issue open if you don't mind, until the issue is solved or at least there's an explanation why this happens. Thank you for your responsiveness and your time.

ninjadev64 commented 1 month ago

Hmm, I closed the issue because I thought it was almost certainly solved.

If you ls ~/.config/opendeck/profiles, what is the output?

ninjadev64 commented 1 month ago

@teras?

teras commented 1 month ago

There's no such file

~ ls ~/.config/opendeck/                                                                                                                                  09:01 
logs  plugins  settings.json  temp
ninjadev64 commented 1 month ago

Very odd, I'll take a look later today. Are you sure there's nothing else in the terminal or log files?

teras commented 1 month ago

No there's not. Maybe the library doesn't understand it? I am attaching th usb information just in case. Again I remind you that the python-based applications grab it and use it properly.

Also my user is in the plugdev group and the relevant udev rules are

SUBSYSTEM=="usb", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="0090", MODE="0660", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0090", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTR{idVendor}=="0fd9", ATTR{idProduct}=="0090", MODE="0660", GROUP="plugdev"
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0090", MODE="0660", GROUP="plugdev"
Here's the usb info ``` Bus 001 Device 023: ID 0fd9:0090 Elgato Systems GmbH Stream Deck Mini Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 [unknown] bDeviceSubClass 0 [unknown] bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x0fd9 Elgato Systems GmbH idProduct 0x0090 Stream Deck Mini bcdDevice 1.10 iManufacturer 1 Elgato Systems iProduct 2 Stream Deck Mini iSerial 3 Invalid SN! bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0029 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 0 bmAttributes 0xa0 (Bus Powered) Remote Wakeup MaxPower 500mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 0 [unknown] bInterfaceProtocol 0 iInterface 0 HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.10 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 217 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 1 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0400 1x 1024 bytes bInterval 1 Device Qualifier (for other device speed): bLength 10 bDescriptorType 6 bcdUSB 2.00 bDeviceClass 0 [unknown] bDeviceSubClass 0 [unknown] bDeviceProtocol 0 bMaxPacketSize0 64 bNumConfigurations 1 Device Status: 0x0000 (Bus Powered) ```
ninjadev64 commented 1 month ago

I've had another look in the OpenDeck code and there's nothing that should cause your serial number to be an issue. This means it must be an issue in the library, so please could you open an issue there upstream? You could also try the library's example to check if it works.

teras commented 1 month ago

I tried to run the sample app, where I had to make a minor change to make it work in Cargo.toml: hidapi = { version = "2.6", default-features = false, features=["linux-static-libusb"] }

Then I found that nothing gets displayed. I know nothing about rust, but I can put some printfs here and there. So I found that the code before for (kind, serial) in list_devices(&hid) { is executed but it doesn't enter the for loop. I will open an issue there but, before trying to find my way in a foreign ground if you can give me some hints before closing the issue :) Any ideas what might be wrong? Of course I have the udev rules and also I tried running the code as root, so it shouldn't be a problem. It looks more like the list_devices produces an empty list.

teras commented 1 month ago

I think the reason is here. Feel free to close this issue. It's not OpenDeck's fault after all.

ninjadev64 commented 1 month ago

I think the reason is here. Feel free to close this issue. It's not OpenDeck's fault after all.

I'll leave the open until it's solved upstream.

teras commented 1 month ago

I'll leave the open until it's solved upstream.

Thank you

ninjadev64 commented 1 month ago

Thank you so much for the donation, by the way!

teras commented 1 month ago

Thank you so much for the donation, by the way!

You are polite and helpful and quick in your responses. This is just a little token of saying thank you, for something that you deserve it :smiley:

teras commented 1 month ago

I tried with the latest versions of both, library and opendeck, and it works. Thank you for the support. I'll close this issue and focus on the other bugs.

teras commented 1 month ago

A question:

Is your app supporting changing profiles based on the active window title/class?

If you want some help on this, I know how to do this in pure C for Linux under X11. No, there's no universal solution on Wayland, it's not officially supported, only if the window manger itself support this.

ninjadev64 commented 1 month ago

Is your app supporting changing profiles based on the active window title/class?

I'm not really sure what you mean. Do you mean switching profiles when the title of another application's window changes?

If so, that's not a planned feature for OpenDeck, but you can write a plugin to do so - OpenDeck implements a custom switchProfile event with device and profile ID parameters that your plugin can use to change the profile.

teras commented 1 month ago

Not the title. When the focus moved to another application's window. For example the focus is on FIrefox, now it's on Nemo, now it's on the Desktop (i.e. none).

I think this is a feature of the app itself, IMHO. This is what other applications are doing, and maybe the paradigm should be similar? It's actually a core feature and it is configured on the list of profiles itself.

Look for example how StreamController is doing it (on the left are the profiles)

image

ninjadev64 commented 1 month ago

I see. I still think this should be implemented as a plugin as not only is OpenDeck focused on feature parity with Stream Deck and not other third-party software, but it also seems like the implementation might be quite unreliable (as you said, there's no way to do it under Wayland, and it probably has to be done in C/C++ which I don't want to include in a memory-safe Rust application).

teras commented 1 month ago

I wouldn't say it's unreliable, it's just how Wayland is ... ermm... well it's not the best software around :stuck_out_tongue_closed_eyes:

When I wrote C, I meant a language that can easily access the system. Actually rust is perfect for this.

I've created a demo project to demonstrate it to you.

Cargo.toml

```toml [package] name = "focus_listener" version = "0.1.0" edition = "2021" [dependencies] x11rb = "0.13.1" ```

test.rs

```rust use std::error::Error; use x11rb::atom_manager; use x11rb::connection::Connection; use x11rb::protocol::xproto::{AtomEnum, ConnectionExt, EventMask, PropertyNotifyEvent, Window}; use x11rb::rust_connection::RustConnection; atom_manager! { pub Atoms: AtomsCookie { _NET_ACTIVE_WINDOW, WM_CLASS, _NET_WM_NAME, WM_NAME, UTF8_STRING, } } struct X11FocusListener { conn: RustConnection, root: Window, atoms: Atoms, last_active_window: Option, } impl X11FocusListener { fn new() -> Result> { let (conn, screen_num) = RustConnection::connect(None)?; let screen = &conn.setup().roots[screen_num]; let root = screen.root; let atoms = Atoms::new(&conn)?.reply()?; conn.change_window_attributes(root, &x11rb::protocol::xproto::ChangeWindowAttributesAux::new() .event_mask(EventMask::PROPERTY_CHANGE | EventMask::SUBSTRUCTURE_NOTIFY))?; for child in conn.query_tree(root)?.reply()?.children { conn.change_window_attributes(child, &x11rb::protocol::xproto::ChangeWindowAttributesAux::new() .event_mask(EventMask::PROPERTY_CHANGE))?; } Ok(Self { conn, root, atoms, last_active_window: None, }) } fn get_next_focus_change(&mut self) -> Result<(String, String), Box> { loop { let event = self.conn.wait_for_event()?; if let x11rb::protocol::Event::PropertyNotify(PropertyNotifyEvent { atom, .. }) = event { if atom == self.atoms._NET_ACTIVE_WINDOW { if let Ok(reply) = self.conn.get_property(false, self.root, self.atoms._NET_ACTIVE_WINDOW, AtomEnum::WINDOW, 0, 1)?.reply() { if let Some(window_id) = reply.value32().and_then(|mut v| v.next()) { if self.last_active_window != Some(window_id) { self.last_active_window = Some(window_id); let wm_class = self.get_window_class(window_id)?; let wm_title = self.get_window_title(window_id)?; return Ok((wm_title.unwrap_or_default(), wm_class.unwrap_or_default())); } } } } } } } fn get_window_class(&self, window: Window) -> Result, Box> { if let Ok(reply) = self.conn.get_property(false, window, self.atoms.WM_CLASS, AtomEnum::STRING, 0, 1024)?.reply() { if let Some(value) = reply.value8() { return Ok(Some(String::from_utf8_lossy(&value.collect::>()).split(' ').filter(|s| !s.is_empty()).collect::>().join("."))); } } Ok(None) } fn get_window_title(&self, window: Window) -> Result, Box> { if let Ok(reply) = self.conn.get_property(false, window, self.atoms._NET_WM_NAME, self.atoms.UTF8_STRING, 0, 1024)?.reply() { if let Some(value) = reply.value8() { return Ok(Some(String::from_utf8_lossy(&value.collect::>()).to_string())); } } if let Ok(reply) = self.conn.get_property(false, window, self.atoms.WM_NAME, AtomEnum::STRING, 0, 1024)?.reply() { if let Some(value) = reply.value8() { return Ok(Some(String::from_utf8_lossy(&value.collect::>()).to_string())); } } Ok(None) } } fn main() -> Result<(), Box> { let mut listener = X11FocusListener::new()?; loop { let (title, class) = listener.get_next_focus_change()?; println!("Class: {}", class); println!("Title: {}", title); } } ```

ninjadev64 commented 1 month ago

Perfect! I've got another repo / crate called openaction-rs which is perfect for making plugins with Rust.

teras commented 1 month ago

OK, so let me elaborate a bit more on this. First of all understand that I write this with all my respect for the work you are doing and I thank you for this. It's not a way to force you change your goals or anything, I am trying to make this product better - even more not even to make you do my job, I think you understand this until now. I am just trying to show you my point of view, which might be different that yours, but maybe it's not a bad idea to listen to other ideas :) Also the discussion now is not technical, if it could be done or not, but more a policy discussion. The final word is always yours.

First of all think about your "clients", there should be Linux users (or periodical Linux users) who either like the idea of streamdeck, or use it under Windows and want to use it in Linux too. They shouldn't be Windows/macOS users, since these will already have an official app that is much more feature full than this one. Moreover there are other, more popular solutions than this one in python mostly, with yours only having one real benefit : support more devices than theirs. They probably have seen the official streamdeck app, probably also the python clients, and while looking around, probably also found yours.

Let me explain why I "insist" that this shouldn't be a plugin. These guys have already an image in their mind of what these apps should be, how the interface is working etc. Not only the python version(s) but also the official app has exactly the behavior I mention. There are profiles, and on the profile list there's the option to select which app will have which profile, or leave it blank. They will open the settings, find nothing, close the settings, close the app, move on to the next one. They won't even think of searching in plugins to see if such a plugin exists. They won't care.

Finally, I also understand that you don't want to implement random stuff that any random guy tells you. I wouldn't do that either. And I understand that you have a vision and part of it you might thing about "purity": you create the core parts and all other stuff should be plugins. But please, reconsider this and, as I show you, IMHO this is a core feature. It is something so crucial as profiles themselves.

Here is also the image of official streamdeck app under windows, which matches the python one:

Screenshot 2024-10-13 180145
ninjadev64 commented 1 month ago

They shouldn't be Windows/macOS users, since these will already have an official app that is much more feature full than this one.

You are definitely correct here.

Moreover there are other, more popular solutions than this one in python mostly, with yours only having one real benefit : support more devices than theirs.

This not so much, I think the primary benefit of OpenDeck is its support for Stream Deck SDK plugins.

As for what we're actually talking about, switching profiles based on the selected application, my initial reason for wanting it to be implemented as a plugin was because I wasn't aware it was part of the official Elgato software. Now that I see it is a part of the official software, I am much less adverse to adding to it and will accept a contribution for it - however, I would ask of the contribution for it to keep in mind that OpenDeck is a cross-platform application, and so the feature should either work on all platforms (Windows, macOS, X11 and Wayland), especially as it is a core feature (as you said) or make it clear to the user that it will only work under certain platforms if it is a real difficulty to implement it for some.

I also believe we should move this discussion to a separate issue :)

teras commented 1 month ago

As for what we're actually talking about, switching profiles based on the selected application, my initial reason for wanting it to be implemented as a plugin was because I wasn't aware it was part of the official Elgato software. Now that I see it is a part of the official software, I am much less adverse to adding to it and will accept a contribution for it - however, I would ask of the contribution for it to keep in mind that OpenDeck is a cross-platform application, and so the feature should either work on all platforms (Windows, macOS, X11 and Wayland), especially as it is a core feature (as you said) or make it clear to the user that it will only work under certain platforms if it is a real difficulty to implement it for some.

As I told you, this, by design, is not technically possible. Yes, that's a dilemma. A dilemma that other applications don't have.

I also believe we should move this discussion to a separate issue :)

Maybe an open one. Maybe convert this as a discussion :)

ninjadev64 commented 1 month ago

Maybe an open one. Maybe convert this as a discussion :)

I think an issue is better than a discussion as a missing feature from the official software can be considered an issue, and it can be closed when the feature is implemented. Feel free to open one!