#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use std::path::PathBuf;
use eframe::egui;
use egui::{TextEdit, Vec2};
use crate::parser::{get_duckyscript_tokens, DuckyScript, DuckyScriptError};
use crate::vm::DuckyScriptVm;
enum ScriptState {
Loaded(DuckyScript),
Error(String),
}
#[derive(Default, Clone, Copy, PartialEq, Eq)]
enum Page {
#[default]
VmRun,
RemoteRun
}
#[derive(Default)]
pub struct DuckyScriptGui {
script_path: std::path::PathBuf,
code: String,
parsed_script: Option<ScriptState>,
page: Page,
}
impl eframe::App for DuckyScriptGui {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.horizontal(|ui| {
self.file_selector(ui);
});
ui.separator();
self.error(ctx, ui);
let tabs = [
("test-run", Page::VmRun),
("run remotely", Page::RemoteRun),
];
ui.horizontal(|ui| {
for ( label, p) in tabs.iter() {
if ui
.add_enabled(*p != self.page, egui::Button::new(*label))
.clicked()
{
self.page = *p;
}
}
});
ui.separator();
match self.page {
Page::VmRun => {
self.test_run(ctx, ui);
},
Page::RemoteRun => {
self.remote_run(ctx, ui);
}
}
});
}
}
impl DuckyScriptGui {
fn test_run(&mut self, ctx: &egui::Context, ui: &mut egui::Ui) {
ui.label("Run script in vm without executng any keyboard events");
}
fn remote_run(&mut self, ctx: &egui::Context, ui: &mut egui::Ui) {
ui.label("Run on a remote device");
}
fn error(&mut self, ctx: &egui::Context, _: &mut egui::Ui) {
let mut clear_script = false;
if let Some(ScriptState::Error(e)) = &self.parsed_script {
egui::Window::new("Parse Error").show(ctx, |ui| {
ui.text_edit_multiline(&mut e.as_ref());
clear_script = ui.button("Close").clicked();
});
}
if clear_script {
self.parsed_script = None;
}
}
fn file_selector(&mut self, ui: &mut egui::Ui) {
ui.with_layout(egui::Layout::right_to_left(egui::Align::RIGHT), |ui| {
if ui.button("Open fileā¦").clicked() {
if let Some(path) = rfd::FileDialog::new().pick_file() {
self.load_script( path);
}
}
ui.add_sized(
ui.available_size(),
TextEdit::singleline(&mut self.script_path.to_str().unwrap_or(""))
.hint_text("Select a ducky script"),
);
});
}
fn load_script(&mut self, path: PathBuf) {
let code = match std::fs::read_to_string(&path) {
Ok( c) => c,
Err(e) => {
self.parsed_script = Some(ScriptState::Error(e.to_string()));
return;
}
};
match get_duckyscript_tokens(&code) {
Ok(tokens) => {
self.script_path = path;
self.parsed_script = Some(ScriptState::Loaded(DuckyScript::parse_tokens(tokens)));
self.code = code;
}
Err(e) => {
self.parsed_script = Some(ScriptState::Error(e.to_string()));
}
}
}
}