feat: add cursor_position getter (#9297)

* feat: add `cursor_position` getter

closes #9250

* js api

* Update mod.rs

* fix build on iOS and android

* use existing wrapper

* fmt

* adjust wording

* update docs

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
This commit is contained in:
Amr Bashir 2024-04-29 18:28:01 +03:00 committed by GitHub
parent 5a213a4bdc
commit 477bb8cd4e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 132 additions and 2 deletions

View File

@ -0,0 +1,5 @@
---
'tauri': 'patch:feat'
---
Add `App/AppHandle/Window/Webview/WebviewWindow::cursor_position` getter to get the current cursor position.

View File

@ -0,0 +1,5 @@
---
'@tauri-apps/api': 'patch:feat'
---
Add `cursorPosition` function in `window` module to get the current cursor position.

View File

@ -2162,6 +2162,17 @@ impl<T: UserEvent> RuntimeHandle<T> for WryHandle<T> {
.collect() .collect()
} }
fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
self
.context
.main_thread
.window_target
.cursor_position()
.map(PhysicalPositionWrapper)
.map(Into::into)
.map_err(|_| Error::FailedToGetCursorPosition)
}
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
fn show(&self) -> tauri_runtime::Result<()> { fn show(&self) -> tauri_runtime::Result<()> {
send_user_message( send_user_message(
@ -2409,6 +2420,17 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
.collect() .collect()
} }
fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
self
.context
.main_thread
.window_target
.cursor_position()
.map(PhysicalPositionWrapper)
.map(Into::into)
.map_err(|_| Error::FailedToGetCursorPosition)
}
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) { fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) {
self self

View File

@ -158,6 +158,9 @@ pub enum Error {
/// Failed to get monitor on window operation. /// Failed to get monitor on window operation.
#[error("failed to get monitor")] #[error("failed to get monitor")]
FailedToGetMonitor, FailedToGetMonitor,
/// Failed to get cursor position.
#[error("failed to get cursor position")]
FailedToGetCursorPosition,
#[error("Invalid header name: {0}")] #[error("Invalid header name: {0}")]
InvalidHeaderName(#[from] InvalidHeaderName), InvalidHeaderName(#[from] InvalidHeaderName),
#[error("Invalid header value: {0}")] #[error("Invalid header value: {0}")]
@ -293,6 +296,8 @@ pub trait RuntimeHandle<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 'st
fn primary_monitor(&self) -> Option<Monitor>; fn primary_monitor(&self) -> Option<Monitor>;
fn available_monitors(&self) -> Vec<Monitor>; fn available_monitors(&self) -> Vec<Monitor>;
fn cursor_position(&self) -> Result<PhysicalPosition<f64>>;
/// Shows the application, but does not automatically focus it. /// Shows the application, but does not automatically focus it.
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))] #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
@ -373,6 +378,8 @@ pub trait Runtime<T: UserEvent>: Debug + Sized + 'static {
fn primary_monitor(&self) -> Option<Monitor>; fn primary_monitor(&self) -> Option<Monitor>;
fn available_monitors(&self) -> Vec<Monitor>; fn available_monitors(&self) -> Vec<Monitor>;
fn cursor_position(&self) -> Result<PhysicalPosition<f64>>;
/// Sets the activation policy for the application. /// Sets the activation policy for the application.
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))] #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]

View File

@ -64,6 +64,7 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
("current_monitor", true), ("current_monitor", true),
("primary_monitor", true), ("primary_monitor", true),
("available_monitors", true), ("available_monitors", true),
("cursor_position", true),
("theme", true), ("theme", true),
// setters // setters
("center", false), ("center", false),

View File

@ -10,6 +10,8 @@
|`deny-create`|Denies the create command without any pre-configured scope.| |`deny-create`|Denies the create command without any pre-configured scope.|
|`allow-current-monitor`|Enables the current_monitor command without any pre-configured scope.| |`allow-current-monitor`|Enables the current_monitor command without any pre-configured scope.|
|`deny-current-monitor`|Denies the current_monitor command without any pre-configured scope.| |`deny-current-monitor`|Denies the current_monitor command without any pre-configured scope.|
|`allow-cursor-position`|Enables the cursor_position command without any pre-configured scope.|
|`deny-cursor-position`|Denies the cursor_position command without any pre-configured scope.|
|`allow-destroy`|Enables the destroy command without any pre-configured scope.| |`allow-destroy`|Enables the destroy command without any pre-configured scope.|
|`deny-destroy`|Denies the destroy command without any pre-configured scope.| |`deny-destroy`|Denies the destroy command without any pre-configured scope.|
|`allow-hide`|Enables the hide command without any pre-configured scope.| |`allow-hide`|Enables the hide command without any pre-configured scope.|

File diff suppressed because one or more lines are too long

View File

