mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-28 07:33:14 -04:00
windows: add locked cursor
This commit is contained in:
@@ -43,6 +43,7 @@ changelog entry.
|
||||
### Added
|
||||
|
||||
- On Windows, add `IconExtWindows::from_resource_name`.
|
||||
- On Windows, add `CursorGrabMode::Locked`.
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ use std::{io, mem, ptr};
|
||||
|
||||
use crate::utils::Lazy;
|
||||
use windows_sys::core::{HRESULT, PCWSTR};
|
||||
use windows_sys::Win32::Foundation::{BOOL, HANDLE, HMODULE, HWND, RECT};
|
||||
use windows_sys::Win32::Foundation::{BOOL, HANDLE, HMODULE, HWND, POINT, RECT};
|
||||
use windows_sys::Win32::Graphics::Gdi::{ClientToScreen, HMONITOR};
|
||||
use windows_sys::Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryA};
|
||||
use windows_sys::Win32::System::SystemServices::IMAGE_DOS_HEADER;
|
||||
@@ -17,9 +17,9 @@ use windows_sys::Win32::UI::HiDpi::{
|
||||
use windows_sys::Win32::UI::Input::KeyboardAndMouse::GetActiveWindow;
|
||||
use windows_sys::Win32::UI::Input::Pointer::{POINTER_INFO, POINTER_PEN_INFO, POINTER_TOUCH_INFO};
|
||||
use windows_sys::Win32::UI::WindowsAndMessaging::{
|
||||
ClipCursor, GetClientRect, GetClipCursor, GetSystemMetrics, GetWindowPlacement, GetWindowRect,
|
||||
IsIconic, ShowCursor, 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,
|
||||
ClipCursor, GetClientRect, GetClipCursor, GetCursorPos, GetSystemMetrics, GetWindowPlacement,
|
||||
GetWindowRect, IsIconic, ShowCursor, 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, SW_MAXIMIZE,
|
||||
WINDOWPLACEMENT,
|
||||
};
|
||||
@@ -99,6 +99,13 @@ pub fn set_cursor_hidden(hidden: bool) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_cursor_position() -> Result<POINT, io::Error> {
|
||||
unsafe {
|
||||
let mut point: POINT = mem::zeroed();
|
||||
win_to_err(GetCursorPos(&mut point)).map(|_| point)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_cursor_clip() -> Result<RECT, io::Error> {
|
||||
unsafe {
|
||||
let mut rect: RECT = mem::zeroed();
|
||||
|
||||
@@ -428,14 +428,6 @@ impl Window {
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> {
|
||||
let confine = match mode {
|
||||
CursorGrabMode::None => false,
|
||||
CursorGrabMode::Confined => true,
|
||||
CursorGrabMode::Locked => {
|
||||
return Err(ExternalError::NotSupported(NotSupportedError::new()))
|
||||
},
|
||||
};
|
||||
|
||||
let window = self.window;
|
||||
let window_state = Arc::clone(&self.window_state);
|
||||
let (tx, rx) = channel();
|
||||
@@ -446,7 +438,10 @@ impl Window {
|
||||
.lock()
|
||||
.unwrap()
|
||||
.mouse
|
||||
.set_cursor_flags(window, |f| f.set(CursorFlags::GRABBED, confine))
|
||||
.set_cursor_flags(window, |f| {
|
||||
f.set(CursorFlags::GRABBED, mode != CursorGrabMode::None);
|
||||
f.set(CursorFlags::LOCKED, mode == CursorGrabMode::Locked);
|
||||
})
|
||||
.map_err(|e| ExternalError::Os(os_error!(e)));
|
||||
let _ = tx.send(result);
|
||||
});
|
||||
|
||||
@@ -77,6 +77,7 @@ bitflags! {
|
||||
const GRABBED = 1 << 0;
|
||||
const HIDDEN = 1 << 1;
|
||||
const IN_WINDOW = 1 << 2;
|
||||
const LOCKED = 1 << 3;
|
||||
}
|
||||
}
|
||||
bitflags! {
|
||||
@@ -485,7 +486,22 @@ impl CursorFlags {
|
||||
if util::is_focused(window) {
|
||||
let cursor_clip = match self.contains(CursorFlags::GRABBED) {
|
||||
true => {
|
||||
if self.contains(CursorFlags::HIDDEN) {
|
||||
if self.contains(CursorFlags::LOCKED) {
|
||||
if let Ok(pos) = util::get_cursor_position() {
|
||||
Some(RECT {
|
||||
left: pos.x,
|
||||
right: pos.x + 1,
|
||||
top: pos.y,
|
||||
bottom: pos.y + 1,
|
||||
})
|
||||
} else {
|
||||
// If lock is applied while the cursor is not available, lock it to the
|
||||
// middle of the window.
|
||||
let cx = (client_rect.left + client_rect.right) / 2;
|
||||
let cy = (client_rect.top + client_rect.bottom) / 2;
|
||||
Some(RECT { left: cx, right: cx + 1, top: cy, bottom: cy + 1 })
|
||||
}
|
||||
} else if self.contains(CursorFlags::HIDDEN) {
|
||||
// Confine the cursor to the center of the window if the cursor is hidden.
|
||||
// This avoids problems with the cursor activating
|
||||
// the taskbar if the window borders or overlaps that.
|
||||
|
||||
@@ -1707,8 +1707,7 @@ pub enum CursorGrabMode {
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **X11 / Windows:** Not implemented. Always returns [`ExternalError::NotSupported`] for
|
||||
/// now.
|
||||
/// - **X11:** Not implemented. Always returns [`ExternalError::NotSupported`] for now.
|
||||
/// - **iOS / Android:** Always returns an [`ExternalError::NotSupported`].
|
||||
Locked,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user