mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-26 23:21:30 +11:00
fe2d37fcdc
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.
173 lines
5.4 KiB
Rust
173 lines
5.4 KiB
Rust
use winapi::ctypes::wchar_t;
|
|
use winapi::shared::minwindef::{DWORD, LPARAM, BOOL, TRUE};
|
|
use winapi::shared::windef::{HMONITOR, HDC, LPRECT, HWND};
|
|
use winapi::um::winuser;
|
|
|
|
use std::collections::VecDeque;
|
|
use std::{mem, ptr};
|
|
|
|
use super::{EventsLoop, util};
|
|
|
|
/// Win32 implementation of the main `MonitorId` object.
|
|
#[derive(Clone)]
|
|
pub struct MonitorId {
|
|
/// The system name of the adapter.
|
|
adapter_name: [wchar_t; 32],
|
|
|
|
/// Monitor handle.
|
|
hmonitor: HMonitor,
|
|
|
|
/// The system name of the monitor.
|
|
monitor_name: String,
|
|
|
|
/// True if this is the primary monitor.
|
|
primary: bool,
|
|
|
|
/// The position of the monitor in pixels on the desktop.
|
|
///
|
|
/// A window that is positioned at these coordinates will overlap the monitor.
|
|
position: (i32, i32),
|
|
|
|
/// The current resolution in pixels on the monitor.
|
|
dimensions: (u32, u32),
|
|
|
|
/// DPI scaling factor.
|
|
hidpi_factor: f32,
|
|
}
|
|
|
|
// Send is not implemented for HMONITOR, we have to wrap it and implement it manually.
|
|
// For more info see:
|
|
// https://github.com/retep998/winapi-rs/issues/360
|
|
// https://github.com/retep998/winapi-rs/issues/396
|
|
#[derive(Clone)]
|
|
struct HMonitor(HMONITOR);
|
|
|
|
unsafe impl Send for HMonitor {}
|
|
|
|
unsafe extern "system" fn monitor_enum_proc(hmonitor: HMONITOR, _: HDC, place: LPRECT, data: LPARAM) -> BOOL {
|
|
let monitors = data as *mut VecDeque<MonitorId>;
|
|
|
|
let place = *place;
|
|
let position = (place.left as i32, place.top as i32);
|
|
let dimensions = ((place.right - place.left) as u32, (place.bottom - place.top) as u32);
|
|
|
|
let mut monitor_info: winuser::MONITORINFOEXW = mem::zeroed();
|
|
monitor_info.cbSize = mem::size_of::<winuser::MONITORINFOEXW>() as DWORD;
|
|
if winuser::GetMonitorInfoW(hmonitor, &mut monitor_info as *mut winuser::MONITORINFOEXW as *mut winuser::MONITORINFO) == 0 {
|
|
// Some error occurred, just skip this monitor and go on.
|
|
return TRUE;
|
|
}
|
|
|
|
(*monitors).push_back(MonitorId {
|
|
adapter_name: monitor_info.szDevice,
|
|
hmonitor: HMonitor(hmonitor),
|
|
monitor_name: util::wchar_to_string(&monitor_info.szDevice),
|
|
primary: monitor_info.dwFlags & winuser::MONITORINFOF_PRIMARY != 0,
|
|
position,
|
|
dimensions,
|
|
hidpi_factor: 1.0,
|
|
});
|
|
|
|
// TRUE means continue enumeration.
|
|
TRUE
|
|
}
|
|
|
|
impl EventsLoop {
|
|
pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
|
|
unsafe {
|
|
let mut result: VecDeque<MonitorId> = VecDeque::new();
|
|
winuser::EnumDisplayMonitors(ptr::null_mut(), ptr::null_mut(), Some(monitor_enum_proc), &mut result as *mut _ as LPARAM);
|
|
result
|
|
}
|
|
}
|
|
|
|
pub fn get_current_monitor(handle: HWND) -> MonitorId {
|
|
unsafe {
|
|
let mut monitor_info: winuser::MONITORINFOEXW = mem::zeroed();
|
|
monitor_info.cbSize = mem::size_of::<winuser::MONITORINFOEXW>() as DWORD;
|
|
|
|
let hmonitor = winuser::MonitorFromWindow(handle, winuser::MONITOR_DEFAULTTONEAREST);
|
|
|
|
winuser::GetMonitorInfoW(
|
|
hmonitor,
|
|
&mut monitor_info as *mut winuser::MONITORINFOEXW as *mut winuser::MONITORINFO,
|
|
);
|
|
|
|
let place = monitor_info.rcMonitor;
|
|
let position = (place.left as i32, place.top as i32);
|
|
let dimensions = (
|
|
(place.right - place.left) as u32,
|
|
(place.bottom - place.top) as u32,
|
|
);
|
|
|
|
MonitorId {
|
|
adapter_name: monitor_info.szDevice,
|
|
hmonitor: super::monitor::HMonitor(hmonitor),
|
|
monitor_name: util::wchar_to_string(&monitor_info.szDevice),
|
|
primary: monitor_info.dwFlags & winuser::MONITORINFOF_PRIMARY != 0,
|
|
position,
|
|
dimensions,
|
|
hidpi_factor: 1.0,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn get_primary_monitor(&self) -> MonitorId {
|
|
// we simply get all available monitors and return the one with the `MONITORINFOF_PRIMARY` flag
|
|
// TODO: it is possible to query the win32 API for the primary monitor, this should be done
|
|
// instead
|
|
for monitor in self.get_available_monitors().into_iter() {
|
|
if monitor.primary {
|
|
return monitor;
|
|
}
|
|
}
|
|
|
|
panic!("Failed to find the primary monitor")
|
|
}
|
|
}
|
|
|
|
impl MonitorId {
|
|
/// See the docs if the crate root file.
|
|
#[inline]
|
|
pub fn get_name(&self) -> Option<String> {
|
|
Some(self.monitor_name.clone())
|
|
}
|
|
|
|
/// See the docs of the crate root file.
|
|
#[inline]
|
|
pub fn get_native_identifier(&self) -> String {
|
|
self.monitor_name.clone()
|
|
}
|
|
|
|
/// See the docs of the crate root file.
|
|
#[inline]
|
|
pub fn get_hmonitor(&self) -> HMONITOR {
|
|
self.hmonitor.0
|
|
}
|
|
|
|
/// See the docs of the crate root file.
|
|
#[inline]
|
|
pub fn get_dimensions(&self) -> (u32, u32) {
|
|
// TODO: retrieve the dimensions every time this is called
|
|
self.dimensions
|
|
}
|
|
|
|
/// This is a Win32-only function for `MonitorId` that returns the system name of the adapter
|
|
/// device.
|
|
#[inline]
|
|
pub fn get_adapter_name(&self) -> &[wchar_t] {
|
|
&self.adapter_name
|
|
}
|
|
|
|
/// A window that is positioned at these coordinates will overlap the monitor.
|
|
#[inline]
|
|
pub fn get_position(&self) -> (i32, i32) {
|
|
self.position
|
|
}
|
|
|
|
#[inline]
|
|
pub fn get_hidpi_factor(&self) -> f32 {
|
|
self.hidpi_factor
|
|
}
|
|
}
|