feat: latch to discord window
This commit is contained in:
parent
2c80d4a41d
commit
edc9db64de
4 changed files with 116 additions and 29 deletions
41
Cargo.lock
generated
41
Cargo.lock
generated
|
@ -2,26 +2,11 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.158"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||
|
||||
[[package]]
|
||||
name = "libc-print"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4a660208db49e35faf57b37484350f1a61072f2a5becf0592af6015d9ddd4b0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "muter"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libc-print",
|
||||
"thiserror",
|
||||
"windows",
|
||||
]
|
||||
|
||||
|
@ -45,15 +30,35 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.77"
|
||||
version = "2.0.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
|
||||
checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.13"
|
||||
|
|
11
Cargo.toml
11
Cargo.toml
|
@ -1,14 +1,21 @@
|
|||
[package]
|
||||
name = "muter"
|
||||
publish = false
|
||||
authors = ["newt <hi@newty.dev>"]
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
libc-print = "0.1.23"
|
||||
thiserror = "2.0.3"
|
||||
|
||||
[dependencies.windows]
|
||||
version = "0.58.0"
|
||||
features = [
|
||||
"Win32_Media_Audio_Endpoints",
|
||||
"Win32_System_Com"
|
||||
|
||||
"Win32_System_Com",
|
||||
"Win32_System_Threading",
|
||||
|
||||
"Win32_UI_Input_KeyboardAndMouse",
|
||||
"Win32_UI_WindowsAndMessaging",
|
||||
]
|
||||
|
|
5
src/lib.rs
Normal file
5
src/lib.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("Failed to initialize COM library: {0}")]
|
||||
Windows(#[from] windows::core::Error),
|
||||
}
|
88
src/main.rs
88
src/main.rs
|
@ -1,15 +1,69 @@
|
|||
#![no_std]
|
||||
|
||||
use libc_print::std_name::println;
|
||||
use std::sync::atomic::{AtomicPtr, Ordering};
|
||||
use std::time::Duration;
|
||||
use std::{ptr, thread};
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::{
|
||||
MapVirtualKeyW, SendInput, INPUT, INPUT_0, INPUT_KEYBOARD, KEYBDINPUT, KEYBD_EVENT_FLAGS,
|
||||
KEYEVENTF_KEYUP, KEYEVENTF_SCANCODE, MAPVK_VK_TO_VSC,
|
||||
};
|
||||
use windows::Win32::UI::WindowsAndMessaging::{FindWindowExW, GetClassNameW, SetForegroundWindow};
|
||||
use windows::Win32::{
|
||||
Foundation::{BOOL, HWND, LPARAM, WPARAM},
|
||||
Media::Audio::{
|
||||
eCapture, eMultimedia, Endpoints::IAudioEndpointVolume, IMMDevice, IMMDeviceEnumerator,
|
||||
MMDeviceEnumerator,
|
||||
},
|
||||
System::Com::{CoCreateInstance, CoInitializeEx, CLSCTX_ALL, COINIT_MULTITHREADED},
|
||||
UI::{
|
||||
Input::KeyboardAndMouse::{VIRTUAL_KEY, VK_CONTROL, VK_M, VK_SHIFT},
|
||||
WindowsAndMessaging::{EnumWindows, GetWindowTextW, PostMessageW, WM_KEYDOWN, WM_KEYUP},
|
||||
},
|
||||
};
|
||||
|
||||
fn main() -> windows::core::Result<()> {
|
||||
static mut DISCORD_WHND: AtomicPtr<HWND> = AtomicPtr::new(ptr::null_mut());
|
||||
|
||||
unsafe extern "system" fn search_windows(hwnd: HWND, _: LPARAM) -> BOOL {
|
||||
let mut name = [0u16; 1024];
|
||||
let len = unsafe { GetWindowTextW(hwnd, &mut name) };
|
||||
let name = String::from_utf16_lossy(&name[..len as usize]);
|
||||
|
||||
if name.to_lowercase().contains(&"- discord".to_string()) {
|
||||
println!("Discord window found: {:?}", name);
|
||||
DISCORD_WHND.store(Box::into_raw(Box::new(hwnd)), Ordering::SeqCst);
|
||||
}
|
||||
|
||||
BOOL(1)
|
||||
}
|
||||
|
||||
unsafe fn press_keys(window: HWND, keys: &[VIRTUAL_KEY]) -> windows::core::Result<()> {
|
||||
let keys = keys.iter().map(|key| {
|
||||
(
|
||||
key.0 as usize,
|
||||
MapVirtualKeyW(key.0.into(), MAPVK_VK_TO_VSC) as isize,
|
||||
)
|
||||
});
|
||||
let down = keys
|
||||
.clone()
|
||||
.map(|(key, scan)| (WPARAM(key), LPARAM(scan << 16)))
|
||||
.collect::<Vec<_>>();
|
||||
let up = keys
|
||||
.map(|(key, scan)| (WPARAM(key), LPARAM(0x7FFF | (scan << 16) | (0b11 << 30))))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for (wparam, lparam) in down {
|
||||
println!("Pressing key: {:?}", wparam);
|
||||
PostMessageW(window, WM_KEYDOWN, wparam, lparam)?;
|
||||
}
|
||||
|
||||
thread::sleep(Duration::from_secs(10));
|
||||
|
||||
for (wparam, lparam) in up {
|
||||
PostMessageW(window, WM_KEYUP, wparam, lparam)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<(), muter::Error> {
|
||||
unsafe {
|
||||
// Initialize the COM library
|
||||
CoInitializeEx(None, COINIT_MULTITHREADED).unwrap();
|
||||
|
@ -24,6 +78,20 @@ fn main() -> windows::core::Result<()> {
|
|||
// Activate the IAudioEndpointVolume interface for the capture device
|
||||
let endpoint_volume: IAudioEndpointVolume = default_device.Activate(CLSCTX_ALL, None)?;
|
||||
|
||||
// Attach process to Discord
|
||||
EnumWindows(Some(search_windows), LPARAM(0))?;
|
||||
|
||||
let discord = {
|
||||
let hwnd = DISCORD_WHND.load(Ordering::SeqCst);
|
||||
|
||||
if hwnd.is_null() {
|
||||
println!("Discord window not found");
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
*hwnd
|
||||
};
|
||||
|
||||
// Check if the microphone is muted
|
||||
let mut is_muted = endpoint_volume.GetMute()?.as_bool();
|
||||
|
||||
|
@ -31,11 +99,13 @@ fn main() -> windows::core::Result<()> {
|
|||
let is_new_muted = endpoint_volume.GetMute()?.as_bool();
|
||||
if is_new_muted != is_muted {
|
||||
is_muted = is_new_muted;
|
||||
if is_muted {
|
||||
println!("Microphone is muted.");
|
||||
} else {
|
||||
println!("Microphone is not muted.");
|
||||
}
|
||||
println!(
|
||||
"Microphone is {}",
|
||||
if is_muted { "muted" } else { "unmuted" }
|
||||
);
|
||||
|
||||
// send keybind to discord (ctrl+shift+m)
|
||||
press_keys(discord, &[VK_CONTROL, VK_SHIFT, VK_M])?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue