Skip to content

Commit

Permalink
Custom Hotkeys
Browse files Browse the repository at this point in the history
  • Loading branch information
Mikachu2333 authored Jun 7, 2024
1 parent a70b93a commit 399bad9
Show file tree
Hide file tree
Showing 3 changed files with 260 additions and 69 deletions.
5 changes: 2 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "sc_starter"
version = "1.0.0"
version = "1.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand All @@ -11,10 +11,9 @@ opt-level = "z"
strip = true

[dependencies]
sha3 = "0.10.8"
directories = "5.0.1"
rust-embed = { version = "8.4.0", default-features = false, features = [
"compression",
] }
#tray-icon = { version = "0.14.3", default-features = false }
windows-hotkeys = "0.2.1"
fslock = "0.2.1"
36 changes: 36 additions & 0 deletions res/config.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
Win+Alt=V
Win+Alt=C
Win+Ctrl+Shift=VK_ESCAPE
Ctrl+Alt=O

# 设置文件使用说明:
#
# ①设置内容不区分大小写,必须按照指定格式书写,否则将无法设置成功
#
#
# ②设置文件共4行,不可更改格式,不可删除其中任意一行
# 第一行:控制截屏
# 第二行:从剪贴板中的图像钉到屏幕
# 第三行:退出软件
# 第四行:打开配置文件
#
#
# ③格式如下:
# 「控制键1」+「控制键2」+「……」=「实际键」
# 【⚠️注意】:为了避免您设定的快捷键与当前系统中其他软件使用的快捷键冲突,请至少选定两个「控制键」,且尽量不要使用「Ctrl」+「Shift」=「X」样式的快捷键。
#
# 可用的控制键列表如下(大小写均可):
# WIN / WINDOWS / SUPER
# CTRL / CONTROL
# ALT
# SHIFT
#
# 可用的实际键列表如下:
# A -> Z
# a -> z
# 0 -> 9
# VK_TAB
# VK_ESCAPE
# VK_INSERT
# VK_NUMPAD0 -> VK_NUMPAD9
# VK_F1 -> VK_F24
288 changes: 222 additions & 66 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use directories::BaseDirs;
use fslock::LockFile;
use rust_embed::*;
use sha3::{Digest, Sha3_256};
use std::{
fs::{self, File},
io::{Read, Write},
io::Read,
os::windows::fs::MetadataExt,
path::PathBuf,
process::{exit, Command},
thread::{self, JoinHandle},
Expand All @@ -16,106 +15,263 @@ use windows_hotkeys::{
HotkeyManagerImpl,
};

fn check_res_exist() -> (bool, bool, PathBuf) {
// 测试是否存在或需要替换exe文件
// (if_res_exist, if_res_latest, res_path)
let mut path_for_res =
PathBuf::from(BaseDirs::new().unwrap().data_local_dir()).join("SC_starter");
if !path_for_res.exists() {
let _ = fs::create_dir_all(&path_for_res);
};
#[derive(Clone, Copy, Debug)]
struct FileExist {
exe_exist: bool,
exe_latest: bool,
conf_exist: bool,
}

let lock_path = path_for_res.join("lock_file");
if !lock_path.exists() {
let _ = File::create(&lock_path).unwrap().write_all(b"Lock");
#[derive(Clone)]
struct PathInfos {
dir_path: PathBuf,
exe_path: PathBuf,
conf_path: PathBuf,
}
impl std::fmt::Display for PathInfos {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"dir: {:?}\nexe: {:?}\nconf: {:?}\n",
self.dir_path, self.exe_path, self.conf_path
)
}
}
#[derive(Clone)]
struct KeyStringGroups {
mod_keys: Vec<String>,
vkey: String,
}
#[derive(Clone, Debug)]
struct KeyVkGroups {
mod_keys: Vec<ModKey>,
vkey: VKey,
}

path_for_res.push("ScreenCapture.exe");
let if_exist_exe = path_for_res.exists();
fn check_res_exist(infos: &PathInfos) -> FileExist {
// 测试是否存在或需要替换exe文件
let mut files_exist = FileExist {
exe_exist: false,
exe_latest: false,
conf_exist: false,
};
if !infos.dir_path.exists() {
let _ = fs::create_dir_all(&infos.dir_path);
};

let mut if_latest = false;
if if_exist_exe {
let read_sha3 = calc_sha3_256(&path_for_res);
if read_sha3 == "A6BA93853EAFD5ECFBB26CEEABE3BABA9F2C0AD1D5FEDECF0A7966A5ECCF1380".to_lowercase() {
if_latest = true;
files_exist.exe_exist = infos.exe_path.exists();
files_exist.conf_exist = infos.conf_path.exists();

if files_exist.exe_exist {
files_exist.exe_exist = true;
if check_exe_latest(&infos.exe_path) {
files_exist.exe_latest = true;
} else {
if_latest = false;
files_exist.exe_latest = false;
}
}

return (if_exist_exe, if_latest, path_for_res);
files_exist
}

fn calc_sha3_256(file_path: &PathBuf) -> String {
let mut file = File::open(file_path).expect("无法打开文件");
let mut buffer = Vec::new();
file.read_to_end(&mut buffer).expect("无法读取文件内容");

let mut hasher = Sha3_256::new();
hasher.update(&buffer);
let result = hasher.finalize();

format!("{:x}", result)
fn check_exe_latest(file_path: &PathBuf) -> bool {
let in_size = file_path.metadata().unwrap().file_size();
let original_size: u64 = 3905024;
if in_size == original_size {
return true;
} else {
return false;
}
}

fn unzip_res(res_path: &PathBuf) {
fn unzip_res(paths: &PathInfos, exists: &FileExist) {
#[derive(Embed)]
#[folder = "res/"]
struct Asset;
let screen_capture_res =
Asset::get("ScreenCapture.exe").expect("Error read embedded res file.");
Asset::get("ScreenCapture.exe").expect("Error read embedded EXE res file.");
let config_res = Asset::get("config.txt").expect("Error read embedded Config res file.");

let _ = fs::write(res_path, screen_capture_res.data.as_ref());
if (!exists.exe_exist) || (!exists.exe_latest) {
let _ = fs::write(&paths.exe_path, screen_capture_res.data.as_ref());
}
if !exists.conf_exist {
let _ = fs::write(&paths.conf_path, config_res.data.as_ref());
}

println!("Finish release Exe.");
}

fn set_hotkeys(exe_path: &PathBuf) -> JoinHandle<()> {
let exe_path = exe_path.to_owned().clone();
fn operate_exe(path: &PathBuf, mode: u8) {
match mode {
0 => {
exit(0);
}
1 => {
Command::new(&path).spawn().unwrap();
}
2 => {
Command::new(&path).arg("--pin:clipboard").spawn().unwrap();
}
3 => {
Command::new("explorer.exe").arg(&path).spawn().unwrap();
}
_ => (),
}
}

fn set_hotkeys(
exe_path: &PathBuf,
conf_path: &PathBuf,
key_groups: Vec<KeyVkGroups>,
) -> JoinHandle<()> {
let exe_path = exe_path.clone();
let conf_path = conf_path.clone();
let key_groups = key_groups.clone();
thread::spawn(move || {
let exe_path = exe_path.clone();
let res_path = exe_path.clone();
let key_groups = key_groups;
let mut hkm = HotkeyManager::new();
hkm.register(VKey::V, &[ModKey::Win, ModKey::Alt], move || {
Command::new(&exe_path).spawn().unwrap();
hkm.register(key_groups[0].vkey, &key_groups[0].mod_keys, move || {
operate_exe(&exe_path, 1);
})
.unwrap();

hkm.register(VKey::C, &[ModKey::Win, ModKey::Alt], move || {
let _ = Command::new(&res_path)
.arg("--pin:clipboard")
.spawn()
.unwrap();
hkm.register(key_groups[1].vkey, &key_groups[1].mod_keys, move || {
operate_exe(&res_path, 2);
})
.unwrap();

hkm.register(VKey::Escape, &[ModKey::Win, ModKey::Alt], move || {
exit(0);
hkm.register(key_groups[2].vkey, &key_groups[2].mod_keys, move || {
operate_exe(&PathBuf::new(), 0);
})
.unwrap();

hkm.register(key_groups[3].vkey, &key_groups[3].mod_keys, move || {
operate_exe(&conf_path, 3);
})
.unwrap();

hkm.event_loop();
})
}

fn main() {
// 检测是否存在并释放
let (if_res_exist, if_res_latest, res_path) = check_res_exist();
let dir_path = res_path.parent().unwrap().to_path_buf();

let mut lock_file = LockFile::open(&dir_path.join("lock_file")).unwrap();
lock_file.lock().unwrap();

if !if_res_exist {
println!("Exe Not exist.");
unzip_res(&res_path);
} else if !if_res_latest {
println!("Exe exist, Not latest.");
unzip_res(&res_path);
} else {
println!("Exe exist, Latest.");
fn match_keys(groups: KeyStringGroups) -> (bool, KeyVkGroups) {
let group1 = groups.mod_keys;
let group2 = groups.vkey;
let mut results_mod: Vec<ModKey> = Vec::new();

for i in &group1 {
let tmp = match ModKey::from_keyname(i) {
Ok(mod_key) => mod_key,
Err(_) => ModKey::NoRepeat,
};
results_mod.push(tmp);
}

let handler = set_hotkeys(&res_path);
let result_vk = match VKey::from_keyname(&group2) {
Ok(vk_key) => vk_key,
Err(_) => VKey::OemClear,
};

let mut success = true;
for i in &results_mod {
if *i == ModKey::NoRepeat {
success = false;
}
}

if result_vk == VKey::OemClear {
success = false;
}

let struct_pack = |x: Vec<ModKey>, y: VKey| {
let tmp = KeyVkGroups {
mod_keys: x,
vkey: y,
};
tmp
};
let temp: KeyVkGroups = struct_pack(results_mod, result_vk);
return (success, temp);
}

fn read_config(conf_path: &PathBuf) -> Vec<KeyVkGroups> {
//Default
let default_setting: Vec<KeyVkGroups> = Vec::from([
KeyVkGroups {
mod_keys: Vec::from([ModKey::Win, ModKey::Alt]),
vkey: VKey::V,
},
KeyVkGroups {
mod_keys: Vec::from([ModKey::Win, ModKey::Alt]),
vkey: VKey::C,
},
KeyVkGroups {
mod_keys: Vec::from([ModKey::Win, ModKey::Ctrl, ModKey::Shift]),
vkey: VKey::Escape,
},
KeyVkGroups {
mod_keys: Vec::from([ModKey::Ctrl, ModKey::Alt]),
vkey: VKey::O,
},
]);
//读取配置
let mut f = File::open(conf_path).unwrap();
let mut full_content = String::new();
let _ = f.read_to_string(&mut full_content);
let full_content: Vec<&str> = full_content.split("\n").collect();
let usefull_content: Vec<&str> = full_content[..4].to_vec();

let struct_pack = |x: Vec<String>, y: String| {
let tmp = KeyStringGroups {
mod_keys: x,
vkey: y,
};
tmp
};

let mut groups: Vec<KeyStringGroups> = Vec::new();
for i in usefull_content {
let sum_keys: Vec<String> = i.split("=").map(String::from).collect();
let mod_keys: Vec<String> = sum_keys[0].split("+").map(String::from).collect();
groups.push(struct_pack(mod_keys, sum_keys[1].clone()));
}

let mut result_groups: Vec<KeyVkGroups> = Vec::new();
let mut count: usize = 0;
for i in groups {
let (status, result) = match_keys(i);
//println!("{} {:?}",&status,&result);
if status {
result_groups.push(result);
} else {
result_groups.push(default_setting[count].clone());
}
count += 1;
}

result_groups
}

fn main() {
//Init
let mut path_infos = PathInfos {
dir_path: PathBuf::from(BaseDirs::new().unwrap().data_local_dir()).join("SC_starter"),
exe_path: PathBuf::new(),
conf_path: PathBuf::new(),
};
path_infos.exe_path = path_infos.dir_path.join("ScreenCapture.exe");
path_infos.conf_path = path_infos.dir_path.join("config.txt");
//println!("{}", &path_infos);

let exist_result = check_res_exist(&path_infos);
//println!("{:?}", &exist_result);
unzip_res(&path_infos, &exist_result);

//Read Setting
let settings = read_config(&path_infos.conf_path);
println!("{:?}", &settings);
//Set Hotkeys
let handler = set_hotkeys(&path_infos.exe_path, &path_infos.conf_path, settings);
handler.join().unwrap();
}

0 comments on commit 399bad9

Please sign in to comment.