Compare commits

..

12 commits

Author SHA1 Message Date
9d61ad5fbd added shell.nix to test 2023-05-06 10:50:07 -07:00
Nickiel12
2dd94631ff should I toss these tests out? 2022-07-16 22:19:24 -07:00
Nickiel12
970eabdda8 removed the unused hotkey_stop flag 2022-07-16 22:18:51 -07:00
Nickiel12
3962a48843 changed tray-message handler to be stateless 2022-07-16 17:56:22 -07:00
Nickiel12
06333b7fe2 ran rustfmt 2022-07-16 21:16:56 -07:00
Nickiel12
a3e675def6 set to non-blocking 2022-07-16 21:14:00 -07:00
Nickiel12
fdb60f6e00 working version of tray_icon events 2022-07-16 21:08:52 -07:00
Nickiel12
1d97546bbe thread start and stop debug statements 2022-07-16 19:32:48 -07:00
Nickiel12
7e97255acb added some closing thread debug prints 2022-07-16 19:28:09 -07:00
Nickiel12
e5e50e5422 fixed bug when disabling default features 2022-07-16 19:15:02 -07:00
Nickiel12
eb37513a4b test windows build now use localhost 2022-07-16 18:58:05 -07:00
Nickiel12
ed38b4aa73 added demo tray_icon. has a bug where clicks get "stuck" in the queue 2022-07-13 22:29:25 -07:00
17 changed files with 944 additions and 340 deletions

View file

@ -11,6 +11,9 @@ ctrlc = "3.2.1"
serde_json = "1.0" serde_json = "1.0"
crossbeam-channel = "0.5" crossbeam-channel = "0.5"
inputbot = {path = "D:\\Inputbot"} inputbot = {path = "D:\\Inputbot"}
winit = "0.25"
winapi = { version = "0.3.9", features = ["winuser", "windef", "minwindef", "shellapi", "libloaderapi", "commctrl", "basetsd"] }
trayicon = { version="0.1.3", features = ["crossbeam-channel"] }
[features] [features]
default = [] default = []

View file

