Skip to content

Commit 477bb8c

Browse files
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>
1 parent 5a213a4 commit 477bb8c

File tree

14 files changed

+132
-2
lines changed

14 files changed

+132
-2
lines changed

Diff for: .changes/cursor_position.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'tauri': 'patch:feat'
3+
---
4+
5+
Add `App/AppHandle/Window/Webview/WebviewWindow::cursor_position` getter to get the current cursor position.

Diff for: .changes/cursor_position_js.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tauri-apps/api': 'patch:feat'
3+
---
4+
5+
Add `cursorPosition` function in `window` module to get the current cursor position.

Diff for: core/tauri-runtime-wry/src/lib.rs

+22
Original file line numberDiff line numberDiff line change
@@ -2162,6 +2162,17 @@ impl<T: UserEvent> RuntimeHandle<T> for WryHandle<T> {
21622162
.collect()
21632163
}
21642164

2165+
fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
2166+
self
2167+
.context
2168+
.main_thread
2169+
.window_target
2170+
.cursor_position()
2171+
.map(PhysicalPositionWrapper)
2172+
.map(Into::into)
2173+
.map_err(|_| Error::FailedToGetCursorPosition)
2174+
}
2175+
21652176
#[cfg(target_os = "macos")]
21662177
fn show(&self) -> tauri_runtime::Result<()> {
21672178
send_user_message(
@@ -2409,6 +2420,17 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
24092420
.collect()
24102421
}
24112422

2423+
fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
2424+
self
2425+
.context
2426+
.main_thread
2427+
.window_target
2428+
.cursor_position()
2429+
.map(PhysicalPositionWrapper)
2430+
.map(Into::into)
2431+
.map_err(|_| Error::FailedToGetCursorPosition)
2432+
}
2433+
24122434
#[cfg(target_os = "macos")]
24132435
fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) {
24142436
self

Diff for: core/tauri-runtime/src/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ pub enum Error {
158158
/// Failed to get monitor on window operation.
159159
#[error("failed to get monitor")]
160160
FailedToGetMonitor,
161+
/// Failed to get cursor position.
162+
#[error("failed to get cursor position")]
163+
FailedToGetCursorPosition,
161164
#[error("Invalid header name: {0}")]
162165
InvalidHeaderName(#[from] InvalidHeaderName),
163166
#[error("Invalid header value: {0}")]
@@ -293,6 +296,8 @@ pub trait RuntimeHandle<T: UserEvent>: Debug + Clone + Send + Sync + Sized + 'st
293296
fn primary_monitor(&self) -> Option<Monitor>;
294297
fn available_monitors(&self) -> Vec<Monitor>;
295298

299+
fn cursor_position(&self) -> Result<PhysicalPosition<f64>>;
300+
296301
/// Shows the application, but does not automatically focus it.
297302
#[cfg(target_os = "macos")]
298303
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
@@ -373,6 +378,8 @@ pub trait Runtime<T: UserEvent>: Debug + Sized + 'static {
373378
fn primary_monitor(&self) -> Option<Monitor>;
374379
fn available_monitors(&self) -> Vec<Monitor>;
375380

381+
fn cursor_position(&self) -> Result<PhysicalPosition<f64>>;
382+
376383
/// Sets the activation policy for the application.
377384
#[cfg(target_os = "macos")]
378385
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]

Diff for: core/tauri/build.rs

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
6464
("current_monitor", true),
6565
("primary_monitor", true),
6666
("available_monitors", true),
67+
("cursor_position", true),
6768
("theme", true),
6869
// setters
6970
("center", false),

Diff for: core/tauri/permissions/window/autogenerated/reference.md

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
|`deny-create`|Denies the create command without any pre-configured scope.|
1111
|`allow-current-monitor`|Enables the current_monitor command without any pre-configured scope.|
1212
|`deny-current-monitor`|Denies the current_monitor command without any pre-configured scope.|
13+
|`allow-cursor-position`|Enables the cursor_position command without any pre-configured scope.|
14+
|`deny-cursor-position`|Denies the cursor_position command without any pre-configured scope.|
1315
|`allow-destroy`|Enables the destroy command without any pre-configured scope.|
1416
|`deny-destroy`|Denies the destroy command without any pre-configured scope.|
1517
|`allow-hide`|Enables the hide command without any pre-configured scope.|

Diff for: core/tauri/scripts/bundle.global.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: core/tauri/src/app.rs

+17
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,23 @@ macro_rules! shared_app_impl {
596596
_ => unreachable!(),
597597
})
598598
}
599+
600+
/// Get the cursor position relative to the top-left hand corner of the desktop.
601+
///
602+
/// Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
603+
/// If the user uses a desktop with multiple monitors,
604+
/// the top-left hand corner of the desktop is the top-left hand corner of the main monitor on Windows and macOS
605+
/// or the top-left of the leftmost monitor on X11.
606+
///
607+
/// The coordinates can be negative if the top-left hand corner of the window is outside of the visible screen region.
608+
pub fn cursor_position(&self) -> crate::Result<PhysicalPosition<f64>> {
609+
Ok(match self.runtime() {
610+
RuntimeOrDispatch::Runtime(h) => h.cursor_position()?,
611+
RuntimeOrDispatch::RuntimeHandle(h) => h.cursor_position()?,
612+
_ => unreachable!(),
613+
})
614+
}
615+
599616
/// Returns the default window icon.
600617
pub fn default_window_icon(&self) -> Option<&Image<'_>> {
601618
self.manager.window.default_icon.as_ref()

