Skip to content

Commit

Permalink
working shortcut keybinds
Browse files Browse the repository at this point in the history
  • Loading branch information
jhideki committed Apr 1, 2024
1 parent 36d3469 commit adaf7de
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 21 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ edition = "2021"

[dependencies]
crossbeam-channel = "0.5"
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }

[dependencies.windows]
version = "0.54"
Expand Down
101 changes: 96 additions & 5 deletions core/src/keybinds.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::user_config::Config;
use crate::window_manager::{Direction, WindowManagerMessage};

use std::io::Error;
use std::path::PathBuf;
use std::process::Command;
use std::sync::mpsc::Sender;
use std::sync::Arc;

Expand All @@ -9,17 +12,28 @@ use windows::Win32::UI::Input::KeyboardAndMouse::{
};

//Hotkey indentifies

const LEADER: i32 = 0;
const EXIT: i32 = 1;
const SWITCH_LEFT: i32 = 2;
const SWITCH_RIGHT: i32 = 3;
const SWITCH_ABOVE: i32 = 4;
const SWITCH_BELOW: i32 = 5;
const SWITCH_NEXT: i32 = 6;
const LEADER: i32 = 7;
const CLOSE_WINDOW: i32 = 8;
const SWITCH_PREVIOUS: i32 = 9;
const SHORTCUT_1: i32 = 10;
const SHORTCUT_2: i32 = 11;
const SHORTCUT_3: i32 = 12;
const SHORTCUT_4: i32 = 13;
const SHORTCUT_5: i32 = 14;
const SHORTCUT_6: i32 = 15;
const SHORTCUT_7: i32 = 16;
const SHORTCUT_8: i32 = 17;
const SHORTCUT_9: i32 = 18;
const SHORTCUT_10: i32 = 19;

//Keycode
//Keycodes
const KEY_H: u32 = 0x48;
const KEY_L: u32 = 0x4C;
const KEY_J: u32 = 0x4A;
Expand All @@ -32,20 +46,32 @@ const SHIFT: u32 = 0x10;
const SPACE: u32 = 0x20;
const ENTER: u32 = 0x0D;
const CAPS: u32 = 0x14;
const KEY_0: u32 = 0x30;
const KEY_1: u32 = 0x31;
const KEY_2: u32 = 0x32;
const KEY_3: u32 = 0x33;
const KEY_4: u32 = 0x34;
const KEY_5: u32 = 0x35;
const KEY_6: u32 = 0x36;
const KEY_7: u32 = 0x37;
const KEY_8: u32 = 0x38;
const KEY_9: u32 = 0x39;