@ -18,8 +18,7 @@
"windows":{ "windows":{
"obs_re": "OBS *", "obs_re": "OBS *",
"propresenter_re": "ProPresenter - .*", "propresenter_re": "ProPresenter - .*",
"chrome_re": ".* - Google Chrome", "chrome_re": ".* - Google Chrome"
"tcp_port": "8005"
}, },
"hotkeys":{ "hotkeys":{
"obs":{ "obs":{

19
shell.nix Normal file
View file

@ -0,0 +1,19 @@
# <shell.nix>
{ pkgs ? import <nixpkgs> {}}:
let
rust_overlay = import (builtins.fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz");
pkgs = import <nixpkgs> { overlays = [ rust_overlay ]; };
ruststable = (pkgs.rust-bin.stable.latest.default.override {
extensions = [
"rust-src"
];
});
in
pkgs.mkShell {
buildInputs = with pkgs; [
ruststable
rust-analyzer
bacon
];
}

BIN
src/icon1.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
src/icon2.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View file

@ -1,61 +1,97 @@
use std::{time::Duration, thread, io::Read};
use crossbeam_channel::unbounded; use crossbeam_channel::unbounded;
use tray_icon::TrayIcon;
use std::{io::Read, thread, time::Duration};
use modules::{socket_handler::Socket, stream_states::stream_state::StreamState, message_handler::{MessageHandler}, external_interface::{Hotkeys, OPTIONS_PATH}}; use modules::{
external_interface::{Hotkeys, OPTIONS_PATH},
message_handler::MessageHandler,
socket_handler::Socket,
stream_states::stream_state::StreamState,
};
use workctl::sync_flag; use workctl::sync_flag;
use crate::modules::stream_states::state_update::StateUpdate; use crate::modules::stream_states::state_update::StateUpdate;
#[cfg(target_os = "windows")]
use modules::tray_icon;
mod modules;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
mod modules;
const SERVER_ADDRESS: &str = "0.0.0.0:"; #[cfg(target_os = "windows")]
const SERVER_ADDRESS: &str = "localhost:5000";
#[cfg(release)]
#[cfg(target_os = "windows")]
const SERVER_ADDRESS: &str = "10.0.0.209:5000";
#[cfg(target_os = "linux")]
const SERVER_ADDRESS: &str = "10.0.0.168:5000";
fn main() { fn main() {
let icon = include_bytes!("icon1.ico");
let tray_icon = tray_icon::TrayIcon::setup(icon);
let settings_json = load_json(); let settings_json = load_json();
let hotkeys = Hotkeys::new(settings_json.clone()); let hotkeys = Hotkeys::new(settings_json);
let (from_socket_tx, from_socket_rx) = unbounded::<String>(); let (from_socket_tx, from_socket_rx) = unbounded::<String>();
let hotkey_channel_tx = from_socket_tx.clone(); let hotkey_channel_tx = from_socket_tx.clone();
println!("Opening on port: {}", settings_json["windows"]["tcp_port"]); let mut socket =
let mut socket = Socket::handle_connections(Socket::make_listener((String::from(SERVER_ADDRESS) + &settings_json["windows"]["tcp_port"].to_string()).as_str()), from_socket_tx); Socket::handle_connections(Socket::make_listener(SERVER_ADDRESS), from_socket_tx);
let (hotkey_close_flag_tx, hotkey_close_flag_rx) = sync_flag::new_syncflag(true); let control_c_called_flag_rx = setup_control_c();
let control_c_called_flag_rx = setup_control_c(hotkey_close_flag_tx);
let hotkey_handle = thread::spawn(move || { let hotkey_handle = thread::spawn(move || {
modules::external_interface::create_keyboard_hooks(hotkey_channel_tx, hotkey_close_flag_rx); println!("starting hotkey thread");
modules::external_interface::create_keyboard_hooks(hotkey_channel_tx);
println!("closing hotkey thread");
}); });
let mut state = StreamState::new(); let mut state = StreamState::new();
//until control_c is caught, check the queue of incoming //until control_c is caught, check the queue of incoming
//requests from the socket handler. //requests from the socket handler.
while !control_c_called_flag_rx.get() { let stop_flag = control_c_called_flag_rx.clone();
match from_socket_rx.recv_timeout(Duration::from_millis(100)) { let messages = tray_icon.message_channel.clone();
Ok(message) => { std::thread::spawn(move || {
println!("main recieved: {}", message); while !control_c_called_flag_rx.get() {
let update = StateUpdate::json_to_state_update( match from_socket_rx.recv_timeout(Duration::from_millis(100)) {
serde_json::from_str(&message).unwrap()); Ok(message) => {
if update == StateUpdate::UpdateClient { println!("main recieved: {}", message);
update_all(&state, &socket); let update =
} else { StateUpdate::json_to_state_update(serde_json::from_str(&message).unwrap());
handle_instructions(vec![update], &mut state, &socket, &hotkeys); if update == StateUpdate::UpdateClient {
update_all(&state, &socket);
} else {
handle_instructions(vec![update], &mut state, &socket, &hotkeys);
}
} }
}, Err(_) => {}
Err(_) => {}, }
let tick_update = state.tick();
handle_instructions(tick_update, &mut state, &socket, &hotkeys);
TrayIcon::handle_tray_messages(&messages);
} }
let tick_update = state.tick(); socket.close();
handle_instructions(tick_update, &mut state, &socket, &hotkeys); });
while !stop_flag.get() {
tray_icon.check_tray_icon_messages();
//tray_icon.check_tray_messages();
} }
println!("closing main thread"); println!("closing main thread");
socket.close();
hotkey_handle.join().unwrap(); hotkey_handle.join().unwrap();
} }
fn handle_instructions(mut instructions: Vec<StateUpdate>, state: &mut StreamState, socket: &Socket, hotkeys: &Hotkeys) { fn handle_instructions(
mut instructions: Vec<StateUpdate>,
state: &mut StreamState,
socket: &Socket,
hotkeys: &Hotkeys,
) {
for i in instructions.iter_mut() { for i in instructions.iter_mut() {
let updates = state.handle_update(i.to_owned(), &hotkeys); let updates = state.handle_update(i.to_owned(), &hotkeys);
if updates.0.is_some() { if updates.0.is_some() {
@ -69,37 +105,84 @@ fn handle_instructions(mut instructions: Vec<StateUpdate>, state: &mut StreamSta
} }
} }
fn setup_control_c(mut hotkey_close_flag_tx: sync_flag::SyncFlagTx) -> sync_flag::SyncFlagRx{ fn setup_control_c() -> sync_flag::SyncFlagRx {
let (mut control_c_flag_tx, control_c_called_flag_rx) = sync_flag::new_syncflag(false); let (mut control_c_flag_tx, control_c_called_flag_rx) = sync_flag::new_syncflag(false);
ctrlc::set_handler(move || { ctrlc::set_handler(move || {
println!("ctrl c caught"); println!("ctrl c caught");
control_c_flag_tx.set(true); control_c_flag_tx.set(true);
hotkey_close_flag_tx.set(false); })
}).expect("control C handler failed!"); .expect("control C handler failed!");
control_c_called_flag_rx control_c_called_flag_rx
} }
fn load_json() -> serde_json::Value { fn load_json() -> serde_json::Value {
let mut settings_file = std::fs::File::open(OPTIONS_PATH).unwrap(); let mut settings_file = std::fs::File::open(OPTIONS_PATH).unwrap();
let mut settings_str = String::new(); let mut settings_str = String::new();
settings_file.read_to_string(&mut settings_str).unwrap(); settings_file.read_to_string(&mut settings_str).unwrap();
drop(settings_file); drop(settings_file);
serde_json::from_str(settings_str.as_str()).unwrap() serde_json::from_str(settings_str.as_str()).unwrap()
} }
fn update_all(state: &StreamState, socket: &Socket) { fn update_all(state: &StreamState, socket: &Socket) {
println!("updating all"); println!("updating all");
socket.send(StateUpdate::StreamRunning(state.stream_running).to_json().to_string()); socket.send(
socket.send(StateUpdate::StreamSoundToggleOn(state.stream_is_muted).to_json().to_string()); StateUpdate::StreamRunning(state.stream_running)
socket.send(StateUpdate::ToggleComputerSoundOn(state.computer_sound_is_on).to_json().to_string()); .to_json()
socket.send(StateUpdate::ChangeSceneOnChangeSlide(state.change_scene_on_slide_hotkey).to_json().to_string()); .to_string(),
socket.send(StateUpdate::SceneIsAugmented(state.scene_is_augmented).to_json().to_string()); );
socket.send(StateUpdate::TimerCanRun(state.timer_can_run).to_json().to_string()); socket.send(
socket.send(StateUpdate::TimerLength(state.timer_length).to_json().to_string()); StateUpdate::StreamSoundToggleOn(state.stream_is_muted)
socket.send(StateUpdate::TimerText(state.timer_text.clone()).to_json().to_string()); .to_json()
socket.send(StateUpdate::SubScene(state.camera_sub_scene).to_json().to_string()); .to_string(),
socket.send(StateUpdate::SubScene(state.screen_sub_scene).to_json().to_string()); );
socket.send(StateUpdate::Scene(state.current_scene).to_json().to_string()); socket.send(
socket.send(StateUpdate::PauseTimer(state.timer_paused_length.is_some()).to_json().to_string()); StateUpdate::ToggleComputerSoundOn(state.computer_sound_is_on)
.to_json()
.to_string(),
);
socket.send(
StateUpdate::ChangeSceneOnChangeSlide(state.change_scene_on_slide_hotkey)
.to_json()
.to_string(),
);
socket.send(
StateUpdate::SceneIsAugmented(state.scene_is_augmented)
.to_json()
.to_string(),
);
socket.send(
StateUpdate::TimerCanRun(state.timer_can_run)
.to_json()
.to_string(),
);
socket.send(
StateUpdate::TimerLength(state.timer_length)
.to_json()
.to_string(),
);
socket.send(
StateUpdate::TimerText(state.timer_text.clone())
.to_json()
.to_string(),
);
socket.send(
StateUpdate::SubScene(state.camera_sub_scene)
.to_json()
.to_string(),
);
socket.send(
StateUpdate::SubScene(state.screen_sub_scene)
.to_json()
.to_string(),
);
socket.send(
StateUpdate::Scene(state.current_scene)
.to_json()
.to_string(),
);
socket.send(
StateUpdate::PauseTimer(state.timer_paused_length.is_some())
.to_json()
.to_string(),
);
} }

View file

@ -1,41 +1,57 @@
use super::stream_states::{
scenes::{Scenes, SlideChange, SubScenes},
state_update::StateUpdate,
};
use std::process::Command; use std::process::Command;
use super::stream_states::{state_update::StateUpdate, scenes::{SlideChange, SubScenes, Scenes}};
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
const AHK_FILES_FOLDER: &str = ".\\ahk_files\\"; const AHK_FILES_FOLDER: &str = ".\\ahk_files\\";
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
pub const OPTIONS_PATH: &str = ".\\options.json"; pub const OPTIONS_PATH: &str = ".\\options.json";
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
const AHK_FILES_FOLDER: &str = "./ahk_files/"; const AHK_FILES_FOLDER: &str = "./ahk_files/";
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
pub const OPTIONS_PATH: &str = "./options.json"; pub const OPTIONS_PATH: &str = "./options.json";
/* /*
const AHK_FILES_FOLDER: &str = "./src/ahk_files/"; const AHK_FILES_FOLDER: &str = "./src/ahk_files/";
pub const OPTIONS_PATH: &str = "./options.json"; pub const OPTIONS_PATH: &str = "./options.json";
*/ */
#[cfg(feature = "default")] pub fn create_keyboard_hooks(
pub fn create_keyboard_hooks(channel_tx: crossbeam_channel::Sender<String>, close_flag: workctl::sync_flag::SyncFlagRx) { channel_tx: crossbeam_channel::Sender<String>,
) {
let tx_1 = channel_tx.clone(); let tx_1 = channel_tx.clone();
inputbot::KeybdKey::PageUpKey.bind(move || { inputbot::KeybdKey::PageUpKey.bind(move || {
tx_1.send(StateUpdate::ChangeSlide(SlideChange::PreviousHotkey).to_json().to_string()).unwrap(); tx_1.send(
StateUpdate::ChangeSlide(SlideChange::PreviousHotkey)
.to_json()
.to_string(),
)
.unwrap();
}); });
let tx_2 = channel_tx.clone(); let tx_2 = channel_tx.clone();
inputbot::KeybdKey::PageDownKey.bind(move || { inputbot::KeybdKey::PageDownKey.bind(move || {
tx_2.send(StateUpdate::ChangeSlide(SlideChange::NextHotkey).to_json().to_string()).unwrap(); tx_2.send(
StateUpdate::ChangeSlide(SlideChange::NextHotkey)
.to_json()
.to_string(),
)
.unwrap();
}); });
#[cfg(feature = "default")]
inputbot::handle_input_events(); inputbot::handle_input_events();
} }
#[cfg(feature = "no_hotkeys")] #[cfg(feature = "no_hotkeys")]
pub fn create_keyboard_hooks(channel_tx: crossbeam_channel::Sender<String>, close_flag: workctl::sync_flag::SyncFlagRx) { pub fn create_keyboard_hooks(
return channel_tx: crossbeam_channel::Sender<String>,
close_flag: workctl::sync_flag::SyncFlagRx,
) {
return;
} }
pub struct Hotkeys { pub struct Hotkeys {
@ -44,20 +60,35 @@ pub struct Hotkeys {
impl Hotkeys { impl Hotkeys {
pub fn new(hotkeys: serde_json::Value) -> Self { pub fn new(hotkeys: serde_json::Value) -> Self {
Hotkeys { Hotkeys { hotkeys }
hotkeys
}
} }
pub fn get_hotkey_from_scene(&self, scene: SubScenes) -> &str { pub fn get_hotkey_from_scene(&self, scene: SubScenes) -> &str {
match scene { match scene {
SubScenes::CameraDefault => {self.hotkeys["hotkeys"]["obs"]["camera_scene_hotkey"].as_str().unwrap()}, SubScenes::CameraDefault => self.hotkeys["hotkeys"]["obs"]["camera_scene_hotkey"]
SubScenes::CameraWithUpperRight => {self.hotkeys["hotkeys"]["obs"]["Camera_Top_Right"].as_str().unwrap()}, .as_str()
SubScenes::CameraWithLargeUpperRight => {self.hotkeys["hotkeys"]["obs"]["Camera_Large_Top_Right"].as_str().unwrap()}, .unwrap(),
SubScenes::CameraWithLowerRight => {self.hotkeys["hotkeys"]["obs"]["Camera_Bottom_Right"].as_str().unwrap()}, SubScenes::CameraWithUpperRight => self.hotkeys["hotkeys"]["obs"]["Camera_Top_Right"]
SubScenes::ScreenDefault => {self.hotkeys["hotkeys"]["obs"]["screen_scene_hotkey"].as_str().unwrap()}, .as_str()
SubScenes::ScreenWithUpperRight => {self.hotkeys["hotkeys"]["obs"]["Screen_Top_Right"].as_str().unwrap()}, .unwrap(),
SubScenes::ScreenWithLowerRight => {self.hotkeys["hotkeys"]["obs"]["Screen_Bottom_Right"].as_str().unwrap()}, SubScenes::CameraWithLargeUpperRight => self.hotkeys["hotkeys"]["obs"]
["Camera_Large_Top_Right"]
.as_str()
.unwrap(),
SubScenes::CameraWithLowerRight => self.hotkeys["hotkeys"]["obs"]
["Camera_Bottom_Right"]
.as_str()
.unwrap(),
SubScenes::ScreenDefault => self.hotkeys["hotkeys"]["obs"]["screen_scene_hotkey"]
.as_str()
.unwrap(),
SubScenes::ScreenWithUpperRight => self.hotkeys["hotkeys"]["obs"]["Screen_Top_Right"]
.as_str()
.unwrap(),
SubScenes::ScreenWithLowerRight => self.hotkeys["hotkeys"]["obs"]
["Screen_Bottom_Right"]
.as_str()
.unwrap(),
} }
} }
@ -65,9 +96,11 @@ impl Hotkeys {
if cfg!(target_family = "windows") { if cfg!(target_family = "windows") {
println!("sending to obs"); println!("sending to obs");
Command::new(String::from(AHK_FILES_FOLDER) + "send_obs_back_to_propre.exe") Command::new(String::from(AHK_FILES_FOLDER) + "send_obs_back_to_propre.exe")
.args([self.hotkeys["windows"]["propresenter_re"].as_str().unwrap(), .args([
self.hotkeys["windows"]["obs_re"].as_str().unwrap(), self.hotkeys["windows"]["propresenter_re"].as_str().unwrap(),
hotkey]) self.hotkeys["windows"]["obs_re"].as_str().unwrap(),
hotkey,
])
.spawn() .spawn()
.expect("next_slide process call failed"); .expect("next_slide process call failed");
std::thread::sleep(std::time::Duration::from_millis(400)); std::thread::sleep(std::time::Duration::from_millis(400));
@ -77,32 +110,58 @@ impl Hotkeys {
} }
pub fn next_slide(&self, from_hotkey: bool) { pub fn next_slide(&self, from_hotkey: bool) {
let from_hotkey_str = {if from_hotkey {"1"} else {"0"}}; let from_hotkey_str = {
if from_hotkey {
"1"
} else {
"0"
}
};
if cfg!(target_family = "windows") { if cfg!(target_family = "windows") {
Command::new(String::from(AHK_FILES_FOLDER) + "propre_send.exe") Command::new(String::from(AHK_FILES_FOLDER) + "propre_send.exe")
.args([self.hotkeys["windows"]["propresenter_re"].as_str().unwrap(), .args([
self.hotkeys["general"]["clicker_forward"].as_str().unwrap(), self.hotkeys["windows"]["propresenter_re"].as_str().unwrap(),
from_hotkey_str]) self.hotkeys["general"]["clicker_forward"].as_str().unwrap(),
from_hotkey_str,
])
.spawn() .spawn()
.expect("next_slide process call failed"); .expect("next_slide process call failed");
std::thread::sleep(std::time::Duration::from_millis(200)); std::thread::sleep(std::time::Duration::from_millis(200));
} else { } else {
println!("pretend linux is sending prosenter next: {}", self.hotkeys["general"]["clicker_forward"].as_str().unwrap()) println!(
"pretend linux is sending prosenter next: {}",
self.hotkeys["general"]["clicker_forward"].as_str().unwrap()
)
}; };
} }
pub fn prev_slide(&self, from_hotkey: bool) { pub fn prev_slide(&self, from_hotkey: bool) {
let from_hotkey_str = {if from_hotkey {"1"} else {"0"}}; let from_hotkey_str = {
if from_hotkey {
"1"
} else {
"0"
}
};
if cfg!(target_family = "windows") { if cfg!(target_family = "windows") {
Command::new(String::from(AHK_FILES_FOLDER) + "propre_send.exe") Command::new(String::from(AHK_FILES_FOLDER) + "propre_send.exe")
.args([self.hotkeys["windows"]["propresenter_re"].as_str().unwrap(), .args([
self.hotkeys["general"]["clicker_backward"].as_str().unwrap(), self.hotkeys["windows"]["propresenter_re"].as_str().unwrap(),
from_hotkey_str]) self.hotkeys["general"]["clicker_backward"]
.as_str()
.unwrap(),
from_hotkey_str,
])
.spawn() .spawn()
.expect("next_slide process call failed"); .expect("next_slide process call failed");
std::thread::sleep(std::time::Duration::from_millis(200)); std::thread::sleep(std::time::Duration::from_millis(200));
} else { } else {
println!("pretend linux is sending prosenter next: {}", self.hotkeys["general"]["clicker_backward"].as_str().unwrap()) println!(
"pretend linux is sending prosenter next: {}",
self.hotkeys["general"]["clicker_backward"]
.as_str()
.unwrap()
)
}; };
} }
@ -110,28 +169,34 @@ impl Hotkeys {
println!("sending: {:?} : {:?}", scene, sub_scene); println!("sending: {:?} : {:?}", scene, sub_scene);
let hotkey: &str; let hotkey: &str;
if scene == Scenes::Augmented { if scene == Scenes::Augmented {
hotkey = self.hotkeys["hotkeys"]["obs"]["camera_scene_augmented"].as_str().unwrap() hotkey = self.hotkeys["hotkeys"]["obs"]["camera_scene_augmented"]
.as_str()
.unwrap()
} else { } else {
hotkey = self.get_hotkey_from_scene(sub_scene.unwrap()) hotkey = self.get_hotkey_from_scene(sub_scene.unwrap())
}; };
self.send_obs(hotkey); self.send_obs(hotkey);
} }
pub fn toggle_stream_sound(&self, turn_on: bool) { pub fn toggle_stream_sound(&self, turn_on: bool) {
let hotkey: &str; let hotkey: &str;
if turn_on { if turn_on {
hotkey = self.hotkeys["hotkeys"]["obs"]["unmute_stream"].as_str().unwrap(); hotkey = self.hotkeys["hotkeys"]["obs"]["unmute_stream"]
.as_str()
.unwrap();
} else { } else {
hotkey = self.hotkeys["hotkeys"]["obs"]["mute_stream"].as_str().unwrap(); hotkey = self.hotkeys["hotkeys"]["obs"]["mute_stream"]
.as_str()
.unwrap();
} }
self.send_obs(hotkey); self.send_obs(hotkey);
} }
pub fn toggle_computer_sound(&self, value: bool) { pub fn toggle_computer_sound(&self, value: bool) {
let time_delay = self.hotkeys["general"]["music_fade_time"].as_i64().unwrap(); let time_delay = self.hotkeys["general"]["music_fade_time"].as_i64().unwrap();
if cfg!(target_family = "windows") { if cfg!(target_family = "windows") {
Command::new(String::from(AHK_FILES_FOLDER) + "music_toggle.exe") Command::new(String::from(AHK_FILES_FOLDER) + "music_toggle.exe")
.arg((value as u8).to_string()) .arg((value as u8).to_string())
.arg(time_delay.to_string()) .arg(time_delay.to_string())
.spawn() .spawn()
.expect("next_slide process call failed"); .expect("next_slide process call failed");
@ -139,20 +204,19 @@ impl Hotkeys {
println!("pretend linux is sending media: {}", value) println!("pretend linux is sending media: {}", value)
}; };
} }
pub fn toggle_media_play_pause(&self) { pub fn toggle_media_play_pause(&self) {
if cfg!(target_family = "windows") { if cfg!(target_family = "windows") {
Command::new(String::from(AHK_FILES_FOLDER) + "pause_play_global.exe") Command::new(String::from(AHK_FILES_FOLDER) + "pause_play_global.exe")
.arg(self.hotkeys["windows"]["propresenter_re"].as_str().unwrap()) .arg(self.hotkeys["windows"]["propresenter_re"].as_str().unwrap())
.spawn() .spawn()
.expect("next_slide process call failed"); .expect("next_slide process call failed");
} else { } else {
println!("pretend linux is sending media pause") println!("pretend linux is sending media pause")
}; };
} }
} }
#[test] #[test]
fn hotkeys() { fn hotkeys() {
use std::io::Read; use std::io::Read;
@ -174,4 +238,4 @@ fn hotkeys() {
hk.toggle_computer_sound(true); hk.toggle_computer_sound(true);
hk.toggle_stream_sound(true); hk.toggle_stream_sound(true);
hk.toggle_media_play_pause(); hk.toggle_media_play_pause();
} }

View file

@ -1,47 +1,62 @@
use std::time::{SystemTime}; use std::time::SystemTime;
use super::{stream_states::{state_update::StateUpdate, stream_state::StreamState, scenes::{SlideChange, Scenes}}, external_interface::{Hotkeys}}; use super::{
external_interface::Hotkeys,
stream_states::{
scenes::{Scenes, SlideChange},
state_update::StateUpdate,
stream_state::StreamState,
},
};
pub trait MessageHandler { //the first one goes to socket, the second propogates pub trait MessageHandler {
fn handle_update(&mut self, update: StateUpdate, hotkey_handler: &Hotkeys) //the first one goes to socket, the second propogates
-> (Option<StateUpdate>, Option<Vec<StateUpdate>>); fn handle_update(
&mut self,
update: StateUpdate,
hotkey_handler: &Hotkeys,
) -> (Option<StateUpdate>, Option<Vec<StateUpdate>>);
fn get_states(&self) -> StreamState; fn get_states(&self) -> StreamState;
fn pause_timer(&mut self, do_pause: bool) -> (Option<StateUpdate>, Option<Vec<StateUpdate>>); fn pause_timer(&mut self, do_pause: bool) -> (Option<StateUpdate>, Option<Vec<StateUpdate>>);
fn tick(&mut self) -> Vec<StateUpdate>; fn tick(&mut self) -> Vec<StateUpdate>;
} }
impl MessageHandler for StreamState { impl MessageHandler for StreamState {
fn handle_update(&mut self, update: StateUpdate, hotkey_handler: &Hotkeys) fn handle_update(
-> (Option<StateUpdate>, Option<Vec<StateUpdate>>) { &mut self,
update: StateUpdate,
if update != StateUpdate::UpdateClient && update != StateUpdate::ChangeSlide(SlideChange::NextApp) && hotkey_handler: &Hotkeys,
update != StateUpdate::ChangeSlide(SlideChange::PreviousApp) && update != StateUpdate::ChangeSlide(SlideChange::PreviousHotkey) ) -> (Option<StateUpdate>, Option<Vec<StateUpdate>>) {
&& update != StateUpdate::ChangeSlide(SlideChange::NextHotkey) { if update != StateUpdate::UpdateClient
&& update != StateUpdate::ChangeSlide(SlideChange::NextApp)
&& update != StateUpdate::ChangeSlide(SlideChange::PreviousApp)
&& update != StateUpdate::ChangeSlide(SlideChange::PreviousHotkey)
&& update != StateUpdate::ChangeSlide(SlideChange::NextHotkey)
{
self.update(update.clone()); self.update(update.clone());
} }
if self.debug_mode { if self.debug_mode {
return (None, None) return (None, None);
} }
match update { match update {
StateUpdate::ChangeSlide(direction) => { StateUpdate::ChangeSlide(direction) => {
match direction { match direction {
SlideChange::NextHotkey => { SlideChange::NextHotkey => {
hotkey_handler.next_slide(true); hotkey_handler.next_slide(true);
}, }
SlideChange::NextApp => { SlideChange::NextApp => {
hotkey_handler.next_slide(false); hotkey_handler.next_slide(false);
}, }
SlideChange::PreviousHotkey => { SlideChange::PreviousHotkey => {
hotkey_handler.prev_slide(true); hotkey_handler.prev_slide(true);
}, }
SlideChange::PreviousApp => { SlideChange::PreviousApp => {
hotkey_handler.prev_slide(false); hotkey_handler.prev_slide(false);
}, }
} }
if self.change_scene_on_slide_hotkey { if self.change_scene_on_slide_hotkey {
if self.timer_can_run { if self.timer_can_run {
self.timer_finished = false; self.timer_finished = false;
@ -50,17 +65,22 @@ impl MessageHandler for StreamState {
let mut instructions = Vec::new(); let mut instructions = Vec::new();
instructions.push(StateUpdate::Scene(Scenes::Screen)); instructions.push(StateUpdate::Scene(Scenes::Screen));
return (None, Some(instructions)) return (None, Some(instructions));
} else {return (None, None)} } else {
return (None, None);
}
}
StateUpdate::ChangeSceneOnChangeSlide(value) => {
self.change_scene_on_slide_hotkey = value;
return (Some(update), None);
} }
StateUpdate::ChangeSceneOnChangeSlide(value) => {self.change_scene_on_slide_hotkey = value; return (Some(update), None)},
StateUpdate::SceneIsAugmented(value) => { StateUpdate::SceneIsAugmented(value) => {
if value { if value {
let mut instructions = Vec::new(); let mut instructions = Vec::new();
instructions.push(StateUpdate::ChangeSceneOnChangeSlide(false)); instructions.push(StateUpdate::ChangeSceneOnChangeSlide(false));
instructions.push(StateUpdate::Scene(Scenes::Augmented)); instructions.push(StateUpdate::Scene(Scenes::Augmented));
instructions.push(StateUpdate::TimerCanRun(false)); instructions.push(StateUpdate::TimerCanRun(false));
return (Some(update), Some(instructions)) return (Some(update), Some(instructions));
} else { } else {
let mut instructions = Vec::new(); let mut instructions = Vec::new();
instructions.push(StateUpdate::Scene(Scenes::Camera)); instructions.push(StateUpdate::Scene(Scenes::Camera));
@ -68,9 +88,9 @@ impl MessageHandler for StreamState {
instructions.push(StateUpdate::TimerCanRun(true)); instructions.push(StateUpdate::TimerCanRun(true));
return (Some(update), Some(instructions)); return (Some(update), Some(instructions));
} }
}, }
StateUpdate::TimerCanRun(value) => { StateUpdate::TimerCanRun(value) => {
if self.timer_paused_length.is_some(){ if self.timer_paused_length.is_some() {
return (None, Some(vec![StateUpdate::PauseTimer(false)])); return (None, Some(vec![StateUpdate::PauseTimer(false)]));
} }
@ -80,70 +100,86 @@ impl MessageHandler for StreamState {
if value { if value {
let mut instruction = Vec::new(); let mut instruction = Vec::new();
instruction.push(StateUpdate::TimerText(String::from("0.0"))); instruction.push(StateUpdate::TimerText(String::from("0.0")));
return (Some(update), Some(instruction)) return (Some(update), Some(instruction));
} else { } else {
return (Some(update), None); return (Some(update), None);
} }
}, }
StateUpdate::PauseTimer(value) => {return self.pause_timer(value)}, StateUpdate::PauseTimer(value) => return self.pause_timer(value),
StateUpdate::TimerLength(value) => {self.timer_length = value; return (Some(update), None)}, StateUpdate::TimerLength(value) => {
StateUpdate::TimerText(value) => {self.timer_text = value.clone(); return (Some(StateUpdate::TimerText(value)), None)}, self.timer_length = value;
return (Some(update), None);
}
StateUpdate::TimerText(value) => {
self.timer_text = value.clone();
return (Some(StateUpdate::TimerText(value)), None);
}
StateUpdate::SubScene(value) => { StateUpdate::SubScene(value) => {
if value.get_type().is_camera() { if value.get_type().is_camera() {
if self.current_scene.is_camera() { if self.current_scene.is_camera() {
hotkey_handler.change_scene(Scenes::Camera, Some(value)); hotkey_handler.change_scene(Scenes::Camera, Some(value));
} }
self.camera_sub_scene = value; self.camera_sub_scene = value;
return (Some(update), None) return (Some(update), None);
} else if value.get_type().is_screen() { } else if value.get_type().is_screen() {
if self.current_scene.is_screen() { if self.current_scene.is_screen() {
hotkey_handler.change_scene(Scenes::Screen, Some(value)); hotkey_handler.change_scene(Scenes::Screen, Some(value));
} }
self.screen_sub_scene = value; self.screen_sub_scene = value;
return (Some(update), None) return (Some(update), None);
} }
}, }
StateUpdate::Scene(value) => { StateUpdate::Scene(value) => {
println!("handling scene: {:?}", value); println!("handling scene: {:?}", value);
let mut instruction = None; let mut instruction = None;
if self.current_scene != value { if self.current_scene != value {
match value { match value {
Scenes::Camera => { Scenes::Camera => {
hotkey_handler.change_scene(Scenes::Camera, Some(self.camera_sub_scene)); hotkey_handler
.change_scene(Scenes::Camera, Some(self.camera_sub_scene));
if self.timer_paused_length.is_none() { if self.timer_paused_length.is_none() {
instruction = Some(vec![StateUpdate::TimerText("0.0".to_string())]); instruction = Some(vec![StateUpdate::TimerText("0.0".to_string())]);
} }
self.timer_finished = true; self.timer_finished = true;
}, }
Scenes::Screen => { Scenes::Screen => {
hotkey_handler.change_scene(Scenes::Screen, Some(self.screen_sub_scene)); hotkey_handler
.change_scene(Scenes::Screen, Some(self.screen_sub_scene));
self.timer_start = SystemTime::now(); self.timer_start = SystemTime::now();
self.timer_finished = false; self.timer_finished = false;
}
},
Scenes::Augmented => { Scenes::Augmented => {
hotkey_handler.change_scene(Scenes::Augmented, None); hotkey_handler.change_scene(Scenes::Augmented, None);
self.timer_finished = true; self.timer_finished = true;
} }
} }
} }
// if the current scene was tapped again // if the current scene was tapped again
else { else {
// current scene can only be the same as value, and timer is paused // current scene can only be the same as value, and timer is paused
if value.is_screen() && self.timer_paused_length.is_some() { if value.is_screen() && self.timer_paused_length.is_some() {
instruction = Some(vec![StateUpdate::PauseTimer(false)]); instruction = Some(vec![StateUpdate::PauseTimer(false)]);
} }
} }
self.current_scene = value; self.current_scene = value;
return (Some(update), instruction); return (Some(update), instruction);
}, }
StateUpdate::StreamSoundToggleOn(value) => {hotkey_handler.toggle_stream_sound(value); return (Some(update), None)}, StateUpdate::StreamSoundToggleOn(value) => {
StateUpdate::ToggleComputerSoundOn(value) => {hotkey_handler.toggle_computer_sound(!value); return (Some(StateUpdate::ToggleComputerSoundOn(!value)), None)}, hotkey_handler.toggle_stream_sound(value);
StateUpdate::ComputerMediaDoPause => {hotkey_handler.toggle_media_play_pause(); return (Some(update), None)}, return (Some(update), None);
StateUpdate::UpdateClient => {}, }
StateUpdate::StreamRunning(_) => {}, StateUpdate::ToggleComputerSoundOn(value) => {
hotkey_handler.toggle_computer_sound(!value);
return (Some(StateUpdate::ToggleComputerSoundOn(!value)), None);
}
StateUpdate::ComputerMediaDoPause => {
hotkey_handler.toggle_media_play_pause();
return (Some(update), None);
}
StateUpdate::UpdateClient => {}
StateUpdate::StreamRunning(_) => {}
//_ => {} //_ => {}
} }
(None, None) (None, None)
@ -152,22 +188,21 @@ impl MessageHandler for StreamState {
fn pause_timer(&mut self, do_pause: bool) -> (Option<StateUpdate>, Option<Vec<StateUpdate>>) { fn pause_timer(&mut self, do_pause: bool) -> (Option<StateUpdate>, Option<Vec<StateUpdate>>) {
let output: StateUpdate; let output: StateUpdate;
let mut instruction: Option<Vec<StateUpdate>> = None; let mut instruction: Option<Vec<StateUpdate>> = None;
// if do pause,
if do_pause {
// if do pause,
if do_pause {
// if camera scene, don't allow it! // if camera scene, don't allow it!
if self.current_scene.is_camera() { if self.current_scene.is_camera() {
return (None, None) return (None, None);
} }
// stop tick from running, // stop tick from running,
self.timer_can_run = false; self.timer_can_run = false;
// get the amount of time left on the clock // get the amount of time left on the clock
let time_left: u16; let time_left: u16;
match self.timer_start.elapsed() { match self.timer_start.elapsed() {
Err(_) => {time_left = 0}, Err(_) => time_left = 0,
Ok(change) => { Ok(change) => {
// take the duration left, multiply it by 10 to save the last decimal, // take the duration left, multiply it by 10 to save the last decimal,
// then drop the rest of the digits with .round() // then drop the rest of the digits with .round()
@ -175,52 +210,63 @@ impl MessageHandler for StreamState {
} }
} }
self.timer_paused_length = Some(time_left); self.timer_paused_length = Some(time_left);
// (Send to socket, process another instruction) // (Send to socket, process another instruction)
// send the pause singal to the socket, and update the timer text (dividing by 10 to return the last digit) // send the pause singal to the socket, and update the timer text (dividing by 10 to return the last digit)
return (Some(StateUpdate::PauseTimer(true)), Some(vec![StateUpdate::TimerText(format!("{:.1}", time_left as f32/10.0))])); return (
Some(StateUpdate::PauseTimer(true)),
Some(vec![StateUpdate::TimerText(format!(
"{:.1}",
time_left as f32 / 10.0
))]),
);
} else { } else {
// if start timer from pause // if start timer from pause
// enable tick() // enable tick()
self.timer_can_run = true; self.timer_can_run = true;
// Some fancy check to not have to use a match statement. The 'expect' should never be called, worry if it does // Some fancy check to not have to use a match statement. The 'expect' should never be called, worry if it does
let timer_paused_length: u16 = self.timer_paused_length.or(Some(0)).expect("timer_paused 'Some' unwrap somehow failed"); let timer_paused_length: u16 = self
.timer_paused_length
.or(Some(0))
.expect("timer_paused 'Some' unwrap somehow failed");
// if camera scene, don't reset the time_start // if camera scene, don't reset the time_start
if self.current_scene.is_camera() { if self.current_scene.is_camera() {
instruction = Some(vec![StateUpdate::TimerText("0.0".to_string())]); instruction = Some(vec![StateUpdate::TimerText("0.0".to_string())]);
self.timer_start += std::time::Duration::from_secs(self.timer_length as u64); self.timer_start += std::time::Duration::from_secs(self.timer_length as u64);
} else { } else {
// update timer_start, taking into account the amount of time already run // update timer_start, taking into account the amount of time already run
self.timer_start = SystemTime::now() - self.timer_start = SystemTime::now()
std::time::Duration::from_millis( - std::time::Duration::from_millis(
// first get the decimal back from timer_paused_length, get the amount of time already run // first get the decimal back from timer_paused_length, get the amount of time already run
// then convert that to milliseconds, then from f32 to u64 // then convert that to milliseconds, then from f32 to u64
((self.timer_length - (timer_paused_length as f32 / 10.0)) * 1000.0) as u64); ((self.timer_length - (timer_paused_length as f32 / 10.0)) * 1000.0) as u64,
);
} }
// Clear the paused time // Clear the paused time
self.timer_paused_length = None; self.timer_paused_length = None;
output = StateUpdate::PauseTimer(false); output = StateUpdate::PauseTimer(false);
} }
return (Some(output), instruction) return (Some(output), instruction);
} }
fn tick(&mut self) -> Vec<StateUpdate> { fn tick(&mut self) -> Vec<StateUpdate> {
let mut instructions = Vec::new(); let mut instructions = Vec::new();
if self.timer_finished == false && self.timer_can_run == true { if self.timer_finished == false && self.timer_can_run == true {
match self.timer_start.elapsed() { match self.timer_start.elapsed() {
Err(_) => {}, Err(_) => {}
Ok(change) => { Ok(change) => {
if change.as_secs_f32() >= self.timer_length { if change.as_secs_f32() >= self.timer_length {
self.timer_finished = true; self.timer_finished = true;
instructions.push(StateUpdate::TimerText(String::from("0.0"))); instructions.push(StateUpdate::TimerText(String::from("0.0")));
instructions.push(StateUpdate::Scene(Scenes::Camera)); instructions.push(StateUpdate::Scene(Scenes::Camera));
} else { } else {
instructions.push(StateUpdate::TimerText( instructions.push(StateUpdate::TimerText(format!(
format!("{:.1}", self.timer_length - ((change.as_secs_f32() * 10.0).round() / 10.0)) "{:.1}",
)); self.timer_length - ((change.as_secs_f32() * 10.0).round() / 10.0)
)));
} }
} }
} }
@ -228,10 +274,9 @@ impl MessageHandler for StreamState {
instructions instructions
} }
fn get_states(&self) -> StreamState{ fn get_states(&self) -> StreamState {
self.clone() self.clone()
} }
} }
#[test] #[test]
@ -266,4 +311,4 @@ fn test_tick_10() {
let mut update = state.tick(); let mut update = state.tick();
state.update(update.pop().unwrap()); state.update(update.pop().unwrap());
assert_eq!(state.timer_text, "5.0"); assert_eq!(state.timer_text, "5.0");
} }

View file

@ -1,10 +1,10 @@
pub mod external_interface;
pub mod message_handler; pub mod message_handler;
pub mod socket_handler; pub mod socket_handler;
pub mod external_interface; pub mod tray_icon;
pub mod stream_states { pub mod stream_states {
pub mod stream_state;
pub mod state_update;
pub mod scenes; pub mod scenes;
} pub mod state_update;
pub mod stream_state;
}

View file

@ -1,19 +1,18 @@
use workctl::sync_flag; use crossbeam_channel::Sender;
use std::net::{TcpListener, TcpStream, Shutdown};
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::sync::{Mutex, Arc}; use std::net::{Shutdown, TcpListener, TcpStream};
use crossbeam_channel::{Sender}; use std::sync::{Arc, Mutex};
use std::thread::{self, JoinHandle}; use std::thread::{self, JoinHandle};
use std::time::Duration; use std::time::Duration;
use workctl::sync_flag;
pub struct Socket{ pub struct Socket {
socket_txs: Arc<Mutex<Vec<Arc<TcpStream>>>>, socket_txs: Arc<Mutex<Vec<Arc<TcpStream>>>>,
stop_listener_flag: sync_flag::SyncFlagTx, stop_listener_flag: sync_flag::SyncFlagTx,
handle_connections_join_handle: Option<JoinHandle<()>>, handle_connections_join_handle: Option<JoinHandle<()>>,
} }
impl Socket { impl Socket {
pub fn make_listener(address: &str) -> TcpListener { pub fn make_listener(address: &str) -> TcpListener {
TcpListener::bind(address).unwrap() TcpListener::bind(address).unwrap()
} }
@ -24,6 +23,7 @@ impl Socket {
let thread_owned_streams = Arc::clone(&socket_streams); let thread_owned_streams = Arc::clone(&socket_streams);
println!("initializing socket connection handling thread");
let handle = thread::spawn(move || { let handle = thread::spawn(move || {
listener.set_nonblocking(true).unwrap(); listener.set_nonblocking(true).unwrap();
let mut service_sockets: Vec<Arc<TcpStream>> = Vec::new(); let mut service_sockets: Vec<Arc<TcpStream>> = Vec::new();
@ -39,7 +39,7 @@ impl Socket {
Socket::service_clients(&mut service_sockets, messenger_tx.clone()); Socket::service_clients(&mut service_sockets, messenger_tx.clone());
thread::sleep(Duration::from_millis(100)); thread::sleep(Duration::from_millis(100));
} }
println!("closed socket loop"); println!("closed socket connection handling thread");
drop(listener); drop(listener);
}); });
@ -60,7 +60,9 @@ impl Socket {
if msg_len == 0 { if msg_len == 0 {
remove.push(i); remove.push(i);
} else { } else {
update_tx.send(String::from_utf8_lossy(&buffer[0..msg_len]).into_owned()).unwrap(); update_tx
.send(String::from_utf8_lossy(&buffer[0..msg_len]).into_owned())
.unwrap();
} }
} }
} }
@ -68,31 +70,32 @@ impl Socket {
streams.get(*i).unwrap().shutdown(Shutdown::Both).unwrap(); streams.get(*i).unwrap().shutdown(Shutdown::Both).unwrap();
streams.remove(*i); streams.remove(*i);
} }
} }
pub fn close(&mut self) { pub fn close(&mut self) {
self.stop_listener_flag.set(false); self.stop_listener_flag.set(false);
self.handle_connections_join_handle self.handle_connections_join_handle
.take().expect("Called on not running thread") .take()
.join().expect("Could not join thread"); .expect("Called on not running thread")
.join()
.expect("Could not join thread");
} }
pub fn send(&self, message: String) { pub fn send(&self, message: String) {
let mut streams = self.socket_txs.lock().unwrap(); let mut streams = self.socket_txs.lock().unwrap();
let mut removes = Vec::<usize>::new(); let mut removes = Vec::<usize>::new();
if streams.len() == 0 {return} if streams.len() == 0 {
for i in 0..streams.len(){ return;
}
for i in 0..streams.len() {
match streams.get(i) { match streams.get(i) {
None => { None => {
removes.push(i); removes.push(i);
}, }
Some(strm) => { Some(strm) => {
let mut tx = strm.as_ref(); let mut tx = strm.as_ref();
match tx.write(message.clone().as_bytes()) { match tx.write(message.clone().as_bytes()) {
Err(_) => { Err(_) => removes.push(i),
removes.push(i)
},
Ok(_) => { Ok(_) => {
tx.write(b"\n").unwrap(); tx.write(b"\n").unwrap();
tx.flush().unwrap(); tx.flush().unwrap();
@ -105,4 +108,4 @@ impl Socket {
streams.remove(*i); streams.remove(*i);
} }
} }
} }

131
src/modules/tray_icon.rs Normal file
View file

@ -0,0 +1,131 @@
use core::mem::MaybeUninit;
use std::time::Duration;
use crossbeam_channel::Receiver;
use trayicon::*;
use winapi::um::winuser;
use workctl::sync_flag::SyncFlagRx;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Events {
ClickTrayIcon,
DoubleClickTrayIcon,
Exit,
Item1,
Item2,
Item3,
Item4,
CheckItem1,
SubItem1,
SubItem2,
SubItem3,
}
pub struct TrayIcon {
tray_icon: trayicon::TrayIcon<Events>,
pub message_channel: crossbeam_channel::Receiver<Events>,
}
impl TrayIcon {
pub fn setup(icon: &[u8]) -> TrayIcon {
let (s, r) = crossbeam_channel::unbounded();
let icon1 = include_bytes!("./../icon1.ico");
let icon2 = include_bytes!("./../icon2.ico");
let second_icon = Icon::from_buffer(icon2, None, None).unwrap();
let first_icon = Icon::from_buffer(icon1, None, None).unwrap();
// Needlessly complicated tray icon with all the whistles and bells
let tray_icon = TrayIconBuilder::new()
.sender_crossbeam(s)
.icon_from_buffer(icon1)
.tooltip("Cool Tray 👀 Icon")
.on_click(Events::ClickTrayIcon)
.on_double_click(Events::DoubleClickTrayIcon)
.menu(
MenuBuilder::new()
.item("Item 3 Replace Menu 👍", Events::Item3)
.item("Item 2 Change Icon Green", Events::Item2)
.item("Item 1 Change Icon Red", Events::Item1)
.separator()
.checkable("This is checkable", true, Events::CheckItem1)
.submenu(
"Sub Menu",
MenuBuilder::new()
.item("Sub item 1", Events::SubItem1)
.item("Sub Item 2", Events::SubItem2)
.item("Sub Item 3", Events::SubItem3),
)
.with(MenuItem::Item {
name: "Item Disabled".into(),
disabled: true, // Disabled entry example
id: Events::Item4,
icon: None,
})
.separator()
.item("E&xit", Events::Exit),
)
.build()
.unwrap();
TrayIcon {
tray_icon,
message_channel: r,
}
}
pub fn check_tray_icon_messages(&self) {
unsafe {
let mut msg = MaybeUninit::uninit();
let bret = winuser::PeekMessageA(msg.as_mut_ptr(), 0 as _, 0, 0, 1);
if bret > 0 {
winuser::TranslateMessage(msg.as_ptr());
winuser::DispatchMessageA(msg.as_ptr());
} else {
return;
}
}
}
pub fn handle_tray_messages(message_channel: &Receiver<Events>) {
let message = message_channel.recv_timeout(Duration::from_millis(10));
match message {
Err(_) => return,
Ok(message) => {
match message {
Events::DoubleClickTrayIcon => {
println!("Double click");
}
Events::ClickTrayIcon => {
println!("Single click");
}
Events::Exit => {
println!("Please exit");
todo!()
}
Events::Item1 => {
println!("item1");
//tray_icon.set_icon(&second_icon).unwrap();
}
Events::Item2 => {
println!("item2");
//tray_icon.set_icon(&first_icon).unwrap();
}
Events::Item3 => {
println!("item3");
/*tray_icon
.set_menu(
&MenuBuilder::new()
.item("New menu item", Events::Item1)
.item("Exit", Events::Exit),
)
.unwrap();*/
}
e => {
println!("{:?}", e);
}
}
}
}
}
}

View file

@ -1,7 +1,8 @@
use workctl::sync_flag; use workctl::sync_flag;
use crate::modules::{stream_states::{ stream_state::StreamState, scenes::Scenes, state_update::StateUpdate}}; use crate::modules::stream_states::{
scenes::Scenes, state_update::StateUpdate, stream_state::StreamState,
};
#[test] #[test]
fn it_works() { fn it_works() {
@ -12,11 +13,10 @@ fn it_works() {
#[test] #[test]
fn can_make_ctrl_c_handler() { fn can_make_ctrl_c_handler() {
let (control_c_flag_tx, _control_c_called_flag_rx) = sync_flag::new_syncflag(false); let (control_c_flag_tx, _control_c_called_flag_rx) = sync_flag::new_syncflag(false);
crate::setup_control_c(control_c_flag_tx); crate::setup_control_c();
drop(_control_c_called_flag_rx); drop(_control_c_called_flag_rx);
} }
#[test] #[test]
fn test_updating_state_from_state_update() { fn test_updating_state_from_state_update() {
let mut state = StreamState::new(); let mut state = StreamState::new();

View file

@ -1,10 +1,13 @@
use crate::modules::{message_handler::{MessageHandler}, stream_states::{state_update::StateUpdate, stream_state::StreamState}, external_interface::Hotkeys}; use crate::modules::{
external_interface::Hotkeys,
message_handler::MessageHandler,
stream_states::{state_update::StateUpdate, stream_state::StreamState},
};
#[test] #[test]
fn does_stream_state_implement_message_handler() { fn does_stream_state_implement_message_handler() {
let hotkeys = Hotkeys { let hotkeys = Hotkeys {
hotkeys: serde_json::Value::Null hotkeys: serde_json::Value::Null,
}; };
let mut state = StreamState::new(); let mut state = StreamState::new();
state.debug_mode = true; state.debug_mode = true;

View file

@ -1,12 +1,11 @@
#[cfg(test)] #[cfg(test)]
pub mod main_tests; pub mod main_tests;
#[cfg(test)]
pub mod stream_states_tests;
#[cfg(test)] #[cfg(test)]
pub mod message_handler_tests; pub mod message_handler_tests;
#[cfg(test)] #[cfg(test)]
pub mod socket_handler_tests; pub mod socket_handler_tests;
#[cfg(test)] #[cfg(test)]
pub mod state_update_tests; pub mod state_update_tests;
#[cfg(test)]
pub mod stream_states_tests;

View file

@ -1,12 +1,12 @@
use crossbeam_channel::unbounded; use crossbeam_channel::unbounded;
use std::io::{Write}; use std::io::Write;
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
use crate::modules::socket_handler::Socket; use crate::modules::socket_handler::Socket;
#[test] #[test]
fn can_make_socket_listener(){ fn can_make_socket_listener() {
let listener = Socket::make_listener("localhost:5001"); let listener = Socket::make_listener("localhost:5001");
drop(listener); drop(listener);
} }
@ -45,7 +45,7 @@ fn can_handle_messages() {
let message = rx_1.recv().unwrap(); let message = rx_1.recv().unwrap();
assert_eq!(message, String::from("this is a test")); assert_eq!(message, String::from("this is a test"));
socket.close(); socket.close();
} }
@ -66,11 +66,10 @@ fn can_handle_delayed_messages() {
let message = rx_1.recv().unwrap(); let message = rx_1.recv().unwrap();
println!("{}", message); println!("{}", message);
assert_eq!(message, String::from("this is a test1\n")); assert_eq!(message, String::from("this is a test1\n"));
let message = rx_1.recv().unwrap(); let message = rx_1.recv().unwrap();
println!("{}", message); println!("{}", message);
assert_eq!(message, String::from("this is a test3\n")); assert_eq!(message, String::from("this is a test3\n"));
socket.close(); socket.close();
} }

View file

@ -1,36 +1,79 @@
use crate::modules::stream_states::{state_update::StateUpdate, scenes::{Scenes, SubScenes, SlideChange}}; use crate::modules::stream_states::{
scenes::{Scenes, SlideChange, SubScenes},
state_update::StateUpdate,
};
#[test] #[test]
fn test_json_to_state_update() { fn test_json_to_state_update() {
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(
"{\"type\": \"update\", \"update\": \"Scene\", \"data\": \"Scene_Camera\"}" StateUpdate::json_to_state_update(
).unwrap()), StateUpdate::Scene(Scenes::Camera)); serde_json::from_str(
"{\"type\": \"update\", \"update\": \"Scene\", \"data\": \"Scene_Camera\"}"
)
.unwrap()
),
StateUpdate::Scene(Scenes::Camera)
);
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(
"{\"type\": \"update\", \"update\": \"Scene\", \"data\": \"Scene_Screen\"}" StateUpdate::json_to_state_update(
).unwrap()), StateUpdate::Scene(Scenes::Screen)); serde_json::from_str(
"{\"type\": \"update\", \"update\": \"Scene\", \"data\": \"Scene_Screen\"}"
)
.unwrap()
),
StateUpdate::Scene(Scenes::Screen)
);
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(
"{\"type\": \"update\", \"update\": \"Scene_Is_Augmented\", \"data\": \"true\"}" StateUpdate::json_to_state_update(
).unwrap()), StateUpdate::SceneIsAugmented(true)); serde_json::from_str(
"{\"type\": \"update\", \"update\": \"Scene_Is_Augmented\", \"data\": \"true\"}"
)
.unwrap()
),
StateUpdate::SceneIsAugmented(true)
);
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(
"{\"type\": \"update\", \"update\": \"Timer_Can_Run\", \"data\": \"true\"}" StateUpdate::json_to_state_update(
).unwrap()), StateUpdate::TimerCanRun(true)); serde_json::from_str(
"{\"type\": \"update\", \"update\": \"Timer_Can_Run\", \"data\": \"true\"}"
)
.unwrap()
),
StateUpdate::TimerCanRun(true)
);
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(
"{\"type\": \"update\", \"update\": \"Timer_Can_Run\", \"data\": \"false\"}" StateUpdate::json_to_state_update(
).unwrap()), StateUpdate::TimerCanRun(false)); serde_json::from_str(
"{\"type\": \"update\", \"update\": \"Timer_Can_Run\", \"data\": \"false\"}"
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( )
"{\"type\": \"update\", \"update\": \"Change_With_Clicker\", \"data\": \"true\"}" .unwrap()
).unwrap()), StateUpdate::ChangeSceneOnChangeSlide(true)); ),
StateUpdate::TimerCanRun(false)
);
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(
"{\"type\": \"update\", \"update\": \"Change_With_Clicker\", \"data\": \"false\"}" StateUpdate::json_to_state_update(
).unwrap()), StateUpdate::ChangeSceneOnChangeSlide(false)); serde_json::from_str(
"{\"type\": \"update\", \"update\": \"Change_With_Clicker\", \"data\": \"true\"}"
)
.unwrap()
),
StateUpdate::ChangeSceneOnChangeSlide(true)
);
assert_eq!(
StateUpdate::json_to_state_update(
serde_json::from_str(
"{\"type\": \"update\", \"update\": \"Change_With_Clicker\", \"data\": \"false\"}"
)
.unwrap()
),
StateUpdate::ChangeSceneOnChangeSlide(false)
);
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str(
"{\"type\": \"update\", \"update\": \"Toggle_Computer_Volume\", \"data\": \"true\"}" "{\"type\": \"update\", \"update\": \"Toggle_Computer_Volume\", \"data\": \"true\"}"
@ -39,100 +82,252 @@ fn test_json_to_state_update() {
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str(
"{\"type\": \"update\", \"update\": \"Toggle_Computer_Volume\", \"data\": \"false\"}" "{\"type\": \"update\", \"update\": \"Toggle_Computer_Volume\", \"data\": \"false\"}"
).unwrap()), StateUpdate::ToggleComputerSoundOn(false)); ).unwrap()), StateUpdate::ToggleComputerSoundOn(false));
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str(
"{\"type\": \"update\", \"update\": \"Toggle_Stream_Volume\", \"data\": \"true\"}"
).unwrap()), StateUpdate::StreamSoundToggleOn(true));
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(
"{\"type\": \"update\", \"update\": \"Toggle_Stream_Volume\", \"data\": \"false\"}" StateUpdate::json_to_state_update(
).unwrap()), StateUpdate::StreamSoundToggleOn(false)); serde_json::from_str(
"{\"type\": \"update\", \"update\": \"Toggle_Stream_Volume\", \"data\": \"true\"}"
)
.unwrap()
),
StateUpdate::StreamSoundToggleOn(true)
);
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(
"{\"type\": \"update\", \"update\": \"Media_Pause_Play\", \"data\": \"true\"}" StateUpdate::json_to_state_update(
).unwrap()), StateUpdate::ComputerMediaDoPause); serde_json::from_str(
"{\"type\": \"update\", \"update\": \"Toggle_Stream_Volume\", \"data\": \"false\"}"
)
.unwrap()
),
StateUpdate::StreamSoundToggleOn(false)
);
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(
"{\"type\": \"update\", \"update\": \"SubScene\", \"data\": \"Camera_None\"}" StateUpdate::json_to_state_update(
).unwrap()), StateUpdate::SubScene(SubScenes::CameraDefault)); serde_json::from_str(
"{\"type\": \"update\", \"update\": \"Media_Pause_Play\", \"data\": \"true\"}"
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( )
"{\"type\": \"update\", \"update\": \"SubScene\", \"data\": \"Camera_Top_Right\"}" .unwrap()
).unwrap()), StateUpdate::SubScene(SubScenes::CameraWithUpperRight)); ),
StateUpdate::ComputerMediaDoPause
);
assert_eq!(
StateUpdate::json_to_state_update(
serde_json::from_str(
"{\"type\": \"update\", \"update\": \"SubScene\", \"data\": \"Camera_None\"}"
)
.unwrap()
),
StateUpdate::SubScene(SubScenes::CameraDefault)
);
assert_eq!(
StateUpdate::json_to_state_update(
serde_json::from_str(
"{\"type\": \"update\", \"update\": \"SubScene\", \"data\": \"Camera_Top_Right\"}"
)
.unwrap()
),
StateUpdate::SubScene(SubScenes::CameraWithUpperRight)
);
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str(
"{\"type\": \"update\", \"update\": \"SubScene\", \"data\": \"Camera_Bottom_Right\"}" "{\"type\": \"update\", \"update\": \"SubScene\", \"data\": \"Camera_Bottom_Right\"}"
).unwrap()), StateUpdate::SubScene(SubScenes::CameraWithLowerRight)); ).unwrap()), StateUpdate::SubScene(SubScenes::CameraWithLowerRight));
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str(
"{\"type\": \"update\", \"update\": \"SubScene\", \"data\": \"Camera_Bottom_Left\"}" "{\"type\": \"update\", \"update\": \"SubScene\", \"data\": \"Camera_Bottom_Left\"}"
).unwrap()), StateUpdate::SubScene(SubScenes::CameraWithLargeUpperRight)); ).unwrap()), StateUpdate::SubScene(SubScenes::CameraWithLargeUpperRight));
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(
"{\"type\": \"update\", \"update\": \"SubScene\", \"data\": \"Screen_None\"}" StateUpdate::json_to_state_update(
).unwrap()), StateUpdate::SubScene(SubScenes::ScreenDefault)); serde_json::from_str(
"{\"type\": \"update\", \"update\": \"SubScene\", \"data\": \"Screen_None\"}"
)
.unwrap()
),
StateUpdate::SubScene(SubScenes::ScreenDefault)
);
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(
"{\"type\": \"update\", \"update\": \"SubScene\", \"data\": \"Screen_Top_Right\"}" StateUpdate::json_to_state_update(
).unwrap()), StateUpdate::SubScene(SubScenes::ScreenWithUpperRight)); serde_json::from_str(
"{\"type\": \"update\", \"update\": \"SubScene\", \"data\": \"Screen_Top_Right\"}"
)
.unwrap()
),
StateUpdate::SubScene(SubScenes::ScreenWithUpperRight)
);
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str(
"{\"type\": \"update\", \"update\": \"SubScene\", \"data\":\"Screen_Bottom_Right\"}" "{\"type\": \"update\", \"update\": \"SubScene\", \"data\":\"Screen_Bottom_Right\"}"
).unwrap()), StateUpdate::SubScene(SubScenes::ScreenWithLowerRight)); ).unwrap()), StateUpdate::SubScene(SubScenes::ScreenWithLowerRight));
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str(
"{\"type\": \"update\", \"update\": \"Timer_Length\", \"data\": \"5.5\"}"
).unwrap()), StateUpdate::TimerLength(5.5));
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(
"{\"type\": \"update\", \"update\": \"Next_Slide\"}" StateUpdate::json_to_state_update(
).unwrap()), StateUpdate::ChangeSlide(SlideChange::NextHotkey)); serde_json::from_str(
"{\"type\": \"update\", \"update\": \"Timer_Length\", \"data\": \"5.5\"}"
)
.unwrap()
),
StateUpdate::TimerLength(5.5)
);
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(
"{\"type\": \"update\", \"update\": \"Prev_Slide\"}" StateUpdate::json_to_state_update(
).unwrap()), StateUpdate::ChangeSlide(SlideChange::PreviousHotkey)); serde_json::from_str("{\"type\": \"update\", \"update\": \"Next_Slide\"}").unwrap()
),
StateUpdate::ChangeSlide(SlideChange::NextHotkey)
);
assert_eq!(StateUpdate::json_to_state_update(serde_json::from_str( assert_eq!(
"{\"type\": \"update\", \"update\":\"all\"}" StateUpdate::json_to_state_update(
).unwrap()), StateUpdate::UpdateClient); serde_json::from_str("{\"type\": \"update\", \"update\": \"Prev_Slide\"}").unwrap()
),
StateUpdate::ChangeSlide(SlideChange::PreviousHotkey)
);
assert_eq!(
StateUpdate::json_to_state_update(
serde_json::from_str("{\"type\": \"update\", \"update\":\"all\"}").unwrap()
),
StateUpdate::UpdateClient
);
} }
#[test] #[test]
#[should_panic] #[should_panic]
fn test_json_to_state_update_fails() { fn test_json_to_state_update_fails() {
StateUpdate::json_to_state_update(serde_json::from_str( StateUpdate::json_to_state_update(
"{\"type\": \"AnUnknownType\"}" serde_json::from_str("{\"type\": \"AnUnknownType\"}").unwrap(),
).unwrap()); );
} }
#[test] #[test]
fn test_state_update_to_json() { fn test_state_update_to_json() {
//Note, this one needs to is dependant on test_json_to_update for correctedness //Note, this one needs to is dependant on test_json_to_update for correctedness
assert_eq!(StateUpdate::StreamRunning(true), (StateUpdate::json_to_state_update(StateUpdate::StreamRunning(true).to_json()))); assert_eq!(
assert_eq!(StateUpdate::StreamRunning(false), StateUpdate::json_to_state_update(StateUpdate::StreamRunning(false).to_json())); StateUpdate::StreamRunning(true),
assert_eq!(StateUpdate::StreamSoundToggleOn(true), StateUpdate::json_to_state_update(StateUpdate::StreamSoundToggleOn(true).to_json())); (StateUpdate::json_to_state_update(StateUpdate::StreamRunning(true).to_json()))
assert_eq!(StateUpdate::StreamSoundToggleOn(false), StateUpdate::json_to_state_update(StateUpdate::StreamSoundToggleOn(false).to_json())); );
assert_eq!(StateUpdate::ToggleComputerSoundOn(true), StateUpdate::json_to_state_update(StateUpdate::ToggleComputerSoundOn(true).to_json())); assert_eq!(
assert_eq!(StateUpdate::ToggleComputerSoundOn(false), StateUpdate::json_to_state_update(StateUpdate::ToggleComputerSoundOn(false).to_json())); StateUpdate::StreamRunning(false),
assert_eq!(StateUpdate::ChangeSceneOnChangeSlide(true), StateUpdate::json_to_state_update(StateUpdate::ChangeSceneOnChangeSlide(true).to_json())); StateUpdate::json_to_state_update(StateUpdate::StreamRunning(false).to_json())
assert_eq!(StateUpdate::ChangeSceneOnChangeSlide(false), StateUpdate::json_to_state_update(StateUpdate::ChangeSceneOnChangeSlide(false).to_json())); );
assert_eq!(StateUpdate::SceneIsAugmented(true), StateUpdate::json_to_state_update(StateUpdate::SceneIsAugmented(true).to_json())); assert_eq!(
assert_eq!(StateUpdate::SceneIsAugmented(false), StateUpdate::json_to_state_update(StateUpdate::SceneIsAugmented(false).to_json())); StateUpdate::StreamSoundToggleOn(true),
assert_eq!(StateUpdate::TimerCanRun(true), StateUpdate::json_to_state_update(StateUpdate::TimerCanRun(true).to_json())); StateUpdate::json_to_state_update(StateUpdate::StreamSoundToggleOn(true).to_json())
assert_eq!(StateUpdate::TimerCanRun(false), StateUpdate::json_to_state_update(StateUpdate::TimerCanRun(false).to_json())); );
assert_eq!(StateUpdate::TimerLength(17.5), StateUpdate::json_to_state_update(StateUpdate::TimerLength(17.5).to_json())); assert_eq!(
assert_eq!(StateUpdate::TimerText(String::from("15.6")), StateUpdate::json_to_state_update(StateUpdate::TimerText(String::from("15.6")).to_json())); StateUpdate::StreamSoundToggleOn(false),
assert_eq!(StateUpdate::SubScene(SubScenes::CameraDefault), StateUpdate::json_to_state_update(StateUpdate::SubScene(SubScenes::CameraDefault).to_json())); StateUpdate::json_to_state_update(StateUpdate::StreamSoundToggleOn(false).to_json())
assert_eq!(StateUpdate::SubScene(SubScenes::CameraWithUpperRight), StateUpdate::json_to_state_update(StateUpdate::SubScene(SubScenes::CameraWithUpperRight).to_json())); );
assert_eq!(StateUpdate::SubScene(SubScenes::CameraWithLowerRight), StateUpdate::json_to_state_update(StateUpdate::SubScene(SubScenes::CameraWithLowerRight).to_json())); assert_eq!(
assert_eq!(StateUpdate::SubScene(SubScenes::CameraWithLargeUpperRight), StateUpdate::json_to_state_update(StateUpdate::SubScene(SubScenes::CameraWithLargeUpperRight).to_json())); StateUpdate::ToggleComputerSoundOn(true),
assert_eq!(StateUpdate::SubScene(SubScenes::ScreenDefault), StateUpdate::json_to_state_update(StateUpdate::SubScene(SubScenes::ScreenDefault).to_json())); StateUpdate::json_to_state_update(StateUpdate::ToggleComputerSoundOn(true).to_json())
assert_eq!(StateUpdate::SubScene(SubScenes::ScreenWithUpperRight), StateUpdate::json_to_state_update(StateUpdate::SubScene(SubScenes::ScreenWithUpperRight).to_json())); );
assert_eq!(StateUpdate::SubScene(SubScenes::ScreenWithLowerRight), StateUpdate::json_to_state_update(StateUpdate::SubScene(SubScenes::ScreenWithLowerRight).to_json())); assert_eq!(
assert_eq!(StateUpdate::Scene(Scenes::Camera), StateUpdate::json_to_state_update(StateUpdate::Scene(Scenes::Camera).to_json())); StateUpdate::ToggleComputerSoundOn(false),
assert_eq!(StateUpdate::Scene(Scenes::Screen), StateUpdate::json_to_state_update(StateUpdate::Scene(Scenes::Screen).to_json())); StateUpdate::json_to_state_update(StateUpdate::ToggleComputerSoundOn(false).to_json())
assert_eq!(StateUpdate::ChangeSlide(SlideChange::NextHotkey), StateUpdate::json_to_state_update(StateUpdate::ChangeSlide(SlideChange::NextHotkey).to_json())); );
assert_eq!(StateUpdate::ChangeSlide(SlideChange::PreviousHotkey), StateUpdate::json_to_state_update(StateUpdate::ChangeSlide(SlideChange::PreviousHotkey).to_json())); assert_eq!(
assert_eq!(StateUpdate::UpdateClient, StateUpdate::json_to_state_update(StateUpdate::UpdateClient.to_json())); StateUpdate::ChangeSceneOnChangeSlide(true),
StateUpdate::json_to_state_update(StateUpdate::ChangeSceneOnChangeSlide(true).to_json())
} );
assert_eq!(
StateUpdate::ChangeSceneOnChangeSlide(false),
StateUpdate::json_to_state_update(StateUpdate::ChangeSceneOnChangeSlide(false).to_json())
);
assert_eq!(
StateUpdate::SceneIsAugmented(true),
StateUpdate::json_to_state_update(StateUpdate::SceneIsAugmented(true).to_json())
);
assert_eq!(
StateUpdate::SceneIsAugmented(false),
StateUpdate::json_to_state_update(StateUpdate::SceneIsAugmented(false).to_json())
);
assert_eq!(
StateUpdate::TimerCanRun(true),
StateUpdate::json_to_state_update(StateUpdate::TimerCanRun(true).to_json())
);
assert_eq!(
StateUpdate::TimerCanRun(false),
StateUpdate::json_to_state_update(StateUpdate::TimerCanRun(false).to_json())
);
assert_eq!(
StateUpdate::TimerLength(17.5),
StateUpdate::json_to_state_update(StateUpdate::TimerLength(17.5).to_json())
);
assert_eq!(
StateUpdate::TimerText(String::from("15.6")),
StateUpdate::json_to_state_update(StateUpdate::TimerText(String::from("15.6")).to_json())
);
assert_eq!(
StateUpdate::SubScene(SubScenes::CameraDefault),
StateUpdate::json_to_state_update(
StateUpdate::SubScene(SubScenes::CameraDefault).to_json()
)
);
assert_eq!(
StateUpdate::SubScene(SubScenes::CameraWithUpperRight),
StateUpdate::json_to_state_update(
StateUpdate::SubScene(SubScenes::CameraWithUpperRight).to_json()
)
);
assert_eq!(
StateUpdate::SubScene(SubScenes::CameraWithLowerRight),
StateUpdate::json_to_state_update(
StateUpdate::SubScene(SubScenes::CameraWithLowerRight).to_json()
)
);
assert_eq!(
StateUpdate::SubScene(SubScenes::CameraWithLargeUpperRight),
StateUpdate::json_to_state_update(
StateUpdate::SubScene(SubScenes::CameraWithLargeUpperRight).to_json()
)
);
assert_eq!(
StateUpdate::SubScene(SubScenes::ScreenDefault),
StateUpdate::json_to_state_update(
StateUpdate::SubScene(SubScenes::ScreenDefault).to_json()
)
);
assert_eq!(
StateUpdate::SubScene(SubScenes::ScreenWithUpperRight),
StateUpdate::json_to_state_update(
StateUpdate::SubScene(SubScenes::ScreenWithUpperRight).to_json()
)
);
assert_eq!(
StateUpdate::SubScene(SubScenes::ScreenWithLowerRight),
StateUpdate::json_to_state_update(
StateUpdate::SubScene(SubScenes::ScreenWithLowerRight).to_json()
)
);
assert_eq!(
StateUpdate::Scene(Scenes::Camera),
StateUpdate::json_to_state_update(StateUpdate::Scene(Scenes::Camera).to_json())
);
assert_eq!(
StateUpdate::Scene(Scenes::Screen),
StateUpdate::json_to_state_update(StateUpdate::Scene(Scenes::Screen).to_json())
);
assert_eq!(
StateUpdate::ChangeSlide(SlideChange::NextHotkey),
StateUpdate::json_to_state_update(
StateUpdate::ChangeSlide(SlideChange::NextHotkey).to_json()
)
);
assert_eq!(
StateUpdate::ChangeSlide(SlideChange::PreviousHotkey),
StateUpdate::json_to_state_update(
StateUpdate::ChangeSlide(SlideChange::PreviousHotkey).to_json()
)
);
assert_eq!(
StateUpdate::UpdateClient,
StateUpdate::json_to_state_update(StateUpdate::UpdateClient.to_json())
);
}

