-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
multi-click support #24023
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
multi-click support #24023
Changes from all commits
8b2c998
6fefb63
b7fa0a1
59f8200
b464f83
1f4d626
baed67e
e5d932e
3b86e25
f9f5528
ca06c7d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -63,6 +63,10 @@ use crate::{ | |
| pointer::{Location, PointerAction, PointerButton, PointerId, PointerInput, PointerMap}, | ||
| }; | ||
|
|
||
| /// Maximum time between clicks for them to count as consecutive clicks. | ||
| // TODO: add optional feature-flagged support for fetching this from the OS preferences | ||
| pub const MULTI_CLICK_DURATION: Duration = Duration::from_millis(500); | ||
|
Comment on lines
+67
to
+68
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be a resource instead so it can be overwritten.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's no crate that does this AFAIK. Instead, we'll eventually need to add OS-specific code in #[cfg(target_os = "windows")]
mod platform {
use super::*;
pub fn get() -> Option<Duration> {
// GetDoubleClickTime returns the interval in milliseconds.
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdoubleclicktime
extern "system" {
fn GetDoubleClickTime() -> u32;
}
let ms = unsafe { GetDoubleClickTime() };
if ms == 0 {
None
} else {
Some(Duration::from_millis(ms as u64))
}
}
}Also, on Linux there's no single setting, you have to parse the Gnome or KDE settings files, this will take some time at startup.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Which is why a separate crate would be nice – Bevy isn't the only library having this issue.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'm just using a constant here because I wanted to keep this a narrow PR focused on the multi-click implementation. It should definitely be user configurable, or fetched from the OS if possible, though.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's spatial tolerance as well, which we'd also want to get from the OS. Left it out from this PR because it has to account for scale factor (which is annoying). |
||
|
|
||
| /// Stores the common data needed for all pointer events. | ||
| /// | ||
| /// The documentation for the [`pointer_events`] explains the events this module exposes and | ||
|
|
@@ -312,6 +316,8 @@ pub struct Click { | |
| pub hit: HitData, | ||
| /// Duration between the pointer pressed and lifted for this click | ||
| pub duration: Duration, | ||
| /// Number of consecutive clicks, starting at `1`. | ||
| pub count: u8, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. New minigame idea just dropped! |
||
| } | ||
|
|
||
| /// Fires while a pointer is moving over the [target entity](EntityEvent::event_target). | ||
|
|
@@ -470,6 +476,8 @@ pub struct Scroll { | |
| pub struct PointerButtonState { | ||
| /// Stores the press location and start time for each button currently being pressed by the pointer. | ||
| pub pressing: EntityHashMap<(Location, Instant, HitData)>, | ||
| /// Stores the latest click time and count for each clicked entity. | ||
| pub clicking: EntityHashMap<(Instant, u8)>, | ||
| /// Stores the starting and current locations for each entity currently being dragged by the pointer. | ||
| pub dragging: EntityHashMap<DragEntry>, | ||
| /// Stores the hit data for each entity currently being dragged over by the pointer. | ||
|
|
@@ -938,6 +946,9 @@ pub fn pointer_events( | |
| } | ||
| PointerAction::Release(button) => { | ||
| let state = pointer_state.get_mut(pointer_id, button); | ||
| state | ||
| .clicking | ||
| .retain(|_, (last_click, _)| now - *last_click <= MULTI_CLICK_DURATION); | ||
|
|
||
| // Emit Click and Release events on all the previously hovered entities. | ||
| for (hovered_entity, hit) in previous_hover_map | ||
|
|
@@ -947,13 +958,19 @@ pub fn pointer_events( | |
| { | ||
| // If this pointer previously pressed the hovered entity, emit a Click event | ||
| if let Some((_, press_instant, _)) = state.pressing.get(&hovered_entity) { | ||
| let count = state | ||
| .clicking | ||
| .get(&hovered_entity) | ||
| .map_or(1, |(_, count)| count.saturating_add(1)); | ||
| state.clicking.insert(hovered_entity, (now, count)); | ||
| let click_event = Pointer::new( | ||
| pointer_id, | ||
| location.clone(), | ||
| Click { | ||
| button, | ||
| hit: hit.clone(), | ||
| duration: now - *press_instant, | ||
| count, | ||
| }, | ||
| hovered_entity, | ||
| ); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.