From 355bcb6877ef08d950632b871e55bdb868397adc Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Thu, 16 Sep 2021 08:05:16 -0700 Subject: [PATCH] feat(windows): expand api wrappers --- bindings/build.rs | 6 +- komorebi/src/windows_api.rs | 285 +++++++++++++++++++++++++++++- komorebi/src/windows_callbacks.rs | 7 + komorebi/src/winevent_listener.rs | 2 +- 4 files changed, 297 insertions(+), 3 deletions(-) diff --git a/bindings/build.rs b/bindings/build.rs index 3c98669a..83b650e2 100644 --- a/bindings/build.rs +++ b/bindings/build.rs @@ -1,5 +1,7 @@ fn main() { windows::build!( + Windows::Win32::Devices::HumanInterfaceDevice::HID_USAGE_PAGE_GENERIC, + Windows::Win32::Devices::HumanInterfaceDevice::HID_USAGE_GENERIC_MOUSE, Windows::Win32::Foundation::RECT, Windows::Win32::Foundation::POINT, Windows::Win32::Foundation::BOOL, @@ -10,6 +12,7 @@ fn main() { Windows::Win32::Graphics::Dwm::*, // error: `Windows.Win32.Graphics.Gdi.MONITOR_DEFAULTTONEAREST` not found in metadata Windows::Win32::Graphics::Gdi::*, + Windows::Win32::System::LibraryLoader::GetModuleHandleW, Windows::Win32::System::Threading::PROCESS_ACCESS_RIGHTS, Windows::Win32::System::Threading::PROCESS_NAME_FORMAT, Windows::Win32::System::Threading::OpenProcess, @@ -17,7 +20,8 @@ fn main() { Windows::Win32::System::Threading::GetCurrentThreadId, Windows::Win32::System::Threading::AttachThreadInput, Windows::Win32::System::Threading::GetCurrentProcessId, - Windows::Win32::UI::KeyboardAndMouseInput::SetFocus, + // error: `Windows.Win32.UI.KeyboardAndMouseInput.RIM_TYPEMOUSE` not found in metadata + Windows::Win32::UI::KeyboardAndMouseInput::*, Windows::Win32::UI::Accessibility::SetWinEventHook, Windows::Win32::UI::Accessibility::HWINEVENTHOOK, // error: `Windows.Win32.UI.WindowsAndMessaging.GWL_EXSTYLE` not found in metadata diff --git a/komorebi/src/windows_api.rs b/komorebi/src/windows_api.rs index be54d0bd..da900351 100644 --- a/komorebi/src/windows_api.rs +++ b/komorebi/src/windows_api.rs @@ -7,8 +7,11 @@ use color_eyre::eyre::anyhow; use color_eyre::eyre::Error; use color_eyre::Result; +use bindings::Windows::Win32::Devices::HumanInterfaceDevice::HID_USAGE_GENERIC_MOUSE; +use bindings::Windows::Win32::Devices::HumanInterfaceDevice::HID_USAGE_PAGE_GENERIC; use bindings::Windows::Win32::Foundation::BOOL; use bindings::Windows::Win32::Foundation::HANDLE; +use bindings::Windows::Win32::Foundation::HINSTANCE; use bindings::Windows::Win32::Foundation::HWND; use bindings::Windows::Win32::Foundation::LPARAM; use bindings::Windows::Win32::Foundation::POINT; @@ -25,11 +28,13 @@ use bindings::Windows::Win32::Graphics::Gdi::EnumDisplayMonitors; use bindings::Windows::Win32::Graphics::Gdi::GetMonitorInfoW; use bindings::Windows::Win32::Graphics::Gdi::MonitorFromPoint; use bindings::Windows::Win32::Graphics::Gdi::MonitorFromWindow; +use bindings::Windows::Win32::Graphics::Gdi::HBRUSH; use bindings::Windows::Win32::Graphics::Gdi::HDC; use bindings::Windows::Win32::Graphics::Gdi::HMONITOR; use bindings::Windows::Win32::Graphics::Gdi::MONITORENUMPROC; use bindings::Windows::Win32::Graphics::Gdi::MONITORINFO; use bindings::Windows::Win32::Graphics::Gdi::MONITOR_DEFAULTTONEAREST; +use bindings::Windows::Win32::System::LibraryLoader::GetModuleHandleW; use bindings::Windows::Win32::System::Threading::AttachThreadInput; use bindings::Windows::Win32::System::Threading::GetCurrentProcessId; use bindings::Windows::Win32::System::Threading::GetCurrentThreadId; @@ -38,9 +43,22 @@ use bindings::Windows::Win32::System::Threading::QueryFullProcessImageNameW; use bindings::Windows::Win32::System::Threading::PROCESS_ACCESS_RIGHTS; use bindings::Windows::Win32::System::Threading::PROCESS_NAME_FORMAT; use bindings::Windows::Win32::System::Threading::PROCESS_QUERY_INFORMATION; +use bindings::Windows::Win32::UI::KeyboardAndMouseInput::GetRawInputBuffer; +use bindings::Windows::Win32::UI::KeyboardAndMouseInput::GetRawInputData; +use bindings::Windows::Win32::UI::KeyboardAndMouseInput::RegisterRawInputDevices; use bindings::Windows::Win32::UI::KeyboardAndMouseInput::SetFocus; +use bindings::Windows::Win32::UI::KeyboardAndMouseInput::HRAWINPUT; +use bindings::Windows::Win32::UI::KeyboardAndMouseInput::RAWINPUT; +use bindings::Windows::Win32::UI::KeyboardAndMouseInput::RAWINPUTDEVICE; +use bindings::Windows::Win32::UI::KeyboardAndMouseInput::RAWINPUTHEADER; +use bindings::Windows::Win32::UI::KeyboardAndMouseInput::RIDEV_INPUTSINK; +use bindings::Windows::Win32::UI::KeyboardAndMouseInput::RIDEV_NOLEGACY; +use bindings::Windows::Win32::UI::KeyboardAndMouseInput::RID_INPUT; use bindings::Windows::Win32::UI::WindowsAndMessaging::AllowSetForegroundWindow; +use bindings::Windows::Win32::UI::WindowsAndMessaging::CreateWindowExW; +use bindings::Windows::Win32::UI::WindowsAndMessaging::DestroyWindow; use bindings::Windows::Win32::UI::WindowsAndMessaging::EnumWindows; +use bindings::Windows::Win32::UI::WindowsAndMessaging::FindWindowExW; use bindings::Windows::Win32::UI::WindowsAndMessaging::GetCursorPos; use bindings::Windows::Win32::UI::WindowsAndMessaging::GetDesktopWindow; use bindings::Windows::Win32::UI::WindowsAndMessaging::GetForegroundWindow; @@ -54,16 +72,23 @@ use bindings::Windows::Win32::UI::WindowsAndMessaging::IsIconic; use bindings::Windows::Win32::UI::WindowsAndMessaging::IsWindow; use bindings::Windows::Win32::UI::WindowsAndMessaging::IsWindowVisible; use bindings::Windows::Win32::UI::WindowsAndMessaging::RealGetWindowClassW; +use bindings::Windows::Win32::UI::WindowsAndMessaging::RegisterClassExW; use bindings::Windows::Win32::UI::WindowsAndMessaging::SetCursorPos; use bindings::Windows::Win32::UI::WindowsAndMessaging::SetForegroundWindow; use bindings::Windows::Win32::UI::WindowsAndMessaging::SetWindowLongPtrW; use bindings::Windows::Win32::UI::WindowsAndMessaging::SetWindowPos; use bindings::Windows::Win32::UI::WindowsAndMessaging::ShowWindow; use bindings::Windows::Win32::UI::WindowsAndMessaging::SystemParametersInfoW; +use bindings::Windows::Win32::UI::WindowsAndMessaging::UnregisterClassW; use bindings::Windows::Win32::UI::WindowsAndMessaging::WindowFromPoint; +use bindings::Windows::Win32::UI::WindowsAndMessaging::CW_USEDEFAULT; use bindings::Windows::Win32::UI::WindowsAndMessaging::GWL_EXSTYLE; use bindings::Windows::Win32::UI::WindowsAndMessaging::GWL_STYLE; use bindings::Windows::Win32::UI::WindowsAndMessaging::GW_HWNDNEXT; +use bindings::Windows::Win32::UI::WindowsAndMessaging::HCURSOR; +use bindings::Windows::Win32::UI::WindowsAndMessaging::HICON; +use bindings::Windows::Win32::UI::WindowsAndMessaging::HMENU; +use bindings::Windows::Win32::UI::WindowsAndMessaging::HWND_MESSAGE; use bindings::Windows::Win32::UI::WindowsAndMessaging::HWND_NOTOPMOST; use bindings::Windows::Win32::UI::WindowsAndMessaging::HWND_TOPMOST; use bindings::Windows::Win32::UI::WindowsAndMessaging::SET_WINDOW_POS_FLAGS; @@ -76,8 +101,13 @@ use bindings::Windows::Win32::UI::WindowsAndMessaging::SW_MAXIMIZE; use bindings::Windows::Win32::UI::WindowsAndMessaging::SW_RESTORE; use bindings::Windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_ACTION; use bindings::Windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS; +use bindings::Windows::Win32::UI::WindowsAndMessaging::WINDOW_EX_STYLE; use bindings::Windows::Win32::UI::WindowsAndMessaging::WINDOW_LONG_PTR_INDEX; +use bindings::Windows::Win32::UI::WindowsAndMessaging::WINDOW_STYLE; +use bindings::Windows::Win32::UI::WindowsAndMessaging::WNDCLASSEXW; +use bindings::Windows::Win32::UI::WindowsAndMessaging::WNDCLASS_STYLES; use bindings::Windows::Win32::UI::WindowsAndMessaging::WNDENUMPROC; +use bindings::Windows::Win32::UI::WindowsAndMessaging::WNDPROC; use komorebi_core::Rect; use crate::container::Container; @@ -87,6 +117,21 @@ use crate::ring::Ring; use crate::set_window_position::SetWindowPosition; use crate::windows_callbacks; +pub trait IntoPWSTR { + fn into_pwstr(self) -> PWSTR; +} + +impl IntoPWSTR for &str { + fn into_pwstr(self) -> PWSTR { + PWSTR( + self.encode_utf16() + .chain([0_u16]) + .collect::>() + .as_mut_ptr(), + ) + } +} + pub enum WindowsResult { Err(E), Ok(T), @@ -102,6 +147,16 @@ impl From for WindowsResult<(), Error> { } } +impl From for WindowsResult { + fn from(return_value: HINSTANCE) -> Self { + if return_value.is_null() { + Self::Err(std::io::Error::last_os_error().into()) + } else { + Self::Ok(return_value) + } + } +} + impl From for WindowsResult { fn from(return_value: HWND) -> Self { if return_value.is_null() { @@ -137,7 +192,7 @@ macro_rules! impl_from_integer_for_windows_result { }; } -impl_from_integer_for_windows_result!(isize, u32, i32); +impl_from_integer_for_windows_result!(isize, u16, u32, i32); impl From> for Result { fn from(result: WindowsResult) -> Self { @@ -165,6 +220,46 @@ impl WindowsApi { })) } + #[allow(dead_code)] + pub fn valid_hwnds() -> Result> { + let mut hwnds: Vec = vec![]; + let hwnds_ref: &mut Vec = hwnds.as_mut(); + Self::enum_windows( + windows_callbacks::valid_hwnds, + hwnds_ref as *mut Vec as isize, + )?; + + Ok(hwnds) + } + + #[allow(dead_code)] + pub fn hwnd_by_class(class: &str) -> Option { + let hwnds = Self::valid_hwnds().ok()?; + for hwnd in hwnds { + if let Ok(hwnd_class) = Self::real_window_class_w(HWND(hwnd)) { + if hwnd_class == class { + return Option::from(hwnd); + } + } + } + + None + } + + #[allow(dead_code)] + pub fn hwnd_by_title(class: &str) -> Option { + let hwnds = Self::valid_hwnds().ok()?; + for hwnd in hwnds { + if let Ok(hwnd_title) = Self::window_text_w(HWND(hwnd)) { + if hwnd_title == class { + return Option::from(hwnd); + } + } + } + + None + } + pub fn valid_hmonitors() -> Result> { let mut monitors: Vec = vec![]; let monitors_ref: &mut Vec = monitors.as_mut(); @@ -615,4 +710,192 @@ impl WindowsApi { SPIF_SENDCHANGE, ) } + + #[allow(dead_code)] + pub fn module_handle_w() -> Result { + Result::from(WindowsResult::from(unsafe { GetModuleHandleW(None) })) + } + + #[allow(dead_code)] + pub fn register_class_ex_w(class: &WNDCLASSEXW) -> Result { + Result::from(WindowsResult::from(unsafe { RegisterClassExW(class) })) + } + + #[allow(clippy::too_many_arguments, dead_code)] + fn create_window_ex_w( + window_ex_style: WINDOW_EX_STYLE, + class_name: PWSTR, + window_name: PWSTR, + window_style: WINDOW_STYLE, + x: i32, + y: i32, + width: i32, + height: i32, + hwnd_parent: HWND, + hmenu: HMENU, + hinstance: HINSTANCE, + lp_param: *mut c_void, + ) -> Result { + Result::from(WindowsResult::from(unsafe { + CreateWindowExW( + window_ex_style, + class_name, + window_name, + window_style, + x, + y, + width, + height, + hwnd_parent, + hmenu, + hinstance, + lp_param, + ) + })) + } + + #[allow(dead_code)] + pub fn hidden_message_window(name: &str, wnd_proc: Option) -> Result { + let hinstance = Self::module_handle_w()?; + + let window_class = WNDCLASSEXW { + cbSize: u32::try_from(std::mem::size_of::())?, + cbClsExtra: 0, + cbWndExtra: 0, + hbrBackground: HBRUSH::NULL, + hCursor: HCURSOR::NULL, + hIcon: HICON::NULL, + hIconSm: HICON::NULL, + hInstance: hinstance, + lpfnWndProc: wnd_proc, + lpszClassName: name.into_pwstr(), + lpszMenuName: PWSTR::NULL, + style: WNDCLASS_STYLES::from(0), + }; + + Self::register_class_ex_w(&window_class)?; + + Self::create_window_ex_w( + WINDOW_EX_STYLE::from(0), + name.into_pwstr(), + name.into_pwstr(), + WINDOW_STYLE::from(0), + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + HWND_MESSAGE, + HMENU::NULL, + hinstance, + std::ptr::null_mut(), + ) + } + + #[allow(dead_code)] + pub fn destroy_window(hwnd: isize) -> Result<()> { + Result::from(WindowsResult::from(unsafe { DestroyWindow(HWND(hwnd)) })) + } + + #[allow(dead_code)] + pub fn unregister_class_w(name: &str) -> Result<()> { + Result::from(WindowsResult::from(unsafe { + UnregisterClassW(name.into_pwstr(), Self::module_handle_w()?) + })) + } + + #[allow(dead_code)] + pub fn register_raw_input_devices(devices: &mut [RAWINPUTDEVICE]) -> Result<()> { + Result::from(WindowsResult::from(unsafe { + RegisterRawInputDevices( + devices.as_mut_ptr(), + u32::try_from(devices.len())?, + u32::try_from(std::mem::size_of::())?, + ) + })) + } + + #[allow(dead_code)] + pub fn register_mice_for_hwnd(hwnd: isize) -> Result<()> { + Self::register_raw_input_devices(&mut [RAWINPUTDEVICE { + dwFlags: RIDEV_NOLEGACY | RIDEV_INPUTSINK, + usUsagePage: HID_USAGE_PAGE_GENERIC, + usUsage: HID_USAGE_GENERIC_MOUSE, + hwndTarget: HWND(hwnd), + }]) + } + + #[allow(dead_code)] + pub fn raw_input_buffer_null(buffer_size: *mut u32, header_size: u32) -> Result<()> { + Result::from(unsafe { + match GetRawInputBuffer(std::ptr::null_mut(), buffer_size, header_size) { + 0 => WindowsResult::Ok(()), + _ => WindowsResult::Err(std::io::Error::last_os_error().into()), + } + }) + } + + #[allow(dead_code)] + pub fn raw_input_buffer( + raw_input_pointer: *mut RAWINPUT, + buffer_size: *mut u32, + header_size: u32, + ) -> Result { + Result::from(unsafe { + WindowsResult::Ok(GetRawInputBuffer( + raw_input_pointer, + buffer_size, + header_size, + )) + }) + } + + #[allow(dead_code)] + pub fn raw_input_data_null(raw_input_handle: HRAWINPUT, buffer_size: &mut u32) -> Result<()> { + Result::from(unsafe { + match GetRawInputData( + raw_input_handle, + RID_INPUT, + std::ptr::null_mut(), + buffer_size, + u32::try_from(std::mem::size_of::())?, + ) { + 0 => WindowsResult::Ok(()), + _ => WindowsResult::Err(std::io::Error::last_os_error().into()), + } + }) + } + + #[allow(dead_code)] + pub fn raw_input_data( + raw_input_handle: HRAWINPUT, + buffer: *mut c_void, + buffer_size: *mut u32, + ) -> Result { + Result::from(unsafe { + match GetRawInputData( + raw_input_handle, + RID_INPUT, + buffer, + buffer_size, + u32::try_from(std::mem::size_of::())?, + ) { + 0 => WindowsResult::Err(std::io::Error::last_os_error().into()), + n => WindowsResult::Ok(n), + } + }) + } + + #[allow(dead_code)] + pub fn find_window_ex_w(parent: HWND, class: &str, title: &str) -> Result { + Result::from(WindowsResult::from(unsafe { + let hwnd = FindWindowExW(parent, HWND::NULL, class.into_pwstr(), title.into_pwstr()); + dbg!(hwnd); + hwnd + })) + } + + #[allow(dead_code)] + pub fn find_message_window(class: &str, title: &str) -> Result { + Self::find_window_ex_w(HWND_MESSAGE, class, title) + } } diff --git a/komorebi/src/windows_callbacks.rs b/komorebi/src/windows_callbacks.rs index cd959918..0e479562 100644 --- a/komorebi/src/windows_callbacks.rs +++ b/komorebi/src/windows_callbacks.rs @@ -49,6 +49,13 @@ pub extern "system" fn enum_display_monitor( true.into() } +#[allow(dead_code)] +pub extern "system" fn valid_hwnds(hwnd: HWND, lparam: LPARAM) -> BOOL { + let hwnds = unsafe { &mut *(lparam.0 as *mut Vec) }; + hwnds.push(hwnd.0); + true.into() +} + pub extern "system" fn enum_window(hwnd: HWND, lparam: LPARAM) -> BOOL { let containers = unsafe { &mut *(lparam.0 as *mut VecDeque) }; diff --git a/komorebi/src/winevent_listener.rs b/komorebi/src/winevent_listener.rs index 10f63f81..55caf2d9 100644 --- a/komorebi/src/winevent_listener.rs +++ b/komorebi/src/winevent_listener.rs @@ -89,7 +89,7 @@ impl MessageLoop { loop { let mut value: Option = None; unsafe { - if !bool::from(!PeekMessageW(&mut msg, HWND(0), 0, 0, PM_REMOVE)) { + if bool::from(PeekMessageW(&mut msg, HWND(0), 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessageW(&msg);