Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cursor_position getter API #2648

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/changelog/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@
- Add `Window::default_attributes` to get default `WindowAttributes`.
- `log` has been replaced with `tracing`. The old behavior can be emulated by setting the `log` feature on the `tracing` crate.
- On Windows, confine cursor to center of window when grabbed and hidden.
- Add `ActiveEventLoop::cursor_position`.
15 changes: 14 additions & 1 deletion src/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ use std::time::{Duration, Instant};
use web_time::{Duration, Instant};

use crate::application::ApplicationHandler;
use crate::error::{EventLoopError, OsError};
use crate::dpi::PhysicalPosition;
use crate::error::{EventLoopError, ExternalError, OsError};
use crate::window::{CustomCursor, CustomCursorSource, Window, WindowAttributes};
use crate::{event::Event, monitor::MonitorHandle, platform_impl};

Expand Down Expand Up @@ -490,6 +491,18 @@ impl ActiveEventLoop {
platform: self.p.owned_display_handle(),
}
}

/// Returns the current cursor position relative to the top-left hand corner of the desktop.
daxpedda marked this conversation as resolved.
Show resolved Hide resolved
///
/// See [`Window::outer_position`] for more information about the coordinates.
///
amrbashir marked this conversation as resolved.
Show resolved Hide resolved
/// ## Platform-specific
///
/// - **iOS / Android / Wayland / Orbital / Web**: Unsupported.
#[inline]
pub fn cursor_position(&self) -> Result<PhysicalPosition<f64>, ExternalError> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It confused me that the return type of this is not PhysicalPosition<i32> like the return type of Window::outer_position, but I guess it matches the CursorMoved event - apparently cursors can be positioned on a sub-pixel scale, didn't know that!

self.p.cursor_position()
}
}

#[cfg(feature = "rwh_06")]
Expand Down
5 changes: 5 additions & 0 deletions src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,11 @@ impl ActiveEventLoop {
pub(crate) fn owned_display_handle(&self) -> OwnedDisplayHandle {
OwnedDisplayHandle
}
pub fn cursor_position(&self) -> Result<PhysicalPosition<f64>, error::ExternalError> {
Err(error::ExternalError::NotSupported(
error::NotSupportedError::new(),
))
}
}

#[derive(Clone)]
Expand Down
7 changes: 6 additions & 1 deletion src/platform_impl/ios/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use icrate::Foundation::{MainThreadMarker, NSString};
use objc2::ClassType;

use crate::{
error::EventLoopError,
dpi::PhysicalPosition,
error::{EventLoopError, ExternalError, NotSupportedError},
event::Event,
event_loop::{
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents, EventLoopClosed,
Expand Down Expand Up @@ -95,6 +96,10 @@ impl ActiveEventLoop {
pub(crate) fn owned_display_handle(&self) -> OwnedDisplayHandle {
OwnedDisplayHandle
}

pub fn cursor_position(&self) -> Result<PhysicalPosition<f64>, ExternalError> {
Err(ExternalError::NotSupported(NotSupportedError::new()))
}
}

#[derive(Clone)]
Expand Down
4 changes: 4 additions & 0 deletions src/platform_impl/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,10 @@ impl ActiveEventLoop {
fn exit_code(&self) -> Option<i32> {
x11_or_wayland!(match self; Self(evlp) => evlp.exit_code())
}

pub fn cursor_position(&self) -> Result<PhysicalPosition<f64>, ExternalError> {
x11_or_wayland!(match self; Self(evlp) => evlp.cursor_position())
}
}

#[derive(Clone)]
Expand Down
8 changes: 6 additions & 2 deletions src/platform_impl/linux/wayland/event_loop/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use sctk::reexports::client::globals;
use sctk::reexports::client::{Connection, QueueHandle};

use crate::cursor::OnlyCursorImage;
use crate::dpi::LogicalSize;
use crate::error::{EventLoopError, OsError as RootOsError};
use crate::dpi::{LogicalSize, PhysicalPosition};
use crate::error::{EventLoopError, ExternalError, NotSupportedError, OsError as RootOsError};
use crate::event::{Event, InnerSizeWriter, StartCause, WindowEvent};
use crate::event_loop::{ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents};
use crate::platform::pump_events::PumpStatus;
Expand Down Expand Up @@ -719,4 +719,8 @@ impl ActiveEventLoop {
})
.into())
}