Diff for: core/tauri/src/test/mock_runtime.rs

+8
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,10 @@ impl<T: UserEvent> RuntimeHandle<T> for MockRuntimeHandle {
268268
{
269269
todo!()
270270
}
271+
272+
fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
273+
Ok(PhysicalPosition::new(0.0, 0.0))
274+
}
271275
}
272276

273277
#[derive(Debug, Clone)]
@@ -1152,4 +1156,8 @@ impl<T: UserEvent> Runtime<T> for MockRuntime {
11521156

11531157
callback(RunEvent::Exit);
11541158
}
1159+
1160+
fn cursor_position(&self) -> Result<PhysicalPosition<f64>> {
1161+
Ok(PhysicalPosition::new(0.0, 0.0))
1162+
}
11551163
}

Diff for: core/tauri/src/webview/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,18 @@ impl<R: Runtime> Webview<R> {
895895
self.webview.dispatcher.print().map_err(Into::into)
896896
}
897897

898+
/// Get the cursor position relative to the top-left hand corner of the desktop.
899+
///
900+
/// Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
901+
/// If the user uses a desktop with multiple monitors,
902+
/// the top-left hand corner of the desktop is the top-left hand corner of the main monitor on Windows and macOS
903+
/// or the top-left of the leftmost monitor on X11.
904+
///
905+
/// The coordinates can be negative if the top-left hand corner of the window is outside of the visible screen region.
906+
pub fn cursor_position(&self) -> crate::Result<PhysicalPosition<f64>> {
907+
self.app_handle.cursor_position()
908+
}
909+
898910
/// Closes this webview.
899911
pub fn close(&self) -> crate::Result<()> {
900912
self.webview.dispatcher.close()?;

Diff for: core/tauri/src/webview/webview_window.rs

+16
Original file line numberDiff line numberDiff line change
@@ -1221,6 +1221,22 @@ impl<R: Runtime> WebviewWindow<R> {
12211221
}
12221222
}
12231223

