diff --git a/Cargo.lock b/Cargo.lock index 00f3f638..54a964bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -827,6 +827,7 @@ dependencies = [ "tracing-subscriber", "uds_windows", "which", + "widestring", "windows", "windows-implement", "windows-interface", @@ -2331,6 +2332,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "widestring" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" + [[package]] name = "winapi" version = "0.2.8" diff --git a/komorebi/Cargo.toml b/komorebi/Cargo.toml index 3a7f7173..4b35ceb9 100644 --- a/komorebi/Cargo.toml +++ b/komorebi/Cargo.toml @@ -45,6 +45,7 @@ windows-implement = { workspace = true } windows = { workspace = true } color-eyre = { workspace = true } dirs = { workspace = true } +widestring = "1" [features] deadlock_detection = [] diff --git a/komorebi/src/border.rs b/komorebi/src/border.rs index 466cf8ca..c3ecb48e 100644 --- a/komorebi/src/border.rs +++ b/komorebi/src/border.rs @@ -2,15 +2,15 @@ use std::sync::atomic::Ordering; use std::time::Duration; use color_eyre::Result; -use windows::core::PCSTR; +use windows::core::PCWSTR; use windows::Win32::Foundation::HWND; -use windows::Win32::UI::WindowsAndMessaging::DispatchMessageA; -use windows::Win32::UI::WindowsAndMessaging::FindWindowA; -use windows::Win32::UI::WindowsAndMessaging::GetMessageA; +use windows::Win32::UI::WindowsAndMessaging::DispatchMessageW; +use windows::Win32::UI::WindowsAndMessaging::FindWindowW; +use windows::Win32::UI::WindowsAndMessaging::GetMessageW; use windows::Win32::UI::WindowsAndMessaging::CS_HREDRAW; use windows::Win32::UI::WindowsAndMessaging::CS_VREDRAW; use windows::Win32::UI::WindowsAndMessaging::MSG; -use windows::Win32::UI::WindowsAndMessaging::WNDCLASSA; +use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW; use komorebi_core::Rect; @@ -43,11 +43,11 @@ impl Border { } pub fn create(name: &str) -> Result<()> { - let name = format!("{name}\0"); + let name: Vec = format!("{name}\0").encode_utf16().collect(); let instance = WindowsApi::module_handle_w()?; - let class_name = PCSTR(name.as_ptr()); + let class_name = PCWSTR(name.as_ptr()); let brush = WindowsApi::create_solid_brush(TRANSPARENCY_COLOUR); - let window_class = WNDCLASSA { + let window_class = WNDCLASSW { hInstance: instance.into(), lpszClassName: class_name, style: CS_HREDRAW | CS_VREDRAW, @@ -56,18 +56,18 @@ impl Border { ..Default::default() }; - let _atom = WindowsApi::register_class_a(&window_class)?; + let _atom = WindowsApi::register_class_w(&window_class)?; let name_cl = name.clone(); std::thread::spawn(move || -> Result<()> { - let hwnd = WindowsApi::create_border_window(PCSTR(name_cl.as_ptr()), instance)?; + let hwnd = WindowsApi::create_border_window(PCWSTR(name_cl.as_ptr()), instance)?; let border = Self::from(hwnd); let mut message = MSG::default(); unsafe { - while GetMessageA(&mut message, border.hwnd(), 0, 0).into() { - DispatchMessageA(&message); + while GetMessageW(&mut message, border.hwnd(), 0, 0).into() { + DispatchMessageW(&message); std::thread::sleep(Duration::from_millis(10)); } } @@ -77,7 +77,7 @@ impl Border { let mut hwnd = HWND(0); while hwnd == HWND(0) { - hwnd = unsafe { FindWindowA(PCSTR(name.as_ptr()), PCSTR::null()) }; + hwnd = unsafe { FindWindowW(PCWSTR(name.as_ptr()), PCWSTR::null()) }; } BORDER_HWND.store(hwnd.0, Ordering::SeqCst); diff --git a/komorebi/src/hidden.rs b/komorebi/src/hidden.rs index 3fe2ad37..47068916 100644 --- a/komorebi/src/hidden.rs +++ b/komorebi/src/hidden.rs @@ -2,15 +2,15 @@ use std::sync::atomic::Ordering; use std::time::Duration; use color_eyre::Result; -use windows::core::PCSTR; +use windows::core::PCWSTR; use windows::Win32::Foundation::HWND; -use windows::Win32::UI::WindowsAndMessaging::DispatchMessageA; -use windows::Win32::UI::WindowsAndMessaging::FindWindowA; -use windows::Win32::UI::WindowsAndMessaging::GetMessageA; +use windows::Win32::UI::WindowsAndMessaging::DispatchMessageW; +use windows::Win32::UI::WindowsAndMessaging::FindWindowW; +use windows::Win32::UI::WindowsAndMessaging::GetMessageW; use windows::Win32::UI::WindowsAndMessaging::CS_HREDRAW; use windows::Win32::UI::WindowsAndMessaging::CS_VREDRAW; use windows::Win32::UI::WindowsAndMessaging::MSG; -use windows::Win32::UI::WindowsAndMessaging::WNDCLASSA; +use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW; use crate::windows_callbacks; use crate::WindowsApi; @@ -34,11 +34,11 @@ impl Hidden { } pub fn create(name: &str) -> Result<()> { - let name = format!("{name}\0"); + let name: Vec = format!("{name}\0").encode_utf16().collect(); let instance = WindowsApi::module_handle_w()?; - let class_name = PCSTR(name.as_ptr()); + let class_name = PCWSTR(name.as_ptr()); let brush = WindowsApi::create_solid_brush(TRANSPARENCY_COLOUR); - let window_class = WNDCLASSA { + let window_class = WNDCLASSW { hInstance: instance.into(), lpszClassName: class_name, style: CS_HREDRAW | CS_VREDRAW, @@ -47,18 +47,18 @@ impl Hidden { ..Default::default() }; - let _atom = WindowsApi::register_class_a(&window_class)?; + let _atom = WindowsApi::register_class_w(&window_class)?; let name_cl = name.clone(); std::thread::spawn(move || -> Result<()> { - let hwnd = WindowsApi::create_hidden_window(PCSTR(name_cl.as_ptr()), instance)?; + let hwnd = WindowsApi::create_hidden_window(PCWSTR(name_cl.as_ptr()), instance)?; let hidden = Self::from(hwnd); let mut message = MSG::default(); unsafe { - while GetMessageA(&mut message, hidden.hwnd(), 0, 0).into() { - DispatchMessageA(&message); + while GetMessageW(&mut message, hidden.hwnd(), 0, 0).into() { + DispatchMessageW(&message); std::thread::sleep(Duration::from_millis(10)); } } @@ -68,7 +68,7 @@ impl Hidden { let mut hwnd = HWND(0); while hwnd == HWND(0) { - hwnd = unsafe { FindWindowA(PCSTR(name.as_ptr()), PCSTR::null()) }; + hwnd = unsafe { FindWindowW(PCWSTR(name.as_ptr()), PCWSTR::null()) }; } HIDDEN_HWND.store(hwnd.0, Ordering::SeqCst); diff --git a/komorebi/src/windows_api.rs b/komorebi/src/windows_api.rs index d5640ad1..103c041c 100644 --- a/komorebi/src/windows_api.rs +++ b/komorebi/src/windows_api.rs @@ -1,15 +1,14 @@ use std::collections::VecDeque; use std::convert::TryFrom; use std::ffi::c_void; -use std::ffi::OsString; -use std::os::windows::ffi::OsStringExt; use std::sync::atomic::Ordering; use color_eyre::eyre::anyhow; use color_eyre::eyre::Error; use color_eyre::Result; +use widestring::U16CStr; use windows::core::Result as WindowsCrateResult; -use windows::core::PCSTR; +use windows::core::PCWSTR; use windows::core::PWSTR; use windows::Win32::Foundation::CloseHandle; use windows::Win32::Foundation::BOOL; @@ -30,13 +29,13 @@ use windows::Win32::Graphics::Dwm::DWM_CLOAKED_APP; use windows::Win32::Graphics::Dwm::DWM_CLOAKED_INHERITED; use windows::Win32::Graphics::Dwm::DWM_CLOAKED_SHELL; use windows::Win32::Graphics::Gdi::CreateSolidBrush; -use windows::Win32::Graphics::Gdi::EnumDisplayDevicesA; +use windows::Win32::Graphics::Gdi::EnumDisplayDevicesW; use windows::Win32::Graphics::Gdi::EnumDisplayMonitors; use windows::Win32::Graphics::Gdi::GetMonitorInfoW; use windows::Win32::Graphics::Gdi::InvalidateRect; use windows::Win32::Graphics::Gdi::MonitorFromPoint; use windows::Win32::Graphics::Gdi::MonitorFromWindow; -use windows::Win32::Graphics::Gdi::DISPLAY_DEVICEA; +use windows::Win32::Graphics::Gdi::DISPLAY_DEVICEW; use windows::Win32::Graphics::Gdi::HBRUSH; use windows::Win32::Graphics::Gdi::HDC; use windows::Win32::Graphics::Gdi::HMONITOR; @@ -69,7 +68,7 @@ use windows::Win32::UI::Shell::Common::DEVICE_SCALE_FACTOR; use windows::Win32::UI::Shell::GetScaleFactorForMonitor; use windows::Win32::UI::WindowsAndMessaging::AllowSetForegroundWindow; use windows::Win32::UI::WindowsAndMessaging::BringWindowToTop; -use windows::Win32::UI::WindowsAndMessaging::CreateWindowExA; +use windows::Win32::UI::WindowsAndMessaging::CreateWindowExW; use windows::Win32::UI::WindowsAndMessaging::EnumWindows; use windows::Win32::UI::WindowsAndMessaging::GetCursorPos; use windows::Win32::UI::WindowsAndMessaging::GetDesktopWindow; @@ -85,7 +84,7 @@ use windows::Win32::UI::WindowsAndMessaging::IsWindow; use windows::Win32::UI::WindowsAndMessaging::IsWindowVisible; use windows::Win32::UI::WindowsAndMessaging::PostMessageW; use windows::Win32::UI::WindowsAndMessaging::RealGetWindowClassW; -use windows::Win32::UI::WindowsAndMessaging::RegisterClassA; +use windows::Win32::UI::WindowsAndMessaging::RegisterClassW; use windows::Win32::UI::WindowsAndMessaging::SetCursorPos; use windows::Win32::UI::WindowsAndMessaging::SetForegroundWindow; use windows::Win32::UI::WindowsAndMessaging::SetLayeredWindowAttributes; @@ -120,7 +119,7 @@ use windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_ACTION; use windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS; use windows::Win32::UI::WindowsAndMessaging::WINDOW_LONG_PTR_INDEX; use windows::Win32::UI::WindowsAndMessaging::WM_CLOSE; -use windows::Win32::UI::WindowsAndMessaging::WNDCLASSA; +use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW; use windows::Win32::UI::WindowsAndMessaging::WNDENUMPROC; use windows::Win32::UI::WindowsAndMessaging::WS_DISABLED; use windows::Win32::UI::WindowsAndMessaging::WS_EX_LAYERED; @@ -242,21 +241,21 @@ impl WindowsApi { pub fn enum_display_devices( index: u32, - lp_device: Option<*const u8>, - ) -> Result { + lp_device: Option<*const u16>, + ) -> Result { #[allow(clippy::option_if_let_else)] let lp_device = match lp_device { - None => PCSTR::null(), - Some(lp_device) => PCSTR(lp_device), + None => PCWSTR::null(), + Some(lp_device) => PCWSTR(lp_device), }; - let mut display_device = DISPLAY_DEVICEA { - cb: u32::try_from(std::mem::size_of::())?, + let mut display_device = DISPLAY_DEVICEW { + cb: u32::try_from(std::mem::size_of::())?, ..Default::default() }; match unsafe { - EnumDisplayDevicesA( + EnumDisplayDevicesW( lp_device, index, std::ptr::addr_of_mut!(display_device), @@ -690,10 +689,10 @@ impl WindowsApi { pub fn monitor(hmonitor: isize) -> Result { let ex_info = Self::monitor_info_w(HMONITOR(hmonitor))?; - let name = OsString::from_wide(&ex_info.szDevice); - let name = name + let name = U16CStr::from_slice_truncate(&ex_info.szDevice) + .expect("monitor name was not a valid u16 c string") + .to_ustring() .to_string_lossy() - .replace('\u{0000}', "") .trim_start_matches(r"\\.\") .to_string(); @@ -799,8 +798,8 @@ impl WindowsApi { unsafe { CreateSolidBrush(COLORREF(colour)) } } - pub fn register_class_a(window_class: &WNDCLASSA) -> Result { - Result::from(WindowsResult::from(unsafe { RegisterClassA(window_class) })) + pub fn register_class_w(window_class: &WNDCLASSW) -> Result { + Result::from(WindowsResult::from(unsafe { RegisterClassW(window_class) })) } pub fn scale_factor_for_monitor(hmonitor: isize) -> Result { @@ -828,9 +827,9 @@ impl WindowsApi { .process() } - pub fn create_border_window(name: PCSTR, instance: HMODULE) -> Result { + pub fn create_border_window(name: PCWSTR, instance: HMODULE) -> Result { unsafe { - let hwnd = CreateWindowExA( + let hwnd = CreateWindowExW( WS_EX_TOOLWINDOW | WS_EX_LAYERED, name, name, @@ -862,9 +861,9 @@ impl WindowsApi { Ok(()) } - pub fn create_hidden_window(name: PCSTR, instance: HMODULE) -> Result { + pub fn create_hidden_window(name: PCWSTR, instance: HMODULE) -> Result { unsafe { - CreateWindowExA( + CreateWindowExW( WS_EX_NOACTIVATE, name, name, diff --git a/komorebi/src/windows_callbacks.rs b/komorebi/src/windows_callbacks.rs index 8ca7e341..7fad8dba 100644 --- a/komorebi/src/windows_callbacks.rs +++ b/komorebi/src/windows_callbacks.rs @@ -1,5 +1,6 @@ use std::collections::VecDeque; use std::sync::atomic::Ordering; +use widestring::U16CStr; use windows::Win32::Foundation::BOOL; use windows::Win32::Foundation::COLORREF; @@ -78,19 +79,24 @@ pub extern "system" fn enum_display_monitor( if let Ok(mut m) = WindowsApi::monitor(hmonitor.0) { #[allow(clippy::cast_possible_truncation)] if let Ok(d) = WindowsApi::enum_display_devices(current_index as u32, None) { - let name = String::from_utf8_lossy(&d.DeviceName); - let clean_name = name - .replace('\u{0000}', "") + let name = U16CStr::from_slice_truncate(d.DeviceName.as_ref()) + .expect("display device name was not a valid u16 c string") + .to_ustring() + .to_string_lossy() .trim_start_matches(r"\\.\") .to_string(); - if clean_name.eq(m.name()) { + if name.eq(m.name()) { if let Ok(device) = WindowsApi::enum_display_devices(0, Some(d.DeviceName.as_ptr())) { - let id = String::from_utf8_lossy(&device.DeviceID); - let clean_id = id.replace('\u{0000}', ""); + let id = U16CStr::from_slice_truncate(device.DeviceID.as_ref()) + .expect("display device id was not a valid u16 c string") + .to_ustring() + .to_string_lossy() + .trim_start_matches(r"\\?\") + .to_string(); - let mut split: Vec<_> = clean_id.split('#').collect(); + let mut split: Vec<_> = id.split('#').collect(); split.remove(0); split.remove(split.len() - 1);