pub fn handle_hotkey(
wparam: i32,
sender: &Arc<Sender<WindowManagerMessage>>,
leader_pressed: bool,
config: &Config,
) -> Result<bool, String> {
if !leader_pressed && wparam == LEADER {
println!("leader pressed");
match register_hotkeys() {
match register_hotkeys(config) {
Ok(_) => return Ok(true),
Err(e) => return Err(format!("Error: {}", e)),
};
}
if leader_pressed {
println!("leader pressed");
match wparam {
EXIT => {
if let Err(err) = sender.send(WindowManagerMessage::EndListener) {
Expand Down Expand Up @@ -96,6 +122,56 @@ pub fn handle_hotkey(
println!("Failed to send message: {}", err);
}
}
SHORTCUT_1 => {
let _ = Command::new(PathBuf::from(config.programs[0].clone()))
.status()
.expect("Failed to oppen program 1");
}
SHORTCUT_2 => {
let _ = Command::new(PathBuf::from(config.programs[1].clone()))
.status()
.expect("Failed to oppen program 1");
}
SHORTCUT_3 => {
let _ = Command::new(PathBuf::from(config.programs[2].clone()))
.status()
.expect("Failed to oppen program 1");
}
SHORTCUT_4 => {
let _ = Command::new(PathBuf::from(config.programs[3].clone()))
.status()
.expect("Failed to oppen program 1");
}
SHORTCUT_5 => {
let _ = Command::new(PathBuf::from(config.programs[4].clone()))
.status()
.expect("Failed to oppen program 1");
}
SHORTCUT_6 => {
let _ = Command::new(PathBuf::from(config.programs[5].clone()))
.status()
.expect("Failed to oppen program 1");
}
SHORTCUT_7 => {
let _ = Command::new(PathBuf::from(config.programs[6].clone()))
.status()
.expect("Failed to oppen program 1");
}
SHORTCUT_8 => {
let _ = Command::new(PathBuf::from(config.programs[7].clone()))
.status()
.expect("Failed to oppen program 1");
}
SHORTCUT_9 => {
let _ = Command::new(PathBuf::from(config.programs[8].clone()))
.status()
.expect("Failed to oppen program 1");
}
SHORTCUT_10 => {
let _ = Command::new(PathBuf::from(config.programs[9].clone()))
.status()
.expect("Failed to oppen program 1");
}
_ => {
println!("idk bru");
}
Expand All @@ -119,8 +195,19 @@ pub fn unregister_leader() {
let _ = UnregisterHotKey(None, LEADER);
}
}
fn register_hotkeys() -> Result<(), Error> {
fn register_hotkeys(config: &Config) -> Result<(), Error> {
unsafe {
for i in 0..config.programs.len() {
if config.programs[i] != "" {
if let Err(e) =
RegisterHotKey(None, i as i32 + 10, HOT_KEY_MODIFIERS(0), i as u32 + 0x31)
{
println!("failed to register key {}. Error: {}", i as u32 + 0x30, e);
} else {
println!("registered key {}", i + 0x30);
}
}
}
if let Err(_) = RegisterHotKey(None, EXIT, HOT_KEY_MODIFIERS(0), ESC) {
println!("failed to register ESC");
}
Expand Down Expand Up @@ -166,6 +253,10 @@ pub fn unregister_hotkeys() {
let _ = UnregisterHotKey(None, SWITCH_NEXT);
let _ = UnregisterHotKey(None, CLOSE_WINDOW);
let _ = UnregisterHotKey(None, SWITCH_PREVIOUS);
let _ = UnregisterHotKey(None, SWITCH_PREVIOUS);
// Unregister shortcuts
for i in 10..20 {
let _ = UnregisterHotKey(None, i as i32);
}
}
}

19 changes: 12 additions & 7 deletions core/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
mod callbacks;
mod keybinds;
mod user_config;
mod window;
mod window_manager;

use callbacks::win_event_proc;
use keybinds::{handle_hotkey, register_leader, unregister_leader};
use window_manager::{WindowManager, WindowManagerMessage};

use std::io::Error;
use std::error::Error;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{channel, Sender};
use std::sync::Arc;
Expand Down Expand Up @@ -69,16 +70,20 @@ fn spawn_hook(
}
}

fn key_listener(sender: Arc<Sender<WindowManagerMessage>>, callback_thread_id: u32) {
println!("key listener running...");
fn key_listener(
sender: Arc<Sender<WindowManagerMessage>>,
callback_thread_id: u32,
) -> Result<(), Box<dyn Error>> {
let config = user_config::read_config()?;

let mut leader_pressed = false;
unsafe {
let mut msg: MSG = MSG::default();
while GetMessageW(&mut msg, None, 0, 0).into() {
if msg.message == WM_HOTKEY {
HOTKEY_PRESSED.store(true, Ordering::Relaxed);
let wparam = msg.wParam.0 as i32;
match handle_hotkey(wparam, &sender, leader_pressed) {
match handle_hotkey(wparam, &sender, leader_pressed, &config) {
Ok(leader) => {
leader_pressed = leader;
}
Expand All @@ -95,9 +100,10 @@ fn key_listener(sender: Arc<Sender<WindowManagerMessage>>, callback_thread_id: u
}
}
}
Ok(())
}

fn main() -> Result<(), Error> {
fn main() -> Result<(), Box<dyn Error>> {
let (sender, receiver) = channel();
let sender_arc = Arc::new(sender);

Expand All @@ -118,13 +124,12 @@ fn main() -> Result<(), Error> {
let sender = Arc::clone(&sender_arc);
thread::spawn(move || spawn_hook(sender, thread_id_sender))
};
let callback_thread_id = callback_receiver.recv().unwrap();

let callback_thread_id = callback_receiver.recv().unwrap();
key_listener(Arc::clone(&sender_arc), callback_thread_id);

window_manger_listener.join().unwrap();
callback_listener.join().unwrap();
unregister_leader();
Ok(())
}

79 changes: 79 additions & 0 deletions core/src/user_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::env;
use std::error::Error;
use std::fs::{File, OpenOptions};
use std::io::Read;
use std::path::PathBuf;

#[derive(Serialize, Deserialize)]
pub struct Config {
pub programs: Vec<String>,
pub keybinds: HashMap<String, u32>,
}

impl Config {
fn new() -> Self {
let mut keybinds = HashMap::new();
keybinds.insert("left".to_string(), 0);
keybinds.insert("right".to_string(), 0);
keybinds.insert("down".to_string(), 0);
keybinds.insert("next".to_string(), 0);
keybinds.insert("prev".to_string(), 0);
keybinds.insert("above".to_string(), 0);
let programs: Vec<String> = vec!["".to_string(); 10];
Config { programs, keybinds }
}
}

pub fn read_config() -> Result<Config, Box<dyn Error>> {
let mut path = match get_path() {
Ok(path) => path,
Err(e) => return Err(e),
};
path.push("config.json");
println!("{:?}", path);
let mut file = match OpenOptions::new()
.write(true)
.read(true)
.create(true)
.open(&path)
{
Ok(file) => file,
Err(e) => {
return Err(format!("Error opening file {}", e).into());
}
};

let mut json_data = String::new();
if let Err(e) = file.read_to_string(&mut json_data) {
return Err(format!("Failed to read user data from file {}", e).into());
}

let config = match serde_json::from_str(&json_data) {
Ok(data) => data,
Err(_) => Config::new(),
};
Ok(config)
}

fn get_path() -> Result<PathBuf, Box<dyn Error>> {
let mut appdata_path = match env::var_os("LOCALAPPDATA") {
Some(path) => PathBuf::from(path),
None => {
eprintln!("Failed to retreive APPDATA env var");
return Err("Failed to retreive APPDATA env var".into());
}
};

if !appdata_path.exists() {
return Err(r"Appdata\Local does not exist".into());
}
appdata_path.push("whirlwin");
if !appdata_path.exists() {
if let Err(err) = std::fs::create_dir_all(&appdata_path) {
return Err("Failed to create whirlwin dir".into());
}
}
Ok(appdata_path)
}
9 changes: 3 additions & 6 deletions core/src/window_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use std::collections::HashSet;
use std::sync::mpsc::Receiver;
use windows::Win32::Foundation::{HWND, LPARAM};
use windows::Win32::UI::WindowsAndMessaging::{
CloseWindow, EnumWindows, GetForegroundWindow, SetForegroundWindow, SetWindowPos, HWND_BOTTOM,
SWP_NOMOVE, SWP_NOSIZE,
CloseWindow, EnumWindows, GetForegroundWindow, SendMessageW, SetForegroundWindow, SetWindowPos,
HWND_BOTTOM, SWP_NOMOVE, SWP_NOSIZE, WM_CLOSE,
};
pub enum Direction {
Left,
Expand Down Expand Up @@ -118,9 +118,7 @@ impl WindowManager {

fn close_window(&mut self) {
unsafe {
if let Err(e) = CloseWindow(self.current.hwnd) {
println!("Failed to close window {}", e);
}
let _ = SendMessageW(self.current.hwnd, WM_CLOSE, None, None);
}
if let Some(window) = &self.next {
self.current = window.to_owned();
Expand Down Expand Up @@ -237,4 +235,3 @@ impl WindowManager {
self.set_windows();
}
}

7 changes: 4 additions & 3 deletions src-tauri/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::collections::HashMap;
use std::env;
use std::error::Error;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::io::{Read, Seek, SeekFrom, Write};
use std::path::PathBuf;

#[derive(Serialize, Deserialize)]
Expand All @@ -27,6 +27,7 @@ impl Config {

fn write_to_file(&self, mut file: File) -> Result<(), Box<dyn Error>> {
let json_data = serde_json::to_string(self)?;
file.seek(SeekFrom::Start(0))?;
file.write_all(json_data.as_bytes())?;
Ok(())
}
Expand Down Expand Up @@ -69,7 +70,7 @@ pub fn set_data(shortcut: PathBuf, shortcut_num: usize) {
};

println!("programs size: {}", config.programs.len());
config.programs[shortcut_num] = shortcut.to_string_lossy().to_string();
config.programs[shortcut_num - 1] = shortcut.to_string_lossy().to_string();
if let Err(e) = config.write_to_file(file) {
eprintln!("Error writing to file: {}", e);
}
Expand All @@ -89,7 +90,7 @@ fn get_path() -> Result<PathBuf, Box<dyn Error>> {
}
appdata_path.push("whirlwin");
if !appdata_path.exists() {
if let Err(err) = std::fs::create_dir_all(&appdata_path) {
if let Err(_) = std::fs::create_dir_all(&appdata_path) {
return Err("Failed to create whirlwin dir".into());
}
}
Expand Down

0 comments on commit adaf7de

Please sign in to comment.