1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/// Definitions of button structs
pub mod button;

/// Methods for interacting with the core
pub mod methods;

use std::collections::HashMap;
use std::sync::{Arc, Mutex, RwLock};
use std::sync::mpsc::{channel, Receiver};
use streamdeck::StreamDeck;
use crate::core::button::Button;
use crate::core::methods::{button_down, button_up, CoreHandle};
use crate::modules::ModuleManager;
use crate::threads::rendering::{RendererHandle, spawn_rendering_thread};
use crate::threads::streamdeck::{spawn_streamdeck_thread, StreamDeckCommand, StreamDeckHandle};

/// Reference counted RwLock of a button, prevents data duplication and lets you edit buttons if they're in many stacks at once
pub type UniqueButton = Arc<RwLock<Button>>;

/// Hashmap of UniqueButtons
pub type ButtonPanel = HashMap<u8, UniqueButton>;

/// Hashmap of raw Buttons
pub type RawButtonPanel = HashMap<u8, Button>;

/// Core struct that contains all relevant information about streamdeck and manages the streamdeck
#[allow(dead_code)]
pub struct SDCore {
    /// Module manager
    pub module_manager: Arc<ModuleManager>,

    /// Current panel stack
    pub current_stack: Mutex<Vec<ButtonPanel>>,

    /// Image size supported by streamdeck
    pub image_size: (usize, usize),

    /// Key count of the streamdeck device
    pub key_count: u8,

    /// Pool rate of how often should the core read events from the device
    pub pool_rate: u32,

    /// Decides if core is dead
    pub should_close: RwLock<bool>,

    handles: Mutex<Option<ThreadHandles>>
}

impl SDCore {
    /// Creates an instance of core that is already dead
    pub fn blank(module_manager: Arc<ModuleManager>) -> Arc<SDCore> {
        Arc::new(SDCore {
            module_manager,
            current_stack: Mutex::new(vec![]),
            handles: Mutex::new(None),
            image_size: (0, 0),
            key_count: 0,
            pool_rate: 0,
            should_close: RwLock::new(true)
        })
    }

    /// Creates an instance of the core over existing streamdeck connection
    pub fn new(module_manager: Arc<ModuleManager>, connection: StreamDeck, pool_rate: u32) -> (Arc<SDCore>, KeyHandler) {
        let (key_tx, key_rx) = channel();

        let core = Arc::new(SDCore {
            module_manager,
            current_stack: Mutex::new(vec![]),
            handles: Mutex::new(None),
            image_size: connection.image_size(),
            key_count: connection.kind().keys(),
            pool_rate,
            should_close: RwLock::new(false)
        });

        let streamdeck = spawn_streamdeck_thread(core.clone(), connection, key_tx);
        let renderer = spawn_rendering_thread(core.clone());

        if let Ok(mut handles) = core.handles.lock() {
            *handles = Some(
                ThreadHandles {
                    streamdeck,
                    renderer
                }
            )
        }

        (core.clone(), KeyHandler {
            core: CoreHandle::wrap(core.clone()),
            receiver: key_rx
        })
    }

    /// Tells renderer's thread it's time to redraw
    pub fn mark_for_redraw(&self) {
        let handles = self.handles.lock().unwrap();

        handles.as_ref().unwrap().renderer.redraw();
    }

    /// Sends commands to streamdeck thread
    pub fn send_commands(&self, commands: Vec<StreamDeckCommand>) {
        let handles = self.handles.lock().unwrap();

        handles.as_ref().unwrap().streamdeck.send(commands);
    }

    /// Checks if core is supposed to be closed
    pub fn is_closed(&self) -> bool {
        *self.should_close.read().unwrap()
    }

    /// Kills the core and all the related threads
    pub fn close(&self) {
        let mut lock = self.should_close.write().unwrap();
        *lock = true;
        self.mark_for_redraw();
    }
}

#[derive(Debug)]
struct ThreadHandles {
    pub streamdeck: StreamDeckHandle,
    pub renderer: RendererHandle
}

/// Routine that acts as a middleman between streamdeck thread and the core, was made as a way to get around Sync restriction
pub struct KeyHandler{
    core: CoreHandle,
    receiver: Receiver<(u8, bool)>
}

impl KeyHandler {
    /// Runs the key handling loop in current thread
    pub fn run_loop(&self) {
        loop {
            if self.core.core().is_closed() {
                break
            }

            if let Ok((key, state)) = self.receiver.recv() {
                if state {
                    button_down(&self.core, key);
                } else {
                    button_up(&self.core, key);
                }
            } else {
                break;
            }
        }
    }
}