View file

@ -39,62 +39,124 @@ fn create_stream_states_class() {
assert_eq!(stream_state.timer_can_run, true); assert_eq!(stream_state.timer_can_run, true);
assert_eq!(stream_state.current_scene, s_s::scenes::Scenes::Camera); assert_eq!(stream_state.current_scene, s_s::scenes::Scenes::Camera);
assert_eq!(stream_state.camera_sub_scene, s_s::scenes::SubScenes::CameraDefault); assert_eq!(
assert_eq!(stream_state.screen_sub_scene, s_s::scenes::SubScenes::ScreenDefault); stream_state.camera_sub_scene,
s_s::scenes::SubScenes::CameraDefault
);
assert_eq!(
stream_state.screen_sub_scene,
s_s::scenes::SubScenes::ScreenDefault
);
} }
#[test] #[test]
fn scene_correctness(){ fn scene_correctness() {
let mut stream_state = s_s::stream_state::StreamState::new(); let mut stream_state = s_s::stream_state::StreamState::new();
assert_eq!(stream_state.current_scene, s_s::scenes::Scenes::Camera); assert_eq!(stream_state.current_scene, s_s::scenes::Scenes::Camera);
assert_eq!(stream_state.camera_sub_scene, s_s::scenes::SubScenes::CameraDefault); assert_eq!(
assert_eq!(stream_state.screen_sub_scene, s_s::scenes::SubScenes::ScreenDefault); stream_state.camera_sub_scene,
s_s::scenes::SubScenes::CameraDefault
);
assert_eq!(
stream_state.screen_sub_scene,
s_s::scenes::SubScenes::ScreenDefault
);
stream_state.update(StateUpdate::SubScene(s_s::scenes::SubScenes::CameraWithUpperRight)); stream_state.update(StateUpdate::SubScene(
s_s::scenes::SubScenes::CameraWithUpperRight,
));
assert_eq!(stream_state.camera_sub_scene, s_s::scenes::SubScenes::CameraWithUpperRight); assert_eq!(
assert_eq!(stream_state.screen_sub_scene, s_s::scenes::SubScenes::ScreenDefault); stream_state.camera_sub_scene,
s_s::scenes::SubScenes::CameraWithUpperRight
);
assert_eq!(
stream_state.screen_sub_scene,
s_s::scenes::SubScenes::ScreenDefault
);
stream_state.update(StateUpdate::SubScene(s_s::scenes::SubScenes::CameraWithLargeUpperRight)); stream_state.update(StateUpdate::SubScene(
s_s::scenes::SubScenes::CameraWithLargeUpperRight,
));
assert_eq!(stream_state.camera_sub_scene, s_s::scenes::SubScenes::CameraWithLargeUpperRight); assert_eq!(
assert_eq!(stream_state.screen_sub_scene, s_s::scenes::SubScenes::ScreenDefault); stream_state.camera_sub_scene,
s_s::scenes::SubScenes::CameraWithLargeUpperRight
);
assert_eq!(
stream_state.screen_sub_scene,
s_s::scenes::SubScenes::ScreenDefault
);
stream_state.update(StateUpdate::SubScene(s_s::scenes::SubScenes::CameraWithLowerRight)); stream_state.update(StateUpdate::SubScene(
s_s::scenes::SubScenes::CameraWithLowerRight,
));
assert_eq!(stream_state.camera_sub_scene, s_s::scenes::SubScenes::CameraWithLowerRight); assert_eq!(
assert_eq!(stream_state.screen_sub_scene, s_s::scenes::SubScenes::ScreenDefault); stream_state.camera_sub_scene,
s_s::scenes::SubScenes::CameraWithLowerRight
);
assert_eq!(
stream_state.screen_sub_scene,
s_s::scenes::SubScenes::ScreenDefault
);
stream_state.update(StateUpdate::SubScene(s_s::scenes::SubScenes::ScreenDefault)); stream_state.update(StateUpdate::SubScene(s_s::scenes::SubScenes::ScreenDefault));
stream_state.update(StateUpdate::Scene(s_s::scenes::Scenes::Screen)); stream_state.update(StateUpdate::Scene(s_s::scenes::Scenes::Screen));
assert_eq!(stream_state.current_scene, s_s::scenes::Scenes::Screen); assert_eq!(stream_state.current_scene, s_s::scenes::Scenes::Screen);
assert_eq!(stream_state.screen_sub_scene, s_s::scenes::SubScenes::ScreenDefault); assert_eq!(
assert_eq!(stream_state.camera_sub_scene, s_s::scenes::SubScenes::CameraWithLowerRight); stream_state.screen_sub_scene,
s_s::scenes::SubScenes::ScreenDefault
);
assert_eq!(
stream_state.camera_sub_scene,
s_s::scenes::SubScenes::CameraWithLowerRight
);
stream_state.update(StateUpdate::SubScene(s_s::scenes::SubScenes::ScreenWithLowerRight)); stream_state.update(StateUpdate::SubScene(
s_s::scenes::SubScenes::ScreenWithLowerRight,
assert_eq!(stream_state.screen_sub_scene, s_s::scenes::SubScenes::ScreenWithLowerRight); ));
assert_eq!(stream_state.camera_sub_scene, s_s::scenes::SubScenes::CameraWithLowerRight);
stream_state.update(StateUpdate::SubScene(s_s::scenes::SubScenes::ScreenWithUpperRight)); assert_eq!(
stream_state.screen_sub_scene,
assert_eq!(stream_state.screen_sub_scene, s_s::scenes::SubScenes::ScreenWithUpperRight); s_s::scenes::SubScenes::ScreenWithLowerRight
assert_eq!(stream_state.camera_sub_scene, s_s::scenes::SubScenes::CameraWithLowerRight); );
assert_eq!(
stream_state.camera_sub_scene,
s_s::scenes::SubScenes::CameraWithLowerRight
);
stream_state.update(StateUpdate::SubScene(
s_s::scenes::SubScenes::ScreenWithUpperRight,
));
assert_eq!(
stream_state.screen_sub_scene,
s_s::scenes::SubScenes::ScreenWithUpperRight
);
assert_eq!(
stream_state.camera_sub_scene,
s_s::scenes::SubScenes::CameraWithLowerRight
);
stream_state.update(StateUpdate::Scene(s_s::scenes::Scenes::Augmented)); stream_state.update(StateUpdate::Scene(s_s::scenes::Scenes::Augmented));
assert_eq!(stream_state.current_scene, s_s::scenes::Scenes::Augmented); assert_eq!(stream_state.current_scene, s_s::scenes::Scenes::Augmented);
assert_eq!(stream_state.screen_sub_scene, s_s::scenes::SubScenes::ScreenWithUpperRight); assert_eq!(
assert_eq!(stream_state.camera_sub_scene, s_s::scenes::SubScenes::CameraWithLowerRight); stream_state.screen_sub_scene,
s_s::scenes::SubScenes::ScreenWithUpperRight
);
assert_eq!(
stream_state.camera_sub_scene,
s_s::scenes::SubScenes::CameraWithLowerRight
);
} }
#[test] #[test]
fn test_updating() { fn test_updating() {
let mut stream_state = s_s::stream_state::StreamState::new(); let mut stream_state = s_s::stream_state::StreamState::new();
assert_eq!(stream_state.timer_can_run, true); assert_eq!(stream_state.timer_can_run, true);
stream_state.update(StateUpdate::TimerCanRun(false)); stream_state.update(StateUpdate::TimerCanRun(false));
assert_eq!(stream_state.timer_can_run, false); assert_eq!(stream_state.timer_can_run, false);
@ -128,7 +190,6 @@ fn test_updating() {
assert_eq!(stream_state.scene_is_augmented, true); assert_eq!(stream_state.scene_is_augmented, true);
} }
#[test] #[test]
fn can_run_in_thread() { fn can_run_in_thread() {
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
@ -149,4 +210,4 @@ fn can_run_in_thread() {
Ok(_) => return, Ok(_) => return,
Err(_) => panic!(), Err(_) => panic!(),
} }
} }