pub fn cursor_position(&self) -> Result<PhysicalPosition<f64>, ExternalError> {
Err(ExternalError::NotSupported(NotSupportedError::new()))
}
}
9 changes: 8 additions & 1 deletion src/platform_impl/linux/x11/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ use x11rb::protocol::xproto::{self, ConnectionExt as _};
use x11rb::x11_utils::X11Error as LogicalError;
use x11rb::xcb_ffi::ReplyOrIdError;

use crate::error::{EventLoopError, OsError as RootOsError};
use crate::dpi::PhysicalPosition;
use crate::error::{EventLoopError, ExternalError, OsError as RootOsError};
use crate::event::{Event, StartCause, WindowEvent};
use crate::event_loop::{ActiveEventLoop as RootAEL, ControlFlow, DeviceEvents, EventLoopClosed};
use crate::platform::pump_events::PumpStatus;
Expand Down Expand Up @@ -757,6 +758,12 @@ impl ActiveEventLoop {
pub(crate) fn exit_code(&self) -> Option<i32> {
self.exit.get()
}

pub fn cursor_position(&self) -> Result<PhysicalPosition<f64>, ExternalError> {
self.xconn
.cursor_position(self.root)
.map_err(|x_err| ExternalError::Os(os_error!(OsError::XError(Arc::new(x_err)))))
}
}

