Skip to content
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
54 changes: 45 additions & 9 deletions desktop/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::preferences;
use crate::render::{RenderError, RenderState};
use crate::ui::{InputEvent, UiCommand, UiInstance};
use crate::window::Window;
use crate::wrapper::messages::{DesktopFrontendMessage, DesktopWrapperMessage, Preferences};
use crate::wrapper::messages::{DesktopFrontendMessage, DesktopWrapperMessage, InputMessage, Key, ModifierKeys, Preferences};
use crate::wrapper::{DesktopWrapper, MmapResourceStorage, NodeGraphExecutionResult, WgpuContext, serialize_frontend_messages};

pub(crate) struct App {
Expand Down Expand Up @@ -352,6 +352,9 @@ impl App {
window.start_pointer_lock();
}
}
DesktopFrontendMessage::PointerUnlock => {
self.unlock_pointer();
}
DesktopFrontendMessage::WindowClose => {
self.app_event_scheduler.schedule(AppEvent::Exit);
}
Expand Down Expand Up @@ -509,6 +512,34 @@ impl App {
}
}
}

fn unlock_pointer(&mut self) {
if let Some(restore) = self.input_state.unlock_pointer() {
if let Some(window) = &self.window {
window.end_pointer_lock();
}
self.ui
.send(UiCommand::Input(InputEvent::pointer().position(restore).moved().modifiers(self.input_state.modifiers()).build()));
}
}

/// Synthesizes an Escape press and release to cancel the active transform, as a user pressing Escape would.
fn send_cancel_escape(&mut self) {
for message in [
InputMessage::KeyDown {
key: Key::Escape,
key_repeat: false,
modifier_keys: ModifierKeys::empty(),
},
InputMessage::KeyUp {
key: Key::Escape,
key_repeat: false,
modifier_keys: ModifierKeys::empty(),
},
] {
self.app_event_scheduler.schedule(AppEvent::DesktopWrapperMessage(DesktopWrapperMessage::Input(message)));
}
}
}
impl ApplicationHandler for App {
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
Expand Down Expand Up @@ -539,20 +570,22 @@ impl ApplicationHandler for App {
}

fn window_event(&mut self, _event_loop: &dyn ActiveEventLoop, _window_id: WindowId, event: WindowEvent) {
// Handle pointer lock release
if let WindowEvent::PointerButton {
state: ElementState::Released,
button,
..
} = &event && button.clone().mouse_button() == Some(MouseButton::Left)
&& let Some(pointer_lock_position) = self.input_state.unlock_pointer()
&& self.input_state.pointer_locked()
{
if let Some(window) = &self.window {
window.end_pointer_lock();
}
self.ui.send(UiCommand::Input(
InputEvent::pointer().position(pointer_lock_position).moved().modifiers(self.input_state.modifiers()).build(),
));
self.unlock_pointer();
}

// The window lost focus while pointer-locked: cancel the transform and release the grab
if let WindowEvent::Focused(false) = &event
&& self.input_state.pointer_locked()
{
self.unlock_pointer();
self.send_cancel_escape();
}

self.input_state.process(
Expand Down Expand Up @@ -641,6 +674,9 @@ impl ApplicationHandler for App {
if self.input_state.pointer_locked()
&& let winit::event::DeviceEvent::PointerMotion { delta: (x, y) } = event
{
// Device deltas are in physical pixels; convert them to logical viewport units
let scale = self.input_state.viewport_scale();
let (x, y) = if scale != 0. { (x / scale, y / scale) } else { (x, y) };
let message = DesktopWrapperMessage::PointerLockMove { x, y };
self.app_event_scheduler.schedule(AppEvent::DesktopWrapperMessage(message));
}
Expand Down
4 changes: 2 additions & 2 deletions desktop/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ impl InputState {
}
}

fn scale(&self) -> f64 {
pub(crate) fn viewport_scale(&self) -> f64 {
self.viewport_info.as_ref().map_or(1., |info| info.scale)
}

Expand All @@ -280,7 +280,7 @@ impl InputState {

fn pointer_state(&self) -> EditorPointerState {
EditorPointerState {
editor_position: (self.pointer_position.x / self.scale(), self.pointer_position.y / self.scale()).into(),
editor_position: (self.pointer_position.x / self.viewport_scale(), self.pointer_position.y / self.viewport_scale()).into(),
mouse_keys: self.pointer_keys(),
time: Some(self.start.elapsed().as_secs_f64() * 1000.),
..Default::default()
Expand Down
3 changes: 3 additions & 0 deletions desktop/wrapper/src/intercept_frontend_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ pub(super) fn intercept_frontend_message(dispatcher: &mut DesktopWrapperMessageD
FrontendMessage::WindowPointerLock => {
dispatcher.respond(DesktopFrontendMessage::PointerLock);
}
FrontendMessage::WindowPointerUnlock => {
dispatcher.respond(DesktopFrontendMessage::PointerUnlock);
}
FrontendMessage::WindowUpdateDirectInput { enabled } => {
dispatcher.respond(DesktopFrontendMessage::WindowUpdateDirectInput { enabled });
}
Expand Down
1 change: 1 addition & 0 deletions desktop/wrapper/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ pub enum DesktopFrontendMessage {
content: String,
},
PointerLock,
PointerUnlock,
WindowClose,
WindowMinimize,
WindowMaximize,
Expand Down
2 changes: 2 additions & 0 deletions editor/src/messages/app_window/app_window_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use crate::messages::prelude::*;
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum AppWindowMessage {
PointerLock,
PointerUnlock,
// Relative pointer movement in logical viewport units (platforms divide physical deltas by the viewport scale)
PointerLockMove { x: f64, y: f64 },
DirectInput { enabled: bool },
Restart,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,14 @@ impl MessageHandler<AppWindowMessage, ()> for AppWindowMessageHandler {
#[cfg(not(target_family = "wasm"))]
responses.add(FrontendMessage::WindowPointerLock);
}
AppWindowMessage::PointerUnlock => {
#[cfg(not(target_family = "wasm"))]
responses.add(FrontendMessage::WindowPointerUnlock);
}
AppWindowMessage::PointerLockMove { x, y } => {
responses.add(FrontendMessage::WindowPointerLockMove { position: (x, y) });
// Send locked deltas only to the transform layer, so number input drags don't move the editor pointer
responses.add(TransformLayerMessage::PointerLockMove { delta: glam::DVec2::new(x, y) });
}
AppWindowMessage::DirectInput { enabled } => {
#[cfg(not(target_family = "wasm"))]
Expand Down
7 changes: 7 additions & 0 deletions editor/src/messages/frontend/frontend_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,13 @@ pub enum FrontendMessage {
position: (f64, f64),
},
#[cfg(not(target_family = "wasm"))]
WindowPointerUnlock,
UpdateSoftwareCursor {
visible: bool,
x: f64,
y: f64,
},
#[cfg(not(target_family = "wasm"))]
WindowUpdateDirectInput {
enabled: bool,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub enum TransformLayerMessage {
ConstrainX,
ConstrainY,
PointerMove { slow_key: Key, increments_key: Key },
PointerLockMove { delta: DVec2 },
SelectionChanged,
TypeBackspace,
TypeDecimalPoint,
Expand Down
Loading