Reorganize codebase into modular structure
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
// Windows platform mouse hook management
|
||||
|
||||
use std::ptr::null_mut;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::time::Instant;
|
||||
use winapi::{
|
||||
um::winuser::{
|
||||
SetWindowsHookExW, UnhookWindowsHookEx, CallNextHookEx, SetWindowPos,
|
||||
WH_MOUSE_LL, HC_ACTION, MSLLHOOKSTRUCT,
|
||||
WM_MOUSEMOVE, WM_RBUTTONDOWN, HWND_TOPMOST, SWP_NOSIZE, SWP_NOMOVE, SWP_NOACTIVATE,
|
||||
},
|
||||
um::libloaderapi::GetModuleHandleW,
|
||||
shared::minwindef::{WPARAM, LPARAM, LRESULT, UINT},
|
||||
};
|
||||
|
||||
use super::types::*;
|
||||
use super::state::*;
|
||||
use super::cursor::update_cursor_position;
|
||||
|
||||
// Low-level mouse hook procedure
|
||||
pub unsafe extern "system" fn low_level_mouse_proc(n_code: i32, w_param: WPARAM, l_param: LPARAM) -> LRESULT {
|
||||
if n_code == HC_ACTION {
|
||||
// Extract mouse position from the hook struct for any mouse event
|
||||
let p_msll_hook_struct = l_param as *const MSLLHOOKSTRUCT;
|
||||
if !p_msll_hook_struct.is_null() {
|
||||
let msll_hook_struct = *p_msll_hook_struct;
|
||||
let current_pos = msll_hook_struct.pt;
|
||||
|
||||
match w_param as UINT {
|
||||
WM_MOUSEMOVE => {
|
||||
let mut last_update_time_guard = LAST_MOUSE_MOVE_TIME.lock().unwrap();
|
||||
let now = Instant::now();
|
||||
|
||||
if last_update_time_guard.map_or(true, |last_time| now.duration_since(last_time) >= MOUSE_UPDATE_INTERVAL) {
|
||||
// update_cursor_position already contains logic to only update if position actually changed via LAST_CURSOR_POS
|
||||
update_cursor_position(¤t_pos);
|
||||
*last_update_time_guard = Some(now);
|
||||
}
|
||||
},
|
||||
// Handle right mouse button down - immediately update cursor position and force topmost
|
||||
WM_RBUTTONDOWN => {
|
||||
// Force an immediate update of the cursor position when right-clicking
|
||||
// This ensures the overlay is visible before the menu appears
|
||||
update_cursor_position(¤t_pos);
|
||||
|
||||
// Force the cursor window to be topmost
|
||||
if let Some(hwnd_wrapper) = *CURSOR_WINDOW.lock().unwrap() {
|
||||
SetWindowPos(
|
||||
hwnd_wrapper.0,
|
||||
HWND_TOPMOST,
|
||||
0, 0, 0, 0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE, // SWP_NOACTIVATE is critical
|
||||
);
|
||||
}
|
||||
},
|
||||
// Handle other mouse events if needed
|
||||
_ => { /* Other mouse messages can be handled here if needed */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call the next hook in the chain.
|
||||
// Pass the HHOOK of our own hook, loaded from CURRENT_HOOK_FOR_CALLBACK.
|
||||
CallNextHookEx(
|
||||
CURRENT_HOOK_FOR_CALLBACK.load(Ordering::Relaxed) as _,
|
||||
n_code,
|
||||
w_param,
|
||||
l_param,
|
||||
)
|
||||
}
|
||||
|
||||
// Install mouse hook function
|
||||
pub fn install_mouse_hook_if_needed() -> bool {
|
||||
let mut hook_guard = MOUSE_HOOK_HANDLE.lock().unwrap();
|
||||
if hook_guard.is_none() {
|
||||
unsafe {
|
||||
// GetModuleHandleW(null_mut()) gets the HMODULE for the current process (EXE)
|
||||
// which is correct for a hook procedure within the same process.
|
||||
let h_instance = GetModuleHandleW(null_mut());
|
||||
if h_instance.is_null() {
|
||||
eprintln!("Failed to get module handle for setting mouse hook: {}", std::io::Error::last_os_error());
|
||||
return false;
|
||||
}
|
||||
|
||||
let hook = SetWindowsHookExW(
|
||||
WH_MOUSE_LL, // Hook type: Low-level mouse
|
||||
Some(low_level_mouse_proc), // Pointer to hook procedure
|
||||
h_instance, // HMODULE of the DLL containing the hook proc (or current process)
|
||||
0 // Thread ID (0 for all threads on current desktop)
|
||||
);
|
||||
|
||||
if !hook.is_null() {
|
||||
// Create wrapped handle
|
||||
let sync_hook = SyncHHOOK(hook);
|
||||
*hook_guard = Some(sync_hook);
|
||||
CURRENT_HOOK_FOR_CALLBACK.store(hook as *mut _, Ordering::SeqCst);
|
||||
println!("Low-level mouse hook installed successfully.");
|
||||
return true;
|
||||
} else {
|
||||
eprintln!("Failed to install low-level mouse hook: {}", std::io::Error::last_os_error());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
true // Already installed
|
||||
}
|
||||
|
||||
// Uninstall mouse hook function
|
||||
pub fn uninstall_mouse_hook() {
|
||||
let mut hook_guard = MOUSE_HOOK_HANDLE.lock().unwrap();
|
||||
if let Some(hook_wrapper) = hook_guard.take() { // .take() removes it from Option and returns it
|
||||
unsafe {
|
||||
// Extract the raw handle using .0
|
||||
let hook = hook_wrapper.0;
|
||||
if UnhookWindowsHookEx(hook) != 0 {
|
||||
CURRENT_HOOK_FOR_CALLBACK.store(std::ptr::null_mut(), Ordering::SeqCst);
|
||||
println!("Low-level mouse hook uninstalled successfully.");
|
||||
} else {
|
||||
eprintln!("Failed to uninstall low-level mouse hook: {}", std::io::Error::last_os_error());
|
||||
// Put it back if unhooking failed, though this is unlikely.
|
||||
*hook_guard = Some(hook_wrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user