mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2025-01-11 13:31:29 +11:00
Adopt windows-sys (#2057)
This commit is contained in:
parent
78e5a395da
commit
b222dde835
|
@ -21,6 +21,8 @@ And please only add new entries to the top of this list, right below the `# Unre
|
|||
- **Breaking:** Replaced `EventLoopExtMacOS` with `EventLoopBuilderExtMacOS` (which also has renamed methods).
|
||||
- **Breaking:** Replaced `EventLoopExtWindows` with `EventLoopBuilderExtWindows` (which also has renamed methods).
|
||||
- **Breaking:** Replaced `EventLoopExtUnix` with `EventLoopBuilderExtUnix` (which also has renamed methods).
|
||||
- **Breaking:** The platform specific extensions for Windows `winit::platform::windows` have changed. All `HANDLE`-like types e.g. `HWND` and `HMENU` were converted from winapi types or `*mut c_void` to `isize`. This was done to be consistent with the type definitions in windows-sys and to not expose internal dependencies.
|
||||
- The internal bindings to the [Windows API](https://docs.microsoft.com/en-us/windows/) were changed from the unofficial [winapi](https://github.com/retep998/winapi-rs) bindings to the official Microsoft [windows-sys](https://github.com/microsoft/windows-rs) bindings.
|
||||
- On Wayland, fix resize and scale factor changes not being propagated properly.
|
||||
|
||||
# 0.26.1 (2022-01-05)
|
||||
|
|
54
Cargo.toml
54
Cargo.toml
|
@ -55,33 +55,35 @@ default_features = false
|
|||
features = ["display_link"]
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
parking_lot = "0.11"
|
||||
parking_lot = "0.12"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies.winapi]
|
||||
version = "0.3.9"
|
||||
[target.'cfg(target_os = "windows")'.dependencies.windows-sys]
|
||||
version = "0.33"
|
||||
features = [
|
||||
"combaseapi",
|
||||
"commctrl",
|
||||
"dwmapi",
|
||||
"errhandlingapi",
|
||||
"imm",
|
||||
"hidusage",
|
||||
"libloaderapi",
|
||||
"objbase",
|
||||
"ole2",
|
||||
"processthreadsapi",
|
||||
"shellapi",
|
||||
"shellscalingapi",
|
||||
"shobjidl_core",
|
||||
"unknwnbase",
|
||||
"winbase",
|
||||
"windowsx",
|
||||
"winerror",
|
||||
"wingdi",
|
||||
"winnt",
|
||||
"winuser",
|
||||
"mmsystem",
|
||||
"timeapi"
|
||||
"Win32_Devices_HumanInterfaceDevice",
|
||||
"Win32_Foundation",
|
||||
"Win32_Globalization",
|
||||
"Win32_Graphics_Dwm",
|
||||
"Win32_Graphics_Gdi",
|
||||
"Win32_Media",
|
||||
"Win32_System_Com_StructuredStorage",
|
||||
"Win32_System_Com",
|
||||
"Win32_System_LibraryLoader",
|
||||
"Win32_System_Ole",
|
||||
"Win32_System_SystemInformation",
|
||||
"Win32_System_SystemServices",
|
||||
"Win32_System_Threading",
|
||||
"Win32_System_WindowsProgramming",
|
||||
"Win32_UI_Accessibility",
|
||||
"Win32_UI_Controls",
|
||||
"Win32_UI_HiDpi",
|
||||
"Win32_UI_Input_Ime",
|
||||
"Win32_UI_Input_KeyboardAndMouse",
|
||||
"Win32_UI_Input_Pointer",
|
||||
"Win32_UI_Input_Touch",
|
||||
"Win32_UI_Shell",
|
||||
"Win32_UI_TextServices",
|
||||
"Win32_UI_WindowsAndMessaging",
|
||||
]
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies]
|
||||
|
@ -91,7 +93,7 @@ sctk = { package = "smithay-client-toolkit", version = "0.15.1", default_feature
|
|||
mio = { version = "0.8", features = ["os-ext"], optional = true }
|
||||
x11-dl = { version = "2.18.5", optional = true }
|
||||
percent-encoding = { version = "2.0", optional = true }
|
||||
parking_lot = { version = "0.11.0", optional = true }
|
||||
parking_lot = { version = "0.12.0", optional = true }
|
||||
libc = "0.2.64"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies.web_sys]
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
#![cfg(target_os = "windows")]
|
||||
|
||||
use std::os::raw::c_void;
|
||||
use std::path::Path;
|
||||
|
||||
use winapi::shared::minwindef::WORD;
|
||||
use winapi::shared::windef::{HMENU, HWND};
|
||||
|
||||
use crate::{
|
||||
dpi::PhysicalSize,
|
||||
event::DeviceId,
|
||||
|
@ -15,6 +11,15 @@ use crate::{
|
|||
window::{BadIcon, Icon, Theme, Window, WindowBuilder},
|
||||
};
|
||||
|
||||
/// Window Handle type used by Win32 API
|
||||
pub type HWND = isize;
|
||||
/// Menu Handle type used by Win32 API
|
||||
pub type HMENU = isize;
|
||||
/// Monitor Handle type used by Win32 API
|
||||
pub type HMONITOR = isize;
|
||||
/// Instance Handle type used by Win32 API
|
||||
pub type HINSTANCE = isize;
|
||||
|
||||
/// Additional methods on `EventLoop` that are specific to Windows.
|
||||
pub trait EventLoopBuilderExtWindows {
|
||||
/// Whether to allow the event loop to be created off of the main thread.
|
||||
|
@ -70,11 +75,11 @@ impl<T> EventLoopBuilderExtWindows for EventLoopBuilder<T> {
|
|||
/// Additional methods on `Window` that are specific to Windows.
|
||||
pub trait WindowExtWindows {
|
||||
/// Returns the HINSTANCE of the window
|
||||
fn hinstance(&self) -> *mut c_void;
|
||||
fn hinstance(&self) -> HINSTANCE;
|
||||
/// Returns the native handle that is used by this window.
|
||||
///
|
||||
/// The pointer will become invalid when the native window was destroyed.
|
||||
fn hwnd(&self) -> *mut c_void;
|
||||
fn hwnd(&self) -> HWND;
|
||||
|
||||
/// Enables or disables mouse and keyboard input to the specified window.
|
||||
///
|
||||
|
@ -100,13 +105,13 @@ pub trait WindowExtWindows {
|
|||
|
||||
impl WindowExtWindows for Window {
|
||||
#[inline]
|
||||
fn hinstance(&self) -> *mut c_void {
|
||||
self.window.hinstance() as *mut _
|
||||
fn hinstance(&self) -> HINSTANCE {
|
||||
self.window.hinstance()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn hwnd(&self) -> *mut c_void {
|
||||
self.window.hwnd() as *mut _
|
||||
fn hwnd(&self) -> HWND {
|
||||
self.window.hwnd()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -150,10 +155,12 @@ pub trait WindowBuilderExtWindows {
|
|||
///
|
||||
/// Parent and menu are mutually exclusive; a child window cannot have a menu!
|
||||
///
|
||||
/// The menu must have been manually created beforehand with [`winapi::um::winuser::CreateMenu`] or similar.
|
||||
/// The menu must have been manually created beforehand with [`CreateMenu`] or similar.
|
||||
///
|
||||
/// Note: Dark mode cannot be supported for win32 menus, it's simply not possible to change how the menus look.
|
||||
/// If you use this, it is recommended that you combine it with `with_theme(Some(Theme::Light))` to avoid a jarring effect.
|
||||
///
|
||||
/// [`CreateMenu`]: windows_sys::Win32::UI::WindowsAndMessaging::CreateMenu
|
||||
fn with_menu(self, menu: HMENU) -> WindowBuilder;
|
||||
|
||||
/// This sets `ICON_BIG`. A good ceiling here is 256x256.
|
||||
|
@ -224,7 +231,7 @@ pub trait MonitorHandleExtWindows {
|
|||
fn native_id(&self) -> String;
|
||||
|
||||
/// Returns the handle of the monitor - `HMONITOR`.
|
||||
fn hmonitor(&self) -> *mut c_void;
|
||||
fn hmonitor(&self) -> HMONITOR;
|
||||
}
|
||||
|
||||
impl MonitorHandleExtWindows for MonitorHandle {
|
||||
|
@ -234,8 +241,8 @@ impl MonitorHandleExtWindows for MonitorHandle {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn hmonitor(&self) -> *mut c_void {
|
||||
self.inner.hmonitor() as *mut _
|
||||
fn hmonitor(&self) -> HMONITOR {
|
||||
self.inner.hmonitor()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,7 +280,7 @@ pub trait IconExtWindows: Sized {
|
|||
///
|
||||
/// In cases where the specified size does not exist in the file, Windows may perform scaling
|
||||
/// to get an icon of the desired size.
|
||||
fn from_resource(ordinal: WORD, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon>;
|
||||
fn from_resource(ordinal: u16, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon>;
|
||||
}
|
||||
|
||||
impl IconExtWindows for Icon {
|
||||
|
@ -285,7 +292,7 @@ impl IconExtWindows for Icon {
|
|||
Ok(Icon { inner: win_icon })
|
||||
}
|
||||
|
||||
fn from_resource(ordinal: WORD, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon> {
|
||||
fn from_resource(ordinal: u16, size: Option<PhysicalSize<u32>>) -> Result<Self, BadIcon> {
|
||||
let win_icon = WinIcon::from_resource(ordinal, size)?;
|
||||
Ok(Icon { inner: win_icon })
|
||||
}
|
||||
|
|
|
@ -1,29 +1,35 @@
|
|||
/// This is a simple implementation of support for Windows Dark Mode,
|
||||
/// which is inspired by the solution in https://github.com/ysc3839/win32-darkmode
|
||||
use std::ffi::OsStr;
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
use std::{ffi::c_void, ptr};
|
||||
|
||||
use winapi::{
|
||||
shared::{
|
||||
basetsd::SIZE_T,
|
||||
minwindef::{BOOL, DWORD, FALSE, WORD},
|
||||
ntdef::{NTSTATUS, NT_SUCCESS, PVOID},
|
||||
windef::HWND,
|
||||
winerror::S_OK,
|
||||
use windows_sys::{
|
||||
core::PCSTR,
|
||||
Win32::{
|
||||
Foundation::{BOOL, HWND, NTSTATUS, S_OK},
|
||||
System::{
|
||||
LibraryLoader::{GetProcAddress, LoadLibraryA},
|
||||
SystemInformation::OSVERSIONINFOW,
|
||||
},
|
||||
UI::{
|
||||
Accessibility::{HCF_HIGHCONTRASTON, HIGHCONTRASTA},
|
||||
Controls::SetWindowTheme,
|
||||
WindowsAndMessaging::{SystemParametersInfoA, SPI_GETHIGHCONTRAST},
|
||||
},
|
||||
},
|
||||
um::{libloaderapi, uxtheme, winnt, winuser},
|
||||
};
|
||||
|
||||
use crate::window::Theme;
|
||||
|
||||
use super::util;
|
||||
|
||||
lazy_static! {
|
||||
static ref WIN10_BUILD_VERSION: Option<DWORD> = {
|
||||
type RtlGetVersion = unsafe extern "system" fn (*mut winnt::OSVERSIONINFOW) -> NTSTATUS;
|
||||
static ref WIN10_BUILD_VERSION: Option<u32> = {
|
||||
type RtlGetVersion = unsafe extern "system" fn (*mut OSVERSIONINFOW) -> NTSTATUS;
|
||||
let handle = get_function!("ntdll.dll", RtlGetVersion);
|
||||
|
||||
if let Some(rtl_get_version) = handle {
|
||||
unsafe {
|
||||
let mut vi = winnt::OSVERSIONINFOW {
|
||||
let mut vi = OSVERSIONINFOW {
|
||||
dwOSVersionInfoSize: 0,
|
||||
dwMajorVersion: 0,
|
||||
dwMinorVersion: 0,
|
||||
|
@ -32,9 +38,9 @@ lazy_static! {
|
|||
szCSDVersion: [0; 128],
|
||||
};
|
||||
|
||||
let status = (rtl_get_version)(&mut vi as _);
|
||||
let status = (rtl_get_version)(&mut vi);
|
||||
|
||||
if NT_SUCCESS(status) && vi.dwMajorVersion == 10 && vi.dwMinorVersion == 0 {
|
||||
if status >= 0 && vi.dwMajorVersion == 10 && vi.dwMinorVersion == 0 {
|
||||
Some(vi.dwBuildNumber)
|
||||
} else {
|
||||
None
|
||||
|
@ -54,8 +60,8 @@ lazy_static! {
|
|||
}
|
||||
};
|
||||
|
||||
static ref DARK_THEME_NAME: Vec<u16> = widestring("DarkMode_Explorer");
|
||||
static ref LIGHT_THEME_NAME: Vec<u16> = widestring("");
|
||||
static ref DARK_THEME_NAME: Vec<u16> = util::encode_wide("DarkMode_Explorer");
|
||||
static ref LIGHT_THEME_NAME: Vec<u16> = util::encode_wide("");
|
||||
}
|
||||
|
||||
/// Attempt to set a theme on a window, if necessary.
|
||||
|
@ -77,7 +83,7 @@ pub fn try_theme(hwnd: HWND, preferred_theme: Option<Theme>) -> Theme {
|
|||
Theme::Light => LIGHT_THEME_NAME.as_ptr(),
|
||||
};
|
||||
|
||||
let status = unsafe { uxtheme::SetWindowTheme(hwnd, theme_name as _, std::ptr::null()) };
|
||||
let status = unsafe { SetWindowTheme(hwnd, theme_name, ptr::null()) };
|
||||
|
||||
if status == S_OK && set_dark_mode_for_window(hwnd, is_dark_mode) {
|
||||
return theme;
|
||||
|
@ -103,8 +109,8 @@ fn set_dark_mode_for_window(hwnd: HWND, is_dark_mode: bool) -> bool {
|
|||
#[repr(C)]
|
||||
struct WINDOWCOMPOSITIONATTRIBDATA {
|
||||
Attrib: WINDOWCOMPOSITIONATTRIB,
|
||||
pvData: PVOID,
|
||||
cbData: SIZE_T,
|
||||
pvData: *mut c_void,
|
||||
cbData: usize,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
|
@ -115,7 +121,7 @@ fn set_dark_mode_for_window(hwnd: HWND, is_dark_mode: bool) -> bool {
|
|||
if let Some(set_window_composition_attribute) = *SET_WINDOW_COMPOSITION_ATTRIBUTE {
|
||||
unsafe {
|
||||
// SetWindowCompositionAttribute needs a bigbool (i32), not bool.
|
||||
let mut is_dark_mode_bigbool = is_dark_mode as BOOL;
|
||||
let mut is_dark_mode_bigbool = BOOL::from(is_dark_mode);
|
||||
|
||||
let mut data = WINDOWCOMPOSITIONATTRIBDATA {
|
||||
Attrib: WCA_USEDARKMODECOLORS,
|
||||
|
@ -123,9 +129,9 @@ fn set_dark_mode_for_window(hwnd: HWND, is_dark_mode: bool) -> bool {
|
|||
cbData: std::mem::size_of_val(&is_dark_mode_bigbool) as _,
|
||||
};
|
||||
|
||||
let status = set_window_composition_attribute(hwnd, &mut data as *mut _);
|
||||
let status = set_window_composition_attribute(hwnd, &mut data);
|
||||
|
||||
status != FALSE
|
||||
status != false.into()
|
||||
}
|
||||
} else {
|
||||
false
|
||||
|
@ -141,24 +147,17 @@ fn should_apps_use_dark_mode() -> bool {
|
|||
lazy_static! {
|
||||
static ref SHOULD_APPS_USE_DARK_MODE: Option<ShouldAppsUseDarkMode> = {
|
||||
unsafe {
|
||||
const UXTHEME_SHOULDAPPSUSEDARKMODE_ORDINAL: WORD = 132;
|
||||
const UXTHEME_SHOULDAPPSUSEDARKMODE_ORDINAL: PCSTR = 132 as PCSTR;
|
||||
|
||||
let module = libloaderapi::LoadLibraryA("uxtheme.dll\0".as_ptr() as _);
|
||||
let module = LoadLibraryA("uxtheme.dll\0".as_ptr());
|
||||
|
||||
if module.is_null() {
|
||||
if module == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let handle = libloaderapi::GetProcAddress(
|
||||
module,
|
||||
winuser::MAKEINTRESOURCEA(UXTHEME_SHOULDAPPSUSEDARKMODE_ORDINAL),
|
||||
);
|
||||
let handle = GetProcAddress(module, UXTHEME_SHOULDAPPSUSEDARKMODE_ORDINAL);
|
||||
|
||||
if handle.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(std::mem::transmute(handle))
|
||||
}
|
||||
handle.map(|handle| std::mem::transmute(handle))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -169,27 +168,20 @@ fn should_apps_use_dark_mode() -> bool {
|
|||
}
|
||||
|
||||
fn is_high_contrast() -> bool {
|
||||
let mut hc = winuser::HIGHCONTRASTA {
|
||||
let mut hc = HIGHCONTRASTA {
|
||||
cbSize: 0,
|
||||
dwFlags: 0,
|
||||
lpszDefaultScheme: std::ptr::null_mut(),
|
||||
lpszDefaultScheme: ptr::null_mut(),
|
||||
};
|
||||
|
||||
let ok = unsafe {
|
||||
winuser::SystemParametersInfoA(
|
||||
winuser::SPI_GETHIGHCONTRAST,
|
||||
SystemParametersInfoA(
|
||||
SPI_GETHIGHCONTRAST,
|
||||
std::mem::size_of_val(&hc) as _,
|
||||
&mut hc as *mut _ as _,
|
||||
0,
|
||||
)
|
||||
};
|
||||
|
||||
ok != FALSE && (winuser::HCF_HIGHCONTRASTON & hc.dwFlags) == 1
|
||||
}
|
||||
|
||||
fn widestring(src: &'static str) -> Vec<u16> {
|
||||
OsStr::new(src)
|
||||
.encode_wide()
|
||||
.chain(Some(0).into_iter())
|
||||
.collect()
|
||||
ok != false.into() && util::has_flag(hc.dwFlags, HCF_HIGHCONTRASTON)
|
||||
}
|
||||
|
|
140
src/platform_impl/windows/definitions.rs
Normal file
140
src/platform_impl/windows/definitions.rs
Normal file
|
@ -0,0 +1,140 @@
|
|||
#![allow(non_snake_case)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
use std::ffi::c_void;
|
||||
|
||||
use windows_sys::{
|
||||
core::{IUnknown, GUID, HRESULT},
|
||||
Win32::{
|
||||
Foundation::{BOOL, HWND, POINTL},
|
||||
System::Com::{
|
||||
IAdviseSink, IDataObject, IEnumFORMATETC, IEnumSTATDATA, FORMATETC, STGMEDIUM,
|
||||
},
|
||||
UI::Shell::ITaskbarList,
|
||||
},
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct IUnknownVtbl {
|
||||
pub QueryInterface: unsafe extern "system" fn(
|
||||
This: *mut IUnknown,
|
||||
riid: *const GUID,
|
||||
ppvObject: *mut *mut c_void,
|
||||
) -> HRESULT,
|
||||
pub AddRef: unsafe extern "system" fn(This: *mut IUnknown) -> u32,
|
||||
pub Release: unsafe extern "system" fn(This: *mut IUnknown) -> u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct IDataObjectVtbl {
|
||||
pub parent: IUnknownVtbl,
|
||||
pub GetData: unsafe extern "system" fn(
|
||||
This: *mut IDataObject,
|
||||
pformatetcIn: *const FORMATETC,
|
||||
pmedium: *mut STGMEDIUM,
|
||||
) -> HRESULT,
|
||||
pub GetDataHere: unsafe extern "system" fn(
|
||||
This: *mut IDataObject,
|
||||
pformatetc: *const FORMATETC,
|
||||
pmedium: *mut STGMEDIUM,
|
||||
) -> HRESULT,
|
||||
QueryGetData:
|
||||
unsafe extern "system" fn(This: *mut IDataObject, pformatetc: *const FORMATETC) -> HRESULT,
|
||||
pub GetCanonicalFormatEtc: unsafe extern "system" fn(
|
||||
This: *mut IDataObject,
|
||||
pformatetcIn: *const FORMATETC,
|
||||
pformatetcOut: *mut FORMATETC,
|
||||
) -> HRESULT,
|
||||
pub SetData: unsafe extern "system" fn(
|
||||
This: *mut IDataObject,
|
||||
pformatetc: *const FORMATETC,
|
||||
pformatetcOut: *const FORMATETC,
|
||||
fRelease: BOOL,
|
||||
) -> HRESULT,
|
||||
pub EnumFormatEtc: unsafe extern "system" fn(
|
||||
This: *mut IDataObject,
|
||||
dwDirection: u32,
|
||||
ppenumFormatEtc: *mut *mut IEnumFORMATETC,
|
||||
) -> HRESULT,
|
||||
pub DAdvise: unsafe extern "system" fn(
|
||||
This: *mut IDataObject,
|
||||
pformatetc: *const FORMATETC,
|
||||
advf: u32,
|
||||
pAdvSInk: *const IAdviseSink,
|
||||
pdwConnection: *mut u32,
|
||||
) -> HRESULT,
|
||||
pub DUnadvise: unsafe extern "system" fn(This: *mut IDataObject, dwConnection: u32) -> HRESULT,
|
||||
pub EnumDAdvise: unsafe extern "system" fn(
|
||||
This: *mut IDataObject,
|
||||
ppenumAdvise: *const *const IEnumSTATDATA,
|
||||
) -> HRESULT,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct IDropTargetVtbl {
|
||||
pub parent: IUnknownVtbl,
|
||||
pub DragEnter: unsafe extern "system" fn(
|
||||
This: *mut IDropTarget,
|
||||
pDataObj: *const IDataObject,
|
||||
grfKeyState: u32,
|
||||
pt: *const POINTL,
|
||||
pdwEffect: *mut u32,
|
||||
) -> HRESULT,
|
||||
pub DragOver: unsafe extern "system" fn(
|
||||
This: *mut IDropTarget,
|
||||
grfKeyState: u32,
|
||||
pt: *const POINTL,
|
||||
pdwEffect: *mut u32,
|
||||
) -> HRESULT,
|
||||
pub DragLeave: unsafe extern "system" fn(This: *mut IDropTarget) -> HRESULT,
|
||||
pub Drop: unsafe extern "system" fn(
|
||||
This: *mut IDropTarget,
|
||||
pDataObj: *const IDataObject,
|
||||
grfKeyState: u32,
|
||||
pt: *const POINTL,
|
||||
pdwEffect: *mut u32,
|
||||
) -> HRESULT,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct IDropTarget {
|
||||
pub lpVtbl: *const IDropTargetVtbl,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ITaskbarListVtbl {
|
||||
pub parent: IUnknownVtbl,
|
||||
pub HrInit: unsafe extern "system" fn(This: *mut ITaskbarList) -> HRESULT,
|
||||
pub AddTab: unsafe extern "system" fn(This: *mut ITaskbarList, hwnd: HWND) -> HRESULT,
|
||||
pub DeleteTab: unsafe extern "system" fn(This: *mut ITaskbarList, hwnd: HWND) -> HRESULT,
|
||||
pub ActivateTab: unsafe extern "system" fn(This: *mut ITaskbarList, hwnd: HWND) -> HRESULT,
|
||||
pub SetActiveAlt: unsafe extern "system" fn(This: *mut ITaskbarList, hwnd: HWND) -> HRESULT,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ITaskbarList2Vtbl {
|
||||
pub parent: ITaskbarListVtbl,
|
||||
pub MarkFullscreenWindow: unsafe extern "system" fn(
|
||||
This: *mut ITaskbarList2,
|
||||
hwnd: HWND,
|
||||
fFullscreen: BOOL,
|
||||
) -> HRESULT,
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct ITaskbarList2 {
|
||||
pub lpVtbl: *const ITaskbarList2Vtbl,
|
||||
}
|
||||
|
||||
pub const CLSID_TaskbarList: GUID = GUID {
|
||||
data1: 0x56fdf344,
|
||||
data2: 0xfd6d,
|
||||
data3: 0x11d0,
|
||||
data4: [0x95, 0x8a, 0x00, 0x60, 0x97, 0xc9, 0xa0, 0x90],
|
||||
};
|
||||
|
||||
pub const IID_ITaskbarList2: GUID = GUID {
|
||||
data1: 0x602d4995,
|
||||
data2: 0xb13a,
|
||||
data3: 0x429b,
|
||||
data4: [0xa6, 0x6e, 0x19, 0x35, 0xe4, 0x4f, 0x43, 0x17],
|
||||
};
|
|
@ -2,24 +2,26 @@
|
|||
|
||||
use std::sync::Once;
|
||||
|
||||
use windows_sys::Win32::{
|
||||
Foundation::{HWND, S_OK},
|
||||
Graphics::Gdi::{
|
||||
GetDC, GetDeviceCaps, MonitorFromWindow, HMONITOR, LOGPIXELSX, MONITOR_DEFAULTTONEAREST,
|
||||
},
|
||||
UI::{
|
||||
HiDpi::{
|
||||
DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE, MDT_EFFECTIVE_DPI,
|
||||
PROCESS_PER_MONITOR_DPI_AWARE,
|
||||
},
|
||||
WindowsAndMessaging::IsProcessDPIAware,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::platform_impl::platform::util::{
|
||||
ENABLE_NON_CLIENT_DPI_SCALING, GET_DPI_FOR_MONITOR, GET_DPI_FOR_WINDOW, SET_PROCESS_DPI_AWARE,
|
||||
SET_PROCESS_DPI_AWARENESS, SET_PROCESS_DPI_AWARENESS_CONTEXT,
|
||||
};
|
||||
use winapi::{
|
||||
shared::{
|
||||
minwindef::FALSE,
|
||||
windef::{DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE, HMONITOR, HWND},
|
||||
winerror::S_OK,
|
||||
},
|
||||
um::{
|
||||
shellscalingapi::{MDT_EFFECTIVE_DPI, PROCESS_PER_MONITOR_DPI_AWARE},
|
||||
wingdi::{GetDeviceCaps, LOGPIXELSX},
|
||||
winuser::{self, MONITOR_DEFAULTTONEAREST},
|
||||
},
|
||||
};
|
||||
|
||||
const DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2: DPI_AWARENESS_CONTEXT = -4isize as _;
|
||||
const DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2: DPI_AWARENESS_CONTEXT = -4;
|
||||
|
||||
pub fn become_dpi_aware() {
|
||||
static ENABLE_DPI_AWARENESS: Once = Once::new();
|
||||
|
@ -28,7 +30,7 @@ pub fn become_dpi_aware() {
|
|||
if let Some(SetProcessDpiAwarenessContext) = *SET_PROCESS_DPI_AWARENESS_CONTEXT {
|
||||
// We are on Windows 10 Anniversary Update (1607) or later.
|
||||
if SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)
|
||||
== FALSE
|
||||
== false.into()
|
||||
{
|
||||
// V2 only works with Windows 10 Creators Update (1703). Try using the older
|
||||
// V1 if we can't set V2.
|
||||
|
@ -76,8 +78,8 @@ pub fn dpi_to_scale_factor(dpi: u32) -> f64 {
|
|||
}
|
||||
|
||||
pub unsafe fn hwnd_dpi(hwnd: HWND) -> u32 {
|
||||
let hdc = winuser::GetDC(hwnd);
|
||||
if hdc.is_null() {
|
||||
let hdc = GetDC(hwnd);
|
||||
if hdc == 0 {
|
||||
panic!("[winit] `GetDC` returned null!");
|
||||
}
|
||||
if let Some(GetDpiForWindow) = *GET_DPI_FOR_WINDOW {
|
||||
|
@ -88,8 +90,8 @@ pub unsafe fn hwnd_dpi(hwnd: HWND) -> u32 {
|
|||
}
|
||||
} else if let Some(GetDpiForMonitor) = *GET_DPI_FOR_MONITOR {
|
||||
// We are on Windows 8.1 or later.
|
||||
let monitor = winuser::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
if monitor.is_null() {
|
||||
let monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
if monitor == 0 {
|
||||
return BASE_DPI;
|
||||
}
|
||||
|
||||
|
@ -102,7 +104,7 @@ pub unsafe fn hwnd_dpi(hwnd: HWND) -> u32 {
|
|||
}
|
||||
} else {
|
||||
// We are on Vista or later.
|
||||
if winuser::IsProcessDPIAware() != FALSE {
|
||||
if IsProcessDPIAware() != false.into() {
|
||||
// If the process is DPI aware, then scaling must be handled by the application using
|
||||
// this DPI value.
|
||||
GetDeviceCaps(hdc, LOGPIXELSX) as u32
|
||||
|
|
|
@ -1,29 +1,28 @@
|
|||
use std::{
|
||||
ffi::OsString,
|
||||
ffi::{c_void, OsString},
|
||||
os::windows::ffi::OsStringExt,
|
||||
path::PathBuf,
|
||||
ptr,
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
use winapi::{
|
||||
ctypes::c_void,
|
||||
shared::{
|
||||
guiddef::REFIID,
|
||||
minwindef::{DWORD, UINT, ULONG},
|
||||
windef::{HWND, POINTL},
|
||||
winerror::S_OK,
|
||||
use windows_sys::{
|
||||
core::{IUnknown, GUID, HRESULT},
|
||||
Win32::{
|
||||
Foundation::{DV_E_FORMATETC, HWND, POINTL, S_OK},
|
||||
System::{
|
||||
Com::{IDataObject, DVASPECT_CONTENT, FORMATETC, TYMED_HGLOBAL},
|
||||
Ole::{DROPEFFECT_COPY, DROPEFFECT_NONE},
|
||||
SystemServices::CF_HDROP,
|
||||
},
|
||||
um::{
|
||||
objidl::IDataObject,
|
||||
oleidl::{IDropTarget, IDropTargetVtbl, DROPEFFECT_COPY, DROPEFFECT_NONE},
|
||||
shellapi, unknwnbase,
|
||||
winnt::HRESULT,
|
||||
UI::Shell::{DragFinish, DragQueryFileW, HDROP},
|
||||
},
|
||||
};
|
||||
|
||||
use crate::platform_impl::platform::WindowId;
|
||||
|
||||
use crate::platform_impl::platform::{
|
||||
definitions::{IDataObjectVtbl, IDropTarget, IDropTargetVtbl, IUnknownVtbl},
|
||||
WindowId,
|
||||
};
|
||||
use crate::{event::Event, window::WindowId as SuperWindowId};
|
||||
|
||||
#[repr(C)]
|
||||
|
@ -32,7 +31,7 @@ pub struct FileDropHandlerData {
|
|||
refcount: AtomicUsize,
|
||||
window: HWND,
|
||||
send_event: Box<dyn Fn(Event<'static, ()>)>,
|
||||
cursor_effect: DWORD,
|
||||
cursor_effect: u32,
|
||||
hovered_is_valid: bool, /* If the currently hovered item is not valid there must not be any `HoveredFileCancelled` emitted */
|
||||
}
|
||||
|
||||
|
@ -60,8 +59,8 @@ impl FileDropHandler {
|
|||
|
||||
// Implement IUnknown
|
||||
pub unsafe extern "system" fn QueryInterface(
|
||||
_this: *mut unknwnbase::IUnknown,
|
||||
_riid: REFIID,
|
||||
_this: *mut IUnknown,
|
||||
_riid: *const GUID,
|
||||
_ppvObject: *mut *mut c_void,
|
||||
) -> HRESULT {
|
||||
// This function doesn't appear to be required for an `IDropTarget`.
|
||||
|
@ -69,28 +68,28 @@ impl FileDropHandler {
|
|||
unimplemented!();
|
||||
}
|
||||
|
||||
pub unsafe extern "system" fn AddRef(this: *mut unknwnbase::IUnknown) -> ULONG {
|
||||
pub unsafe extern "system" fn AddRef(this: *mut IUnknown) -> u32 {
|
||||
let drop_handler_data = Self::from_interface(this);
|
||||
let count = drop_handler_data.refcount.fetch_add(1, Ordering::Release) + 1;
|
||||
count as ULONG
|
||||
count as u32
|
||||
}
|
||||
|
||||
pub unsafe extern "system" fn Release(this: *mut unknwnbase::IUnknown) -> ULONG {
|
||||
pub unsafe extern "system" fn Release(this: *mut IUnknown) -> u32 {
|
||||
let drop_handler = Self::from_interface(this);
|
||||
let count = drop_handler.refcount.fetch_sub(1, Ordering::Release) - 1;
|
||||
if count == 0 {
|
||||
// Destroy the underlying data
|
||||
Box::from_raw(drop_handler as *mut FileDropHandlerData);
|
||||
}
|
||||
count as ULONG
|
||||
count as u32
|
||||
}
|
||||
|
||||
pub unsafe extern "system" fn DragEnter(
|
||||
this: *mut IDropTarget,
|
||||
pDataObj: *const IDataObject,
|
||||
_grfKeyState: DWORD,
|
||||
_grfKeyState: u32,
|
||||
_pt: *const POINTL,
|
||||
pdwEffect: *mut DWORD,
|
||||
pdwEffect: *mut u32,
|
||||
) -> HRESULT {
|
||||
use crate::event::WindowEvent::HoveredFile;
|
||||
let drop_handler = Self::from_interface(this);
|
||||
|
@ -113,9 +112,9 @@ impl FileDropHandler {
|
|||
|
||||
pub unsafe extern "system" fn DragOver(
|
||||
this: *mut IDropTarget,
|
||||
_grfKeyState: DWORD,
|
||||
_grfKeyState: u32,
|
||||
_pt: *const POINTL,
|
||||
pdwEffect: *mut DWORD,
|
||||
pdwEffect: *mut u32,
|
||||
) -> HRESULT {
|
||||
let drop_handler = Self::from_interface(this);
|
||||
*pdwEffect = drop_handler.cursor_effect;
|
||||
|
@ -139,9 +138,9 @@ impl FileDropHandler {
|
|||
pub unsafe extern "system" fn Drop(
|
||||
this: *mut IDropTarget,
|
||||
pDataObj: *const IDataObject,
|
||||
_grfKeyState: DWORD,
|
||||
_grfKeyState: u32,
|
||||
_pt: *const POINTL,
|
||||
_pdwEffect: *mut DWORD,
|
||||
_pdwEffect: *mut u32,
|
||||
) -> HRESULT {
|
||||
use crate::event::WindowEvent::DroppedFile;
|
||||
let drop_handler = Self::from_interface(this);
|
||||
|
@ -152,7 +151,7 @@ impl FileDropHandler {
|
|||
});
|
||||
});
|
||||
if let Some(hdrop) = hdrop {
|
||||
shellapi::DragFinish(hdrop);
|
||||
DragFinish(hdrop);
|
||||
}
|
||||
|
||||
S_OK
|
||||
|
@ -162,38 +161,23 @@ impl FileDropHandler {
|
|||
&mut *(this as *mut _)
|
||||
}
|
||||
|
||||
unsafe fn iterate_filenames<F>(
|
||||
data_obj: *const IDataObject,
|
||||
callback: F,
|
||||
) -> Option<shellapi::HDROP>
|
||||
unsafe fn iterate_filenames<F>(data_obj: *const IDataObject, callback: F) -> Option<HDROP>
|
||||
where
|
||||
F: Fn(PathBuf),
|
||||
{
|
||||
use winapi::{
|
||||
shared::{
|
||||
winerror::{DV_E_FORMATETC, SUCCEEDED},
|
||||
wtypes::{CLIPFORMAT, DVASPECT_CONTENT},
|
||||
},
|
||||
um::{
|
||||
objidl::{FORMATETC, TYMED_HGLOBAL},
|
||||
shellapi::DragQueryFileW,
|
||||
winuser::CF_HDROP,
|
||||
},
|
||||
};
|
||||
|
||||
let drop_format = FORMATETC {
|
||||
cfFormat: CF_HDROP as CLIPFORMAT,
|
||||
ptd: ptr::null(),
|
||||
dwAspect: DVASPECT_CONTENT,
|
||||
cfFormat: CF_HDROP as u16,
|
||||
ptd: ptr::null_mut(),
|
||||
dwAspect: DVASPECT_CONTENT as u32,
|
||||
lindex: -1,
|
||||
tymed: TYMED_HGLOBAL,
|
||||
tymed: TYMED_HGLOBAL as u32,
|
||||
};
|
||||
|
||||
let mut medium = std::mem::zeroed();
|
||||
let get_data_result = (*data_obj).GetData(&drop_format, &mut medium);
|
||||
if SUCCEEDED(get_data_result) {
|
||||
let hglobal = (*medium.u).hGlobal();
|
||||
let hdrop = (*hglobal) as shellapi::HDROP;
|
||||
let get_data_fn = (*(*data_obj).cast::<IDataObjectVtbl>()).GetData;
|
||||
let get_data_result = get_data_fn(data_obj as *mut _, &drop_format, &mut medium);
|
||||
if get_data_result >= 0 {
|
||||
let hdrop = medium.Anonymous.hGlobal;
|
||||
|
||||
// The second parameter (0xFFFFFFFF) instructs the function to return the item count
|
||||
let item_count = DragQueryFileW(hdrop, 0xFFFFFFFF, ptr::null_mut(), 0);
|
||||
|
@ -207,7 +191,7 @@ impl FileDropHandler {
|
|||
|
||||
// Fill path_buf with the null-terminated file name
|
||||
let mut path_buf = Vec::with_capacity(str_len);
|
||||
DragQueryFileW(hdrop, i, path_buf.as_mut_ptr(), str_len as UINT);
|
||||
DragQueryFileW(hdrop, i, path_buf.as_mut_ptr(), str_len as u32);
|
||||
path_buf.set_len(str_len);
|
||||
|
||||
callback(OsString::from_wide(&path_buf[0..character_count]).into());
|
||||
|
@ -235,13 +219,13 @@ impl FileDropHandlerData {
|
|||
impl Drop for FileDropHandler {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
FileDropHandler::Release(self.data as *mut unknwnbase::IUnknown);
|
||||
FileDropHandler::Release(self.data as *mut IUnknown);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static DROP_TARGET_VTBL: IDropTargetVtbl = IDropTargetVtbl {
|
||||
parent: unknwnbase::IUnknownVtbl {
|
||||
parent: IUnknownVtbl {
|
||||
QueryInterface: FileDropHandler::QueryInterface,
|
||||
AddRef: FileDropHandler::AddRef,
|
||||
Release: FileDropHandler::Release,
|
||||
|
|
|
@ -1,37 +1,60 @@
|
|||
use std::{
|
||||
char,
|
||||
os::raw::c_int,
|
||||
ptr,
|
||||
sync::atomic::{AtomicBool, AtomicPtr, Ordering},
|
||||
sync::atomic::{AtomicBool, AtomicIsize, Ordering},
|
||||
};
|
||||
|
||||
use windows_sys::Win32::{
|
||||
Foundation::{LPARAM, WPARAM},
|
||||
UI::{
|
||||
Input::KeyboardAndMouse::{
|
||||
GetKeyState, GetKeyboardLayout, GetKeyboardState, MapVirtualKeyA, ToUnicodeEx,
|
||||
VIRTUAL_KEY, VK_0, VK_1, VK_2, VK_3, VK_4, VK_5, VK_6, VK_7, VK_8, VK_9, VK_A, VK_ADD,
|
||||
VK_APPS, VK_B, VK_BACK, VK_BROWSER_BACK, VK_BROWSER_FAVORITES, VK_BROWSER_FORWARD,
|
||||
VK_BROWSER_HOME, VK_BROWSER_REFRESH, VK_BROWSER_SEARCH, VK_BROWSER_STOP, VK_C,
|
||||
VK_CAPITAL, VK_CONTROL, VK_CONVERT, VK_D, VK_DECIMAL, VK_DELETE, VK_DIVIDE, VK_DOWN,
|
||||
VK_E, VK_END, VK_ESCAPE, VK_F, VK_F1, VK_F10, VK_F11, VK_F12, VK_F13, VK_F14, VK_F15,
|
||||
VK_F16, VK_F17, VK_F18, VK_F19, VK_F2, VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, VK_F3,
|
||||
VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_G, VK_H, VK_HOME, VK_I, VK_INSERT, VK_J,
|
||||
VK_K, VK_KANA, VK_KANJI, VK_L, VK_LAUNCH_MAIL, VK_LAUNCH_MEDIA_SELECT, VK_LCONTROL,
|
||||
VK_LEFT, VK_LMENU, VK_LSHIFT, VK_LWIN, VK_M, VK_MEDIA_NEXT_TRACK, VK_MEDIA_PLAY_PAUSE,
|
||||
VK_MEDIA_PREV_TRACK, VK_MEDIA_STOP, VK_MENU, VK_MULTIPLY, VK_N, VK_NEXT, VK_NONCONVERT,
|
||||
VK_NUMLOCK, VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4, VK_NUMPAD5,
|
||||
VK_NUMPAD6, VK_NUMPAD7, VK_NUMPAD8, VK_NUMPAD9, VK_O, VK_OEM_1, VK_OEM_102, VK_OEM_2,
|
||||
VK_OEM_3, VK_OEM_4, VK_OEM_5, VK_OEM_6, VK_OEM_7, VK_OEM_COMMA, VK_OEM_MINUS,
|
||||
VK_OEM_PERIOD, VK_OEM_PLUS, VK_P, VK_PAUSE, VK_PRIOR, VK_Q, VK_R, VK_RCONTROL,
|
||||
VK_RETURN, VK_RIGHT, VK_RMENU, VK_RSHIFT, VK_RWIN, VK_S, VK_SCROLL, VK_SHIFT, VK_SLEEP,
|
||||
VK_SNAPSHOT, VK_SPACE, VK_SUBTRACT, VK_T, VK_TAB, VK_U, VK_UP, VK_V, VK_VOLUME_DOWN,
|
||||
VK_VOLUME_MUTE, VK_VOLUME_UP, VK_W, VK_X, VK_Y, VK_Z,
|
||||
},
|
||||
TextServices::HKL,
|
||||
WindowsAndMessaging::{MAPVK_VK_TO_CHAR, MAPVK_VSC_TO_VK_EX},
|
||||
},
|
||||
};
|
||||
|
||||
use crate::event::{ModifiersState, ScanCode, VirtualKeyCode};
|
||||
|
||||
use winapi::{
|
||||
shared::minwindef::{HKL, HKL__, LPARAM, UINT, WPARAM},
|
||||
um::winuser,
|
||||
};
|
||||
use super::util::has_flag;
|
||||
|
||||
fn key_pressed(vkey: c_int) -> bool {
|
||||
unsafe { (winuser::GetKeyState(vkey) & (1 << 15)) == (1 << 15) }
|
||||
fn key_pressed(vkey: VIRTUAL_KEY) -> bool {
|
||||
unsafe { has_flag(GetKeyState(vkey as i32), 1 << 15) }
|
||||
}
|
||||
|
||||
pub fn get_key_mods() -> ModifiersState {
|
||||
let filter_out_altgr = layout_uses_altgr() && key_pressed(winuser::VK_RMENU);
|
||||
let filter_out_altgr = layout_uses_altgr() && key_pressed(VK_RMENU);
|
||||
|
||||
let mut mods = ModifiersState::empty();
|
||||
mods.set(ModifiersState::SHIFT, key_pressed(winuser::VK_SHIFT));
|
||||
mods.set(ModifiersState::SHIFT, key_pressed(VK_SHIFT));
|
||||
mods.set(
|
||||
ModifiersState::CTRL,
|
||||
key_pressed(winuser::VK_CONTROL) && !filter_out_altgr,
|
||||
key_pressed(VK_CONTROL) && !filter_out_altgr,
|
||||
);
|
||||
mods.set(
|
||||
ModifiersState::ALT,
|
||||
key_pressed(winuser::VK_MENU) && !filter_out_altgr,
|
||||
key_pressed(VK_MENU) && !filter_out_altgr,
|
||||
);
|
||||
mods.set(
|
||||
ModifiersState::LOGO,
|
||||
key_pressed(winuser::VK_LWIN) || key_pressed(winuser::VK_RWIN),
|
||||
key_pressed(VK_LWIN) || key_pressed(VK_RWIN),
|
||||
);
|
||||
mods
|
||||
}
|
||||
|
@ -85,19 +108,19 @@ impl From<ModifiersStateSide> for ModifiersState {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_pressed_keys() -> impl Iterator<Item = c_int> {
|
||||
pub fn get_pressed_keys() -> impl Iterator<Item = VIRTUAL_KEY> {
|
||||
let mut keyboard_state = vec![0u8; 256];
|
||||
unsafe { winuser::GetKeyboardState(keyboard_state.as_mut_ptr()) };
|
||||
unsafe { GetKeyboardState(keyboard_state.as_mut_ptr()) };
|
||||
keyboard_state
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.filter(|(_, p)| (*p & (1 << 7)) != 0) // whether or not a key is pressed is communicated via the high-order bit
|
||||
.map(|(i, _)| i as c_int)
|
||||
.map(|(i, _)| i as u16)
|
||||
}
|
||||
|
||||
unsafe fn get_char(keyboard_state: &[u8; 256], v_key: u32, hkl: HKL) -> Option<char> {
|
||||
let mut unicode_bytes = [0u16; 5];
|
||||
let len = winuser::ToUnicodeEx(
|
||||
let len = ToUnicodeEx(
|
||||
v_key,
|
||||
0,
|
||||
keyboard_state.as_ptr(),
|
||||
|
@ -126,10 +149,10 @@ unsafe fn get_char(keyboard_state: &[u8; 256], v_key: u32, hkl: HKL) -> Option<c
|
|||
/// [source]: https://github.com/mozilla/gecko-dev/blob/265e6721798a455604328ed5262f430cfcc37c2f/widget/windows/KeyboardLayout.cpp#L4356-L4416
|
||||
fn layout_uses_altgr() -> bool {
|
||||
unsafe {
|
||||
static ACTIVE_LAYOUT: AtomicPtr<HKL__> = AtomicPtr::new(ptr::null_mut());
|
||||
static ACTIVE_LAYOUT: AtomicIsize = AtomicIsize::new(0);
|
||||
static USES_ALTGR: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
let hkl = winuser::GetKeyboardLayout(0);
|
||||
let hkl = GetKeyboardLayout(0);
|
||||
let old_hkl = ACTIVE_LAYOUT.swap(hkl, Ordering::SeqCst);
|
||||
|
||||
if hkl == old_hkl {
|
||||
|
@ -139,8 +162,8 @@ fn layout_uses_altgr() -> bool {
|
|||
let mut keyboard_state_altgr = [0u8; 256];
|
||||
// AltGr is an alias for Ctrl+Alt for... some reason. Whatever it is, those are the keypresses
|
||||
// we have to emulate to do an AltGr test.
|
||||
keyboard_state_altgr[winuser::VK_MENU as usize] = 0x80;
|
||||
keyboard_state_altgr[winuser::VK_CONTROL as usize] = 0x80;
|
||||
keyboard_state_altgr[VK_MENU as usize] = 0x80;
|
||||
keyboard_state_altgr[VK_CONTROL as usize] = 0x80;
|
||||
|
||||
let keyboard_state_empty = [0u8; 256];
|
||||
|
||||
|
@ -160,206 +183,204 @@ fn layout_uses_altgr() -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn vkey_to_winit_vkey(vkey: c_int) -> Option<VirtualKeyCode> {
|
||||
pub fn vkey_to_winit_vkey(vkey: VIRTUAL_KEY) -> Option<VirtualKeyCode> {
|
||||
// VK_* codes are documented here https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
|
||||
match vkey {
|
||||
//winuser::VK_LBUTTON => Some(VirtualKeyCode::Lbutton),
|
||||
//winuser::VK_RBUTTON => Some(VirtualKeyCode::Rbutton),
|
||||
//winuser::VK_CANCEL => Some(VirtualKeyCode::Cancel),
|
||||
//winuser::VK_MBUTTON => Some(VirtualKeyCode::Mbutton),
|
||||
//winuser::VK_XBUTTON1 => Some(VirtualKeyCode::Xbutton1),
|
||||
//winuser::VK_XBUTTON2 => Some(VirtualKeyCode::Xbutton2),
|
||||
winuser::VK_BACK => Some(VirtualKeyCode::Back),
|
||||
winuser::VK_TAB => Some(VirtualKeyCode::Tab),
|
||||
//winuser::VK_CLEAR => Some(VirtualKeyCode::Clear),
|
||||
winuser::VK_RETURN => Some(VirtualKeyCode::Return),
|
||||
winuser::VK_LSHIFT => Some(VirtualKeyCode::LShift),
|
||||
winuser::VK_RSHIFT => Some(VirtualKeyCode::RShift),
|
||||
winuser::VK_LCONTROL => Some(VirtualKeyCode::LControl),
|
||||
winuser::VK_RCONTROL => Some(VirtualKeyCode::RControl),
|
||||
winuser::VK_LMENU => Some(VirtualKeyCode::LAlt),
|
||||
winuser::VK_RMENU => Some(VirtualKeyCode::RAlt),
|
||||
winuser::VK_PAUSE => Some(VirtualKeyCode::Pause),
|
||||
winuser::VK_CAPITAL => Some(VirtualKeyCode::Capital),
|
||||
winuser::VK_KANA => Some(VirtualKeyCode::Kana),
|
||||
//winuser::VK_HANGUEL => Some(VirtualKeyCode::Hanguel),
|
||||
//winuser::VK_HANGUL => Some(VirtualKeyCode::Hangul),
|
||||
//winuser::VK_JUNJA => Some(VirtualKeyCode::Junja),
|
||||
//winuser::VK_FINAL => Some(VirtualKeyCode::Final),
|
||||
//winuser::VK_HANJA => Some(VirtualKeyCode::Hanja),
|
||||
winuser::VK_KANJI => Some(VirtualKeyCode::Kanji),
|
||||
winuser::VK_ESCAPE => Some(VirtualKeyCode::Escape),
|
||||
winuser::VK_CONVERT => Some(VirtualKeyCode::Convert),
|
||||
winuser::VK_NONCONVERT => Some(VirtualKeyCode::NoConvert),
|
||||
//winuser::VK_ACCEPT => Some(VirtualKeyCode::Accept),
|
||||
//winuser::VK_MODECHANGE => Some(VirtualKeyCode::Modechange),
|
||||
winuser::VK_SPACE => Some(VirtualKeyCode::Space),
|
||||
winuser::VK_PRIOR => Some(VirtualKeyCode::PageUp),
|
||||
winuser::VK_NEXT => Some(VirtualKeyCode::PageDown),
|
||||
winuser::VK_END => Some(VirtualKeyCode::End),
|
||||
winuser::VK_HOME => Some(VirtualKeyCode::Home),
|
||||
winuser::VK_LEFT => Some(VirtualKeyCode::Left),
|
||||
winuser::VK_UP => Some(VirtualKeyCode::Up),
|
||||
winuser::VK_RIGHT => Some(VirtualKeyCode::Right),
|
||||
winuser::VK_DOWN => Some(VirtualKeyCode::Down),
|
||||
//winuser::VK_SELECT => Some(VirtualKeyCode::Select),
|
||||
//winuser::VK_PRINT => Some(VirtualKeyCode::Print),
|
||||
//winuser::VK_EXECUTE => Some(VirtualKeyCode::Execute),
|
||||
winuser::VK_SNAPSHOT => Some(VirtualKeyCode::Snapshot),
|
||||
winuser::VK_INSERT => Some(VirtualKeyCode::Insert),
|
||||
winuser::VK_DELETE => Some(VirtualKeyCode::Delete),
|
||||
//winuser::VK_HELP => Some(VirtualKeyCode::Help),
|
||||
0x30 => Some(VirtualKeyCode::Key0),
|
||||
0x31 => Some(VirtualKeyCode::Key1),
|
||||
0x32 => Some(VirtualKeyCode::Key2),
|
||||
0x33 => Some(VirtualKeyCode::Key3),
|
||||
0x34 => Some(VirtualKeyCode::Key4),
|
||||
0x35 => Some(VirtualKeyCode::Key5),
|
||||
0x36 => Some(VirtualKeyCode::Key6),
|
||||
0x37 => Some(VirtualKeyCode::Key7),
|
||||
0x38 => Some(VirtualKeyCode::Key8),
|
||||
0x39 => Some(VirtualKeyCode::Key9),
|
||||
0x41 => Some(VirtualKeyCode::A),
|
||||
0x42 => Some(VirtualKeyCode::B),
|
||||
0x43 => Some(VirtualKeyCode::C),
|
||||
0x44 => Some(VirtualKeyCode::D),
|
||||
0x45 => Some(VirtualKeyCode::E),
|
||||
0x46 => Some(VirtualKeyCode::F),
|
||||
0x47 => Some(VirtualKeyCode::G),
|
||||
0x48 => Some(VirtualKeyCode::H),
|
||||
0x49 => Some(VirtualKeyCode::I),
|
||||
0x4A => Some(VirtualKeyCode::J),
|
||||
0x4B => Some(VirtualKeyCode::K),
|
||||
0x4C => Some(VirtualKeyCode::L),
|
||||
0x4D => Some(VirtualKeyCode::M),
|
||||
0x4E => Some(VirtualKeyCode::N),
|
||||
0x4F => Some(VirtualKeyCode::O),
|
||||
0x50 => Some(VirtualKeyCode::P),
|
||||
0x51 => Some(VirtualKeyCode::Q),
|
||||
0x52 => Some(VirtualKeyCode::R),
|
||||
0x53 => Some(VirtualKeyCode::S),
|
||||
0x54 => Some(VirtualKeyCode::T),
|
||||
0x55 => Some(VirtualKeyCode::U),
|
||||
0x56 => Some(VirtualKeyCode::V),
|
||||
0x57 => Some(VirtualKeyCode::W),
|
||||
0x58 => Some(VirtualKeyCode::X),
|
||||
0x59 => Some(VirtualKeyCode::Y),
|
||||
0x5A => Some(VirtualKeyCode::Z),
|
||||
winuser::VK_LWIN => Some(VirtualKeyCode::LWin),
|
||||
winuser::VK_RWIN => Some(VirtualKeyCode::RWin),
|
||||
winuser::VK_APPS => Some(VirtualKeyCode::Apps),
|
||||
winuser::VK_SLEEP => Some(VirtualKeyCode::Sleep),
|
||||
winuser::VK_NUMPAD0 => Some(VirtualKeyCode::Numpad0),
|
||||
winuser::VK_NUMPAD1 => Some(VirtualKeyCode::Numpad1),
|
||||
winuser::VK_NUMPAD2 => Some(VirtualKeyCode::Numpad2),
|
||||
winuser::VK_NUMPAD3 => Some(VirtualKeyCode::Numpad3),
|
||||
winuser::VK_NUMPAD4 => Some(VirtualKeyCode::Numpad4),
|
||||
winuser::VK_NUMPAD5 => Some(VirtualKeyCode::Numpad5),
|
||||
winuser::VK_NUMPAD6 => Some(VirtualKeyCode::Numpad6),
|
||||
winuser::VK_NUMPAD7 => Some(VirtualKeyCode::Numpad7),
|
||||
winuser::VK_NUMPAD8 => Some(VirtualKeyCode::Numpad8),
|
||||
winuser::VK_NUMPAD9 => Some(VirtualKeyCode::Numpad9),
|
||||
winuser::VK_MULTIPLY => Some(VirtualKeyCode::NumpadMultiply),
|
||||
winuser::VK_ADD => Some(VirtualKeyCode::NumpadAdd),
|
||||
//winuser::VK_SEPARATOR => Some(VirtualKeyCode::Separator),
|
||||
winuser::VK_SUBTRACT => Some(VirtualKeyCode::NumpadSubtract),
|
||||
winuser::VK_DECIMAL => Some(VirtualKeyCode::NumpadDecimal),
|
||||
winuser::VK_DIVIDE => Some(VirtualKeyCode::NumpadDivide),
|
||||
winuser::VK_F1 => Some(VirtualKeyCode::F1),
|
||||
winuser::VK_F2 => Some(VirtualKeyCode::F2),
|
||||
winuser::VK_F3 => Some(VirtualKeyCode::F3),
|
||||
winuser::VK_F4 => Some(VirtualKeyCode::F4),
|
||||
winuser::VK_F5 => Some(VirtualKeyCode::F5),
|
||||
winuser::VK_F6 => Some(VirtualKeyCode::F6),
|
||||
winuser::VK_F7 => Some(VirtualKeyCode::F7),
|
||||
winuser::VK_F8 => Some(VirtualKeyCode::F8),
|
||||
winuser::VK_F9 => Some(VirtualKeyCode::F9),
|
||||
winuser::VK_F10 => Some(VirtualKeyCode::F10),
|
||||
winuser::VK_F11 => Some(VirtualKeyCode::F11),
|
||||
winuser::VK_F12 => Some(VirtualKeyCode::F12),
|
||||
winuser::VK_F13 => Some(VirtualKeyCode::F13),
|
||||
winuser::VK_F14 => Some(VirtualKeyCode::F14),
|
||||
winuser::VK_F15 => Some(VirtualKeyCode::F15),
|
||||
winuser::VK_F16 => Some(VirtualKeyCode::F16),
|
||||
winuser::VK_F17 => Some(VirtualKeyCode::F17),
|
||||
winuser::VK_F18 => Some(VirtualKeyCode::F18),
|
||||
winuser::VK_F19 => Some(VirtualKeyCode::F19),
|
||||
winuser::VK_F20 => Some(VirtualKeyCode::F20),
|
||||
winuser::VK_F21 => Some(VirtualKeyCode::F21),
|
||||
winuser::VK_F22 => Some(VirtualKeyCode::F22),
|
||||
winuser::VK_F23 => Some(VirtualKeyCode::F23),
|
||||
winuser::VK_F24 => Some(VirtualKeyCode::F24),
|
||||
winuser::VK_NUMLOCK => Some(VirtualKeyCode::Numlock),
|
||||
winuser::VK_SCROLL => Some(VirtualKeyCode::Scroll),
|
||||
winuser::VK_BROWSER_BACK => Some(VirtualKeyCode::NavigateBackward),
|
||||
winuser::VK_BROWSER_FORWARD => Some(VirtualKeyCode::NavigateForward),
|
||||
winuser::VK_BROWSER_REFRESH => Some(VirtualKeyCode::WebRefresh),
|
||||
winuser::VK_BROWSER_STOP => Some(VirtualKeyCode::WebStop),
|
||||
winuser::VK_BROWSER_SEARCH => Some(VirtualKeyCode::WebSearch),
|
||||
winuser::VK_BROWSER_FAVORITES => Some(VirtualKeyCode::WebFavorites),
|
||||
winuser::VK_BROWSER_HOME => Some(VirtualKeyCode::WebHome),
|
||||
winuser::VK_VOLUME_MUTE => Some(VirtualKeyCode::Mute),
|
||||
winuser::VK_VOLUME_DOWN => Some(VirtualKeyCode::VolumeDown),
|
||||
winuser::VK_VOLUME_UP => Some(VirtualKeyCode::VolumeUp),
|
||||
winuser::VK_MEDIA_NEXT_TRACK => Some(VirtualKeyCode::NextTrack),
|
||||
winuser::VK_MEDIA_PREV_TRACK => Some(VirtualKeyCode::PrevTrack),
|
||||
winuser::VK_MEDIA_STOP => Some(VirtualKeyCode::MediaStop),
|
||||
winuser::VK_MEDIA_PLAY_PAUSE => Some(VirtualKeyCode::PlayPause),
|
||||
winuser::VK_LAUNCH_MAIL => Some(VirtualKeyCode::Mail),
|
||||
winuser::VK_LAUNCH_MEDIA_SELECT => Some(VirtualKeyCode::MediaSelect),
|
||||
/*winuser::VK_LAUNCH_APP1 => Some(VirtualKeyCode::Launch_app1),
|
||||
winuser::VK_LAUNCH_APP2 => Some(VirtualKeyCode::Launch_app2),*/
|
||||
winuser::VK_OEM_PLUS => Some(VirtualKeyCode::Equals),
|
||||
winuser::VK_OEM_COMMA => Some(VirtualKeyCode::Comma),
|
||||
winuser::VK_OEM_MINUS => Some(VirtualKeyCode::Minus),
|
||||
winuser::VK_OEM_PERIOD => Some(VirtualKeyCode::Period),
|
||||
winuser::VK_OEM_1 => map_text_keys(vkey),
|
||||
winuser::VK_OEM_2 => map_text_keys(vkey),
|
||||
winuser::VK_OEM_3 => map_text_keys(vkey),
|
||||
winuser::VK_OEM_4 => map_text_keys(vkey),
|
||||
winuser::VK_OEM_5 => map_text_keys(vkey),
|
||||
winuser::VK_OEM_6 => map_text_keys(vkey),
|
||||
winuser::VK_OEM_7 => map_text_keys(vkey),
|
||||
/* winuser::VK_OEM_8 => Some(VirtualKeyCode::Oem_8), */
|
||||
winuser::VK_OEM_102 => Some(VirtualKeyCode::OEM102),
|
||||
/*winuser::VK_PROCESSKEY => Some(VirtualKeyCode::Processkey),
|
||||
winuser::VK_PACKET => Some(VirtualKeyCode::Packet),
|
||||
winuser::VK_ATTN => Some(VirtualKeyCode::Attn),
|
||||
winuser::VK_CRSEL => Some(VirtualKeyCode::Crsel),
|
||||
winuser::VK_EXSEL => Some(VirtualKeyCode::Exsel),
|
||||
winuser::VK_EREOF => Some(VirtualKeyCode::Ereof),
|
||||
winuser::VK_PLAY => Some(VirtualKeyCode::Play),
|
||||
winuser::VK_ZOOM => Some(VirtualKeyCode::Zoom),
|
||||
winuser::VK_NONAME => Some(VirtualKeyCode::Noname),
|
||||
winuser::VK_PA1 => Some(VirtualKeyCode::Pa1),
|
||||
winuser::VK_OEM_CLEAR => Some(VirtualKeyCode::Oem_clear),*/
|
||||
//VK_LBUTTON => Some(VirtualKeyCode::Lbutton),
|
||||
//VK_RBUTTON => Some(VirtualKeyCode::Rbutton),
|
||||
//VK_CANCEL => Some(VirtualKeyCode::Cancel),
|
||||
//VK_MBUTTON => Some(VirtualKeyCode::Mbutton),
|
||||
//VK_XBUTTON1 => Some(VirtualKeyCode::Xbutton1),
|
||||
//VK_XBUTTON2 => Some(VirtualKeyCode::Xbutton2),
|
||||
VK_BACK => Some(VirtualKeyCode::Back),
|
||||
VK_TAB => Some(VirtualKeyCode::Tab),
|
||||
//VK_CLEAR => Some(VirtualKeyCode::Clear),
|
||||
VK_RETURN => Some(VirtualKeyCode::Return),
|
||||
VK_LSHIFT => Some(VirtualKeyCode::LShift),
|
||||
VK_RSHIFT => Some(VirtualKeyCode::RShift),
|
||||
VK_LCONTROL => Some(VirtualKeyCode::LControl),
|
||||
VK_RCONTROL => Some(VirtualKeyCode::RControl),
|
||||
VK_LMENU => Some(VirtualKeyCode::LAlt),
|
||||
VK_RMENU => Some(VirtualKeyCode::RAlt),
|
||||
VK_PAUSE => Some(VirtualKeyCode::Pause),
|
||||
VK_CAPITAL => Some(VirtualKeyCode::Capital),
|
||||
VK_KANA => Some(VirtualKeyCode::Kana),
|
||||
//VK_HANGUEL => Some(VirtualKeyCode::Hanguel),
|
||||
//VK_HANGUL => Some(VirtualKeyCode::Hangul),
|
||||
//VK_JUNJA => Some(VirtualKeyCode::Junja),
|
||||
//VK_FINAL => Some(VirtualKeyCode::Final),
|
||||
//VK_HANJA => Some(VirtualKeyCode::Hanja),
|
||||
VK_KANJI => Some(VirtualKeyCode::Kanji),
|
||||
VK_ESCAPE => Some(VirtualKeyCode::Escape),
|
||||
VK_CONVERT => Some(VirtualKeyCode::Convert),
|
||||
VK_NONCONVERT => Some(VirtualKeyCode::NoConvert),
|
||||
//VK_ACCEPT => Some(VirtualKeyCode::Accept),
|
||||
//VK_MODECHANGE => Some(VirtualKeyCode::Modechange),
|
||||
VK_SPACE => Some(VirtualKeyCode::Space),
|
||||
VK_PRIOR => Some(VirtualKeyCode::PageUp),
|
||||
VK_NEXT => Some(VirtualKeyCode::PageDown),
|
||||
VK_END => Some(VirtualKeyCode::End),
|
||||
VK_HOME => Some(VirtualKeyCode::Home),
|
||||
VK_LEFT => Some(VirtualKeyCode::Left),
|
||||
VK_UP => Some(VirtualKeyCode::Up),
|
||||
VK_RIGHT => Some(VirtualKeyCode::Right),
|
||||
VK_DOWN => Some(VirtualKeyCode::Down),
|
||||
//VK_SELECT => Some(VirtualKeyCode::Select),
|
||||
//VK_PRINT => Some(VirtualKeyCode::Print),
|
||||
//VK_EXECUTE => Some(VirtualKeyCode::Execute),
|
||||
VK_SNAPSHOT => Some(VirtualKeyCode::Snapshot),
|
||||
VK_INSERT => Some(VirtualKeyCode::Insert),
|
||||
VK_DELETE => Some(VirtualKeyCode::Delete),
|
||||
//VK_HELP => Some(VirtualKeyCode::Help),
|
||||
VK_0 => Some(VirtualKeyCode::Key0),
|
||||
VK_1 => Some(VirtualKeyCode::Key1),
|
||||
VK_2 => Some(VirtualKeyCode::Key2),
|
||||
VK_3 => Some(VirtualKeyCode::Key3),
|
||||
VK_4 => Some(VirtualKeyCode::Key4),
|
||||
VK_5 => Some(VirtualKeyCode::Key5),
|
||||
VK_6 => Some(VirtualKeyCode::Key6),
|
||||
VK_7 => Some(VirtualKeyCode::Key7),
|
||||
VK_8 => Some(VirtualKeyCode::Key8),
|
||||
VK_9 => Some(VirtualKeyCode::Key9),
|
||||
VK_A => Some(VirtualKeyCode::A),
|
||||
VK_B => Some(VirtualKeyCode::B),
|
||||
VK_C => Some(VirtualKeyCode::C),
|
||||
VK_D => Some(VirtualKeyCode::D),
|
||||
VK_E => Some(VirtualKeyCode::E),
|
||||
VK_F => Some(VirtualKeyCode::F),
|
||||
VK_G => Some(VirtualKeyCode::G),
|
||||
VK_H => Some(VirtualKeyCode::H),
|
||||
VK_I => Some(VirtualKeyCode::I),
|
||||
VK_J => Some(VirtualKeyCode::J),
|
||||
VK_K => Some(VirtualKeyCode::K),
|
||||
VK_L => Some(VirtualKeyCode::L),
|
||||
VK_M => Some(VirtualKeyCode::M),
|
||||
VK_N => Some(VirtualKeyCode::N),
|
||||
VK_O => Some(VirtualKeyCode::O),
|
||||
VK_P => Some(VirtualKeyCode::P),
|
||||
VK_Q => Some(VirtualKeyCode::Q),
|
||||
VK_R => Some(VirtualKeyCode::R),
|
||||
VK_S => Some(VirtualKeyCode::S),
|
||||
VK_T => Some(VirtualKeyCode::T),
|
||||
VK_U => Some(VirtualKeyCode::U),
|
||||
VK_V => Some(VirtualKeyCode::V),
|
||||
VK_W => Some(VirtualKeyCode::W),
|
||||
VK_X => Some(VirtualKeyCode::X),
|
||||
VK_Y => Some(VirtualKeyCode::Y),
|
||||
VK_Z => Some(VirtualKeyCode::Z),
|
||||
VK_LWIN => Some(VirtualKeyCode::LWin),
|
||||
VK_RWIN => Some(VirtualKeyCode::RWin),
|
||||
VK_APPS => Some(VirtualKeyCode::Apps),
|
||||
VK_SLEEP => Some(VirtualKeyCode::Sleep),
|
||||
VK_NUMPAD0 => Some(VirtualKeyCode::Numpad0),
|
||||
VK_NUMPAD1 => Some(VirtualKeyCode::Numpad1),
|
||||
VK_NUMPAD2 => Some(VirtualKeyCode::Numpad2),
|
||||
VK_NUMPAD3 => Some(VirtualKeyCode::Numpad3),
|
||||
VK_NUMPAD4 => Some(VirtualKeyCode::Numpad4),
|
||||
VK_NUMPAD5 => Some(VirtualKeyCode::Numpad5),
|
||||
VK_NUMPAD6 => Some(VirtualKeyCode::Numpad6),
|
||||
VK_NUMPAD7 => Some(VirtualKeyCode::Numpad7),
|
||||
VK_NUMPAD8 => Some(VirtualKeyCode::Numpad8),
|
||||
VK_NUMPAD9 => Some(VirtualKeyCode::Numpad9),
|
||||
VK_MULTIPLY => Some(VirtualKeyCode::NumpadMultiply),
|
||||
VK_ADD => Some(VirtualKeyCode::NumpadAdd),
|
||||
//VK_SEPARATOR => Some(VirtualKeyCode::Separator),
|
||||
VK_SUBTRACT => Some(VirtualKeyCode::NumpadSubtract),
|
||||
VK_DECIMAL => Some(VirtualKeyCode::NumpadDecimal),
|
||||
VK_DIVIDE => Some(VirtualKeyCode::NumpadDivide),
|
||||
VK_F1 => Some(VirtualKeyCode::F1),
|
||||
VK_F2 => Some(VirtualKeyCode::F2),
|
||||
VK_F3 => Some(VirtualKeyCode::F3),
|
||||
VK_F4 => Some(VirtualKeyCode::F4),
|
||||
VK_F5 => Some(VirtualKeyCode::F5),
|
||||
VK_F6 => Some(VirtualKeyCode::F6),
|
||||
VK_F7 => Some(VirtualKeyCode::F7),
|
||||
VK_F8 => Some(VirtualKeyCode::F8),
|
||||
VK_F9 => Some(VirtualKeyCode::F9),
|
||||
VK_F10 => Some(VirtualKeyCode::F10),
|
||||
VK_F11 => Some(VirtualKeyCode::F11),
|
||||
VK_F12 => Some(VirtualKeyCode::F12),
|
||||
VK_F13 => Some(VirtualKeyCode::F13),
|
||||
VK_F14 => Some(VirtualKeyCode::F14),
|
||||
VK_F15 => Some(VirtualKeyCode::F15),
|
||||
VK_F16 => Some(VirtualKeyCode::F16),
|
||||
VK_F17 => Some(VirtualKeyCode::F17),
|
||||
VK_F18 => Some(VirtualKeyCode::F18),
|
||||
VK_F19 => Some(VirtualKeyCode::F19),
|
||||
VK_F20 => Some(VirtualKeyCode::F20),
|
||||
VK_F21 => Some(VirtualKeyCode::F21),
|
||||
VK_F22 => Some(VirtualKeyCode::F22),
|
||||
VK_F23 => Some(VirtualKeyCode::F23),
|
||||
VK_F24 => Some(VirtualKeyCode::F24),
|
||||
VK_NUMLOCK => Some(VirtualKeyCode::Numlock),
|
||||
VK_SCROLL => Some(VirtualKeyCode::Scroll),
|
||||
VK_BROWSER_BACK => Some(VirtualKeyCode::NavigateBackward),
|
||||
VK_BROWSER_FORWARD => Some(VirtualKeyCode::NavigateForward),
|
||||
VK_BROWSER_REFRESH => Some(VirtualKeyCode::WebRefresh),
|
||||
VK_BROWSER_STOP => Some(VirtualKeyCode::WebStop),
|
||||
VK_BROWSER_SEARCH => Some(VirtualKeyCode::WebSearch),
|
||||
VK_BROWSER_FAVORITES => Some(VirtualKeyCode::WebFavorites),
|
||||
VK_BROWSER_HOME => Some(VirtualKeyCode::WebHome),
|
||||
VK_VOLUME_MUTE => Some(VirtualKeyCode::Mute),
|
||||
VK_VOLUME_DOWN => Some(VirtualKeyCode::VolumeDown),
|
||||
VK_VOLUME_UP => Some(VirtualKeyCode::VolumeUp),
|
||||
VK_MEDIA_NEXT_TRACK => Some(VirtualKeyCode::NextTrack),
|
||||
VK_MEDIA_PREV_TRACK => Some(VirtualKeyCode::PrevTrack),
|
||||
VK_MEDIA_STOP => Some(VirtualKeyCode::MediaStop),
|
||||
VK_MEDIA_PLAY_PAUSE => Some(VirtualKeyCode::PlayPause),
|
||||
VK_LAUNCH_MAIL => Some(VirtualKeyCode::Mail),
|
||||
VK_LAUNCH_MEDIA_SELECT => Some(VirtualKeyCode::MediaSelect),
|
||||
/*VK_LAUNCH_APP1 => Some(VirtualKeyCode::Launch_app1),
|
||||
VK_LAUNCH_APP2 => Some(VirtualKeyCode::Launch_app2),*/
|
||||
VK_OEM_PLUS => Some(VirtualKeyCode::Equals),
|
||||
VK_OEM_COMMA => Some(VirtualKeyCode::Comma),
|
||||
VK_OEM_MINUS => Some(VirtualKeyCode::Minus),
|
||||
VK_OEM_PERIOD => Some(VirtualKeyCode::Period),
|
||||
VK_OEM_1 => map_text_keys(vkey),
|
||||
VK_OEM_2 => map_text_keys(vkey),
|
||||
VK_OEM_3 => map_text_keys(vkey),
|
||||
VK_OEM_4 => map_text_keys(vkey),
|
||||
VK_OEM_5 => map_text_keys(vkey),
|
||||
VK_OEM_6 => map_text_keys(vkey),
|
||||
VK_OEM_7 => map_text_keys(vkey),
|
||||
/* VK_OEM_8 => Some(VirtualKeyCode::Oem_8), */
|
||||
VK_OEM_102 => Some(VirtualKeyCode::OEM102),
|
||||
/*VK_PROCESSKEY => Some(VirtualKeyCode::Processkey),
|
||||
VK_PACKET => Some(VirtualKeyCode::Packet),
|
||||
VK_ATTN => Some(VirtualKeyCode::Attn),
|
||||
VK_CRSEL => Some(VirtualKeyCode::Crsel),
|
||||
VK_EXSEL => Some(VirtualKeyCode::Exsel),
|
||||
VK_EREOF => Some(VirtualKeyCode::Ereof),
|
||||
VK_PLAY => Some(VirtualKeyCode::Play),
|
||||
VK_ZOOM => Some(VirtualKeyCode::Zoom),
|
||||
VK_NONAME => Some(VirtualKeyCode::Noname),
|
||||
VK_PA1 => Some(VirtualKeyCode::Pa1),
|
||||
VK_OEM_CLEAR => Some(VirtualKeyCode::Oem_clear),*/
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_extended_keys(
|
||||
vkey: c_int,
|
||||
mut scancode: UINT,
|
||||
vkey: VIRTUAL_KEY,
|
||||
mut scancode: u32,
|
||||
extended: bool,
|
||||
) -> Option<(c_int, UINT)> {
|
||||
) -> Option<(VIRTUAL_KEY, u32)> {
|
||||
// Welcome to hell https://blog.molecular-matters.com/2011/09/05/properly-handling-keyboard-input/
|
||||
scancode |= if extended { 0xE000 } else { 0x0000 };
|
||||
let vkey = match vkey {
|
||||
winuser::VK_SHIFT => unsafe {
|
||||
winuser::MapVirtualKeyA(scancode, winuser::MAPVK_VSC_TO_VK_EX) as _
|
||||
},
|
||||
winuser::VK_CONTROL => {
|
||||
VK_SHIFT => (unsafe { MapVirtualKeyA(scancode, MAPVK_VSC_TO_VK_EX) } as u16),
|
||||
VK_CONTROL => {
|
||||
if extended {
|
||||
winuser::VK_RCONTROL
|
||||
VK_RCONTROL
|
||||
} else {
|
||||
winuser::VK_LCONTROL
|
||||
VK_LCONTROL
|
||||
}
|
||||
}
|
||||
winuser::VK_MENU => {
|
||||
VK_MENU => {
|
||||
if extended {
|
||||
winuser::VK_RMENU
|
||||
VK_RMENU
|
||||
} else {
|
||||
winuser::VK_LMENU
|
||||
VK_LMENU
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
@ -367,20 +388,20 @@ pub fn handle_extended_keys(
|
|||
// When VK_PAUSE is pressed it emits a LeftControl + NumLock scancode event sequence, but reports VK_PAUSE
|
||||
// as the virtual key on both events, or VK_PAUSE on the first event or 0xFF when using raw input.
|
||||
// Don't emit anything for the LeftControl event in the pair...
|
||||
0xE01D if vkey == winuser::VK_PAUSE => return None,
|
||||
0xE01D if vkey == VK_PAUSE => return None,
|
||||
// ...and emit the Pause event for the second event in the pair.
|
||||
0x45 if vkey == winuser::VK_PAUSE || vkey == 0xFF => {
|
||||
0x45 if vkey == VK_PAUSE || vkey == 0xFF => {
|
||||
scancode = 0xE059;
|
||||
winuser::VK_PAUSE
|
||||
VK_PAUSE
|
||||
}
|
||||
// VK_PAUSE has an incorrect vkey value when used with modifiers. VK_PAUSE also reports a different
|
||||
// scancode when used with modifiers than when used without
|
||||
0xE046 => {
|
||||
scancode = 0xE059;
|
||||
winuser::VK_PAUSE
|
||||
VK_PAUSE
|
||||
}
|
||||
// VK_SCROLL has an incorrect vkey value when used with modifiers.
|
||||
0x46 => winuser::VK_SCROLL,
|
||||
0x46 => VK_SCROLL,
|
||||
_ => vkey,
|
||||
}
|
||||
}
|
||||
|
@ -392,18 +413,16 @@ pub fn process_key_params(
|
|||
wparam: WPARAM,
|
||||
lparam: LPARAM,
|
||||
) -> Option<(ScanCode, Option<VirtualKeyCode>)> {
|
||||
let scancode = ((lparam >> 16) & 0xff) as UINT;
|
||||
let scancode = ((lparam >> 16) & 0xff) as u32;
|
||||
let extended = (lparam & 0x01000000) != 0;
|
||||
handle_extended_keys(wparam as _, scancode, extended)
|
||||
handle_extended_keys(wparam as u16, scancode, extended)
|
||||
.map(|(vkey, scancode)| (scancode, vkey_to_winit_vkey(vkey)))
|
||||
}
|
||||
|
||||
// This is needed as windows doesn't properly distinguish
|
||||
// some virtual key codes for different keyboard layouts
|
||||
fn map_text_keys(win_virtual_key: i32) -> Option<VirtualKeyCode> {
|
||||
let char_key =
|
||||
unsafe { winuser::MapVirtualKeyA(win_virtual_key as u32, winuser::MAPVK_VK_TO_CHAR) }
|
||||
& 0x7FFF;
|
||||
fn map_text_keys(win_virtual_key: VIRTUAL_KEY) -> Option<VirtualKeyCode> {
|
||||
let char_key = unsafe { MapVirtualKeyA(win_virtual_key as u32, MAPVK_VK_TO_CHAR) } & 0x7FFF;
|
||||
match char::from_u32(char_key) {
|
||||
Some(';') => Some(VirtualKeyCode::Semicolon),
|
||||
Some('/') => Some(VirtualKeyCode::Slash),
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,9 +7,9 @@ use std::{
|
|||
time::Instant,
|
||||
};
|
||||
|
||||
use winapi::{
|
||||
shared::{minwindef::DWORD, windef::HWND},
|
||||
um::winuser,
|
||||
use windows_sys::Win32::{
|
||||
Foundation::HWND,
|
||||
Graphics::Gdi::{RedrawWindow, RDW_INTERNALPAINT},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -24,7 +24,7 @@ pub(crate) type EventLoopRunnerShared<T> = Rc<EventLoopRunner<T>>;
|
|||
pub(crate) struct EventLoopRunner<T: 'static> {
|
||||
// The event loop's win32 handles
|
||||
pub(super) thread_msg_target: HWND,
|
||||
wait_thread_id: DWORD,
|
||||
wait_thread_id: u32,
|
||||
|
||||
control_flow: Cell<ControlFlow>,
|
||||
runner_state: Cell<RunnerState>,
|
||||
|
@ -63,7 +63,7 @@ enum BufferedEvent<T: 'static> {
|
|||
}
|
||||
|
||||
impl<T> EventLoopRunner<T> {
|
||||
pub(crate) fn new(thread_msg_target: HWND, wait_thread_id: DWORD) -> EventLoopRunner<T> {
|
||||
pub(crate) fn new(thread_msg_target: HWND, wait_thread_id: u32) -> EventLoopRunner<T> {
|
||||
EventLoopRunner {
|
||||
thread_msg_target,
|
||||
wait_thread_id,
|
||||
|
@ -113,7 +113,7 @@ impl<T> EventLoopRunner<T> {
|
|||
self.thread_msg_target
|
||||
}
|
||||
|
||||
pub fn wait_thread_id(&self) -> DWORD {
|
||||
pub fn wait_thread_id(&self) -> u32 {
|
||||
self.wait_thread_id
|
||||
}
|
||||
|
||||
|
@ -208,8 +208,7 @@ impl<T> EventLoopRunner<T> {
|
|||
self.move_state_to(RunnerState::HandlingRedrawEvents);
|
||||
}
|
||||
self.call_event_handler(event);
|
||||
} else {
|
||||
if self.should_buffer() {
|
||||
} else if self.should_buffer() {
|
||||
// If the runner is already borrowed, we're in the middle of an event loop invocation. Add
|
||||
// the event to a buffer to be processed later.
|
||||
self.event_buffer
|
||||
|
@ -221,7 +220,6 @@ impl<T> EventLoopRunner<T> {
|
|||
self.dispatch_buffered_events();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn main_events_cleared(&self) {
|
||||
self.move_state_to(RunnerState::HandlingRedrawEvents);
|
||||
|
@ -394,12 +392,7 @@ impl<T> EventLoopRunner<T> {
|
|||
};
|
||||
self.call_event_handler(Event::NewEvents(start_cause));
|
||||
self.dispatch_buffered_events();
|
||||
winuser::RedrawWindow(
|
||||
self.thread_msg_target,
|
||||
ptr::null(),
|
||||
ptr::null_mut(),
|
||||
winuser::RDW_INTERNALPAINT,
|
||||
);
|
||||
RedrawWindow(self.thread_msg_target, ptr::null(), 0, RDW_INTERNALPAINT);
|
||||
}
|
||||
|
||||
unsafe fn call_redraw_events_cleared(&self) {
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
use std::{fmt, io, iter::once, mem, os::windows::ffi::OsStrExt, path::Path, ptr, sync::Arc};
|
||||
use std::{fmt, io, mem, path::Path, ptr, sync::Arc};
|
||||
|
||||
use winapi::{
|
||||
ctypes::{c_int, wchar_t},
|
||||
shared::{
|
||||
minwindef::{BYTE, LPARAM, WORD, WPARAM},
|
||||
windef::{HICON, HWND},
|
||||
use windows_sys::{
|
||||
core::PCWSTR,
|
||||
Win32::{
|
||||
Foundation::HWND,
|
||||
System::LibraryLoader::GetModuleHandleW,
|
||||
UI::WindowsAndMessaging::{
|
||||
CreateIcon, DestroyIcon, LoadImageW, SendMessageW, HICON, ICON_BIG, ICON_SMALL,
|
||||
IMAGE_ICON, LR_DEFAULTSIZE, LR_LOADFROMFILE, WM_SETICON,
|
||||
},
|
||||
},
|
||||
um::libloaderapi,
|
||||
um::winuser,
|
||||
};
|
||||
|
||||
use crate::dpi::PhysicalSize;
|
||||
use crate::icon::*;
|
||||
|
||||
use super::util;
|
||||
|
||||
impl Pixel {
|
||||
fn to_bgra(&mut self) {
|
||||
mem::swap(&mut self.r, &mut self.b);
|
||||
|
@ -21,28 +25,28 @@ impl Pixel {
|
|||
|
||||
impl RgbaIcon {
|
||||
fn into_windows_icon(self) -> Result<WinIcon, BadIcon> {
|
||||
let mut rgba = self.rgba;
|
||||
let rgba = self.rgba;
|
||||
let pixel_count = rgba.len() / PIXEL_SIZE;
|
||||
let mut and_mask = Vec::with_capacity(pixel_count);
|
||||
let pixels =
|
||||
unsafe { std::slice::from_raw_parts_mut(rgba.as_mut_ptr() as *mut Pixel, pixel_count) };
|
||||
unsafe { std::slice::from_raw_parts_mut(rgba.as_ptr() as *mut Pixel, pixel_count) };
|
||||
for pixel in pixels {
|
||||
and_mask.push(pixel.a.wrapping_sub(std::u8::MAX)); // invert alpha channel
|
||||
pixel.to_bgra();
|
||||
}
|
||||
assert_eq!(and_mask.len(), pixel_count);
|
||||
let handle = unsafe {
|
||||
winuser::CreateIcon(
|
||||
ptr::null_mut(),
|
||||
self.width as c_int,
|
||||
self.height as c_int,
|
||||
CreateIcon(
|
||||
0,
|
||||
self.width as i32,
|
||||
self.height as i32,
|
||||
1,
|
||||
(PIXEL_SIZE * 8) as BYTE,
|
||||
and_mask.as_ptr() as *const BYTE,
|
||||
rgba.as_ptr() as *const BYTE,
|
||||
) as HICON
|
||||
(PIXEL_SIZE * 8) as u8,
|
||||
and_mask.as_ptr(),
|
||||
rgba.as_ptr(),
|
||||
)
|
||||
};
|
||||
if !handle.is_null() {
|
||||
if handle != 0 {
|
||||
Ok(WinIcon::from_handle(handle))
|
||||
} else {
|
||||
Err(BadIcon::OsError(io::Error::last_os_error()))
|
||||
|
@ -52,8 +56,8 @@ impl RgbaIcon {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub enum IconType {
|
||||
Small = winuser::ICON_SMALL as isize,
|
||||
Big = winuser::ICON_BIG as isize,
|
||||
Small = ICON_SMALL as isize,
|
||||
Big = ICON_BIG as isize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -77,51 +81,46 @@ impl WinIcon {
|
|||
path: P,
|
||||
size: Option<PhysicalSize<u32>>,
|
||||
) -> Result<Self, BadIcon> {
|
||||
let wide_path: Vec<u16> = path
|
||||
.as_ref()
|
||||
.as_os_str()
|
||||
.encode_wide()
|
||||
.chain(once(0))
|
||||
.collect();
|
||||
|
||||
// width / height of 0 along with LR_DEFAULTSIZE tells windows to load the default icon size
|
||||
let (width, height) = size.map(Into::into).unwrap_or((0, 0));
|
||||
|
||||
let wide_path = util::encode_wide(path.as_ref());
|
||||
|
||||
let handle = unsafe {
|
||||
winuser::LoadImageW(
|
||||
ptr::null_mut(),
|
||||
wide_path.as_ptr() as *const wchar_t,
|
||||
winuser::IMAGE_ICON,
|
||||
width as c_int,
|
||||
height as c_int,
|
||||
winuser::LR_DEFAULTSIZE | winuser::LR_LOADFROMFILE,
|
||||
) as HICON
|
||||
LoadImageW(
|
||||
0,
|
||||
wide_path.as_ptr(),
|
||||
IMAGE_ICON,
|
||||
width as i32,
|
||||
height as i32,
|
||||
LR_DEFAULTSIZE | LR_LOADFROMFILE,
|
||||
)
|
||||
};
|
||||
if !handle.is_null() {
|
||||
Ok(WinIcon::from_handle(handle))
|
||||
if handle != 0 {
|
||||
Ok(WinIcon::from_handle(handle as HICON))
|
||||
} else {
|
||||
Err(BadIcon::OsError(io::Error::last_os_error()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_resource(
|
||||
resource_id: WORD,
|
||||
resource_id: u16,
|
||||
size: Option<PhysicalSize<u32>>,
|
||||
) -> Result<Self, BadIcon> {
|
||||
// width / height of 0 along with LR_DEFAULTSIZE tells windows to load the default icon size
|
||||
let (width, height) = size.map(Into::into).unwrap_or((0, 0));
|
||||
let handle = unsafe {
|
||||
winuser::LoadImageW(
|
||||
libloaderapi::GetModuleHandleW(ptr::null_mut()),
|
||||
winuser::MAKEINTRESOURCEW(resource_id),
|
||||
winuser::IMAGE_ICON,
|
||||
width as c_int,
|
||||
height as c_int,
|
||||
winuser::LR_DEFAULTSIZE,
|
||||
) as HICON
|
||||
LoadImageW(
|
||||
GetModuleHandleW(ptr::null()),
|
||||
resource_id as PCWSTR,
|
||||
IMAGE_ICON,
|
||||
width as i32,
|
||||
height as i32,
|
||||
LR_DEFAULTSIZE,
|
||||
)
|
||||
};
|
||||
if !handle.is_null() {
|
||||
Ok(WinIcon::from_handle(handle))
|
||||
if handle != 0 {
|
||||
Ok(WinIcon::from_handle(handle as HICON))
|
||||
} else {
|
||||
Err(BadIcon::OsError(io::Error::last_os_error()))
|
||||
}
|
||||
|
@ -134,12 +133,7 @@ impl WinIcon {
|
|||
|
||||
pub fn set_for_window(&self, hwnd: HWND, icon_type: IconType) {
|
||||
unsafe {
|
||||
winuser::SendMessageW(
|
||||
hwnd,
|
||||
winuser::WM_SETICON,
|
||||
icon_type as WPARAM,
|
||||
self.as_raw_handle() as LPARAM,
|
||||
);
|
||||
SendMessageW(hwnd, WM_SETICON, icon_type as usize, self.as_raw_handle());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,7 +146,7 @@ impl WinIcon {
|
|||
|
||||
impl Drop for RaiiIcon {
|
||||
fn drop(&mut self) {
|
||||
unsafe { winuser::DestroyIcon(self.handle) };
|
||||
unsafe { DestroyIcon(self.handle) };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,6 +158,6 @@ impl fmt::Debug for WinIcon {
|
|||
|
||||
pub fn unset_for_window(hwnd: HWND, icon_type: IconType) {
|
||||
unsafe {
|
||||
winuser::SendMessageW(hwnd, winuser::WM_SETICON, icon_type as WPARAM, 0 as LPARAM);
|
||||
SendMessageW(hwnd, WM_SETICON, icon_type as usize, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#![cfg(target_os = "windows")]
|
||||
|
||||
use winapi::{self, shared::windef::HMENU, shared::windef::HWND};
|
||||
use windows_sys::Win32::{
|
||||
Foundation::{HANDLE, HWND},
|
||||
UI::WindowsAndMessaging::{HMENU, WINDOW_LONG_PTR_INDEX},
|
||||
};
|
||||
|
||||
pub(crate) use self::{
|
||||
event_loop::{
|
||||
|
@ -52,7 +55,7 @@ unsafe impl Sync for PlatformSpecificWindowBuilderAttributes {}
|
|||
|
||||
// Cursor name in UTF-16. Used to set cursor in `WM_SETCURSOR`.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Cursor(pub *const winapi::ctypes::wchar_t);
|
||||
pub struct Cursor(pub *const u16);
|
||||
unsafe impl Send for Cursor {}
|
||||
unsafe impl Sync for Cursor {}
|
||||
|
||||
|
@ -68,7 +71,7 @@ impl DeviceId {
|
|||
impl DeviceId {
|
||||
pub fn persistent_identifier(&self) -> Option<String> {
|
||||
if self.0 != 0 {
|
||||
raw_input::get_raw_input_device_name(self.0 as _)
|
||||
raw_input::get_raw_input_device_name(self.0 as HANDLE)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -91,15 +94,59 @@ unsafe impl Sync for WindowId {}
|
|||
|
||||
impl WindowId {
|
||||
pub const unsafe fn dummy() -> Self {
|
||||
use std::ptr::null_mut;
|
||||
|
||||
WindowId(null_mut())
|
||||
WindowId(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
const fn get_xbutton_wparam(x: u32) -> u16 {
|
||||
loword(x)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
const fn get_x_lparam(x: u32) -> u16 {
|
||||
loword(x)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
const fn get_y_lparam(x: u32) -> u16 {
|
||||
hiword(x)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
const fn loword(x: u32) -> u16 {
|
||||
(x & 0xFFFF) as u16
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
const fn hiword(x: u32) -> u16 {
|
||||
((x >> 16) & 0xFFFF) as u16
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn get_window_long(hwnd: HWND, nindex: WINDOW_LONG_PTR_INDEX) -> isize {
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
return windows_sys::Win32::UI::WindowsAndMessaging::GetWindowLongPtrW(hwnd, nindex);
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
return windows_sys::Win32::UI::WindowsAndMessaging::GetWindowLongW(hwnd, nindex) as isize;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn set_window_long(hwnd: HWND, nindex: WINDOW_LONG_PTR_INDEX, dwnewlong: isize) -> isize {
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
return windows_sys::Win32::UI::WindowsAndMessaging::SetWindowLongPtrW(hwnd, nindex, dwnewlong);
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
return windows_sys::Win32::UI::WindowsAndMessaging::SetWindowLongW(
|
||||
hwnd,
|
||||
nindex,
|
||||
dwnewlong as i32,
|
||||
) as isize;
|
||||
}
|
||||
|
||||
#[macro_use]
|
||||
mod util;
|
||||
mod dark_mode;
|
||||
mod definitions;
|
||||
mod dpi;
|
||||
mod drop_handler;
|
||||
mod event;
|
||||
|
|
|
@ -1,22 +1,28 @@
|
|||
use winapi::{
|
||||
shared::{
|
||||
minwindef::{BOOL, DWORD, LPARAM, TRUE, WORD},
|
||||
windef::{HDC, HMONITOR, HWND, LPRECT, POINT},
|
||||
},
|
||||
um::{wingdi, winuser},
|
||||
};
|
||||
|
||||
use std::{
|
||||
collections::{BTreeSet, VecDeque},
|
||||
io, mem, ptr,
|
||||
ffi::OsString,
|
||||
hash::Hash,
|
||||
io, mem,
|
||||
os::windows::prelude::OsStringExt,
|
||||
ptr,
|
||||
};
|
||||
|
||||
use windows_sys::Win32::{
|
||||
Foundation::{BOOL, HWND, LPARAM, POINT, RECT},
|
||||
Graphics::Gdi::{
|
||||
EnumDisplayMonitors, EnumDisplaySettingsExW, GetMonitorInfoW, MonitorFromPoint,
|
||||
MonitorFromWindow, DEVMODEW, DM_BITSPERPEL, DM_DISPLAYFREQUENCY, DM_PELSHEIGHT,
|
||||
DM_PELSWIDTH, HDC, HMONITOR, MONITORINFO, MONITORINFOEXW, MONITOR_DEFAULTTONEAREST,
|
||||
MONITOR_DEFAULTTOPRIMARY,
|
||||
},
|
||||
};
|
||||
|
||||
use super::util;
|
||||
use crate::{
|
||||
dpi::{PhysicalPosition, PhysicalSize},
|
||||
monitor::{MonitorHandle as RootMonitorHandle, VideoMode as RootVideoMode},
|
||||
platform_impl::platform::{
|
||||
dpi::{dpi_to_scale_factor, get_monitor_dpi},
|
||||
util::has_flag,
|
||||
window::Window,
|
||||
},
|
||||
};
|
||||
|
@ -27,7 +33,7 @@ pub struct VideoMode {
|
|||
pub(crate) bit_depth: u16,
|
||||
pub(crate) refresh_rate: u16,
|
||||
pub(crate) monitor: MonitorHandle,
|
||||
pub(crate) native_video_mode: wingdi::DEVMODEW,
|
||||
pub(crate) native_video_mode: DEVMODEW,
|
||||
}
|
||||
|
||||
impl PartialEq for VideoMode {
|
||||
|
@ -94,20 +100,20 @@ unsafe impl Send for MonitorHandle {}
|
|||
unsafe extern "system" fn monitor_enum_proc(
|
||||
hmonitor: HMONITOR,
|
||||
_hdc: HDC,
|
||||
_place: LPRECT,
|
||||
_place: *mut RECT,
|
||||
data: LPARAM,
|
||||
) -> BOOL {
|
||||
let monitors = data as *mut VecDeque<MonitorHandle>;
|
||||
(*monitors).push_back(MonitorHandle::new(hmonitor));
|
||||
TRUE // continue enumeration
|
||||
true.into() // continue enumeration
|
||||
}
|
||||
|
||||
pub fn available_monitors() -> VecDeque<MonitorHandle> {
|
||||
let mut monitors: VecDeque<MonitorHandle> = VecDeque::new();
|
||||
unsafe {
|
||||
winuser::EnumDisplayMonitors(
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
EnumDisplayMonitors(
|
||||
0,
|
||||
ptr::null(),
|
||||
Some(monitor_enum_proc),
|
||||
&mut monitors as *mut _ as LPARAM,
|
||||
);
|
||||
|
@ -117,12 +123,12 @@ pub fn available_monitors() -> VecDeque<MonitorHandle> {
|
|||
|
||||
pub fn primary_monitor() -> MonitorHandle {
|
||||
const ORIGIN: POINT = POINT { x: 0, y: 0 };
|
||||
let hmonitor = unsafe { winuser::MonitorFromPoint(ORIGIN, winuser::MONITOR_DEFAULTTOPRIMARY) };
|
||||
let hmonitor = unsafe { MonitorFromPoint(ORIGIN, MONITOR_DEFAULTTOPRIMARY) };
|
||||
MonitorHandle::new(hmonitor)
|
||||
}
|
||||
|
||||
pub fn current_monitor(hwnd: HWND) -> MonitorHandle {
|
||||
let hmonitor = unsafe { winuser::MonitorFromWindow(hwnd, winuser::MONITOR_DEFAULTTONEAREST) };
|
||||
let hmonitor = unsafe { MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST) };
|
||||
MonitorHandle::new(hmonitor)
|
||||
}
|
||||
|
||||
|
@ -137,16 +143,16 @@ impl Window {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_monitor_info(hmonitor: HMONITOR) -> Result<winuser::MONITORINFOEXW, io::Error> {
|
||||
let mut monitor_info: winuser::MONITORINFOEXW = unsafe { mem::zeroed() };
|
||||
monitor_info.cbSize = mem::size_of::<winuser::MONITORINFOEXW>() as DWORD;
|
||||
pub(crate) fn get_monitor_info(hmonitor: HMONITOR) -> Result<MONITORINFOEXW, io::Error> {
|
||||
let mut monitor_info: MONITORINFOEXW = unsafe { mem::zeroed() };
|
||||
monitor_info.monitorInfo.cbSize = mem::size_of::<MONITORINFOEXW>() as u32;
|
||||
let status = unsafe {
|
||||
winuser::GetMonitorInfoW(
|
||||
GetMonitorInfoW(
|
||||
hmonitor,
|
||||
&mut monitor_info as *mut winuser::MONITORINFOEXW as *mut winuser::MONITORINFO,
|
||||
&mut monitor_info as *mut MONITORINFOEXW as *mut MONITORINFO,
|
||||
)
|
||||
};
|
||||
if status == 0 {
|
||||
if status == false.into() {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(monitor_info)
|
||||
|
@ -161,7 +167,11 @@ impl MonitorHandle {
|
|||
#[inline]
|
||||
pub fn name(&self) -> Option<String> {
|
||||
let monitor_info = get_monitor_info(self.0).unwrap();
|
||||
Some(util::wchar_ptr_to_string(monitor_info.szDevice.as_ptr()))
|
||||
Some(
|
||||
OsString::from_wide(&monitor_info.szDevice)
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -176,19 +186,19 @@ impl MonitorHandle {
|
|||
|
||||
#[inline]
|
||||
pub fn size(&self) -> PhysicalSize<u32> {
|
||||
let monitor_info = get_monitor_info(self.0).unwrap();
|
||||
let rc_monitor = get_monitor_info(self.0).unwrap().monitorInfo.rcMonitor;
|
||||
PhysicalSize {
|
||||
width: (monitor_info.rcMonitor.right - monitor_info.rcMonitor.left) as u32,
|
||||
height: (monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top) as u32,
|
||||
width: (rc_monitor.right - rc_monitor.left) as u32,
|
||||
height: (rc_monitor.bottom - rc_monitor.top) as u32,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn position(&self) -> PhysicalPosition<i32> {
|
||||
let monitor_info = get_monitor_info(self.0).unwrap();
|
||||
let rc_monitor = get_monitor_info(self.0).unwrap().monitorInfo.rcMonitor;
|
||||
PhysicalPosition {
|
||||
x: monitor_info.rcMonitor.left,
|
||||
y: monitor_info.rcMonitor.top,
|
||||
x: rc_monitor.left,
|
||||
y: rc_monitor.top,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,18 +219,16 @@ impl MonitorHandle {
|
|||
unsafe {
|
||||
let monitor_info = get_monitor_info(self.0).unwrap();
|
||||
let device_name = monitor_info.szDevice.as_ptr();
|
||||
let mut mode: wingdi::DEVMODEW = mem::zeroed();
|
||||
mode.dmSize = mem::size_of_val(&mode) as WORD;
|
||||
if winuser::EnumDisplaySettingsExW(device_name, i, &mut mode, 0) == 0 {
|
||||
let mut mode: DEVMODEW = mem::zeroed();
|
||||
mode.dmSize = mem::size_of_val(&mode) as u16;
|
||||
if EnumDisplaySettingsExW(device_name, i, &mut mode, 0) == false.into() {
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
|
||||
const REQUIRED_FIELDS: DWORD = wingdi::DM_BITSPERPEL
|
||||
| wingdi::DM_PELSWIDTH
|
||||
| wingdi::DM_PELSHEIGHT
|
||||
| wingdi::DM_DISPLAYFREQUENCY;
|
||||
assert!(mode.dmFields & REQUIRED_FIELDS == REQUIRED_FIELDS);
|
||||
const REQUIRED_FIELDS: u32 =
|
||||
(DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY) as u32;
|
||||
assert!(has_flag(mode.dmFields, REQUIRED_FIELDS));
|
||||
|
||||
modes.insert(RootVideoMode {
|
||||
video_mode: VideoMode {
|
||||
|
|
|
@ -1,22 +1,26 @@
|
|||
use std::{
|
||||
ffi::OsString,
|
||||
mem::{self, size_of},
|
||||
os::windows::prelude::OsStringExt,
|
||||
ptr,
|
||||
};
|
||||
|
||||
use winapi::{
|
||||
ctypes::wchar_t,
|
||||
shared::{
|
||||
hidusage::{HID_USAGE_GENERIC_KEYBOARD, HID_USAGE_GENERIC_MOUSE, HID_USAGE_PAGE_GENERIC},
|
||||
minwindef::{TRUE, UINT, USHORT},
|
||||
windef::HWND,
|
||||
use windows_sys::Win32::{
|
||||
Devices::HumanInterfaceDevice::{
|
||||
HID_USAGE_GENERIC_KEYBOARD, HID_USAGE_GENERIC_MOUSE, HID_USAGE_PAGE_GENERIC,
|
||||
},
|
||||
um::{
|
||||
winnt::HANDLE,
|
||||
winuser::{
|
||||
self, HRAWINPUT, RAWINPUT, RAWINPUTDEVICE, RAWINPUTDEVICELIST, RAWINPUTHEADER,
|
||||
RIDEV_DEVNOTIFY, RIDEV_INPUTSINK, RIDI_DEVICEINFO, RIDI_DEVICENAME, RID_DEVICE_INFO,
|
||||
RID_DEVICE_INFO_HID, RID_DEVICE_INFO_KEYBOARD, RID_DEVICE_INFO_MOUSE, RID_INPUT,
|
||||
RIM_TYPEHID, RIM_TYPEKEYBOARD, RIM_TYPEMOUSE,
|
||||
Foundation::{HANDLE, HWND},
|
||||
UI::{
|
||||
Input::{
|
||||
GetRawInputData, GetRawInputDeviceInfoW, GetRawInputDeviceList,
|
||||
RegisterRawInputDevices, HRAWINPUT, RAWINPUT, RAWINPUTDEVICE, RAWINPUTDEVICELIST,
|
||||
RAWINPUTHEADER, RIDEV_DEVNOTIFY, RIDEV_INPUTSINK, RIDI_DEVICEINFO, RIDI_DEVICENAME,
|
||||
RID_DEVICE_INFO, RID_DEVICE_INFO_HID, RID_DEVICE_INFO_KEYBOARD, RID_DEVICE_INFO_MOUSE,
|
||||
RID_INPUT, RIM_TYPEHID, RIM_TYPEKEYBOARD, RIM_TYPEMOUSE,
|
||||
},
|
||||
WindowsAndMessaging::{
|
||||
RI_MOUSE_LEFT_BUTTON_DOWN, RI_MOUSE_LEFT_BUTTON_UP, RI_MOUSE_MIDDLE_BUTTON_DOWN,
|
||||
RI_MOUSE_MIDDLE_BUTTON_UP, RI_MOUSE_RIGHT_BUTTON_DOWN, RI_MOUSE_RIGHT_BUTTON_UP,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -25,23 +29,21 @@ use crate::{event::ElementState, platform_impl::platform::util};
|
|||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_raw_input_device_list() -> Option<Vec<RAWINPUTDEVICELIST>> {
|
||||
let list_size = size_of::<RAWINPUTDEVICELIST>() as UINT;
|
||||
let list_size = size_of::<RAWINPUTDEVICELIST>() as u32;
|
||||
|
||||
let mut num_devices = 0;
|
||||
let status =
|
||||
unsafe { winuser::GetRawInputDeviceList(ptr::null_mut(), &mut num_devices, list_size) };
|
||||
let status = unsafe { GetRawInputDeviceList(ptr::null_mut(), &mut num_devices, list_size) };
|
||||
|
||||
if status == UINT::max_value() {
|
||||
if status == u32::MAX {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut buffer = Vec::with_capacity(num_devices as _);
|
||||
|
||||
let num_stored = unsafe {
|
||||
winuser::GetRawInputDeviceList(buffer.as_ptr() as _, &mut num_devices, list_size)
|
||||
};
|
||||
let num_stored =
|
||||
unsafe { GetRawInputDeviceList(buffer.as_mut_ptr(), &mut num_devices, list_size) };
|
||||
|
||||
if num_stored == UINT::max_value() {
|
||||
if num_stored == u32::MAX {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -63,9 +65,9 @@ impl From<RID_DEVICE_INFO> for RawDeviceInfo {
|
|||
fn from(info: RID_DEVICE_INFO) -> Self {
|
||||
unsafe {
|
||||
match info.dwType {
|
||||
RIM_TYPEMOUSE => RawDeviceInfo::Mouse(*info.u.mouse()),
|
||||
RIM_TYPEKEYBOARD => RawDeviceInfo::Keyboard(*info.u.keyboard()),
|
||||
RIM_TYPEHID => RawDeviceInfo::Hid(*info.u.hid()),
|
||||
RIM_TYPEMOUSE => RawDeviceInfo::Mouse(info.Anonymous.mouse),
|
||||
RIM_TYPEKEYBOARD => RawDeviceInfo::Keyboard(info.Anonymous.keyboard),
|
||||
RIM_TYPEHID => RawDeviceInfo::Hid(info.Anonymous.hid),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -75,13 +77,13 @@ impl From<RID_DEVICE_INFO> for RawDeviceInfo {
|
|||
#[allow(dead_code)]
|
||||
pub fn get_raw_input_device_info(handle: HANDLE) -> Option<RawDeviceInfo> {
|
||||
let mut info: RID_DEVICE_INFO = unsafe { mem::zeroed() };
|
||||
let info_size = size_of::<RID_DEVICE_INFO>() as UINT;
|
||||
let info_size = size_of::<RID_DEVICE_INFO>() as u32;
|
||||
|
||||
info.cbSize = info_size;
|
||||
|
||||
let mut minimum_size = 0;
|
||||
let status = unsafe {
|
||||
winuser::GetRawInputDeviceInfoW(
|
||||
GetRawInputDeviceInfoW(
|
||||
handle,
|
||||
RIDI_DEVICEINFO,
|
||||
&mut info as *mut _ as _,
|
||||
|
@ -89,7 +91,7 @@ pub fn get_raw_input_device_info(handle: HANDLE) -> Option<RawDeviceInfo> {
|
|||
)
|
||||
};
|
||||
|
||||
if status == UINT::max_value() || status == 0 {
|
||||
if status == u32::MAX || status == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -101,17 +103,17 @@ pub fn get_raw_input_device_info(handle: HANDLE) -> Option<RawDeviceInfo> {
|
|||
pub fn get_raw_input_device_name(handle: HANDLE) -> Option<String> {
|
||||
let mut minimum_size = 0;
|
||||
let status = unsafe {
|
||||
winuser::GetRawInputDeviceInfoW(handle, RIDI_DEVICENAME, ptr::null_mut(), &mut minimum_size)
|
||||
GetRawInputDeviceInfoW(handle, RIDI_DEVICENAME, ptr::null_mut(), &mut minimum_size)
|
||||
};
|
||||
|
||||
if status != 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut name: Vec<wchar_t> = Vec::with_capacity(minimum_size as _);
|
||||
let mut name: Vec<u16> = Vec::with_capacity(minimum_size as _);
|
||||
|
||||
let status = unsafe {
|
||||
winuser::GetRawInputDeviceInfoW(
|
||||
GetRawInputDeviceInfoW(
|
||||
handle,
|
||||
RIDI_DEVICENAME,
|
||||
name.as_ptr() as _,
|
||||
|
@ -119,7 +121,7 @@ pub fn get_raw_input_device_name(handle: HANDLE) -> Option<String> {
|
|||
)
|
||||
};
|
||||
|
||||
if status == UINT::max_value() || status == 0 {
|
||||
if status == u32::MAX || status == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -127,17 +129,15 @@ pub fn get_raw_input_device_name(handle: HANDLE) -> Option<String> {
|
|||
|
||||
unsafe { name.set_len(minimum_size as _) };
|
||||
|
||||
Some(util::wchar_to_string(&name))
|
||||
OsString::from_wide(&name).into_string().ok()
|
||||
}
|
||||
|
||||
pub fn register_raw_input_devices(devices: &[RAWINPUTDEVICE]) -> bool {
|
||||
let device_size = size_of::<RAWINPUTDEVICE>() as UINT;
|
||||
let device_size = size_of::<RAWINPUTDEVICE>() as u32;
|
||||
|
||||
let success = unsafe {
|
||||
winuser::RegisterRawInputDevices(devices.as_ptr() as _, devices.len() as _, device_size)
|
||||
};
|
||||
|
||||
success == TRUE
|
||||
unsafe {
|
||||
RegisterRawInputDevices(devices.as_ptr(), devices.len() as u32, device_size) == true.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_all_mice_and_keyboards_for_raw_input(window_handle: HWND) -> bool {
|
||||
|
@ -165,11 +165,11 @@ pub fn register_all_mice_and_keyboards_for_raw_input(window_handle: HWND) -> boo
|
|||
|
||||
pub fn get_raw_input_data(handle: HRAWINPUT) -> Option<RAWINPUT> {
|
||||
let mut data: RAWINPUT = unsafe { mem::zeroed() };
|
||||
let mut data_size = size_of::<RAWINPUT>() as UINT;
|
||||
let header_size = size_of::<RAWINPUTHEADER>() as UINT;
|
||||
let mut data_size = size_of::<RAWINPUT>() as u32;
|
||||
let header_size = size_of::<RAWINPUTHEADER>() as u32;
|
||||
|
||||
let status = unsafe {
|
||||
winuser::GetRawInputData(
|
||||
GetRawInputData(
|
||||
handle,
|
||||
RID_INPUT,
|
||||
&mut data as *mut _ as _,
|
||||
|
@ -178,7 +178,7 @@ pub fn get_raw_input_data(handle: HRAWINPUT) -> Option<RAWINPUT> {
|
|||
)
|
||||
};
|
||||
|
||||
if status == UINT::max_value() || status == 0 {
|
||||
if status == u32::MAX || status == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -186,9 +186,9 @@ pub fn get_raw_input_data(handle: HRAWINPUT) -> Option<RAWINPUT> {
|
|||
}
|
||||
|
||||
fn button_flags_to_element_state(
|
||||
button_flags: USHORT,
|
||||
down_flag: USHORT,
|
||||
up_flag: USHORT,
|
||||
button_flags: u32,
|
||||
down_flag: u32,
|
||||
up_flag: u32,
|
||||
) -> Option<ElementState> {
|
||||
// We assume the same button won't be simultaneously pressed and released.
|
||||
if util::has_flag(button_flags, down_flag) {
|
||||
|
@ -200,22 +200,22 @@ fn button_flags_to_element_state(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_raw_mouse_button_state(button_flags: USHORT) -> [Option<ElementState>; 3] {
|
||||
pub fn get_raw_mouse_button_state(button_flags: u32) -> [Option<ElementState>; 3] {
|
||||
[
|
||||
button_flags_to_element_state(
|
||||
button_flags,
|
||||
winuser::RI_MOUSE_LEFT_BUTTON_DOWN,
|
||||
winuser::RI_MOUSE_LEFT_BUTTON_UP,
|
||||
RI_MOUSE_LEFT_BUTTON_DOWN,
|
||||
RI_MOUSE_LEFT_BUTTON_UP,
|
||||
),
|
||||
button_flags_to_element_state(
|
||||
button_flags,
|
||||
winuser::RI_MOUSE_MIDDLE_BUTTON_DOWN,
|
||||
winuser::RI_MOUSE_MIDDLE_BUTTON_UP,
|
||||
RI_MOUSE_MIDDLE_BUTTON_DOWN,
|
||||
RI_MOUSE_MIDDLE_BUTTON_UP,
|
||||
),
|
||||
button_flags_to_element_state(
|
||||
button_flags,
|
||||
winuser::RI_MOUSE_RIGHT_BUTTON_DOWN,
|
||||
winuser::RI_MOUSE_RIGHT_BUTTON_UP,
|
||||
RI_MOUSE_RIGHT_BUTTON_DOWN,
|
||||
RI_MOUSE_RIGHT_BUTTON_UP,
|
||||
),
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,27 +1,42 @@
|
|||
use std::{
|
||||
io, mem,
|
||||
ffi::{c_void, OsStr},
|
||||
io,
|
||||
iter::once,
|
||||
mem,
|
||||
ops::BitAnd,
|
||||
os::raw::c_void,
|
||||
ptr, slice,
|
||||
os::windows::prelude::OsStrExt,
|
||||
ptr,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
|
||||
use crate::{dpi::PhysicalSize, window::CursorIcon};
|
||||
use winapi::{
|
||||
ctypes::wchar_t,
|
||||
shared::{
|
||||
minwindef::{BOOL, DWORD, UINT},
|
||||
windef::{DPI_AWARENESS_CONTEXT, HMONITOR, HWND, LPRECT, RECT},
|
||||
use windows_sys::{
|
||||
core::{HRESULT, PCWSTR},
|
||||
Win32::{
|
||||
Foundation::{BOOL, HWND, RECT},
|
||||
Graphics::Gdi::{ClientToScreen, InvalidateRgn, HMONITOR},
|
||||
System::LibraryLoader::{GetProcAddress, LoadLibraryA},
|
||||
UI::{
|
||||
HiDpi::{DPI_AWARENESS_CONTEXT, MONITOR_DPI_TYPE, PROCESS_DPI_AWARENESS},
|
||||
Input::KeyboardAndMouse::GetActiveWindow,
|
||||
WindowsAndMessaging::{
|
||||
AdjustWindowRectEx, ClipCursor, GetClientRect, GetClipCursor, GetMenu,
|
||||
GetSystemMetrics, GetWindowLongW, GetWindowRect, SetWindowPos, ShowCursor,
|
||||
GWL_EXSTYLE, GWL_STYLE, IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_HELP,
|
||||
IDC_IBEAM, IDC_NO, IDC_SIZEALL, IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE, IDC_SIZEWE,
|
||||
IDC_WAIT, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, SM_XVIRTUALSCREEN,
|
||||
SM_YVIRTUALSCREEN, SWP_ASYNCWINDOWPOS, SWP_NOACTIVATE, SWP_NOMOVE,
|
||||
SWP_NOREPOSITION, SWP_NOZORDER, WINDOW_EX_STYLE, WINDOW_STYLE,
|
||||
},
|
||||
},
|
||||
um::{
|
||||
libloaderapi::{GetProcAddress, LoadLibraryA},
|
||||
shellscalingapi::{MONITOR_DPI_TYPE, PROCESS_DPI_AWARENESS},
|
||||
winbase::lstrlenW,
|
||||
winnt::{HRESULT, LONG, LPCSTR},
|
||||
winuser,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{dpi::PhysicalSize, window::CursorIcon};
|
||||
|
||||
pub fn encode_wide(string: impl AsRef<OsStr>) -> Vec<u16> {
|
||||
string.as_ref().encode_wide().chain(once(0)).collect()
|
||||
}
|
||||
|
||||
pub fn has_flag<T>(bitset: T, flag: T) -> bool
|
||||
where
|
||||
T: Copy + PartialEq + BitAnd<T, Output = T>,
|
||||
|
@ -29,19 +44,9 @@ where
|
|||
bitset & flag == flag
|
||||
}
|
||||
|
||||
pub fn wchar_to_string(wchar: &[wchar_t]) -> String {
|
||||
String::from_utf16_lossy(wchar)
|
||||
}
|
||||
|
||||
pub fn wchar_ptr_to_string(wchar: *const wchar_t) -> String {
|
||||
let len = unsafe { lstrlenW(wchar) } as usize;
|
||||
let wchar_slice = unsafe { slice::from_raw_parts(wchar, len) };
|
||||
wchar_to_string(wchar_slice)
|
||||
}
|
||||
|
||||
pub unsafe fn status_map<T, F: FnMut(&mut T) -> BOOL>(mut fun: F) -> Option<T> {
|
||||
let mut data: T = mem::zeroed();
|
||||
if fun(&mut data) != 0 {
|
||||
if fun(&mut data) != false.into() {
|
||||
Some(data)
|
||||
} else {
|
||||
None
|
||||
|
@ -49,7 +54,7 @@ pub unsafe fn status_map<T, F: FnMut(&mut T) -> BOOL>(mut fun: F) -> Option<T> {
|
|||
}
|
||||
|
||||
fn win_to_err<F: FnOnce() -> BOOL>(f: F) -> Result<(), io::Error> {
|
||||
if f() != 0 {
|
||||
if f() != false.into() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(io::Error::last_os_error())
|
||||
|
@ -57,7 +62,7 @@ fn win_to_err<F: FnOnce() -> BOOL>(f: F) -> Result<(), io::Error> {
|
|||
}
|
||||
|
||||
pub fn get_window_rect(hwnd: HWND) -> Option<RECT> {
|
||||
unsafe { status_map(|rect| winuser::GetWindowRect(hwnd, rect)) }
|
||||
unsafe { status_map(|rect| GetWindowRect(hwnd, rect)) }
|
||||
}
|
||||
|
||||
pub fn get_client_rect(hwnd: HWND) -> Result<RECT, io::Error> {
|
||||
|
@ -65,8 +70,8 @@ pub fn get_client_rect(hwnd: HWND) -> Result<RECT, io::Error> {
|
|||
let mut rect = mem::zeroed();
|
||||
let mut top_left = mem::zeroed();
|
||||
|
||||
win_to_err(|| winuser::ClientToScreen(hwnd, &mut top_left))?;
|
||||
win_to_err(|| winuser::GetClientRect(hwnd, &mut rect))?;
|
||||
win_to_err(|| ClientToScreen(hwnd, &mut top_left))?;
|
||||
win_to_err(|| GetClientRect(hwnd, &mut rect))?;
|
||||
rect.left += top_left.x;
|
||||
rect.top += top_left.y;
|
||||
rect.right += top_left.x;
|
||||
|
@ -80,9 +85,9 @@ pub fn adjust_size(hwnd: HWND, size: PhysicalSize<u32>) -> PhysicalSize<u32> {
|
|||
let (width, height): (u32, u32) = size.into();
|
||||
let rect = RECT {
|
||||
left: 0,
|
||||
right: width as LONG,
|
||||
right: width as i32,
|
||||
top: 0,
|
||||
bottom: height as LONG,
|
||||
bottom: height as i32,
|
||||
};
|
||||
let rect = adjust_window_rect(hwnd, rect).unwrap_or(rect);
|
||||
PhysicalSize::new((rect.right - rect.left) as _, (rect.bottom - rect.top) as _)
|
||||
|
@ -95,57 +100,53 @@ pub(crate) fn set_inner_size_physical(window: HWND, x: u32, y: u32) {
|
|||
RECT {
|
||||
top: 0,
|
||||
left: 0,
|
||||
bottom: y as LONG,
|
||||
right: x as LONG,
|
||||
bottom: y as i32,
|
||||
right: x as i32,
|
||||
},
|
||||
)
|
||||
.expect("adjust_window_rect failed");
|
||||
|
||||
let outer_x = (rect.right - rect.left).abs() as _;
|
||||
let outer_y = (rect.top - rect.bottom).abs() as _;
|
||||
winuser::SetWindowPos(
|
||||
SetWindowPos(
|
||||
window,
|
||||
ptr::null_mut(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
outer_x,
|
||||
outer_y,
|
||||
winuser::SWP_ASYNCWINDOWPOS
|
||||
| winuser::SWP_NOZORDER
|
||||
| winuser::SWP_NOREPOSITION
|
||||
| winuser::SWP_NOMOVE
|
||||
| winuser::SWP_NOACTIVATE,
|
||||
SWP_ASYNCWINDOWPOS | SWP_NOZORDER | SWP_NOREPOSITION | SWP_NOMOVE | SWP_NOACTIVATE,
|
||||
);
|
||||
winuser::InvalidateRgn(window, ptr::null_mut(), 0);
|
||||
InvalidateRgn(window, 0, false.into());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn adjust_window_rect(hwnd: HWND, rect: RECT) -> Option<RECT> {
|
||||
unsafe {
|
||||
let style = winuser::GetWindowLongW(hwnd, winuser::GWL_STYLE);
|
||||
let style_ex = winuser::GetWindowLongW(hwnd, winuser::GWL_EXSTYLE);
|
||||
adjust_window_rect_with_styles(hwnd, style as _, style_ex as _, rect)
|
||||
let style = GetWindowLongW(hwnd, GWL_STYLE) as u32;
|
||||
let style_ex = GetWindowLongW(hwnd, GWL_EXSTYLE) as u32;
|
||||
adjust_window_rect_with_styles(hwnd, style, style_ex, rect)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn adjust_window_rect_with_styles(
|
||||
hwnd: HWND,
|
||||
style: DWORD,
|
||||
style_ex: DWORD,
|
||||
style: WINDOW_STYLE,
|
||||
style_ex: WINDOW_EX_STYLE,
|
||||
rect: RECT,
|
||||
) -> Option<RECT> {
|
||||
unsafe {
|
||||
status_map(|r| {
|
||||
*r = rect;
|
||||
|
||||
let b_menu = !winuser::GetMenu(hwnd).is_null() as BOOL;
|
||||
let b_menu = GetMenu(hwnd) != 0;
|
||||
if let (Some(get_dpi_for_window), Some(adjust_window_rect_ex_for_dpi)) =
|
||||
(*GET_DPI_FOR_WINDOW, *ADJUST_WINDOW_RECT_EX_FOR_DPI)
|
||||
{
|
||||
let dpi = get_dpi_for_window(hwnd);
|
||||
adjust_window_rect_ex_for_dpi(r, style as _, b_menu, style_ex as _, dpi)
|
||||
adjust_window_rect_ex_for_dpi(r, style, b_menu.into(), style_ex, dpi)
|
||||
} else {
|
||||
winuser::AdjustWindowRectEx(r, style as _, b_menu, style_ex as _)
|
||||
AdjustWindowRectEx(r, style, b_menu.into(), style_ex)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -155,14 +156,14 @@ pub fn set_cursor_hidden(hidden: bool) {
|
|||
static HIDDEN: AtomicBool = AtomicBool::new(false);
|
||||
let changed = HIDDEN.swap(hidden, Ordering::SeqCst) ^ hidden;
|
||||
if changed {
|
||||
unsafe { winuser::ShowCursor(!hidden as BOOL) };
|
||||
unsafe { ShowCursor(BOOL::from(!hidden)) };
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_cursor_clip() -> Result<RECT, io::Error> {
|
||||
unsafe {
|
||||
let mut rect: RECT = mem::zeroed();
|
||||
win_to_err(|| winuser::GetClipCursor(&mut rect)).map(|_| rect)
|
||||
win_to_err(|| GetClipCursor(&mut rect)).map(|_| rect)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,56 +176,52 @@ pub fn set_cursor_clip(rect: Option<RECT>) -> Result<(), io::Error> {
|
|||
.as_ref()
|
||||
.map(|r| r as *const RECT)
|
||||
.unwrap_or(ptr::null());
|
||||
win_to_err(|| winuser::ClipCursor(rect_ptr))
|
||||
win_to_err(|| ClipCursor(rect_ptr))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_desktop_rect() -> RECT {
|
||||
unsafe {
|
||||
let left = winuser::GetSystemMetrics(winuser::SM_XVIRTUALSCREEN);
|
||||
let top = winuser::GetSystemMetrics(winuser::SM_YVIRTUALSCREEN);
|
||||
let left = GetSystemMetrics(SM_XVIRTUALSCREEN);
|
||||
let top = GetSystemMetrics(SM_YVIRTUALSCREEN);
|
||||
RECT {
|
||||
left,
|
||||
top,
|
||||
right: left + winuser::GetSystemMetrics(winuser::SM_CXVIRTUALSCREEN),
|
||||
bottom: top + winuser::GetSystemMetrics(winuser::SM_CYVIRTUALSCREEN),
|
||||
right: left + GetSystemMetrics(SM_CXVIRTUALSCREEN),
|
||||
bottom: top + GetSystemMetrics(SM_CYVIRTUALSCREEN),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_focused(window: HWND) -> bool {
|
||||
window == unsafe { winuser::GetActiveWindow() }
|
||||
window == unsafe { GetActiveWindow() }
|
||||
}
|
||||
|
||||
impl CursorIcon {
|
||||
pub(crate) fn to_windows_cursor(self) -> *const wchar_t {
|
||||
pub(crate) fn to_windows_cursor(self) -> PCWSTR {
|
||||
match self {
|
||||
CursorIcon::Arrow | CursorIcon::Default => winuser::IDC_ARROW,
|
||||
CursorIcon::Hand => winuser::IDC_HAND,
|
||||
CursorIcon::Crosshair => winuser::IDC_CROSS,
|
||||
CursorIcon::Text | CursorIcon::VerticalText => winuser::IDC_IBEAM,
|
||||
CursorIcon::NotAllowed | CursorIcon::NoDrop => winuser::IDC_NO,
|
||||
CursorIcon::Arrow | CursorIcon::Default => IDC_ARROW,
|
||||
CursorIcon::Hand => IDC_HAND,
|
||||
CursorIcon::Crosshair => IDC_CROSS,
|
||||
CursorIcon::Text | CursorIcon::VerticalText => IDC_IBEAM,
|
||||
CursorIcon::NotAllowed | CursorIcon::NoDrop => IDC_NO,
|
||||
CursorIcon::Grab | CursorIcon::Grabbing | CursorIcon::Move | CursorIcon::AllScroll => {
|
||||
winuser::IDC_SIZEALL
|
||||
IDC_SIZEALL
|
||||
}
|
||||
CursorIcon::EResize
|
||||
| CursorIcon::WResize
|
||||
| CursorIcon::EwResize
|
||||
| CursorIcon::ColResize => winuser::IDC_SIZEWE,
|
||||
| CursorIcon::ColResize => IDC_SIZEWE,
|
||||
CursorIcon::NResize
|
||||
| CursorIcon::SResize
|
||||
| CursorIcon::NsResize
|
||||
| CursorIcon::RowResize => winuser::IDC_SIZENS,
|
||||
CursorIcon::NeResize | CursorIcon::SwResize | CursorIcon::NeswResize => {
|
||||
winuser::IDC_SIZENESW
|
||||
}
|
||||
CursorIcon::NwResize | CursorIcon::SeResize | CursorIcon::NwseResize => {
|
||||
winuser::IDC_SIZENWSE
|
||||
}
|
||||
CursorIcon::Wait => winuser::IDC_WAIT,
|
||||
CursorIcon::Progress => winuser::IDC_APPSTARTING,
|
||||
CursorIcon::Help => winuser::IDC_HELP,
|
||||
_ => winuser::IDC_ARROW, // use arrow for the missing cases.
|
||||
| CursorIcon::RowResize => IDC_SIZENS,
|
||||
CursorIcon::NeResize | CursorIcon::SwResize | CursorIcon::NeswResize => IDC_SIZENESW,
|
||||
CursorIcon::NwResize | CursorIcon::SeResize | CursorIcon::NwseResize => IDC_SIZENWSE,
|
||||
CursorIcon::Wait => IDC_WAIT,
|
||||
CursorIcon::Progress => IDC_APPSTARTING,
|
||||
CursorIcon::Help => IDC_HELP,
|
||||
_ => IDC_ARROW, // use arrow for the missing cases.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -236,17 +233,12 @@ pub(super) fn get_function_impl(library: &str, function: &str) -> Option<*const
|
|||
assert_eq!(function.chars().last(), Some('\0'));
|
||||
|
||||
// Library names we will use are ASCII so we can use the A version to avoid string conversion.
|
||||
let module = unsafe { LoadLibraryA(library.as_ptr() as LPCSTR) };
|
||||
if module.is_null() {
|
||||
let module = unsafe { LoadLibraryA(library.as_ptr()) };
|
||||
if module == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let function_ptr = unsafe { GetProcAddress(module, function.as_ptr() as LPCSTR) };
|
||||
if function_ptr.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(function_ptr as _)
|
||||
unsafe { GetProcAddress(module, function.as_ptr()) }.map(|function_ptr| function_ptr as _)
|
||||
}
|
||||
|
||||
macro_rules! get_function {
|
||||
|
@ -264,20 +256,20 @@ pub type SetProcessDpiAwareness =
|
|||
unsafe extern "system" fn(value: PROCESS_DPI_AWARENESS) -> HRESULT;
|
||||
pub type SetProcessDpiAwarenessContext =
|
||||
unsafe extern "system" fn(value: DPI_AWARENESS_CONTEXT) -> BOOL;
|
||||
pub type GetDpiForWindow = unsafe extern "system" fn(hwnd: HWND) -> UINT;
|
||||
pub type GetDpiForWindow = unsafe extern "system" fn(hwnd: HWND) -> u32;
|
||||
pub type GetDpiForMonitor = unsafe extern "system" fn(
|
||||
hmonitor: HMONITOR,
|
||||
dpi_type: MONITOR_DPI_TYPE,
|
||||
dpi_x: *mut UINT,
|
||||
dpi_y: *mut UINT,
|
||||
dpi_x: *mut u32,
|
||||
dpi_y: *mut u32,
|
||||
) -> HRESULT;
|
||||
pub type EnableNonClientDpiScaling = unsafe extern "system" fn(hwnd: HWND) -> BOOL;
|
||||
pub type AdjustWindowRectExForDpi = unsafe extern "system" fn(
|
||||
rect: LPRECT,
|
||||
dwStyle: DWORD,
|
||||
rect: *mut RECT,
|
||||
dwStyle: u32,
|
||||
bMenu: BOOL,
|
||||
dwExStyle: DWORD,
|
||||
dpi: UINT,
|
||||
dwExStyle: u32,
|
||||
dpi: u32,
|
||||
) -> BOOL;
|
||||
|
||||
lazy_static! {
|
||||
|
|
|
@ -4,31 +4,54 @@ use parking_lot::Mutex;
|
|||
use raw_window_handle::{RawWindowHandle, Win32Handle};
|
||||
use std::{
|
||||
cell::Cell,
|
||||
ffi::OsStr,
|
||||
io, mem,
|
||||
os::windows::ffi::OsStrExt,
|
||||
panic, ptr,
|
||||
ffi::c_void,
|
||||
io, mem, panic, ptr,
|
||||
sync::{mpsc::channel, Arc},
|
||||
};
|
||||
|
||||
use winapi::{
|
||||
ctypes::c_int,
|
||||
shared::{
|
||||
minwindef::{HINSTANCE, LPARAM, UINT, WPARAM},
|
||||
windef::{HWND, POINT, POINTS, RECT},
|
||||
winerror::SUCCEEDED,
|
||||
use windows_sys::Win32::{
|
||||
Foundation::{
|
||||
HINSTANCE, HWND, LPARAM, OLE_E_WRONGCOMPOBJ, POINT, POINTS, RECT, RPC_E_CHANGED_MODE, S_OK,
|
||||
WPARAM,
|
||||
},
|
||||
Graphics::{
|
||||
Dwm::{DwmEnableBlurBehindWindow, DWM_BB_BLURREGION, DWM_BB_ENABLE, DWM_BLURBEHIND},
|
||||
Gdi::{
|
||||
ChangeDisplaySettingsExW, ClientToScreen, CreateRectRgn, DeleteObject, InvalidateRgn,
|
||||
RedrawWindow, CDS_FULLSCREEN, DISP_CHANGE_BADFLAGS, DISP_CHANGE_BADMODE,
|
||||
DISP_CHANGE_BADPARAM, DISP_CHANGE_FAILED, DISP_CHANGE_SUCCESSFUL, RDW_INTERNALPAINT,
|
||||
},
|
||||
},
|
||||
System::{
|
||||
Com::{
|
||||
CoCreateInstance, CoInitializeEx, CoUninitialize, CLSCTX_ALL, COINIT_APARTMENTTHREADED,
|
||||
},
|
||||
LibraryLoader::GetModuleHandleW,
|
||||
Ole::{OleInitialize, RegisterDragDrop},
|
||||
},
|
||||
UI::{
|
||||
Input::{
|
||||
Ime::{
|
||||
ImmGetContext, ImmReleaseContext, ImmSetCompositionWindow, CFS_POINT,
|
||||
COMPOSITIONFORM,
|
||||
},
|
||||
KeyboardAndMouse::{
|
||||
EnableWindow, GetActiveWindow, MapVirtualKeyW, ReleaseCapture, SendInput, INPUT,
|
||||
INPUT_0, INPUT_KEYBOARD, KEYBDINPUT, KEYEVENTF_EXTENDEDKEY, KEYEVENTF_KEYUP,
|
||||
VK_LMENU, VK_MENU,
|
||||
},
|
||||
Touch::{RegisterTouchWindow, TWF_WANTPALM},
|
||||
},
|
||||
WindowsAndMessaging::{
|
||||
CreateWindowExW, FlashWindowEx, GetClientRect, GetCursorPos, GetForegroundWindow,
|
||||
GetSystemMetrics, GetWindowPlacement, IsWindowVisible, LoadCursorW, PeekMessageW,
|
||||
PostMessageW, RegisterClassExW, SetCursor, SetCursorPos, SetForegroundWindow,
|
||||
SetWindowPlacement, SetWindowPos, SetWindowTextW, CS_HREDRAW, CS_OWNDC, CS_VREDRAW,
|
||||
CW_USEDEFAULT, FLASHWINFO, FLASHW_ALL, FLASHW_STOP, FLASHW_TIMERNOFG, FLASHW_TRAY,
|
||||
GWLP_HINSTANCE, HTCAPTION, MAPVK_VK_TO_VSC, NID_READY, PM_NOREMOVE, SM_DIGITIZER,
|
||||
SM_IMMENABLED, SWP_ASYNCWINDOWPOS, SWP_NOACTIVATE, SWP_NOSIZE, SWP_NOZORDER,
|
||||
WM_NCLBUTTONDOWN, WNDCLASSEXW,
|
||||
},
|
||||
um::{
|
||||
combaseapi, dwmapi,
|
||||
imm::{CFS_POINT, COMPOSITIONFORM},
|
||||
libloaderapi,
|
||||
objbase::COINIT_APARTMENTTHREADED,
|
||||
ole2,
|
||||
oleidl::LPDROPTARGET,
|
||||
shobjidl_core::{CLSID_TaskbarList, ITaskbarList2},
|
||||
wingdi::{CreateRectRgn, DeleteObject},
|
||||
winnt::{LPCWSTR, SHORT},
|
||||
winuser,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -39,9 +62,11 @@ use crate::{
|
|||
monitor::MonitorHandle as RootMonitorHandle,
|
||||
platform_impl::platform::{
|
||||
dark_mode::try_theme,
|
||||
definitions::ITaskbarList2,
|
||||
definitions::{CLSID_TaskbarList, IID_ITaskbarList2},
|
||||
dpi::{dpi_to_scale_factor, enable_non_client_dpi_scaling, hwnd_dpi},
|
||||
drop_handler::FileDropHandler,
|
||||
event_loop::{self, EventLoopWindowTarget, WindowLongPtr, DESTROY_MSG_ID},
|
||||
event_loop::{self, EventLoopWindowTarget, DESTROY_MSG_ID},
|
||||
icon::{self, IconType},
|
||||
monitor, util,
|
||||
window_state::{CursorFlags, SavedWindow, WindowFlags, WindowState},
|
||||
|
@ -76,12 +101,9 @@ impl Window {
|
|||
}
|
||||
|
||||
pub fn set_title(&self, text: &str) {
|
||||
let text = OsStr::new(text)
|
||||
.encode_wide()
|
||||
.chain(Some(0).into_iter())
|
||||
.collect::<Vec<_>>();
|
||||
let wide_text = util::encode_wide(text);
|
||||
unsafe {
|
||||
winuser::SetWindowTextW(self.window.0, text.as_ptr() as LPCWSTR);
|
||||
SetWindowTextW(self.hwnd(), wide_text.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,24 +121,19 @@ impl Window {
|
|||
|
||||
#[inline]
|
||||
pub fn is_visible(&self) -> Option<bool> {
|
||||
Some(unsafe { winuser::IsWindowVisible(self.window.0) == 1 })
|
||||
Some(unsafe { IsWindowVisible(self.window.0) == 1 })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn request_redraw(&self) {
|
||||
unsafe {
|
||||
winuser::RedrawWindow(
|
||||
self.window.0,
|
||||
ptr::null(),
|
||||
ptr::null_mut(),
|
||||
winuser::RDW_INTERNALPAINT,
|
||||
);
|
||||
RedrawWindow(self.hwnd(), ptr::null(), 0, RDW_INTERNALPAINT);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
|
||||
util::get_window_rect(self.window.0)
|
||||
util::get_window_rect(self.hwnd())
|
||||
.map(|rect| Ok(PhysicalPosition::new(rect.left as i32, rect.top as i32)))
|
||||
.expect("Unexpected GetWindowRect failure; please report this error to https://github.com/rust-windowing/winit")
|
||||
}
|
||||
|
@ -124,7 +141,7 @@ impl Window {
|
|||
#[inline]
|
||||
pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
|
||||
let mut position: POINT = unsafe { mem::zeroed() };
|
||||
if unsafe { winuser::ClientToScreen(self.window.0, &mut position) } == 0 {
|
||||
if unsafe { ClientToScreen(self.hwnd(), &mut position) } == false.into() {
|
||||
panic!("Unexpected ClientToScreen failure: please report this error to https://github.com/rust-windowing/winit")
|
||||
}
|
||||
Ok(PhysicalPosition::new(position.x as i32, position.y as i32))
|
||||
|
@ -144,26 +161,23 @@ impl Window {
|
|||
});
|
||||
|
||||
unsafe {
|
||||
winuser::SetWindowPos(
|
||||
self.window.0,
|
||||
ptr::null_mut(),
|
||||
x as c_int,
|
||||
y as c_int,
|
||||
SetWindowPos(
|
||||
self.hwnd(),
|
||||
0,
|
||||
x,
|
||||
y,
|
||||
0,
|
||||
0,
|
||||
winuser::SWP_ASYNCWINDOWPOS
|
||||
| winuser::SWP_NOZORDER
|
||||
| winuser::SWP_NOSIZE
|
||||
| winuser::SWP_NOACTIVATE,
|
||||
SWP_ASYNCWINDOWPOS | SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE,
|
||||
);
|
||||
winuser::InvalidateRgn(self.window.0, ptr::null_mut(), 0);
|
||||
InvalidateRgn(self.hwnd(), 0, false.into());
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn inner_size(&self) -> PhysicalSize<u32> {
|
||||
let mut rect: RECT = unsafe { mem::zeroed() };
|
||||
if unsafe { winuser::GetClientRect(self.window.0, &mut rect) } == 0 {
|
||||
if unsafe { GetClientRect(self.hwnd(), &mut rect) } == false.into() {
|
||||
panic!("Unexpected GetClientRect failure: please report this error to https://github.com/rust-windowing/winit")
|
||||
}
|
||||
PhysicalSize::new(
|
||||
|
@ -174,7 +188,7 @@ impl Window {
|
|||
|
||||
#[inline]
|
||||
pub fn outer_size(&self) -> PhysicalSize<u32> {
|
||||
util::get_window_rect(self.window.0)
|
||||
util::get_window_rect(self.hwnd())
|
||||
.map(|rect| {
|
||||
PhysicalSize::new(
|
||||
(rect.right - rect.left) as u32,
|
||||
|
@ -198,7 +212,7 @@ impl Window {
|
|||
});
|
||||
});
|
||||
|
||||
util::set_inner_size_physical(self.window.0, width, height);
|
||||
util::set_inner_size_physical(self.hwnd(), width, height);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -244,7 +258,7 @@ impl Window {
|
|||
|
||||
#[inline]
|
||||
pub fn hinstance(&self) -> HINSTANCE {
|
||||
unsafe { winuser::GetWindowLongPtrW(self.hwnd(), winuser::GWLP_HINSTANCE) as *mut _ }
|
||||
unsafe { super::get_window_long(self.hwnd(), GWLP_HINSTANCE) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -259,8 +273,8 @@ impl Window {
|
|||
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
|
||||
self.window_state.lock().mouse.cursor = cursor;
|
||||
self.thread_executor.execute_in_thread(move || unsafe {
|
||||
let cursor = winuser::LoadCursorW(ptr::null_mut(), cursor.to_windows_cursor());
|
||||
winuser::SetCursor(cursor);
|
||||
let cursor = LoadCursorW(0, cursor.to_windows_cursor());
|
||||
SetCursor(cursor);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -312,10 +326,10 @@ impl Window {
|
|||
|
||||
let mut point = POINT { x, y };
|
||||
unsafe {
|
||||
if winuser::ClientToScreen(self.window.0, &mut point) == 0 {
|
||||
if ClientToScreen(self.hwnd(), &mut point) == false.into() {
|
||||
return Err(ExternalError::Os(os_error!(io::Error::last_os_error())));
|
||||
}
|
||||
if winuser::SetCursorPos(point.x, point.y) == 0 {
|
||||
if SetCursorPos(point.x, point.y) == false.into() {
|
||||
return Err(ExternalError::Os(os_error!(io::Error::last_os_error())));
|
||||
}
|
||||
}
|
||||
|
@ -327,18 +341,18 @@ impl Window {
|
|||
unsafe {
|
||||
let points = {
|
||||
let mut pos = mem::zeroed();
|
||||
winuser::GetCursorPos(&mut pos);
|
||||
GetCursorPos(&mut pos);
|
||||
pos
|
||||
};
|
||||
let points = POINTS {
|
||||
x: points.x as SHORT,
|
||||
y: points.y as SHORT,
|
||||
x: points.x as i16,
|
||||
y: points.y as i16,
|
||||
};
|
||||
winuser::ReleaseCapture();
|
||||
winuser::PostMessageW(
|
||||
self.window.0,
|
||||
winuser::WM_NCLBUTTONDOWN,
|
||||
winuser::HTCAPTION as WPARAM,
|
||||
ReleaseCapture();
|
||||
PostMessageW(
|
||||
self.hwnd(),
|
||||
WM_NCLBUTTONDOWN,
|
||||
HTCAPTION as WPARAM,
|
||||
&points as *const _ as LPARAM,
|
||||
);
|
||||
}
|
||||
|
@ -348,7 +362,7 @@ impl Window {
|
|||
|
||||
#[inline]
|
||||
pub fn id(&self) -> WindowId {
|
||||
WindowId(self.window.0)
|
||||
WindowId(self.hwnd())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -415,50 +429,43 @@ impl Window {
|
|||
| (&Some(Fullscreen::Exclusive(_)), &Some(Fullscreen::Exclusive(ref video_mode))) =>
|
||||
{
|
||||
let monitor = video_mode.monitor();
|
||||
let monitor_info = monitor::get_monitor_info(monitor.inner.hmonitor()).unwrap();
|
||||
|
||||
let mut display_name = OsStr::new(&monitor.inner.native_identifier())
|
||||
.encode_wide()
|
||||
.collect::<Vec<_>>();
|
||||
// `encode_wide` does not add a null-terminator but
|
||||
// `ChangeDisplaySettingsExW` requires a null-terminated
|
||||
// string, so add it
|
||||
display_name.push(0);
|
||||
|
||||
let mut native_video_mode = video_mode.video_mode.native_video_mode;
|
||||
let native_video_mode = video_mode.video_mode.native_video_mode;
|
||||
|
||||
let res = unsafe {
|
||||
winuser::ChangeDisplaySettingsExW(
|
||||
display_name.as_ptr(),
|
||||
&mut native_video_mode,
|
||||
std::ptr::null_mut(),
|
||||
winuser::CDS_FULLSCREEN,
|
||||
std::ptr::null_mut(),
|
||||
ChangeDisplaySettingsExW(
|
||||
monitor_info.szDevice.as_ptr(),
|
||||
&native_video_mode,
|
||||
0,
|
||||
CDS_FULLSCREEN,
|
||||
ptr::null(),
|
||||
)
|
||||
};
|
||||
|
||||
debug_assert!(res != winuser::DISP_CHANGE_BADFLAGS);
|
||||
debug_assert!(res != winuser::DISP_CHANGE_BADMODE);
|
||||
debug_assert!(res != winuser::DISP_CHANGE_BADPARAM);
|
||||
debug_assert!(res != winuser::DISP_CHANGE_FAILED);
|
||||
assert_eq!(res, winuser::DISP_CHANGE_SUCCESSFUL);
|
||||
debug_assert!(res != DISP_CHANGE_BADFLAGS);
|
||||
debug_assert!(res != DISP_CHANGE_BADMODE);
|
||||
debug_assert!(res != DISP_CHANGE_BADPARAM);
|
||||
debug_assert!(res != DISP_CHANGE_FAILED);
|
||||
assert_eq!(res, DISP_CHANGE_SUCCESSFUL);
|
||||
}
|
||||
(&Some(Fullscreen::Exclusive(_)), &None)
|
||||
| (&Some(Fullscreen::Exclusive(_)), &Some(Fullscreen::Borderless(_))) => {
|
||||
let res = unsafe {
|
||||
winuser::ChangeDisplaySettingsExW(
|
||||
std::ptr::null_mut(),
|
||||
std::ptr::null_mut(),
|
||||
std::ptr::null_mut(),
|
||||
winuser::CDS_FULLSCREEN,
|
||||
std::ptr::null_mut(),
|
||||
ChangeDisplaySettingsExW(
|
||||
ptr::null(),
|
||||
ptr::null(),
|
||||
0,
|
||||
CDS_FULLSCREEN,
|
||||
ptr::null(),
|
||||
)
|
||||
};
|
||||
|
||||
debug_assert!(res != winuser::DISP_CHANGE_BADFLAGS);
|
||||
debug_assert!(res != winuser::DISP_CHANGE_BADMODE);
|
||||
debug_assert!(res != winuser::DISP_CHANGE_BADPARAM);
|
||||
debug_assert!(res != winuser::DISP_CHANGE_FAILED);
|
||||
assert_eq!(res, winuser::DISP_CHANGE_SUCCESSFUL);
|
||||
debug_assert!(res != DISP_CHANGE_BADFLAGS);
|
||||
debug_assert!(res != DISP_CHANGE_BADMODE);
|
||||
debug_assert!(res != DISP_CHANGE_BADPARAM);
|
||||
debug_assert!(res != DISP_CHANGE_FAILED);
|
||||
assert_eq!(res, DISP_CHANGE_SUCCESSFUL);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -473,7 +480,7 @@ impl Window {
|
|||
// fine, taking control back from the DWM and ensuring that the `SetWindowPos` call
|
||||
// below goes through.
|
||||
let mut msg = mem::zeroed();
|
||||
winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 0);
|
||||
PeekMessageW(&mut msg, 0, 0, 0, PM_NOREMOVE);
|
||||
}
|
||||
|
||||
// Update window style
|
||||
|
@ -494,7 +501,7 @@ impl Window {
|
|||
// Save window bounds before entering fullscreen
|
||||
let placement = unsafe {
|
||||
let mut placement = mem::zeroed();
|
||||
winuser::GetWindowPlacement(window.0, &mut placement);
|
||||
GetWindowPlacement(window.0, &mut placement);
|
||||
placement
|
||||
};
|
||||
|
||||
|
@ -512,16 +519,16 @@ impl Window {
|
|||
let size: (u32, u32) = monitor.size().into();
|
||||
|
||||
unsafe {
|
||||
winuser::SetWindowPos(
|
||||
SetWindowPos(
|
||||
window.0,
|
||||
ptr::null_mut(),
|
||||
0,
|
||||
position.0,
|
||||
position.1,
|
||||
size.0 as i32,
|
||||
size.1 as i32,
|
||||
winuser::SWP_ASYNCWINDOWPOS | winuser::SWP_NOZORDER,
|
||||
SWP_ASYNCWINDOWPOS | SWP_NOZORDER,
|
||||
);
|
||||
winuser::InvalidateRgn(window.0, ptr::null_mut(), 0);
|
||||
InvalidateRgn(window.0, 0, false.into());
|
||||
}
|
||||
}
|
||||
None => {
|
||||
|
@ -529,8 +536,8 @@ impl Window {
|
|||
if let Some(SavedWindow { placement }) = window_state_lock.saved_window.take() {
|
||||
drop(window_state_lock);
|
||||
unsafe {
|
||||
winuser::SetWindowPlacement(window.0, &placement);
|
||||
winuser::InvalidateRgn(window.0, ptr::null_mut(), 0);
|
||||
SetWindowPlacement(window.0, &placement);
|
||||
InvalidateRgn(window.0, 0, false.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -577,7 +584,7 @@ impl Window {
|
|||
#[inline]
|
||||
pub fn current_monitor(&self) -> Option<RootMonitorHandle> {
|
||||
Some(RootMonitorHandle {
|
||||
inner: monitor::current_monitor(self.window.0),
|
||||
inner: monitor::current_monitor(self.hwnd()),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -586,16 +593,16 @@ impl Window {
|
|||
if let Some(ref window_icon) = window_icon {
|
||||
window_icon
|
||||
.inner
|
||||
.set_for_window(self.window.0, IconType::Small);
|
||||
.set_for_window(self.hwnd(), IconType::Small);
|
||||
} else {
|
||||
icon::unset_for_window(self.window.0, IconType::Small);
|
||||
icon::unset_for_window(self.hwnd(), IconType::Small);
|
||||
}
|
||||
self.window_state.lock().window_icon = window_icon;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_enable(&self, enabled: bool) {
|
||||
unsafe { winuser::EnableWindow(self.hwnd() as _, enabled as _) };
|
||||
unsafe { EnableWindow(self.hwnd(), enabled.into()) };
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -603,24 +610,24 @@ impl Window {
|
|||
if let Some(ref taskbar_icon) = taskbar_icon {
|
||||
taskbar_icon
|
||||
.inner
|
||||
.set_for_window(self.window.0, IconType::Big);
|
||||
.set_for_window(self.hwnd(), IconType::Big);
|
||||
} else {
|
||||
icon::unset_for_window(self.window.0, IconType::Big);
|
||||
icon::unset_for_window(self.hwnd(), IconType::Big);
|
||||
}
|
||||
self.window_state.lock().taskbar_icon = taskbar_icon;
|
||||
}
|
||||
|
||||
pub(crate) fn set_ime_position_physical(&self, x: i32, y: i32) {
|
||||
if unsafe { winuser::GetSystemMetrics(winuser::SM_IMMENABLED) } != 0 {
|
||||
let mut composition_form = COMPOSITIONFORM {
|
||||
if unsafe { GetSystemMetrics(SM_IMMENABLED) } != 0 {
|
||||
let composition_form = COMPOSITIONFORM {
|
||||
dwStyle: CFS_POINT,
|
||||
ptCurrentPos: POINT { x, y },
|
||||
rcArea: unsafe { mem::zeroed() },
|
||||
};
|
||||
unsafe {
|
||||
let himc = winapi::um::imm::ImmGetContext(self.window.0);
|
||||
winapi::um::imm::ImmSetCompositionWindow(himc, &mut composition_form);
|
||||
winapi::um::imm::ImmReleaseContext(self.window.0, himc);
|
||||
let himc = ImmGetContext(self.hwnd());
|
||||
ImmSetCompositionWindow(himc, &composition_form);
|
||||
ImmReleaseContext(self.hwnd(), himc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -634,7 +641,7 @@ impl Window {
|
|||
#[inline]
|
||||
pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
|
||||
let window = self.window.clone();
|
||||
let active_window_handle = unsafe { winuser::GetActiveWindow() };
|
||||
let active_window_handle = unsafe { GetActiveWindow() };
|
||||
if window.0 == active_window_handle {
|
||||
return;
|
||||
}
|
||||
|
@ -643,23 +650,19 @@ impl Window {
|
|||
let _ = &window;
|
||||
let (flags, count) = request_type
|
||||
.map(|ty| match ty {
|
||||
UserAttentionType::Critical => {
|
||||
(winuser::FLASHW_ALL | winuser::FLASHW_TIMERNOFG, u32::MAX)
|
||||
}
|
||||
UserAttentionType::Informational => {
|
||||
(winuser::FLASHW_TRAY | winuser::FLASHW_TIMERNOFG, 0)
|
||||
}
|
||||
UserAttentionType::Critical => (FLASHW_ALL | FLASHW_TIMERNOFG, u32::MAX),
|
||||
UserAttentionType::Informational => (FLASHW_TRAY | FLASHW_TIMERNOFG, 0),
|
||||
})
|
||||
.unwrap_or((winuser::FLASHW_STOP, 0));
|
||||
.unwrap_or((FLASHW_STOP, 0));
|
||||
|
||||
let mut flash_info = winuser::FLASHWINFO {
|
||||
cbSize: mem::size_of::<winuser::FLASHWINFO>() as UINT,
|
||||
let flash_info = FLASHWINFO {
|
||||
cbSize: mem::size_of::<FLASHWINFO>() as u32,
|
||||
hwnd: window.0,
|
||||
dwFlags: flags,
|
||||
uCount: count,
|
||||
dwTimeout: 0,
|
||||
};
|
||||
winuser::FlashWindowEx(&mut flash_info);
|
||||
FlashWindowEx(&flash_info);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -675,7 +678,7 @@ impl Window {
|
|||
|
||||
let is_visible = window_flags.contains(WindowFlags::VISIBLE);
|
||||
let is_minimized = window_flags.contains(WindowFlags::MINIMIZED);
|
||||
let is_foreground = window.0 == unsafe { winuser::GetForegroundWindow() };
|
||||
let is_foreground = window.0 == unsafe { GetForegroundWindow() };
|
||||
|
||||
if is_visible && !is_minimized && !is_foreground {
|
||||
unsafe { force_window_active(window.0) };
|
||||
|
@ -689,7 +692,7 @@ impl Drop for Window {
|
|||
unsafe {
|
||||
// The window must be destroyed from the same thread that created it, so we send a
|
||||
// custom message to be handled by our callback to do the actual work.
|
||||
winuser::PostMessageW(self.window.0, *DESTROY_MSG_ID, 0, 0);
|
||||
PostMessageW(self.hwnd(), *DESTROY_MSG_ID, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -720,9 +723,9 @@ impl<'a, T: 'static> InitData<'a, T> {
|
|||
unsafe fn create_window(&self, window: HWND) -> Window {
|
||||
// Register for touch events if applicable
|
||||
{
|
||||
let digitizer = winuser::GetSystemMetrics(winuser::SM_DIGITIZER) as u32;
|
||||
if digitizer & winuser::NID_READY != 0 {
|
||||
winuser::RegisterTouchWindow(window, winuser::TWF_WANTPALM);
|
||||
let digitizer = GetSystemMetrics(SM_DIGITIZER) as u32;
|
||||
if digitizer & NID_READY != 0 {
|
||||
RegisterTouchWindow(window, TWF_WANTPALM);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -758,9 +761,7 @@ impl<'a, T: 'static> InitData<'a, T> {
|
|||
|
||||
unsafe fn create_window_data(&self, win: &Window) -> event_loop::WindowData<T> {
|
||||
let file_drop_handler = if self.pl_attribs.drag_and_drop {
|
||||
use winapi::shared::winerror::{OLE_E_WRONGCOMPOBJ, RPC_E_CHANGED_MODE, S_OK};
|
||||
|
||||
let ole_init_result = ole2::OleInitialize(ptr::null_mut());
|
||||
let ole_init_result = OleInitialize(ptr::null_mut());
|
||||
// It is ok if the initialize result is `S_FALSE` because it might happen that
|
||||
// multiple windows are created on the same thread.
|
||||
if ole_init_result == OLE_E_WRONGCOMPOBJ {
|
||||
|
@ -782,12 +783,11 @@ impl<'a, T: 'static> InitData<'a, T> {
|
|||
}
|
||||
}),
|
||||
);
|
||||
let handler_interface_ptr = &mut (*file_drop_handler.data).interface as LPDROPTARGET;
|
||||
|
||||
assert_eq!(
|
||||
ole2::RegisterDragDrop(win.window.0, handler_interface_ptr),
|
||||
S_OK
|
||||
);
|
||||
let handler_interface_ptr =
|
||||
&mut (*file_drop_handler.data).interface as *mut _ as *mut c_void;
|
||||
|
||||
assert_eq!(RegisterDragDrop(win.window.0, handler_interface_ptr), S_OK);
|
||||
Some(file_drop_handler)
|
||||
} else {
|
||||
None
|
||||
|
@ -806,7 +806,7 @@ impl<'a, T: 'static> InitData<'a, T> {
|
|||
|
||||
// Returns a pointer to window user data on success.
|
||||
// The user data will be registered for the window and can be accessed within the window event callback.
|
||||
pub unsafe fn on_nccreate(&mut self, window: HWND) -> Option<WindowLongPtr> {
|
||||
pub unsafe fn on_nccreate(&mut self, window: HWND) -> Option<isize> {
|
||||
let runner = self.event_loop.runner_shared.clone();
|
||||
let result = runner.catch_unwind(|| {
|
||||
let mut window = self.create_window(window);
|
||||
|
@ -829,20 +829,20 @@ impl<'a, T: 'static> InitData<'a, T> {
|
|||
// Empty region for the blur effect, so the window is fully transparent
|
||||
let region = CreateRectRgn(0, 0, -1, -1);
|
||||
|
||||
let bb = dwmapi::DWM_BLURBEHIND {
|
||||
dwFlags: dwmapi::DWM_BB_ENABLE | dwmapi::DWM_BB_BLURREGION,
|
||||
fEnable: 1,
|
||||
let bb = DWM_BLURBEHIND {
|
||||
dwFlags: DWM_BB_ENABLE | DWM_BB_BLURREGION,
|
||||
fEnable: true.into(),
|
||||
hRgnBlur: region,
|
||||
fTransitionOnMaximized: 0,
|
||||
fTransitionOnMaximized: false.into(),
|
||||
};
|
||||
let hr = dwmapi::DwmEnableBlurBehindWindow(win.hwnd(), &bb);
|
||||
if !SUCCEEDED(hr) {
|
||||
let hr = DwmEnableBlurBehindWindow(win.hwnd(), &bb);
|
||||
if hr < 0 {
|
||||
warn!(
|
||||
"Setting transparent window is failed. HRESULT Code: 0x{:X}",
|
||||
hr
|
||||
);
|
||||
}
|
||||
DeleteObject(region as _);
|
||||
DeleteObject(region);
|
||||
}
|
||||
|
||||
let attributes = self.attributes.clone();
|
||||
|
@ -879,12 +879,8 @@ unsafe fn init<T>(
|
|||
where
|
||||
T: 'static,
|
||||
{
|
||||
let title = OsStr::new(&attributes.title)
|
||||
.encode_wide()
|
||||
.chain(Some(0).into_iter())
|
||||
.collect::<Vec<_>>();
|
||||
let title = util::encode_wide(&attributes.title);
|
||||
|
||||
// registering the window class
|
||||
let class_name = register_window_class::<T>(&attributes.window_icon, &pl_attribs.taskbar_icon);
|
||||
|
||||
let mut window_flags = WindowFlags::empty();
|
||||
|
@ -925,18 +921,18 @@ where
|
|||
};
|
||||
|
||||
let (style, ex_style) = window_flags.to_window_styles();
|
||||
let handle = winuser::CreateWindowExW(
|
||||
let handle = CreateWindowExW(
|
||||
ex_style,
|
||||
class_name.as_ptr(),
|
||||
title.as_ptr() as LPCWSTR,
|
||||
title.as_ptr(),
|
||||
style,
|
||||
winuser::CW_USEDEFAULT,
|
||||
winuser::CW_USEDEFAULT,
|
||||
winuser::CW_USEDEFAULT,
|
||||
winuser::CW_USEDEFAULT,
|
||||
parent.unwrap_or(ptr::null_mut()),
|
||||
pl_attribs.menu.unwrap_or(ptr::null_mut()),
|
||||
libloaderapi::GetModuleHandleW(ptr::null()),
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
parent.unwrap_or(0),
|
||||
pl_attribs.menu.unwrap_or(0),
|
||||
GetModuleHandleW(ptr::null()),
|
||||
&mut initdata as *mut _ as *mut _,
|
||||
);
|
||||
|
||||
|
@ -945,7 +941,7 @@ where
|
|||
panic::resume_unwind(panic_error)
|
||||
}
|
||||
|
||||
if handle.is_null() {
|
||||
if handle == 0 {
|
||||
return Err(os_error!(io::Error::last_os_error()));
|
||||
}
|
||||
|
||||
|
@ -958,30 +954,27 @@ unsafe fn register_window_class<T: 'static>(
|
|||
window_icon: &Option<Icon>,
|
||||
taskbar_icon: &Option<Icon>,
|
||||
) -> Vec<u16> {
|
||||
let class_name: Vec<_> = OsStr::new("Window Class")
|
||||
.encode_wide()
|
||||
.chain(Some(0).into_iter())
|
||||
.collect();
|
||||
let class_name = util::encode_wide("Window Class");
|
||||
|
||||
let h_icon = taskbar_icon
|
||||
.as_ref()
|
||||
.map(|icon| icon.inner.as_raw_handle())
|
||||
.unwrap_or(ptr::null_mut());
|
||||
.unwrap_or(0);
|
||||
let h_icon_small = window_icon
|
||||
.as_ref()
|
||||
.map(|icon| icon.inner.as_raw_handle())
|
||||
.unwrap_or(ptr::null_mut());
|
||||
.unwrap_or(0);
|
||||
|
||||
let class = winuser::WNDCLASSEXW {
|
||||
cbSize: mem::size_of::<winuser::WNDCLASSEXW>() as UINT,
|
||||
style: winuser::CS_HREDRAW | winuser::CS_VREDRAW | winuser::CS_OWNDC,
|
||||
let class = WNDCLASSEXW {
|
||||
cbSize: mem::size_of::<WNDCLASSEXW>() as u32,
|
||||
style: CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
|
||||
lpfnWndProc: Some(super::event_loop::public_window_callback::<T>),
|
||||
cbClsExtra: 0,
|
||||
cbWndExtra: 0,
|
||||
hInstance: libloaderapi::GetModuleHandleW(ptr::null()),
|
||||
hInstance: GetModuleHandleW(ptr::null()),
|
||||
hIcon: h_icon,
|
||||
hCursor: ptr::null_mut(), // must be null in order for cursor state to work properly
|
||||
hbrBackground: ptr::null_mut(),
|
||||
hCursor: 0, // must be null in order for cursor state to work properly
|
||||
hbrBackground: 0,
|
||||
lpszMenuName: ptr::null(),
|
||||
lpszClassName: class_name.as_ptr(),
|
||||
hIconSm: h_icon_small,
|
||||
|
@ -991,7 +984,7 @@ unsafe fn register_window_class<T: 'static>(
|
|||
// an error, and because errors here are detected during CreateWindowEx anyway.
|
||||
// Also since there is no weird element in the struct, there is no reason for this
|
||||
// call to fail.
|
||||
winuser::RegisterClassExW(&class);
|
||||
RegisterClassExW(&class);
|
||||
|
||||
class_name
|
||||
}
|
||||
|
@ -999,14 +992,14 @@ unsafe fn register_window_class<T: 'static>(
|
|||
struct ComInitialized(*mut ());
|
||||
impl Drop for ComInitialized {
|
||||
fn drop(&mut self) {
|
||||
unsafe { combaseapi::CoUninitialize() };
|
||||
unsafe { CoUninitialize() };
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static COM_INITIALIZED: ComInitialized = {
|
||||
unsafe {
|
||||
combaseapi::CoInitializeEx(ptr::null_mut(), COINIT_APARTMENTTHREADED);
|
||||
CoInitializeEx(ptr::null(), COINIT_APARTMENTTHREADED);
|
||||
ComInitialized(ptr::null_mut())
|
||||
}
|
||||
};
|
||||
|
@ -1033,17 +1026,17 @@ unsafe fn taskbar_mark_fullscreen(handle: HWND, fullscreen: bool) {
|
|||
let mut task_bar_list = task_bar_list_ptr.get();
|
||||
|
||||
if task_bar_list.is_null() {
|
||||
use winapi::{shared::winerror::S_OK, Interface};
|
||||
|
||||
let hr = combaseapi::CoCreateInstance(
|
||||
let hr = CoCreateInstance(
|
||||
&CLSID_TaskbarList,
|
||||
ptr::null_mut(),
|
||||
combaseapi::CLSCTX_ALL,
|
||||
&ITaskbarList2::uuidof(),
|
||||
CLSCTX_ALL,
|
||||
&IID_ITaskbarList2,
|
||||
&mut task_bar_list as *mut _ as *mut _,
|
||||
);
|
||||
|
||||
if hr != S_OK || (*task_bar_list).HrInit() != S_OK {
|
||||
let hr_init = (*(*task_bar_list).lpVtbl).parent.HrInit;
|
||||
|
||||
if hr != S_OK || hr_init(task_bar_list.cast()) != S_OK {
|
||||
// In some old windows, the taskbar object could not be created, we just ignore it
|
||||
return;
|
||||
}
|
||||
|
@ -1051,7 +1044,8 @@ unsafe fn taskbar_mark_fullscreen(handle: HWND, fullscreen: bool) {
|
|||
}
|
||||
|
||||
task_bar_list = task_bar_list_ptr.get();
|
||||
(*task_bar_list).MarkFullscreenWindow(handle, if fullscreen { 1 } else { 0 });
|
||||
let mark_fullscreen_window = (*(*task_bar_list).lpVtbl).MarkFullscreenWindow;
|
||||
mark_fullscreen_window(task_bar_list, handle, if fullscreen { 1 } else { 0 });
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1060,25 +1054,41 @@ unsafe fn force_window_active(handle: HWND) {
|
|||
// This is a little hack which can "steal" the foreground window permission
|
||||
// We only call this function in the window creation, so it should be fine.
|
||||
// See : https://stackoverflow.com/questions/10740346/setforegroundwindow-only-working-while-visual-studio-is-open
|
||||
let alt_sc = winuser::MapVirtualKeyW(winuser::VK_MENU as _, winuser::MAPVK_VK_TO_VSC);
|
||||
let alt_sc = MapVirtualKeyW(VK_MENU as u32, MAPVK_VK_TO_VSC);
|
||||
|
||||
let mut inputs: [winuser::INPUT; 2] = mem::zeroed();
|
||||
inputs[0].type_ = winuser::INPUT_KEYBOARD;
|
||||
inputs[0].u.ki_mut().wVk = winuser::VK_LMENU as _;
|
||||
inputs[0].u.ki_mut().wScan = alt_sc as _;
|
||||
inputs[0].u.ki_mut().dwFlags = winuser::KEYEVENTF_EXTENDEDKEY;
|
||||
|
||||
inputs[1].type_ = winuser::INPUT_KEYBOARD;
|
||||
inputs[1].u.ki_mut().wVk = winuser::VK_LMENU as _;
|
||||
inputs[1].u.ki_mut().wScan = alt_sc as _;
|
||||
inputs[1].u.ki_mut().dwFlags = winuser::KEYEVENTF_EXTENDEDKEY | winuser::KEYEVENTF_KEYUP;
|
||||
let inputs = [
|
||||
INPUT {
|
||||
r#type: INPUT_KEYBOARD,
|
||||
Anonymous: INPUT_0 {
|
||||
ki: KEYBDINPUT {
|
||||
wVk: VK_LMENU,
|
||||
wScan: alt_sc as u16,
|
||||
dwFlags: KEYEVENTF_EXTENDEDKEY,
|
||||
dwExtraInfo: 0,
|
||||
time: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
INPUT {
|
||||
r#type: INPUT_KEYBOARD,
|
||||
Anonymous: INPUT_0 {
|
||||
ki: KEYBDINPUT {
|
||||
wVk: VK_LMENU,
|
||||
wScan: alt_sc as u16,
|
||||
dwFlags: KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
|
||||
dwExtraInfo: 0,
|
||||
time: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
// Simulate a key press and release
|
||||
winuser::SendInput(
|
||||
inputs.len() as _,
|
||||
inputs.as_mut_ptr(),
|
||||
mem::size_of::<winuser::INPUT>() as _,
|
||||
SendInput(
|
||||
inputs.len() as u32,
|
||||
inputs.as_ptr(),
|
||||
mem::size_of::<INPUT>() as i32,
|
||||
);
|
||||
|
||||
winuser::SetForegroundWindow(handle);
|
||||
SetForegroundWindow(handle);
|
||||
}
|
||||
|
|
|
@ -6,13 +6,20 @@ use crate::{
|
|||
window::{CursorIcon, Fullscreen, Theme, WindowAttributes},
|
||||
};
|
||||
use parking_lot::MutexGuard;
|
||||
use std::{io, ptr};
|
||||
use winapi::{
|
||||
shared::{
|
||||
minwindef::DWORD,
|
||||
windef::{HWND, RECT},
|
||||
use std::io;
|
||||
use windows_sys::Win32::{
|
||||
Foundation::{HWND, RECT},
|
||||
Graphics::Gdi::InvalidateRgn,
|
||||
UI::WindowsAndMessaging::{
|
||||
SendMessageW, SetWindowLongW, SetWindowPos, ShowWindow, GWL_EXSTYLE, GWL_STYLE,
|
||||
HWND_NOTOPMOST, HWND_TOPMOST, SWP_ASYNCWINDOWPOS, SWP_FRAMECHANGED, SWP_NOACTIVATE,
|
||||
SWP_NOMOVE, SWP_NOSIZE, SWP_NOZORDER, SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE,
|
||||
SW_SHOW, WINDOWPLACEMENT, WINDOW_EX_STYLE, WINDOW_STYLE, WS_BORDER, WS_CAPTION, WS_CHILD,
|
||||
WS_CLIPCHILDREN, WS_CLIPSIBLINGS, WS_EX_ACCEPTFILES, WS_EX_APPWINDOW, WS_EX_LEFT,
|
||||
WS_EX_NOREDIRECTIONBITMAP, WS_EX_TOPMOST, WS_EX_WINDOWEDGE, WS_MAXIMIZE, WS_MAXIMIZEBOX,
|
||||
WS_MINIMIZE, WS_MINIMIZEBOX, WS_OVERLAPPED, WS_OVERLAPPEDWINDOW, WS_POPUP, WS_SIZEBOX,
|
||||
WS_SYSMENU, WS_VISIBLE,
|
||||
},
|
||||
um::winuser,
|
||||
};
|
||||
|
||||
/// Contains information about states and the window that the callback is going to use.
|
||||
|
@ -39,7 +46,7 @@ pub struct WindowState {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct SavedWindow {
|
||||
pub placement: winuser::WINDOWPLACEMENT,
|
||||
pub placement: WINDOWPLACEMENT,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -187,10 +194,8 @@ impl WindowFlags {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn to_window_styles(self) -> (DWORD, DWORD) {
|
||||
use winapi::um::winuser::*;
|
||||
|
||||
let (mut style, mut style_ex) = (0, 0);
|
||||
pub fn to_window_styles(self) -> (WINDOW_STYLE, WINDOW_EX_STYLE) {
|
||||
let (mut style, mut style_ex) = (WS_OVERLAPPED, WS_EX_LEFT);
|
||||
|
||||
if self.contains(WindowFlags::RESIZABLE) {
|
||||
style |= WS_SIZEBOX | WS_MAXIMIZEBOX;
|
||||
|
@ -248,43 +253,40 @@ impl WindowFlags {
|
|||
|
||||
if diff.contains(WindowFlags::VISIBLE) {
|
||||
unsafe {
|
||||
winuser::ShowWindow(
|
||||
ShowWindow(
|
||||
window,
|
||||
match new.contains(WindowFlags::VISIBLE) {
|
||||
true => winuser::SW_SHOW,
|
||||
false => winuser::SW_HIDE,
|
||||
true => SW_SHOW,
|
||||
false => SW_HIDE,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
if diff.contains(WindowFlags::ALWAYS_ON_TOP) {
|
||||
unsafe {
|
||||
winuser::SetWindowPos(
|
||||
SetWindowPos(
|
||||
window,
|
||||
match new.contains(WindowFlags::ALWAYS_ON_TOP) {
|
||||
true => winuser::HWND_TOPMOST,
|
||||
false => winuser::HWND_NOTOPMOST,
|
||||
true => HWND_TOPMOST,
|
||||
false => HWND_NOTOPMOST,
|
||||
},
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
winuser::SWP_ASYNCWINDOWPOS
|
||||
| winuser::SWP_NOMOVE
|
||||
| winuser::SWP_NOSIZE
|
||||
| winuser::SWP_NOACTIVATE,
|
||||
SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE,
|
||||
);
|
||||
winuser::InvalidateRgn(window, ptr::null_mut(), 0);
|
||||
InvalidateRgn(window, 0, false.into());
|
||||
}
|
||||
}
|
||||
|
||||
if diff.contains(WindowFlags::MAXIMIZED) || new.contains(WindowFlags::MAXIMIZED) {
|
||||
unsafe {
|
||||
winuser::ShowWindow(
|
||||
ShowWindow(
|
||||
window,
|
||||
match new.contains(WindowFlags::MAXIMIZED) {
|
||||
true => winuser::SW_MAXIMIZE,
|
||||
false => winuser::SW_RESTORE,
|
||||
true => SW_MAXIMIZE,
|
||||
false => SW_RESTORE,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -293,11 +295,11 @@ impl WindowFlags {
|
|||
// Minimize operations should execute after maximize for proper window animations
|
||||
if diff.contains(WindowFlags::MINIMIZED) {
|
||||
unsafe {
|
||||
winuser::ShowWindow(
|
||||
ShowWindow(
|
||||
window,
|
||||
match new.contains(WindowFlags::MINIMIZED) {
|
||||
true => winuser::SW_MINIMIZE,
|
||||
false => winuser::SW_RESTORE,
|
||||
true => SW_MINIMIZE,
|
||||
false => SW_RESTORE,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -307,18 +309,15 @@ impl WindowFlags {
|
|||
let (style, style_ex) = new.to_window_styles();
|
||||
|
||||
unsafe {
|
||||
winuser::SendMessageW(window, *event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID, 1, 0);
|
||||
SendMessageW(window, *event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID, 1, 0);
|
||||
|
||||
// This condition is necessary to avoid having an unrestorable window
|
||||
if !new.contains(WindowFlags::MINIMIZED) {
|
||||
winuser::SetWindowLongW(window, winuser::GWL_STYLE, style as _);
|
||||
winuser::SetWindowLongW(window, winuser::GWL_EXSTYLE, style_ex as _);
|
||||
SetWindowLongW(window, GWL_STYLE, style as i32);
|
||||
SetWindowLongW(window, GWL_EXSTYLE, style_ex as i32);
|
||||
}
|
||||
|
||||
let mut flags = winuser::SWP_NOZORDER
|
||||
| winuser::SWP_NOMOVE
|
||||
| winuser::SWP_NOSIZE
|
||||
| winuser::SWP_FRAMECHANGED;
|
||||
let mut flags = SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED;
|
||||
|
||||
// We generally don't want style changes here to affect window
|
||||
// focus, but for fullscreen windows they must be activated
|
||||
|
@ -326,12 +325,12 @@ impl WindowFlags {
|
|||
if !new.contains(WindowFlags::MARKER_EXCLUSIVE_FULLSCREEN)
|
||||
&& !new.contains(WindowFlags::MARKER_BORDERLESS_FULLSCREEN)
|
||||
{
|
||||
flags |= winuser::SWP_NOACTIVATE;
|
||||
flags |= SWP_NOACTIVATE;
|
||||
}
|
||||
|
||||
// Refresh the window frame
|
||||
winuser::SetWindowPos(window, ptr::null_mut(), 0, 0, 0, 0, flags);
|
||||
winuser::SendMessageW(window, *event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID, 0, 0);
|
||||
SetWindowPos(window, 0, 0, 0, 0, 0, flags);
|
||||
SendMessageW(window, *event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue