summaryrefslogtreecommitdiff
path: root/engine/src/windowing.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/windowing.rs')
-rw-r--r--engine/src/windowing.rs731
1 files changed, 386 insertions, 345 deletions
diff --git a/engine/src/windowing.rs b/engine/src/windowing.rs
index 2493851..3e27075 100644
--- a/engine/src/windowing.rs
+++ b/engine/src/windowing.rs
@@ -24,7 +24,6 @@ use winit::window::{Window as WinitWindow, WindowId as WinitWindowId};
use crate::ecs::actions::Actions;
use crate::ecs::component::Component;
-use crate::ecs::entity::obtainer::Obtainer as EntityObtainer;
use crate::ecs::event::component::{Added, Changed, EventMatchExt, Removed};
use crate::ecs::pair::{ChildOf, Pair};
use crate::ecs::phase::{Phase, PRE_UPDATE as PRE_UPDATE_PHASE};
@@ -32,11 +31,11 @@ use crate::ecs::sole::Single;
use crate::ecs::system::observer::Observe;
use crate::ecs::uid::Uid;
use crate::ecs::util::StreamingIterator;
-use crate::ecs::{declare_entity, pair, Query, Sole};
+use crate::ecs::{declare_entity, pair, Query, Sole, World};
use crate::util::BitArray;
use crate::vector::Vec2;
-use crate::windowing::dpi::{PhysicalPosition, PhysicalSize, Position};
-use crate::windowing::keyboard::{Key, KeyState, Keyboard, UnknownKeyCodeError};
+use crate::windowing::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize, Position};
+use crate::windowing::keyboard::{Key, KeyState, Keyboard};
use crate::windowing::monitor::Handle as MonitorHandle;
use crate::windowing::mouse::{
Button as MouseButton,
@@ -82,7 +81,7 @@ impl crate::ecs::extension::Extension for Extension
fn collect(self, mut collector: crate::ecs::extension::Collector<'_>)
{
if !CONTEXT_CREATED.load(Ordering::Relaxed) {
- collector.add_sole(Context::new()).ok();
+ collector.add_sole(Context::new_global()).ok();
}
collector.add_sole(Keyboard::default()).ok();
@@ -135,118 +134,55 @@ fn update_stuff(
mut mouse: Single<Mouse>,
mut mouse_buttons: Single<MouseButtons>,
mut actions: Actions,
- entity_obtainer: EntityObtainer,
+ world: &World,
) -> Result<(), EngineError>
{
let Ok(context) = context.get_mut() else {
unreachable!();
};
- let keyboard = keyboard.get_mut()?;
- let mouse = mouse.get_mut()?;
- let mouse_buttons = mouse_buttons.get_mut()?;
-
if context.display_handle.is_none() {
cold_path();
actions.stop();
return Ok(());
}
- keyboard.make_key_states_previous();
-
- {
- let Some(mut input) = context
- .shared_state
- .input
- .try_lock_for(Duration::from_millis(100))
- else {
- tracing::error!("Locking input mutex timed out after 100ms");
- return Ok(());
- };
-
- mouse.curr_tick_position_delta = input.relative_mouse_pos_delta;
- mouse.position = input.absolute_mouse_pos.clone();
- mouse.curr_tick_scroll_delta = input.mouse_scroll_delta.clone();
-
- for (mouse_button, mouse_button_input) in input.mouse_buttons.iter_mut() {
- mouse_buttons.set_previous_to_current(mouse_button);
-
- if mouse_button_input.flags.is_all() {
- match mouse_buttons.get_previous(mouse_button) {
- MouseButtonState::Pressed => {
- mouse_buttons.set(mouse_button, MouseButtonState::Released);
-
- mouse_button_input.flags.remove(MouseButtonFlags::RELEASED);
- }
- MouseButtonState::Released => {
- mouse_buttons.set(mouse_button, MouseButtonState::Pressed);
-
- mouse_button_input.flags.remove(MouseButtonFlags::PRESSED);
- }
- }
-
- continue;
- }
-
- let mouse_button_state = if mouse_button_input.flags.is_empty() {
- let Some(mouse_button_state) = mouse_button_input.lagged.pop_front()
- else {
- continue;
- };
-
- mouse_button_state
- } else {
- bitflags_match!(mouse_button_input.flags, {
- MouseButtonFlags::PRESSED => MouseButtonState::Pressed,
- MouseButtonFlags::RELEASED => MouseButtonState::Released,
- _ => unreachable!()
- })
- };
-
- mouse_buttons.set(mouse_button, mouse_button_state);
-
- mouse_button_input.flags.clear();
- }
-
- let mut key_updates = input.keys.iter_occupied_mut();
-
- while let Some(mut key_item) = key_updates.streaming_next() {
- let key = Key::KEYS[key_item.index];
-
- if key_item.bits == KEY_PRESSED_BITS | KEY_RELEASED_BITS {
- match keyboard.get_key_state(key) {
- KeyState::Pressed => {
- keyboard.set_key_state(key, KeyState::Released);
+ let keyboard = keyboard.get_mut()?;
+ let mouse = mouse.get_mut()?;
+ let mouse_buttons = mouse_buttons.get_mut()?;
- key_item.clear_and_set(KEY_PRESSED_BITS, u8::MAX);
- }
- KeyState::Released => {
- keyboard.set_key_state(key, KeyState::Pressed);
+ update_inputs(context, keyboard, mouse, mouse_buttons);
- key_item.clear_and_set(KEY_RELEASED_BITS, u8::MAX);
- }
- }
+ receive_app_messages(context, &mut actions, world);
- continue;
- }
+ if context.shared_state.thread_panicked.load(Ordering::Relaxed) {
+ cold_path();
+ return Err(error!("Windowing app thread panicked"));
+ }
- let key_state = match key_item.bits {
- KEY_PRESSED_BITS => KeyState::Pressed,
- KEY_RELEASED_BITS => KeyState::Released,
- _ => unreachable!(),
- };
+ if context.shared_state.has_thread_err.load(Ordering::Relaxed) {
+ cold_path();
- keyboard.set_key_state(key, key_state);
+ let Ok(mut err) = context.shared_state.thread_err.try_lock() else {
+ // The windowing app thread always unlocks the thread_err mutex before
+ // setting the has_thread_err atomic
+ unreachable!();
+ };
- key_item.clear_and_set(0, u8::MAX);
- }
+ let Some(err) = err.take() else {
+ // The has_thread_err atomic is set to true so this option is always
+ // Some
+ unreachable!();
+ };
- input.relative_mouse_pos_delta = Vec2 { x: 0.0, y: 0.0 };
- input.mouse_scroll_delta = MouseScrollDelta { vert_lines: 0.0, hor_lines: 0.0 };
- };
+ return Err(err.into());
+ }
- keyboard.set_text_keys(iter_array_queue(&context.shared_state.text_keys));
+ Ok(())
+}
+fn receive_app_messages(context: &mut Context, actions: &mut Actions, world: &World)
+{
let Context {
ref mut windows, ref shared_state, ..
} = *context;
@@ -255,11 +191,11 @@ fn update_stuff(
tracing::trace!(message=?message, "Received message from app");
match message {
- MessageFromApp::WindowCreated(
+ MessageFromApp::Window(WindowMessage::Created(
window_ent_id,
winit_window,
window_creation_attrs,
- ) => {
+ )) => {
actions.add_components(
window_ent_id,
(Window::new(&winit_window, &window_creation_attrs),),
@@ -277,7 +213,10 @@ fn update_stuff(
"Window creation completed"
);
}
- MessageFromApp::WindowResized(window_id, new_window_size) => {
+ MessageFromApp::Window(WindowMessage::Resized(
+ window_id,
+ new_window_size,
+ )) => {
tracing::trace!(
window_id = ?window_id,
"Received window resized message"
@@ -293,7 +232,7 @@ fn update_stuff(
continue;
};
- let Some(window_ent) = entity_obtainer.get_entity(*window_ent_id) else {
+ let Some(window_ent) = world.get_entity(*window_ent_id) else {
continue;
};
@@ -305,7 +244,7 @@ fn update_stuff(
window.set_changed();
}
- MessageFromApp::WindowCloseRequested(window_id) => {
+ MessageFromApp::Window(WindowMessage::CloseRequested(window_id)) => {
let Some(window_ent_id) =
windows.get(window_id).map(|(_, ent_id)| ent_id)
else {
@@ -318,7 +257,10 @@ fn update_stuff(
actions.remove_comps::<(Window,)>(*window_ent_id);
}
- MessageFromApp::WindowScaleFactorChanged(window_id, scale_factor) => {
+ MessageFromApp::Window(WindowMessage::ScaleFactorChanged(
+ window_id,
+ scale_factor,
+ )) => {
let Some(window_ent_id) =
windows.get(window_id).map(|(_, ent_id)| ent_id)
else {
@@ -329,7 +271,7 @@ fn update_stuff(
continue;
};
- let Some(window_ent) = entity_obtainer.get_entity(*window_ent_id) else {
+ let Some(window_ent) = world.get_entity(*window_ent_id) else {
continue;
};
@@ -343,31 +285,109 @@ fn update_stuff(
}
}
}
+}
- if shared_state.thread_panicked.load(Ordering::Relaxed) {
- cold_path();
- return Err(error!("Windowing app thread panicked"));
- }
-
- if shared_state.has_thread_err.load(Ordering::Relaxed) {
- cold_path();
+fn update_inputs(
+ context: &Context,
+ keyboard: &mut Keyboard,
+ mouse: &mut Mouse,
+ mouse_buttons: &mut MouseButtons,
+)
+{
+ keyboard.make_key_states_previous();
- let Ok(mut err) = shared_state.thread_err.try_lock() else {
- // The windowing app thread always unlocks the thread_err mutex before
- // setting the has_thread_err atomic
- unreachable!();
+ {
+ let Some(mut input) = context
+ .shared_state
+ .input
+ .try_lock_for(Duration::from_millis(100))
+ else {
+ tracing::error!("Locking input mutex timed out after 100ms");
+ return;
};
- let Some(err) = err.take() else {
- // The has_thread_err atomic is set to true so this option is always
- // Some
- unreachable!();
- };
+ mouse.curr_tick_position_delta = input.relative_mouse_pos_delta;
+ mouse.position = input.absolute_mouse_pos;
+ mouse.curr_tick_scroll_delta = input.mouse_scroll_delta.clone();
- return Err(err.into());
- }
+ for (mouse_button, mouse_button_input) in &mut input.mouse_buttons {
+ mouse_buttons.set_previous_to_current(mouse_button);
- Ok(())
+ if mouse_button_input.flags.is_all() {
+ match mouse_buttons.get_previous(mouse_button) {
+ MouseButtonState::Pressed => {
+ mouse_buttons.set(mouse_button, MouseButtonState::Released);
+
+ mouse_button_input.flags.remove(MouseButtonFlags::RELEASED);
+ }
+ MouseButtonState::Released => {
+ mouse_buttons.set(mouse_button, MouseButtonState::Pressed);
+
+ mouse_button_input.flags.remove(MouseButtonFlags::PRESSED);
+ }
+ }
+
+ continue;
+ }
+
+ let mouse_button_state = if mouse_button_input.flags.is_empty() {
+ let Some(mouse_button_state) = mouse_button_input.lagged.pop_front()
+ else {
+ continue;
+ };
+
+ mouse_button_state
+ } else {
+ bitflags_match!(mouse_button_input.flags, {
+ MouseButtonFlags::PRESSED => MouseButtonState::Pressed,
+ MouseButtonFlags::RELEASED => MouseButtonState::Released,
+ _ => unreachable!()
+ })
+ };
+
+ mouse_buttons.set(mouse_button, mouse_button_state);
+
+ mouse_button_input.flags.clear();
+ }
+
+ let mut key_updates = input.keys.iter_occupied_mut();
+
+ while let Some(mut key_item) = key_updates.streaming_next() {
+ let key = Key::KEYS[key_item.index];
+
+ if key_item.bits == KEY_PRESSED_BITS | KEY_RELEASED_BITS {
+ match keyboard.get_key_state(key) {
+ KeyState::Pressed => {
+ keyboard.set_key_state(key, KeyState::Released);
+
+ key_item.clear_and_set(KEY_PRESSED_BITS, u8::MAX);
+ }
+ KeyState::Released => {
+ keyboard.set_key_state(key, KeyState::Pressed);
+
+ key_item.clear_and_set(KEY_RELEASED_BITS, u8::MAX);
+ }
+ }
+
+ continue;
+ }
+
+ let key_state = match key_item.bits {
+ KEY_PRESSED_BITS => KeyState::Pressed,
+ KEY_RELEASED_BITS => KeyState::Released,
+ _ => unreachable!(),
+ };
+
+ keyboard.set_key_state(key, key_state);
+
+ key_item.clear_and_set(0, u8::MAX);
+ }
+
+ input.relative_mouse_pos_delta = Vec2 { x: 0.0, y: 0.0 };
+ input.mouse_scroll_delta = MouseScrollDelta { vert_lines: 0.0, hor_lines: 0.0 };
+ };
+
+ keyboard.set_text_keys(iter_array_queue(&context.shared_state.text_keys));
}
fn handle_window_changed(
@@ -442,6 +462,7 @@ pub struct Context
impl Context
{
+ #[must_use]
pub fn display_handle(&self) -> Option<DisplayHandle<'_>>
{
self.display_handle.as_ref()?.display_handle().ok()
@@ -451,6 +472,7 @@ impl Context
///
/// # Safety
/// The Window handle must only be used with thread safe APIs.
+ #[must_use]
pub unsafe fn get_window_as_handle(
&self,
window_id: &WindowId,
@@ -476,6 +498,7 @@ impl Context
/// Returns the last known primary monitor. This monitor may or may not exist any
/// longer and it may or may not be the primary monitor any longer.
+ #[must_use]
pub fn get_primary_monitor(&self) -> Option<&MonitorHandle>
{
self.primary_monitor.as_ref()
@@ -509,11 +532,12 @@ impl Context
///
/// # Panics
/// Will panic if a windowing context have already been created.
- pub fn new() -> Self
+ pub fn new_global() -> Self
{
- if CONTEXT_CREATED.swap(true, Ordering::Relaxed) {
- panic!("A windowing context have already been created");
- }
+ assert!(
+ !CONTEXT_CREATED.swap(true, Ordering::Relaxed),
+ "A windowing context have already been created"
+ );
let shared_state = Arc::new(SharedState::default());
let shared_state_b = shared_state.clone();
@@ -521,58 +545,7 @@ impl Context
if let Err(err) = ThreadBuilder::new()
.name("windowing app".to_string())
.spawn(move || {
- let shared_state_c = shared_state_b.clone();
-
- match catch_unwind(move || {
- let mut app = App {
- shared_state: shared_state_b,
- windows: IntMap::with_capacity(1),
- };
-
- let event_loop = match create_event_loop() {
- Ok(event_loop) => event_loop,
- Err(err) => {
- return Err((app, AppThreadError::CreateEventLoop(err)));
- }
- };
-
- event_loop.set_control_flow(EventLoopControlFlow::Poll);
-
- event_loop
- .run_app(&mut app)
- .map_err(|err| (app, AppThreadError::StartEventLoop(err)))?;
-
- Ok(())
- }) {
- Ok(Ok(())) => {}
- Ok(Err((app, err))) => {
- {
- let Ok(mut thread_err) =
- app.shared_state.thread_err.try_lock()
- else {
- // The thread_err mutex is only locked by the main thread
- // when the has_thread_err atomic is set to true, which
- // it can not be set to yet
- unreachable!();
- };
-
- *thread_err = Some(err);
- }
-
- app.shared_state
- .has_thread_err
- .store(true, Ordering::Relaxed);
-
- app.shared_state.init_data_cond.notify_one();
- }
- Err(_) => {
- shared_state_c
- .thread_panicked
- .store(true, Ordering::Relaxed);
-
- shared_state_c.init_data_cond.notify_one();
- }
- };
+ app_thread_main(shared_state_b);
})
{
tracing::error!(
@@ -664,6 +637,58 @@ impl Drop for Context
}
}
+fn app_thread_main(shared_state: Arc<SharedState>)
+{
+ let shared_state_c = shared_state.clone();
+
+ match catch_unwind(move || {
+ let mut app = App {
+ shared_state,
+ windows: IntMap::with_capacity(1),
+ };
+
+ let event_loop = match create_event_loop() {
+ Ok(event_loop) => event_loop,
+ Err(err) => {
+ return Err(AppThreadError::CreateEventLoop(err));
+ }
+ };
+
+ event_loop.set_control_flow(EventLoopControlFlow::Poll);
+
+ event_loop
+ .run_app(&mut app)
+ .map_err(AppThreadError::StartEventLoop)?;
+
+ Ok(())
+ }) {
+ Ok(Ok(())) => {}
+ Ok(Err(err)) => {
+ {
+ let Ok(mut thread_err) = shared_state_c.thread_err.try_lock() else {
+ // The thread_err mutex is only locked by the main thread
+ // when the has_thread_err atomic is set to true, which
+ // it can not be set to yet
+ unreachable!();
+ };
+
+ *thread_err = Some(err);
+ }
+
+ shared_state_c.has_thread_err.store(true, Ordering::Relaxed);
+
+ shared_state_c.init_data_cond.notify_one();
+ }
+ Err(_) => {
+ shared_state_c
+ .thread_panicked
+ .store(true, Ordering::Relaxed);
+
+ shared_state_c.init_data_cond.notify_one();
+ }
+ };
+}
+
fn create_event_loop() -> Result<EventLoop<()>, EventLoopError>
{
let mut event_loop_builder = EventLoop::builder();
@@ -702,10 +727,16 @@ enum AppThreadError
#[derive(Debug)]
enum MessageFromApp
{
- WindowCreated(Uid, Arc<WinitWindow>, WindowCreationAttributes),
- WindowResized(WindowId, PhysicalSize<u32>),
- WindowCloseRequested(WindowId),
- WindowScaleFactorChanged(WindowId, f64),
+ Window(WindowMessage),
+}
+
+#[derive(Debug)]
+enum WindowMessage
+{
+ Created(Uid, Arc<WinitWindow>, WindowCreationAttributes),
+ Resized(WindowId, PhysicalSize<u32>),
+ CloseRequested(WindowId),
+ ScaleFactorChanged(WindowId, f64),
}
#[derive(Debug)]
@@ -855,11 +886,11 @@ impl App
),
);
- self.send_message(MessageFromApp::WindowCreated(
+ self.send_message(MessageFromApp::Window(WindowMessage::Created(
window_ent_id,
winit_window,
window_creation_attrs,
- ));
+ )));
}
MessageToApp::SetWindowCursorGrabMode(window_id, cursor_grab_mode) => {
let Some((_, window_settings)) = self.windows.get_mut(window_id)
@@ -896,6 +927,153 @@ impl App
.input
.try_lock_for(Duration::from_millis(100))
}
+
+ fn handle_keyboard_input(&self, keyboard_event: winit::event::KeyEvent)
+ {
+ if let Some(key_text) = keyboard_event
+ .text
+ .filter(|_| keyboard_event.state.is_pressed())
+ {
+ for character in key_text.chars() {
+ if self.shared_state.text_keys.is_full() {
+ cold_path();
+ tracing::warn!("Text key queue is full. Dropping oldest character");
+ }
+
+ self.shared_state.text_keys.force_push(character);
+ }
+ }
+
+ if keyboard_event.repeat {
+ return;
+ }
+
+ let key_code = match keyboard_event.physical_key {
+ PhysicalKey::Code(key_code) => key_code,
+ PhysicalKey::Unidentified(native_key) => {
+ tracing::warn!("Ignoring unidentified key: {native_key:?}");
+ return;
+ }
+ };
+
+ let key: Key = if let Ok(key) = key_code.try_into() {
+ key
+ } else {
+ tracing::warn!("Ignoring key with unknown key code {key_code:?}");
+ return;
+ };
+
+ let Some(mut input) = self.lock_input() else {
+ tracing::error!("Locking input mutex timed out after 100ms");
+ return;
+ };
+
+ let key_state_bits = match keyboard_event.state.into() {
+ KeyState::Pressed => KEY_PRESSED_BITS,
+ KeyState::Released => KEY_RELEASED_BITS,
+ };
+
+ input.keys.clear_and_set(key as usize, key_state_bits, 0);
+ }
+
+ fn handle_cursor_moved(&self, position: PhysicalPosition<f64>, window_id: WindowId)
+ {
+ {
+ let Some(mut input) = self.lock_input() else {
+ tracing::error!("Locking input mutex timed out after 100ms");
+ return;
+ };
+
+ input.absolute_mouse_pos = position;
+ }
+
+ let Some((window, window_settings)) = self.windows.get(window_id) else {
+ cold_path();
+ return;
+ };
+
+ if window_settings.cursor_grab_mode != CursorGrabMode::Locked {
+ return;
+ }
+
+ let Some(window) = window.upgrade() else {
+ cold_path();
+ return;
+ };
+
+ if !window.has_focus() {
+ return;
+ }
+
+ let window_size = window.inner_size().to_logical::<f64>(window.scale_factor());
+
+ if let Err(err) = window.set_cursor_position(Position::Logical(LogicalPosition {
+ x: window_size.width / 2.0,
+ y: window_size.height / 2.0,
+ })) {
+ cold_path();
+ tracing::error!(
+ window_id=?window_id,
+ "Failed to lock cursor position: {:#}",
+ crate::Error::new(err)
+ );
+ }
+ }
+
+ fn handle_mouse_wheel(&self, delta: winit::event::MouseScrollDelta)
+ {
+ let (hor_lines, vert_lines) = match delta {
+ winit::event::MouseScrollDelta::LineDelta(hor_lines, vert_lines) => {
+ (hor_lines, vert_lines)
+ }
+ winit::event::MouseScrollDelta::PixelDelta(pos_delta) => {
+ let hor_lines = match pos_delta.x.partial_cmp(&0.0) {
+ Some(std::cmp::Ordering::Greater) => 1.0,
+ Some(std::cmp::Ordering::Less) => -1.0,
+ _ => 0.0,
+ };
+
+ let vert_lines = match pos_delta.y.partial_cmp(&0.0) {
+ Some(std::cmp::Ordering::Greater) => 1.0,
+ Some(std::cmp::Ordering::Less) => -1.0,
+ _ => 0.0,
+ };
+
+ (hor_lines, vert_lines)
+ }
+ };
+
+ let Some(mut input) = self.lock_input() else {
+ tracing::error!("Locking input mutex timed out after 100ms");
+ return;
+ };
+
+ input.mouse_scroll_delta.hor_lines += hor_lines;
+ input.mouse_scroll_delta.vert_lines += vert_lines;
+ }
+
+ fn handle_mouse_input(&self, button: MouseButton, button_state: MouseButtonState)
+ {
+ let Some(mut input) = self.lock_input() else {
+ tracing::error!("Locking input mutex timed out after 100ms");
+ return;
+ };
+
+ let button_input = input
+ .mouse_buttons
+ .entry(button)
+ .or_insert_with(MouseButtonInput::default);
+
+ if button_input.flags.is_all() || !button_input.lagged.is_empty() {
+ button_input.lagged.push_back(button_state);
+ return;
+ }
+
+ button_input.flags.insert(match button_state {
+ MouseButtonState::Pressed => MouseButtonFlags::PRESSED,
+ MouseButtonState::Released => MouseButtonFlags::RELEASED,
+ });
+ }
}
impl ApplicationHandler for App
@@ -917,10 +1095,10 @@ impl ApplicationHandler for App
*init_data = Some(InitData {
display: event_loop.owned_display_handle(),
- available_monitors: available_monitors,
+ available_monitors,
primary_monitor: event_loop
.primary_monitor()
- .map(|monitor| MonitorHandle::from_winit_monitor_handle(monitor)),
+ .map(MonitorHandle::from_winit_monitor_handle),
});
self.shared_state.init_data_cond.notify_one();
@@ -960,173 +1138,39 @@ impl ApplicationHandler for App
{
match event {
WindowEvent::Resized(new_window_size) => {
- self.send_message(MessageFromApp::WindowResized(
+ self.send_message(MessageFromApp::Window(WindowMessage::Resized(
WindowId::from_inner(window_id),
new_window_size.into(),
- ));
+ )));
}
WindowEvent::CloseRequested => {
- self.send_message(MessageFromApp::WindowCloseRequested(
+ self.send_message(MessageFromApp::Window(WindowMessage::CloseRequested(
WindowId::from_inner(window_id),
- ));
+ )));
}
WindowEvent::KeyboardInput {
device_id: _,
event: keyboard_event,
is_synthetic: _,
- } => {
- if let Some(key_text) = keyboard_event
- .text
- .filter(|_| keyboard_event.state.is_pressed())
- {
- for character in key_text.chars() {
- if self.shared_state.text_keys.is_full() {
- cold_path();
- tracing::warn!(
- "Text key queue is full. Dropping oldest character"
- );
- }
-
- self.shared_state.text_keys.force_push(character);
- }
- }
-
- if keyboard_event.repeat {
- return;
- }
-
- let key_code = match keyboard_event.physical_key {
- PhysicalKey::Code(key_code) => key_code,
- PhysicalKey::Unidentified(native_key) => {
- tracing::warn!("Ignoring unidentified key: {native_key:?}");
- return;
- }
- };
-
- let key: Key = match key_code.try_into() {
- Ok(key) => key,
- Err(UnknownKeyCodeError) => {
- tracing::warn!("Ignoring key with unknown key code {key_code:?}");
- return;
- }
- };
-
- let Some(mut input) = self.lock_input() else {
- tracing::error!("Locking input mutex timed out after 100ms");
- return;
- };
-
- let key_state_bits = match keyboard_event.state.into() {
- KeyState::Pressed => KEY_PRESSED_BITS,
- KeyState::Released => KEY_RELEASED_BITS,
- };
-
- input.keys.clear_and_set(key as usize, key_state_bits, 0);
- }
+ } => self.handle_keyboard_input(keyboard_event),
WindowEvent::CursorMoved { device_id: _, position } => {
- {
- let Some(mut input) = self.lock_input() else {
- tracing::error!("Locking input mutex timed out after 100ms");
- return;
- };
-
- input.absolute_mouse_pos = position.into();
- }
-
- let Some((window, window_settings)) =
- self.windows.get(WindowId::from_inner(window_id))
- else {
- cold_path();
- return;
- };
-
- if window_settings.cursor_grab_mode != CursorGrabMode::Locked {
- return;
- }
-
- let Some(window) = window.upgrade() else {
- cold_path();
- return;
- };
-
- if !window.has_focus() {
- return;
- }
-
- let window_size = window.inner_size();
-
- if let Err(err) =
- window.set_cursor_position(Position::Physical(PhysicalPosition {
- x: window_size.width as i32 / 2,
- y: window_size.height as i32 / 2,
- }))
- {
- cold_path();
- tracing::error!(
- window_id=?window_id,
- "Failed to lock cursor position: {:#}",
- crate::Error::new(err)
- );
- };
+ self.handle_cursor_moved(
+ position.into(),
+ WindowId::from_inner(window_id),
+ );
}
WindowEvent::MouseWheel { device_id: _, delta, phase: _ } => {
- let (hor_lines, vert_lines) = match delta {
- winit::event::MouseScrollDelta::LineDelta(hor_lines, vert_lines) => {
- (hor_lines, vert_lines)
- }
- winit::event::MouseScrollDelta::PixelDelta(pos_delta) => {
- let hor_lines = match pos_delta.x.partial_cmp(&0.0) {
- Some(std::cmp::Ordering::Greater) => 1.0,
- Some(std::cmp::Ordering::Less) => -1.0,
- _ => 0.0,
- };
-
- let vert_lines = match pos_delta.y.partial_cmp(&0.0) {
- Some(std::cmp::Ordering::Greater) => 1.0,
- Some(std::cmp::Ordering::Less) => -1.0,
- _ => 0.0,
- };
-
- (hor_lines, vert_lines)
- }
- };
-
- let Some(mut input) = self.lock_input() else {
- tracing::error!("Locking input mutex timed out after 100ms");
- return;
- };
-
- input.mouse_scroll_delta.hor_lines += hor_lines;
- input.mouse_scroll_delta.vert_lines += vert_lines;
+ self.handle_mouse_wheel(delta);
}
WindowEvent::MouseInput { device_id: _, state, button } => {
- let Some(mut input) = self.lock_input() else {
- tracing::error!("Locking input mutex timed out after 100ms");
- return;
- };
-
- let button = MouseButton::from(button);
- let button_state = MouseButtonState::from(state);
-
- let button_input = input
- .mouse_buttons
- .entry(button)
- .or_insert_with(|| MouseButtonInput::default());
-
- if button_input.flags.is_all() || !button_input.lagged.is_empty() {
- button_input.lagged.push_back(button_state);
- return;
- }
-
- button_input.flags.insert(match button_state {
- MouseButtonState::Pressed => MouseButtonFlags::PRESSED,
- MouseButtonState::Released => MouseButtonFlags::RELEASED,
- });
+ self.handle_mouse_input(button.into(), state.into());
}
WindowEvent::ScaleFactorChanged { scale_factor, inner_size_writer: _ } => {
- self.send_message(MessageFromApp::WindowScaleFactorChanged(
- WindowId::from_inner(window_id),
- scale_factor,
+ self.send_message(MessageFromApp::Window(
+ WindowMessage::ScaleFactorChanged(
+ WindowId::from_inner(window_id),
+ scale_factor,
+ ),
));
}
_ => {}
@@ -1141,16 +1185,13 @@ impl ApplicationHandler for App
device_event: DeviceEvent,
)
{
- match device_event {
- DeviceEvent::MouseMotion { delta } => {
- let Some(mut input) = self.lock_input() else {
- tracing::error!("Locking input mutex timed out after 100ms");
- return;
- };
+ if let DeviceEvent::MouseMotion { delta } = device_event {
+ let Some(mut input) = self.lock_input() else {
+ tracing::error!("Locking input mutex timed out after 100ms");
+ return;
+ };
- input.relative_mouse_pos_delta += Vec2::from(delta);
- }
- _ => {}
+ input.relative_mouse_pos_delta += Vec2::from(delta);
}
}
}