2019-06-21 11:33:15 -04:00
|
|
|
use std::{
|
2022-04-30 13:58:51 +02:00
|
|
|
ffi::{c_void, OsStr, OsString},
|
2022-03-07 22:58:12 +01:00
|
|
|
io,
|
|
|
|
|
iter::once,
|
|
|
|
|
mem,
|
2019-06-21 11:33:15 -04:00
|
|
|
ops::BitAnd,
|
2022-04-30 13:58:51 +02:00
|
|
|
os::windows::prelude::{OsStrExt, OsStringExt},
|
2022-03-07 22:58:12 +01:00
|
|
|
ptr,
|
2019-06-21 11:33:15 -04:00
|
|
|
sync::atomic::{AtomicBool, Ordering},
|
|
|
|
|
};
|
Windows: Implement DeviceEvents (#482)
Fixes #467
All variants other than Text have been implemented. While Text can
be implemented using ToUnicode, that doesn't play nice with dead
keys, IME, etc.
Most of the mouse DeviceEvents were already implemented, but due
to the flags that were used when registering for raw input events,
they only worked when the window was in the foreground.
This is also a step forward for #338, as DeviceIds are no longer
useless on Windows. On DeviceEvents, the DeviceId contains that
device's handle. While that handle could ostensibly be used by
developers to query device information, my actual reason for
choosing it is because it's simply a very easy way to handle this.
As a fun bonus, this enabled me to create this method:
DevideIdExt::get_persistent_identifier() -> Option<String>
Using this gives you a unique identifier for the device that
persists across replugs/reboots/etc., so it's ideal for something
like device-specific configuration.
There's a notable caveat to the new DeviceIds, which is that the
value will always be 0 for a WindowEvent. There doesn't seem to be
any straightforward way around this limitation.
I was concerned that multi-window applications would receive n
copies of every DeviceEvent, but Windows only sends them to one
window per application.
Lastly, there's a chance that these additions will cause
antivirus/etc. software to detect winit applications as keyloggers.
I don't know how likely that is to actually happen to people, but
if it does become an issue, the raw input code is neatly
sequestered and would be easy to make optional during compilation.
2018-04-28 12:42:33 -04:00
|
|
|
|
2022-03-07 22:58:12 +01:00
|
|
|
use windows_sys::{
|
|
|
|
|
core::{HRESULT, PCWSTR},
|
|
|
|
|
Win32::{
|
2022-05-29 17:12:46 +02:00
|
|
|
Foundation::{BOOL, HINSTANCE, HWND, RECT},
|
2022-03-07 22:58:12 +01:00
|
|
|
Graphics::Gdi::{ClientToScreen, InvalidateRgn, HMONITOR},
|
2022-05-29 17:12:46 +02:00
|
|
|
System::{
|
|
|
|
|
LibraryLoader::{GetProcAddress, LoadLibraryA},
|
|
|
|
|
SystemServices::IMAGE_DOS_HEADER,
|
|
|
|
|
},
|
2022-03-07 22:58:12 +01:00
|
|
|
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,
|
|
|
|
|
},
|
|
|
|
|
},
|
2019-07-05 18:37:25 +02:00
|
|
|
},
|
2019-06-21 11:33:15 -04:00
|
|
|
};
|
Windows: Implement DeviceEvents (#482)
Fixes #467
All variants other than Text have been implemented. While Text can
be implemented using ToUnicode, that doesn't play nice with dead
keys, IME, etc.
Most of the mouse DeviceEvents were already implemented, but due
to the flags that were used when registering for raw input events,
they only worked when the window was in the foreground.
This is also a step forward for #338, as DeviceIds are no longer
useless on Windows. On DeviceEvents, the DeviceId contains that
device's handle. While that handle could ostensibly be used by
developers to query device information, my actual reason for
choosing it is because it's simply a very easy way to handle this.
As a fun bonus, this enabled me to create this method:
DevideIdExt::get_persistent_identifier() -> Option<String>
Using this gives you a unique identifier for the device that
persists across replugs/reboots/etc., so it's ideal for something
like device-specific configuration.
There's a notable caveat to the new DeviceIds, which is that the
value will always be 0 for a WindowEvent. There doesn't seem to be
any straightforward way around this limitation.
I was concerned that multi-window applications would receive n
copies of every DeviceEvent, but Windows only sends them to one
window per application.
Lastly, there's a chance that these additions will cause
antivirus/etc. software to detect winit applications as keyloggers.
I don't know how likely that is to actually happen to people, but
if it does become an issue, the raw input code is neatly
sequestered and would be easy to make optional during compilation.
2018-04-28 12:42:33 -04:00
|
|
|
|
2022-03-07 22:58:12 +01:00
|
|
|
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()
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-30 13:58:51 +02:00
|
|
|
pub fn decode_wide(mut wide_c_string: &[u16]) -> OsString {
|
|
|
|
|
if let Some(null_pos) = wide_c_string.iter().position(|c| *c == 0) {
|
|
|
|
|
wide_c_string = &wide_c_string[..null_pos];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OsString::from_wide(wide_c_string)
|
|
|
|
|
}
|
|
|
|
|
|
Windows: Implement DeviceEvents (#482)
Fixes #467
All variants other than Text have been implemented. While Text can
be implemented using ToUnicode, that doesn't play nice with dead
keys, IME, etc.
Most of the mouse DeviceEvents were already implemented, but due
to the flags that were used when registering for raw input events,
they only worked when the window was in the foreground.
This is also a step forward for #338, as DeviceIds are no longer
useless on Windows. On DeviceEvents, the DeviceId contains that
device's handle. While that handle could ostensibly be used by
developers to query device information, my actual reason for
choosing it is because it's simply a very easy way to handle this.
As a fun bonus, this enabled me to create this method:
DevideIdExt::get_persistent_identifier() -> Option<String>
Using this gives you a unique identifier for the device that
persists across replugs/reboots/etc., so it's ideal for something
like device-specific configuration.
There's a notable caveat to the new DeviceIds, which is that the
value will always be 0 for a WindowEvent. There doesn't seem to be
any straightforward way around this limitation.
I was concerned that multi-window applications would receive n
copies of every DeviceEvent, but Windows only sends them to one
window per application.
Lastly, there's a chance that these additions will cause
antivirus/etc. software to detect winit applications as keyloggers.
I don't know how likely that is to actually happen to people, but
if it does become an issue, the raw input code is neatly
sequestered and would be easy to make optional during compilation.
2018-04-28 12:42:33 -04:00
|
|
|
pub fn has_flag<T>(bitset: T, flag: T) -> bool
|
2019-06-21 11:33:15 -04:00
|
|
|
where
|
|
|
|
|
T: Copy + PartialEq + BitAnd<T, Output = T>,
|
Windows: Implement DeviceEvents (#482)
Fixes #467
All variants other than Text have been implemented. While Text can
be implemented using ToUnicode, that doesn't play nice with dead
keys, IME, etc.
Most of the mouse DeviceEvents were already implemented, but due
to the flags that were used when registering for raw input events,
they only worked when the window was in the foreground.
This is also a step forward for #338, as DeviceIds are no longer
useless on Windows. On DeviceEvents, the DeviceId contains that
device's handle. While that handle could ostensibly be used by
developers to query device information, my actual reason for
choosing it is because it's simply a very easy way to handle this.
As a fun bonus, this enabled me to create this method:
DevideIdExt::get_persistent_identifier() -> Option<String>
Using this gives you a unique identifier for the device that
persists across replugs/reboots/etc., so it's ideal for something
like device-specific configuration.
There's a notable caveat to the new DeviceIds, which is that the
value will always be 0 for a WindowEvent. There doesn't seem to be
any straightforward way around this limitation.
I was concerned that multi-window applications would receive n
copies of every DeviceEvent, but Windows only sends them to one
window per application.
Lastly, there's a chance that these additions will cause
antivirus/etc. software to detect winit applications as keyloggers.
I don't know how likely that is to actually happen to people, but
if it does become an issue, the raw input code is neatly
sequestered and would be easy to make optional during compilation.
2018-04-28 12:42:33 -04:00
|
|
|
{
|
|
|
|
|
bitset & flag == flag
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-01 11:01:46 -04:00
|
|
|
pub unsafe fn status_map<T, F: FnMut(&mut T) -> BOOL>(mut fun: F) -> Option<T> {
|
2019-06-29 00:07:36 +02:00
|
|
|
let mut data: T = mem::zeroed();
|
2022-03-07 22:58:12 +01:00
|
|
|
if fun(&mut data) != false.into() {
|
2018-07-01 11:01:46 -04:00
|
|
|
Some(data)
|
2018-06-14 19:42:18 -04:00
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
Windows: Implement DeviceEvents (#482)
Fixes #467
All variants other than Text have been implemented. While Text can
be implemented using ToUnicode, that doesn't play nice with dead
keys, IME, etc.
Most of the mouse DeviceEvents were already implemented, but due
to the flags that were used when registering for raw input events,
they only worked when the window was in the foreground.
This is also a step forward for #338, as DeviceIds are no longer
useless on Windows. On DeviceEvents, the DeviceId contains that
device's handle. While that handle could ostensibly be used by
developers to query device information, my actual reason for
choosing it is because it's simply a very easy way to handle this.
As a fun bonus, this enabled me to create this method:
DevideIdExt::get_persistent_identifier() -> Option<String>
Using this gives you a unique identifier for the device that
persists across replugs/reboots/etc., so it's ideal for something
like device-specific configuration.
There's a notable caveat to the new DeviceIds, which is that the
value will always be 0 for a WindowEvent. There doesn't seem to be
any straightforward way around this limitation.
I was concerned that multi-window applications would receive n
copies of every DeviceEvent, but Windows only sends them to one
window per application.
Lastly, there's a chance that these additions will cause
antivirus/etc. software to detect winit applications as keyloggers.
I don't know how likely that is to actually happen to people, but
if it does become an issue, the raw input code is neatly
sequestered and would be easy to make optional during compilation.
2018-04-28 12:42:33 -04:00
|
|
|
}
|
2018-05-07 17:36:21 -04:00
|
|
|
|
2019-02-04 11:52:00 -05:00
|
|
|
fn win_to_err<F: FnOnce() -> BOOL>(f: F) -> Result<(), io::Error> {
|
2022-03-07 22:58:12 +01:00
|
|
|
if f() != false.into() {
|
2019-02-04 11:52:00 -05:00
|
|
|
Ok(())
|
|
|
|
|
} else {
|
|
|
|
|
Err(io::Error::last_os_error())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-01 11:01:46 -04:00
|
|
|
pub fn get_window_rect(hwnd: HWND) -> Option<RECT> {
|
2022-03-07 22:58:12 +01:00
|
|
|
unsafe { status_map(|rect| GetWindowRect(hwnd, rect)) }
|
2018-07-01 11:01:46 -04:00
|
|
|
}
|
|
|
|
|
|
2019-02-04 11:52:00 -05:00
|
|
|
pub fn get_client_rect(hwnd: HWND) -> Result<RECT, io::Error> {
|
|
|
|
|
unsafe {
|
2019-06-29 00:07:36 +02:00
|
|
|
let mut rect = mem::zeroed();
|
2018-11-20 15:57:06 -05:00
|
|
|
let mut top_left = mem::zeroed();
|
2019-02-04 11:52:00 -05:00
|
|
|
|
2022-03-07 22:58:12 +01:00
|
|
|
win_to_err(|| ClientToScreen(hwnd, &mut top_left))?;
|
|
|
|
|
win_to_err(|| GetClientRect(hwnd, &mut rect))?;
|
2018-11-20 15:57:06 -05:00
|
|
|
rect.left += top_left.x;
|
|
|
|
|
rect.top += top_left.y;
|
|
|
|
|
rect.right += top_left.x;
|
|
|
|
|
rect.bottom += top_left.y;
|
2019-02-04 11:52:00 -05:00
|
|
|
|
|
|
|
|
Ok(rect)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn adjust_size(hwnd: HWND, size: PhysicalSize<u32>) -> PhysicalSize<u32> {
|
2020-01-04 01:29:40 -05:00
|
|
|
let (width, height): (u32, u32) = size.into();
|
|
|
|
|
let rect = RECT {
|
|
|
|
|
left: 0,
|
2022-03-07 22:58:12 +01:00
|
|
|
right: width as i32,
|
2020-01-04 01:29:40 -05:00
|
|
|
top: 0,
|
2022-03-07 22:58:12 +01:00
|
|
|
bottom: height as i32,
|
2020-01-04 01:29:40 -05:00
|
|
|
};
|
|
|
|
|
let rect = adjust_window_rect(hwnd, rect).unwrap_or(rect);
|
|
|
|
|
PhysicalSize::new((rect.right - rect.left) as _, (rect.bottom - rect.top) as _)
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-06 15:28:58 -05:00
|
|
|
pub(crate) fn set_inner_size_physical(window: HWND, x: u32, y: u32) {
|
|
|
|
|
unsafe {
|
|
|
|
|
let rect = adjust_window_rect(
|
|
|
|
|
window,
|
|
|
|
|
RECT {
|
|
|
|
|
top: 0,
|
|
|
|
|
left: 0,
|
2022-03-07 22:58:12 +01:00
|
|
|
bottom: y as i32,
|
|
|
|
|
right: x as i32,
|
2020-01-06 15:28:58 -05:00
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
.expect("adjust_window_rect failed");
|
|
|
|
|
|
|
|
|
|
let outer_x = (rect.right - rect.left).abs() as _;
|
|
|
|
|
let outer_y = (rect.top - rect.bottom).abs() as _;
|
2022-03-07 22:58:12 +01:00
|
|
|
SetWindowPos(
|
2020-01-06 15:28:58 -05:00
|
|
|
window,
|
2022-03-07 22:58:12 +01:00
|
|
|
0,
|
2020-01-06 15:28:58 -05:00
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
outer_x,
|
|
|
|
|
outer_y,
|
2022-03-07 22:58:12 +01:00
|
|
|
SWP_ASYNCWINDOWPOS | SWP_NOZORDER | SWP_NOREPOSITION | SWP_NOMOVE | SWP_NOACTIVATE,
|
2020-01-06 15:28:58 -05:00
|
|
|
);
|
2022-03-07 22:58:12 +01:00
|
|
|
InvalidateRgn(window, 0, false.into());
|
2020-01-06 15:28:58 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-04 11:52:00 -05:00
|
|
|
pub fn adjust_window_rect(hwnd: HWND, rect: RECT) -> Option<RECT> {
|
|
|
|
|
unsafe {
|
2022-03-07 22:58:12 +01:00
|
|
|
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)
|
2019-02-04 11:52:00 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-21 11:33:15 -04:00
|
|
|
pub fn adjust_window_rect_with_styles(
|
|
|
|
|
hwnd: HWND,
|
2022-03-07 22:58:12 +01:00
|
|
|
style: WINDOW_STYLE,
|
|
|
|
|
style_ex: WINDOW_EX_STYLE,
|
2019-06-21 11:33:15 -04:00
|
|
|
rect: RECT,
|
|
|
|
|
) -> Option<RECT> {
|
|
|
|
|
unsafe {
|
|
|
|
|
status_map(|r| {
|
|
|
|
|
*r = rect;
|
2019-02-04 11:52:00 -05:00
|
|
|
|
2022-03-07 22:58:12 +01:00
|
|
|
let b_menu = GetMenu(hwnd) != 0;
|
2020-01-04 01:29:40 -05:00
|
|
|
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);
|
2022-03-07 22:58:12 +01:00
|
|
|
adjust_window_rect_ex_for_dpi(r, style, b_menu.into(), style_ex, dpi)
|
2020-01-04 01:29:40 -05:00
|
|
|
} else {
|
2022-03-07 22:58:12 +01:00
|
|
|
AdjustWindowRectEx(r, style, b_menu.into(), style_ex)
|
2020-01-04 01:29:40 -05:00
|
|
|
}
|
2019-06-21 11:33:15 -04:00
|
|
|
})
|
|
|
|
|
}
|
2018-11-20 15:57:06 -05:00
|
|
|
}
|
|
|
|
|
|
2019-02-04 11:52:00 -05:00
|
|
|
pub fn set_cursor_hidden(hidden: bool) {
|
|
|
|
|
static HIDDEN: AtomicBool = AtomicBool::new(false);
|
|
|
|
|
let changed = HIDDEN.swap(hidden, Ordering::SeqCst) ^ hidden;
|
|
|
|
|
if changed {
|
2022-03-07 22:58:12 +01:00
|
|
|
unsafe { ShowCursor(BOOL::from(!hidden)) };
|
2019-02-04 11:52:00 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-17 11:34:48 -04:00
|
|
|
pub fn get_cursor_clip() -> Result<RECT, io::Error> {
|
|
|
|
|
unsafe {
|
|
|
|
|
let mut rect: RECT = mem::zeroed();
|
2022-03-07 22:58:12 +01:00
|
|
|
win_to_err(|| GetClipCursor(&mut rect)).map(|_| rect)
|
2019-09-17 11:34:48 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Sets the cursor's clip rect.
|
|
|
|
|
///
|
|
|
|
|
/// Note that calling this will automatically dispatch a `WM_MOUSEMOVE` event.
|
2019-02-04 11:52:00 -05:00
|
|
|
pub fn set_cursor_clip(rect: Option<RECT>) -> Result<(), io::Error> {
|
|
|
|
|
unsafe {
|
2019-06-21 11:33:15 -04:00
|
|
|
let rect_ptr = rect
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|r| r as *const RECT)
|
|
|
|
|
.unwrap_or(ptr::null());
|
2022-03-07 22:58:12 +01:00
|
|
|
win_to_err(|| ClipCursor(rect_ptr))
|
2019-02-04 11:52:00 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-17 11:34:48 -04:00
|
|
|
pub fn get_desktop_rect() -> RECT {
|
|
|
|
|
unsafe {
|
2022-03-07 22:58:12 +01:00
|
|
|
let left = GetSystemMetrics(SM_XVIRTUALSCREEN);
|
|
|
|
|
let top = GetSystemMetrics(SM_YVIRTUALSCREEN);
|
2019-09-17 11:34:48 -04:00
|
|
|
RECT {
|
|
|
|
|
left,
|
|
|
|
|
top,
|
2022-03-07 22:58:12 +01:00
|
|
|
right: left + GetSystemMetrics(SM_CXVIRTUALSCREEN),
|
|
|
|
|
bottom: top + GetSystemMetrics(SM_CYVIRTUALSCREEN),
|
2019-09-17 11:34:48 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-04 11:52:00 -05:00
|
|
|
pub fn is_focused(window: HWND) -> bool {
|
2022-03-07 22:58:12 +01:00
|
|
|
window == unsafe { GetActiveWindow() }
|
2018-05-19 12:02:57 -04:00
|
|
|
}
|
|
|
|
|
|
2022-05-29 17:12:46 +02:00
|
|
|
pub fn get_instance_handle() -> HINSTANCE {
|
|
|
|
|
// Gets the instance handle by taking the address of the
|
|
|
|
|
// pseudo-variable created by the microsoft linker:
|
|
|
|
|
// https://devblogs.microsoft.com/oldnewthing/20041025-00/?p=37483
|
|
|
|
|
|
|
|
|
|
// This is preferred over GetModuleHandle(NULL) because it also works in DLLs:
|
|
|
|
|
// https://stackoverflow.com/questions/21718027/getmodulehandlenull-vs-hinstance
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
static __ImageBase: IMAGE_DOS_HEADER;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsafe { &__ImageBase as *const _ as _ }
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-29 21:29:54 -04:00
|
|
|
impl CursorIcon {
|
2022-03-07 22:58:12 +01:00
|
|
|
pub(crate) fn to_windows_cursor(self) -> PCWSTR {
|
2019-02-04 11:52:00 -05:00
|
|
|
match self {
|
2022-03-07 22:58:12 +01:00
|
|
|
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,
|
2019-06-21 11:33:15 -04:00
|
|
|
CursorIcon::Grab | CursorIcon::Grabbing | CursorIcon::Move | CursorIcon::AllScroll => {
|
2022-03-07 22:58:12 +01:00
|
|
|
IDC_SIZEALL
|
2019-06-24 12:14:55 -04:00
|
|
|
}
|
2019-06-21 11:33:15 -04:00
|
|
|
CursorIcon::EResize
|
|
|
|
|
| CursorIcon::WResize
|
|
|
|
|
| CursorIcon::EwResize
|
2022-03-07 22:58:12 +01:00
|
|
|
| CursorIcon::ColResize => IDC_SIZEWE,
|
2019-06-21 11:33:15 -04:00
|
|
|
CursorIcon::NResize
|
|
|
|
|
| CursorIcon::SResize
|
|
|
|
|
| CursorIcon::NsResize
|
2022-03-07 22:58:12 +01:00
|
|
|
| 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.
|
2019-02-04 11:52:00 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-01-04 01:29:40 -05:00
|
|
|
|
|
|
|
|
// Helper function to dynamically load function pointer.
|
|
|
|
|
// `library` and `function` must be zero-terminated.
|
|
|
|
|
pub(super) fn get_function_impl(library: &str, function: &str) -> Option<*const c_void> {
|
|
|
|
|
assert_eq!(library.chars().last(), Some('\0'));
|
|
|
|
|
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.
|
2022-03-07 22:58:12 +01:00
|
|
|
let module = unsafe { LoadLibraryA(library.as_ptr()) };
|
|
|
|
|
if module == 0 {
|
2020-01-04 01:29:40 -05:00
|
|
|
return None;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-07 22:58:12 +01:00
|
|
|
unsafe { GetProcAddress(module, function.as_ptr()) }.map(|function_ptr| function_ptr as _)
|
2020-01-04 01:29:40 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! get_function {
|
|
|
|
|
($lib:expr, $func:ident) => {
|
|
|
|
|
crate::platform_impl::platform::util::get_function_impl(
|
|
|
|
|
concat!($lib, '\0'),
|
|
|
|
|
concat!(stringify!($func), '\0'),
|
|
|
|
|
)
|
|
|
|
|
.map(|f| unsafe { std::mem::transmute::<*const _, $func>(f) })
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub type SetProcessDPIAware = unsafe extern "system" fn() -> BOOL;
|
|
|
|
|
pub type SetProcessDpiAwareness =
|
|
|
|
|
unsafe extern "system" fn(value: PROCESS_DPI_AWARENESS) -> HRESULT;
|
|
|
|
|
pub type SetProcessDpiAwarenessContext =
|
|
|
|
|
unsafe extern "system" fn(value: DPI_AWARENESS_CONTEXT) -> BOOL;
|
2022-03-07 22:58:12 +01:00
|
|
|
pub type GetDpiForWindow = unsafe extern "system" fn(hwnd: HWND) -> u32;
|
2020-01-04 01:29:40 -05:00
|
|
|
pub type GetDpiForMonitor = unsafe extern "system" fn(
|
|
|
|
|
hmonitor: HMONITOR,
|
|
|
|
|
dpi_type: MONITOR_DPI_TYPE,
|
2022-03-07 22:58:12 +01:00
|
|
|
dpi_x: *mut u32,
|
|
|
|
|
dpi_y: *mut u32,
|
2020-01-04 01:29:40 -05:00
|
|
|
) -> HRESULT;
|
|
|
|
|
pub type EnableNonClientDpiScaling = unsafe extern "system" fn(hwnd: HWND) -> BOOL;
|
|
|
|
|
pub type AdjustWindowRectExForDpi = unsafe extern "system" fn(
|
2022-03-07 22:58:12 +01:00
|
|
|
rect: *mut RECT,
|
|
|
|
|
dwStyle: u32,
|
2020-01-04 01:29:40 -05:00
|
|
|
bMenu: BOOL,
|
2022-03-07 22:58:12 +01:00
|
|
|
dwExStyle: u32,
|
|
|
|
|
dpi: u32,
|
2020-01-04 01:29:40 -05:00
|
|
|
) -> BOOL;
|
|
|
|
|
|
|
|
|
|
lazy_static! {
|
|
|
|
|
pub static ref GET_DPI_FOR_WINDOW: Option<GetDpiForWindow> =
|
|
|
|
|
get_function!("user32.dll", GetDpiForWindow);
|
|
|
|
|
pub static ref ADJUST_WINDOW_RECT_EX_FOR_DPI: Option<AdjustWindowRectExForDpi> =
|
|
|
|
|
get_function!("user32.dll", AdjustWindowRectExForDpi);
|
|
|
|
|
pub static ref GET_DPI_FOR_MONITOR: Option<GetDpiForMonitor> =
|
|
|
|
|
get_function!("shcore.dll", GetDpiForMonitor);
|
|
|
|
|
pub static ref ENABLE_NON_CLIENT_DPI_SCALING: Option<EnableNonClientDpiScaling> =
|
|
|
|
|
get_function!("user32.dll", EnableNonClientDpiScaling);
|
|
|
|
|
pub static ref SET_PROCESS_DPI_AWARENESS_CONTEXT: Option<SetProcessDpiAwarenessContext> =
|
|
|
|
|
get_function!("user32.dll", SetProcessDpiAwarenessContext);
|
|
|
|
|
pub static ref SET_PROCESS_DPI_AWARENESS: Option<SetProcessDpiAwareness> =
|
|
|
|
|
get_function!("shcore.dll", SetProcessDpiAwareness);
|
|
|
|
|
pub static ref SET_PROCESS_DPI_AWARE: Option<SetProcessDPIAware> =
|
|
|
|
|
get_function!("user32.dll", SetProcessDPIAware);
|
|
|
|
|
}
|