impl<T: 'static> EventLoopProxy<T> {
Expand Down
9 changes: 9 additions & 0 deletions src/platform_impl/linux/x11/util/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::{

use x11rb::connection::Connection;

use crate::dpi::PhysicalPosition;
use crate::{platform_impl::PlatformCustomCursorSource, window::CursorIcon};

use super::super::ActiveEventLoop;
Expand Down Expand Up @@ -96,6 +97,14 @@ impl XConnection {
self.xcb_connection().flush()?;
Ok(())
}

pub fn cursor_position(
&self,
window: xproto::Window,
) -> Result<PhysicalPosition<f64>, X11Error> {
let reply = self.xcb_connection().query_pointer(window)?.reply()?;
Ok((reply.root_x, reply.root_y).into())
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down
16 changes: 14 additions & 2 deletions src/platform_impl/macos/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ use core_foundation::runloop::{
};
use icrate::AppKit::{
NSApplication, NSApplicationActivationPolicyAccessory, NSApplicationActivationPolicyProhibited,
NSApplicationActivationPolicyRegular, NSWindow,
NSApplicationActivationPolicyRegular, NSEvent, NSWindow,
};
use icrate::Foundation::{MainThreadMarker, NSObjectProtocol};
use icrate::Foundation::{CGRect, CGSize, MainThreadMarker, NSObjectProtocol};
use objc2::{msg_send_id, ClassType};
use objc2::{
rc::{autoreleasepool, Id},
Expand All @@ -34,6 +34,8 @@ use super::{
monitor::{self, MonitorHandle},
observer::setup_control_flow_observers,
};
use crate::dpi::{LogicalPosition, PhysicalPosition};
use crate::error::ExternalError;
use crate::platform_impl::platform::cursor::CustomCursor;
use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource};
use crate::{
Expand Down Expand Up @@ -146,6 +148,16 @@ impl ActiveEventLoop {
pub(crate) fn owned_display_handle(&self) -> OwnedDisplayHandle {
OwnedDisplayHandle
}

#[inline]
pub fn cursor_position(&self) -> Result<PhysicalPosition<f64>, ExternalError> {
let point = unsafe { NSEvent::mouseLocation() };
// The cursor is sizeless
let rect = CGRect::new(point, CGSize::new(0.0, 0.0));
let point = monitor::flip_window_screen_coordinates(rect);
let point = LogicalPosition::new(point.x, point.y);
Ok(point.to_physical(monitor::primary_monitor().scale_factor()))
}
}

impl ActiveEventLoop {
Expand Down
7 changes: 6 additions & 1 deletion src/platform_impl/orbital/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ use orbclient::{
use smol_str::SmolStr;

use crate::{
error::EventLoopError,
dpi::PhysicalPosition,
error::{EventLoopError, ExternalError, NotSupportedError},
event::{self, Ime, Modifiers, StartCause},
event_loop::{self, ControlFlow, DeviceEvents},
keyboard::{
Expand Down Expand Up @@ -860,6 +861,10 @@ impl ActiveEventLoop {
pub(crate) fn owned_display_handle(&self) -> OwnedDisplayHandle {
OwnedDisplayHandle
}

pub fn cursor_position(&self) -> Result<PhysicalPosition<f64>, ExternalError> {
Err(ExternalError::NotSupported(NotSupportedError::new()))
}
}

#[derive(Clone)]
Expand Down
6 changes: 6 additions & 0 deletions src/platform_impl/web/event_loop/window_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use super::{
runner,
window::WindowId,
};
use crate::dpi::PhysicalPosition;
use crate::error::{ExternalError, NotSupportedError};
use crate::event::{
DeviceId as RootDeviceId, ElementState, Event, KeyEvent, Touch, TouchPhase, WindowEvent,
};
Expand Down Expand Up @@ -722,6 +724,10 @@ impl ActiveEventLoop {
pub(crate) fn owned_display_handle(&self) -> OwnedDisplayHandle {
OwnedDisplayHandle
}

pub fn cursor_position(&self) -> Result<PhysicalPosition<f64>, ExternalError> {
Err(ExternalError::NotSupported(NotSupportedError::new()))
}
}

#[derive(Clone)]
Expand Down
6 changes: 5 additions & 1 deletion src/platform_impl/windows/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::{
time::{Duration, Instant},
};

use crate::utils::Lazy;
use crate::{error::ExternalError, utils::Lazy};

use windows_sys::Win32::{
Devices::HumanInterfaceDevice::MOUSE_MOVE_RELATIVE,
Expand Down Expand Up @@ -596,6 +596,10 @@ impl ActiveEventLoop {
OwnedDisplayHandle
}

pub fn cursor_position(&self) -> Result<PhysicalPosition<f64>, ExternalError> {
util::cursor_position()
}

fn exit_code(&self) -> Option<i32> {
self.runner_shared.exit_code()
}
Expand Down
22 changes: 15 additions & 7 deletions src/platform_impl/windows/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::utils::Lazy;
use windows_sys::{
core::{HRESULT, PCWSTR},
Win32::{
Foundation::{BOOL, HANDLE, HMODULE, HWND, RECT},
Foundation::{BOOL, HANDLE, HMODULE, HWND, POINT, RECT},
Graphics::Gdi::{ClientToScreen, HMONITOR},
System::{
LibraryLoader::{GetProcAddress, LoadLibraryA},
Expand All @@ -26,17 +26,18 @@ use windows_sys::{
Pointer::{POINTER_INFO, POINTER_PEN_INFO, POINTER_TOUCH_INFO},
},
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, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN,
SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN, SW_MAXIMIZE, WINDOWPLACEMENT,
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,
},
},
},
};

use crate::window::CursorIcon;
use crate::{dpi::PhysicalPosition, error::ExternalError, window::CursorIcon};

pub fn encode_wide(string: impl AsRef<OsStr>) -> Vec<u16> {
string.as_ref().encode_wide().chain(once(0)).collect()
Expand Down Expand Up @@ -167,6 +168,13 @@ pub fn get_instance_handle() -> HMODULE {
unsafe { &__ImageBase as *const _ as _ }
}

pub fn cursor_position() -> Result<PhysicalPosition<f64>, ExternalError> {
let mut pt = POINT { x: 0, y: 0 };
win_to_err(unsafe { GetCursorPos(&mut pt) })
.map(|_| (pt.x, pt.y).into())
.map_err(|e| ExternalError::Os(os_error!(e)))
}

pub(crate) fn to_windows_cursor(cursor: CursorIcon) -> PCWSTR {
match cursor {
CursorIcon::Default => IDC_ARROW,
Expand Down