1224+
/// Desktop window getters.
1225+
#[cfg(desktop)]
1226+
impl<R: Runtime> WebviewWindow<R> {
1227+
/// Get the cursor position relative to the top-left hand corner of the desktop.
1228+
///
1229+
/// Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
1230+
/// If the user uses a desktop with multiple monitors,
1231+
/// the top-left hand corner of the desktop is the top-left hand corner of the main monitor on Windows and macOS
1232+
/// or the top-left of the leftmost monitor on X11.
1233+
///
1234+
/// The coordinates can be negative if the top-left hand corner of the window is outside of the visible screen region.
1235+
pub fn cursor_position(&self) -> crate::Result<PhysicalPosition<f64>> {
1236+
self.webview.cursor_position()
1237+
}
1238+
}
1239+
12241240
/// Desktop window setters and actions.
12251241
#[cfg(desktop)]
12261242
impl<R: Runtime> WebviewWindow<R> {

Diff for: core/tauri/src/window/mod.rs

+16
Original file line numberDiff line numberDiff line change
@@ -1553,6 +1553,22 @@ impl<R: Runtime> Window<R> {
15531553
}
15541554
}
15551555

1556+
/// Desktop window getters.
1557+
#[cfg(desktop)]
1558+
impl<R: Runtime> Window<R> {
1559+
/// Get the cursor position relative to the top-left hand corner of the desktop.
1560+
///
1561+
/// Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
1562+
/// If the user uses a desktop with multiple monitors,
1563+
/// the top-left hand corner of the desktop is the top-left hand corner of the main monitor on Windows and macOS
1564+
/// or the top-left of the leftmost monitor on X11.
1565+
///
1566+
/// The coordinates can be negative if the top-left hand corner of the window is outside of the visible screen region.
1567+
pub fn cursor_position(&self) -> crate::Result<PhysicalPosition<f64>> {
1568+
self.app_handle.cursor_position()
1569+
}
1570+
}
1571+
15561572
/// Desktop window setters and actions.
15571573
#[cfg(desktop)]
15581574
impl<R: Runtime> Window<R> {

Diff for: core/tauri/src/window/plugin.rs

+2
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ mod desktop_commands {
9090
getter!(current_monitor, Option<Monitor>);
9191
getter!(primary_monitor, Option<Monitor>);
9292
getter!(available_monitors, Vec<Monitor>);
93+
getter!(cursor_position, PhysicalPosition<f64>);
9394
getter!(theme, Theme);
9495

9596
setter!(center);
@@ -222,6 +223,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
222223
desktop_commands::current_monitor,
223224
desktop_commands::primary_monitor,
224225
desktop_commands::available_monitors,
226+
desktop_commands::cursor_position,
225227
desktop_commands::theme,
226228
// setters
227229
desktop_commands::center,

Diff for: tooling/api/src/window.ts

+18-1
Original file line numberDiff line numberDiff line change
@@ -2256,6 +2256,22 @@ async function availableMonitors(): Promise<Monitor[]> {
22562256
)
22572257
}
22582258

2259+
/**
2260+
* Get the cursor position relative to the top-left hand corner of the desktop.
2261+
*
2262+
* Note that the top-left hand corner of the desktop is not necessarily the same as the screen.
2263+
* If the user uses a desktop with multiple monitors,
2264+
* the top-left hand corner of the desktop is the top-left hand corner of the main monitor on Windows and macOS
2265+
* or the top-left of the leftmost monitor on X11.
2266+
*
2267+
* The coordinates can be negative if the top-left hand corner of the window is outside of the visible screen region.
2268+
*/
2269+
async function cursorPosition(): Promise<PhysicalPosition> {
2270+
return invoke<PhysicalPosition>('plugin:window|cursor_position').then(
2271+
mapPhysicalPosition
2272+
)
2273+
}
2274+
22592275
export {
22602276
Window,
22612277
CloseRequestedEvent,
@@ -2270,7 +2286,8 @@ export {
22702286
EffectState,
22712287
currentMonitor,
22722288
primaryMonitor,
2273-
availableMonitors
2289+
availableMonitors,
2290+
cursorPosition
22742291
}
22752292

22762293
export type {

0 commit comments

Comments
 (0)