tao icon indicating copy to clipboard operation
tao copied to clipboard

Ability to get mouse position while dragging files onto Tauri window

Open Boscop opened this issue 4 years ago • 0 comments

Is your feature request related to a problem? Please describe. The problem is inherited from winit. In short: Winit doesn't send any CursorMoved events (nor CursorEntered) before DroppedFile, only immediately after. That's too late, if you want to know the mouse position before DroppedFile is received, e.g. if your app has different drop areas, and you need to know onto which one the files are dropped!

Describe the solution you'd like Tao should send CursorEntered event as soon as the file-dragging cursor moves over the Tao window, and continuously send CursorMoved events as the cursor moves.

Describe alternatives you've considered In my imgui-rs based frontend I worked around this by delaying all DroppedFile events until the first CursorMoved event is received, so that at the time of processing DroppedFile, imgui has already received the latest mouse pos. (On Win 8.1, CursorMoved always seems to come 2 frames after DroppedFile.)

// This event processor delays DroppedFile events until the first CursorMoved event is received,
// so that at the time of processing DroppedFile, imgui has the correct mouse pos.
// (On Win 8.1, CursorMoved always seems to come 2 frames after DroppedFile.)
/*
unfixed:
frame 446, DroppedFile: foo.txt
frame 448, CursorMoved: (377.0, 79.0)
desired:
frame 448, CursorMoved: (377.0, 79.0)
frame 448, DroppedFile: foo.txt
*/
#[derive(Default)]
pub struct CursorMovedB4DroppedFile<'a> {
	event_queue: Vec<Event<'a, ()>>,
	waiting_for_cursor_moved_event: bool,
}

impl<'a> CursorMovedB4DroppedFile<'a> {
	// each frame, call push before poll
	fn push(&mut self, ev: Event<'a, ()>) {
		// TODO: respect event's window_id ?
		let move_dropped_file_events_to_end_of_queue = match &ev {
			Event::WindowEvent { event: WindowEvent::DroppedFile(_path), .. } => {
				self.waiting_for_cursor_moved_event = true;
				false
			}
			Event::WindowEvent { event: WindowEvent::CursorMoved { .. }, .. } => {
				self.waiting_for_cursor_moved_event = false;
				true
			}
			_ => false,
		};
		self.event_queue.push(ev);
		if move_dropped_file_events_to_end_of_queue {
			self.event_queue.sort_by_key(|ev| {
				matches!(ev, Event::WindowEvent { event: WindowEvent::DroppedFile(_), .. })
			});
		}
	}

	fn poll(&mut self) -> impl Iterator<Item = Event<'a, ()>> + '_ {
		let waiting_for_cursor_moved_event = self.waiting_for_cursor_moved_event;
		self.event_queue.drain_filter(move |ev| match ev {
			Event::WindowEvent { event: WindowEvent::DroppedFile(_path), .. } => {
				!waiting_for_cursor_moved_event
			}
			_ => true,
		})
	}

	pub fn push_and_poll(&mut self, ev: Event<'a, ()>) -> impl Iterator<Item = Event<'a, ()>> + '_ {
		self.push(ev);
		self.poll()
	}
}

Note that I cannot use this workaround with Tauri because it doesn't let me process the events coming from Tao.

Additional context Note: My workaround is not a satisfying solution, because in my frontend, while the user is dragging files and hovering the mouse, I would like to highlight the currently hovered drop area, which is not possible with this workaround because I only receive the CursorMoved event in the same frame as the DroppedFile event(s). But I'd still advocate for including this workaround in Tao if the full fix is infeasible for now, because it's better than having the wrong mouse pos at the time of drop, so that the user is left wondering why the drop area hasn't received the file. (Currently Tao/winit thinks the mouse pos at the time of receiving DroppedFile is still where it was before the cursor last left the window, which is a totally confusing behavior for the user.)

Boscop avatar May 18 '21 21:05 Boscop