windows: add locked cursor
This commit is contained in:
parent
6461cfa9b1
commit
ab96fa8395
5 changed files with 35 additions and 17 deletions
|
|
@ -78,6 +78,7 @@ changelog entry.
|
|||
- Add `CustomCursorSource::Url`, `CustomCursorSource::from_animation`.
|
||||
- Implement `CustomIconProvider` for `RgbaIcon`.
|
||||
- Add `icon` module that exposes winit's icon API.
|
||||
- On Windows, add `CursorGrabMode::Locked`.
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
|||
use std::{io, mem, ptr};
|
||||
|
||||
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;
|
||||
|
|
@ -16,9 +16,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_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();
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ use super::icon::WinCursor;
|
|||
use super::MonitorHandle;
|
||||
use crate::cursor::Cursor;
|
||||
use crate::dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size};
|
||||
use crate::error::{NotSupportedError, RequestError};
|
||||
use crate::error::RequestError;
|
||||
use crate::icon::{Icon, RgbaIcon};
|
||||
use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle, MonitorHandleProvider};
|
||||
use crate::platform::windows::{BackdropType, Color, CornerPreference, WinIcon};
|
||||
|
|
@ -652,14 +652,6 @@ impl CoreWindow for Window {
|
|||
}
|
||||
|
||||
fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), RequestError> {
|
||||
let confine = match mode {
|
||||
CursorGrabMode::None => false,
|
||||
CursorGrabMode::Confined => true,
|
||||
CursorGrabMode::Locked => {
|
||||
return Err(NotSupportedError::new("locked cursor is not supported").into())
|
||||
},
|
||||
};
|
||||
|
||||
let window = self.window;
|
||||
let window_state = Arc::clone(&self.window_state);
|
||||
let (tx, rx) = channel();
|
||||
|
|
@ -670,7 +662,10 @@ impl CoreWindow for Window {
|
|||
.lock()
|
||||
.unwrap()
|
||||
.mouse
|
||||
.set_cursor_flags(window.hwnd(), |f| f.set(CursorFlags::GRABBED, confine))
|
||||
.set_cursor_flags(window.hwnd(), |f| {
|
||||
f.set(CursorFlags::GRABBED, mode != CursorGrabMode::None);
|
||||
f.set(CursorFlags::LOCKED, mode == CursorGrabMode::Locked);
|
||||
})
|
||||
.map_err(|err| os_error!(err).into());
|
||||
let _ = tx.send(result);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ bitflags! {
|
|||
const GRABBED = 1 << 0;
|
||||
const HIDDEN = 1 << 1;
|
||||
const IN_WINDOW = 1 << 2;
|
||||
const LOCKED = 1 << 3;
|
||||
}
|
||||
}
|
||||
bitflags! {
|
||||
|
|
@ -495,7 +496,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.
|
||||
|
|
|
|||
|
|
@ -1396,8 +1396,7 @@ pub enum CursorGrabMode {
|
|||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **X11 / Windows:** Not implemented. Always returns [`RequestError::NotSupported`] for
|
||||
/// now.
|
||||
/// - **X11:** Not implemented. Always returns [`RequestError::NotSupported`] for now.
|
||||
/// - **iOS / Android:** Always returns an [`RequestError::NotSupported`].
|
||||
Locked,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue