From 613d69a73724346afcf8c0c495688fc1f2ad474f Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Thu, 15 Dec 2022 17:08:23 -0800 Subject: [PATCH] feat(wm): add force-focus command On rare occasions and usually with Firefox, the desired application will fail to be focused with the regular focus commands. This commit introduces a new command, force-focus, which can be used to simulate a left-click on a window that has failed to take focus, since this is what I have to do to work around the issue anyway. --- komorebi-core/src/lib.rs | 1 + komorebi/src/process_command.rs | 3 +++ komorebi/src/windows_api.rs | 43 +++++++++++++++++++++++++++++++++ komorebic.lib.ahk | 4 +++ komorebic/src/main.rs | 5 ++++ 5 files changed, 56 insertions(+) diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index ee3e1e77..d3fbbe5e 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -53,6 +53,7 @@ pub enum SocketMessage { CycleSendContainerToWorkspace(CycleDirection), SendContainerToMonitorWorkspaceNumber(usize, usize), MoveWorkspaceToMonitorNumber(usize), + ForceFocus, Close, Minimize, Promote, diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 4f74afaa..9c831a83 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -179,6 +179,9 @@ impl WindowManager { SocketMessage::CycleStack(direction) => { self.cycle_container_window_in_direction(direction)?; } + SocketMessage::ForceFocus => { + WindowsApi::left_click(); + } SocketMessage::Close => self.focused_window()?.close()?, SocketMessage::Minimize => self.focused_window()?.minimize(), SocketMessage::ToggleFloat => self.toggle_float()?, diff --git a/komorebi/src/windows_api.rs b/komorebi/src/windows_api.rs index 1e840f0b..a4a1713c 100644 --- a/komorebi/src/windows_api.rs +++ b/komorebi/src/windows_api.rs @@ -52,7 +52,14 @@ use windows::Win32::System::Threading::PROCESS_NAME_WIN32; use windows::Win32::System::Threading::PROCESS_QUERY_INFORMATION; use windows::Win32::UI::HiDpi::SetProcessDpiAwarenessContext; use windows::Win32::UI::HiDpi::DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2; +use windows::Win32::UI::Input::KeyboardAndMouse::SendInput; use windows::Win32::UI::Input::KeyboardAndMouse::SetFocus; +use windows::Win32::UI::Input::KeyboardAndMouse::INPUT; +use windows::Win32::UI::Input::KeyboardAndMouse::INPUT_0; +use windows::Win32::UI::Input::KeyboardAndMouse::INPUT_MOUSE; +use windows::Win32::UI::Input::KeyboardAndMouse::MOUSEEVENTF_LEFTDOWN; +use windows::Win32::UI::Input::KeyboardAndMouse::MOUSEEVENTF_LEFTUP; +use windows::Win32::UI::Input::KeyboardAndMouse::MOUSEINPUT; use windows::Win32::UI::Shell::Common::DEVICE_SCALE_FACTOR; use windows::Win32::UI::Shell::GetScaleFactorForMonitor; use windows::Win32::UI::WindowsAndMessaging::AllowSetForegroundWindow; @@ -789,4 +796,40 @@ impl WindowsApi { .ok() .process() } + + pub fn left_click() -> u32 { + let inputs = [ + INPUT { + r#type: INPUT_MOUSE, + Anonymous: INPUT_0 { + mi: MOUSEINPUT { + dx: 0, + dy: 0, + mouseData: 0, + dwFlags: MOUSEEVENTF_LEFTDOWN, + time: 0, + dwExtraInfo: 0, + }, + }, + }, + INPUT { + r#type: INPUT_MOUSE, + Anonymous: INPUT_0 { + mi: MOUSEINPUT { + dx: 0, + dy: 0, + mouseData: 0, + dwFlags: MOUSEEVENTF_LEFTUP, + time: 0, + dwExtraInfo: 0, + }, + }, + }, + ]; + + #[allow(clippy::cast_possible_wrap, clippy::cast_possible_truncation)] + unsafe { + SendInput(&inputs, std::mem::size_of::() as i32) + } + } } diff --git a/komorebic.lib.ahk b/komorebic.lib.ahk index 46e068ab..fceed6b0 100644 --- a/komorebic.lib.ahk +++ b/komorebic.lib.ahk @@ -60,6 +60,10 @@ Close() { RunWait, komorebic.exe close, , Hide } +ForceFocus() { + RunWait, komorebic.exe force-focus, , Hide +} + CycleFocus(cycle_direction) { RunWait, komorebic.exe cycle-focus %cycle_direction%, , Hide } diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index c79591a7..102810ae 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -557,6 +557,8 @@ enum SubCommand { Minimize, /// Close the focused window Close, + /// Forcibly focus the window at the cursor with a left mouse click + ForceFocus, /// Change focus to the window in the specified cycle direction #[clap(arg_required_else_help = true)] CycleFocus(CycleFocus), @@ -831,6 +833,9 @@ fn main() -> Result<()> { SubCommand::Focus(arg) => { send_message(&SocketMessage::FocusWindow(arg.operation_direction).as_bytes()?)?; } + SubCommand::ForceFocus => { + send_message(&SocketMessage::ForceFocus.as_bytes()?)?; + } SubCommand::Close => { send_message(&SocketMessage::Close.as_bytes()?)?; }