@ -596,6 +596,23 @@ macro_rules! shared_app_impl {
_ => unreachable!(), _ => unreachable!(),
}) })
} }
/// Get the cursor position relative to the top-left hand corner of the desktop.
///
/// Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
/// If the user uses a desktop with multiple monitors,
/// the top-left hand corner of the desktop is the top-left hand corner of the main monitor on Windows and macOS
/// or the top-left of the leftmost monitor on X11.
///
/// The coordinates can be negative if the top-left hand corner of the window is outside of the visible screen region.
pub fn cursor_position(&self) -> crate::Result<PhysicalPosition<f64>> {
Ok(match self.runtime() {
RuntimeOrDispatch::Runtime(h) => h.cursor_position()?,
RuntimeOrDispatch::RuntimeHandle(h) => h.cursor_position()?,
_ => unreachable!(),
})
}
/// Returns the default window icon. /// Returns the default window icon.
pub fn default_window_icon(&self) -> Option<&Image<'_>> { pub fn default_window_icon(&self) -> Option<&Image<'_>> {
self.manager.window.default_icon.as_ref() self.manager.window.default_icon.as_ref()

View File

@ -268,6 +268,10 @@ impl<T: UserEvent> RuntimeHandle<T> for MockRuntimeHandle {
{ {
todo!() todo!()
} }
fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
Ok(PhysicalPosition::new(0.0, 0.0))
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -1152,4 +1156,8 @@ impl<T: UserEvent> Runtime<T> for MockRuntime {
callback(RunEvent::Exit); callback(RunEvent::Exit);
} }
fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
Ok(PhysicalPosition::new(0.0, 0.0))
}
} }

View File

@ -895,6 +895,18 @@ impl<R: Runtime> Webview<R> {
self.webview.dispatcher.print().map_err(Into::into) self.webview.dispatcher.print().map_err(Into::into)
} }
/// Get the cursor position relative to the top-left hand corner of the desktop.
///
/// Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
/// If the user uses a desktop with multiple monitors,
/// the top-left hand corner of the desktop is the top-left hand corner of the main monitor on Windows and macOS
/// or the top-left of the leftmost monitor on X11.
///
/// The coordinates can be negative if the top-left hand corner of the window is outside of the visible screen region.
pub fn cursor_position(&self) -> crate::Result<PhysicalPosition<f64>> {
self.app_handle.cursor_position()
}
/// Closes this webview. /// Closes this webview.
pub fn close(&self) -> crate::Result<()> { pub fn close(&self) -> crate::Result<()> {
self.webview.dispatcher.close()?; self.webview.dispatcher.close()?;

View File

@ -1221,6 +1221,22 @@ impl<R: Runtime> WebviewWindow<R> {
} }
} }
/// Desktop window getters.
#[cfg(desktop)]
impl<R: Runtime> WebviewWindow<R> {
/// Get the cursor position relative to the top-left hand corner of the desktop.
///
/// Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
/// If the user uses a desktop with multiple monitors,
/// the top-left hand corner of the desktop is the top-left hand corner of the main monitor on Windows and macOS
/// or the top-left of the leftmost monitor on X11.
///
/// The coordinates can be negative if the top-left hand corner of the window is outside of the visible screen region.
pub fn cursor_position(&self) -> crate::Result<PhysicalPosition<f64>> {
self.webview.cursor_position()
}
}
/// Desktop window setters and actions. /// Desktop window setters and actions.
#[cfg(desktop)] #[cfg(desktop)]
impl<R: Runtime> WebviewWindow<R> { impl<R: Runtime> WebviewWindow<R> {

View File

@ -1553,6 +1553,22 @@ impl<R: Runtime> Window<R> {
} }
} }
/// Desktop window getters.
#[cfg(desktop)]
impl<R: Runtime> Window<R> {
/// Get the cursor position relative to the top-left hand corner of the desktop.
///
/// Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
/// If the user uses a desktop with multiple monitors,
/// the top-left hand corner of the desktop is the top-left hand corner of the main monitor on Windows and macOS
/// or the top-left of the leftmost monitor on X11.
///
/// The coordinates can be negative if the top-left hand corner of the window is outside of the visible screen region.
pub fn cursor_position(&self) -> crate::Result<PhysicalPosition<f64>> {
self.app_handle.cursor_position()
}
}
/// Desktop window setters and actions. /// Desktop window setters and actions.
#[cfg(desktop)] #[cfg(desktop)]
impl<R: Runtime> Window<R> { impl<R: Runtime> Window<R> {

View File

@ -90,6 +90,7 @@ mod desktop_commands {
getter!(current_monitor, Option<Monitor>); getter!(current_monitor, Option<Monitor>);
getter!(primary_monitor, Option<Monitor>); getter!(primary_monitor, Option<Monitor>);
getter!(available_monitors, Vec<Monitor>); getter!(available_monitors, Vec<Monitor>);
getter!(cursor_position, PhysicalPosition<f64>);
getter!(theme, Theme); getter!(theme, Theme);
setter!(center); setter!(center);
@ -222,6 +223,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
desktop_commands::current_monitor, desktop_commands::current_monitor,
desktop_commands::primary_monitor, desktop_commands::primary_monitor,
desktop_commands::available_monitors, desktop_commands::available_monitors,
desktop_commands::cursor_position,
desktop_commands::theme, desktop_commands::theme,
// setters // setters
desktop_commands::center, desktop_commands::center,

View File

@ -2256,6 +2256,22 @@ async function availableMonitors(): Promise<Monitor[]> {
) )
} }
/**
* Get the cursor position relative to the top-left hand corner of the desktop.
*
* Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
* If the user uses a desktop with multiple monitors,
* the top-left hand corner of the desktop is the top-left hand corner of the main monitor on Windows and macOS
* or the top-left of the leftmost monitor on X11.
*
* The coordinates can be negative if the top-left hand corner of the window is outside of the visible screen region.
*/
async function cursorPosition(): Promise<PhysicalPosition> {
return invoke<PhysicalPosition>('plugin:window|cursor_position').then(
mapPhysicalPosition
)
}
export { export {
Window, Window,
CloseRequestedEvent, CloseRequestedEvent,
@ -2270,7 +2286,8 @@ export {
EffectState, EffectState,
currentMonitor, currentMonitor,
primaryMonitor, primaryMonitor,
availableMonitors availableMonitors,
cursorPosition
} }
export type { export type {