use winit::dpi::PhysicalSize;
use winit::event::{DeviceEvent, MouseButton, WindowEvent};
use winit::keyboard::{Key, KeyCode, PhysicalKey};
use crate::current_input::{
mouse_button_to_int, CurrentInput, KeyAction, MouseAction, ScanCodeAction,
};
use std::{path::PathBuf, time::Duration};
use web_time::Instant;
#[derive(Clone)]
pub struct WinitInputHelper {
current: Option<CurrentInput>,
dropped_file: Option<PathBuf>,
window_resized: Option<PhysicalSize<u32>>,
window_size: Option<(u32, u32)>,
scale_factor_changed: Option<f64>,
scale_factor: Option<f64>,
destroyed: bool,
close_requested: bool,
step_start: Option<Instant>,
step_duration: Option<Duration>,
}
impl Default for WinitInputHelper {
fn default() -> Self {
Self::new()
}
}
impl WinitInputHelper {
pub fn new() -> WinitInputHelper {
WinitInputHelper {
current: Some(CurrentInput::new()),
dropped_file: None,
window_resized: None,
window_size: None,
scale_factor_changed: None,
scale_factor: None,
destroyed: false,
close_requested: false,
step_start: None,
step_duration: None,
}
}
pub fn step(&mut self) {
self.dropped_file = None;
self.window_resized = None;
self.scale_factor_changed = None;
self.close_requested = false;
self.step_start.get_or_insert(Instant::now());
self.step_duration = None;
if let Some(current) = &mut self.current {
current.step();
}
}
pub fn process_window_event(&mut self, event: &WindowEvent) -> bool {
let mut received_redraw_request = false;
match event {
WindowEvent::CloseRequested => self.close_requested = true,
WindowEvent::Destroyed => self.destroyed = true,
WindowEvent::Focused(false) => self.current = None,
WindowEvent::Focused(true) => {
if self.current.is_none() {
self.current = Some(CurrentInput::new())
}
}
WindowEvent::DroppedFile(path) => self.dropped_file = Some(path.clone()),
WindowEvent::Resized(size) => {
self.window_resized = Some(*size);
self.window_size = Some((*size).into());
}
WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
self.scale_factor_changed = Some(*scale_factor);
self.scale_factor = Some(*scale_factor);
}
WindowEvent::RedrawRequested => {
received_redraw_request = true;
}
_ => {}
}
if let Some(current) = &mut self.current {
current.handle_event(event);
}
received_redraw_request
}
pub fn process_device_event(&mut self, event: &DeviceEvent) {
if let Some(ref mut current) = self.current {
current.handle_device_event(event);
}
}
pub fn end_step(&mut self) {
self.step_duration = self.step_start.map(|start| start.elapsed());
self.step_start = Some(Instant::now());
}
pub fn key_pressed(&self, keycode: KeyCode) -> bool {
let key = PhysicalKey::Code(keycode);
if let Some(current) = &self.current {
let searched_action = ScanCodeAction::Pressed(key);
if current.scancode_actions.contains(&searched_action) {
return true;
}
}
false
}
pub fn key_pressed_os(&self, keycode: KeyCode) -> bool {
let key = PhysicalKey::Code(keycode);
if let Some(current) = &self.current {
let searched_action = ScanCodeAction::PressedOs(key);
if current.scancode_actions.contains(&searched_action) {
return true;
}
}
false
}
pub fn key_released(&self, keycode: KeyCode) -> bool {
let key = PhysicalKey::Code(keycode);
if let Some(current) = &self.current {
let searched_action = ScanCodeAction::Released(key);
if current.scancode_actions.contains(&searched_action) {
return true;
}
}
false
}
pub fn key_held(&self, keycode: KeyCode) -> bool {
let key = PhysicalKey::Code(keycode);
if let Some(current) = &self.current {
return current.scancode_held.contains(&key);
}
false
}
pub fn held_shift(&self) -> bool {
self.key_held(KeyCode::ShiftLeft) || self.key_held(KeyCode::ShiftRight)
}
pub fn held_control(&self) -> bool {
self.key_held(KeyCode::ControlLeft) || self.key_held(KeyCode::ControlRight)
}
pub fn held_alt(&self) -> bool {
self.key_held(KeyCode::AltLeft) || self.key_held(KeyCode::AltRight)
}
pub fn key_pressed_logical(&self, check_key: Key<&str>) -> bool {
if let Some(current) = &self.current {
for action in ¤t.key_actions {
if let KeyAction::Pressed(key) = action {
if key.as_ref() == check_key {
return true;
}
}
}
}
false
}
pub fn key_pressed_os_logical(&self, check_key: Key<&str>) -> bool {
if let Some(current) = &self.current {
for action in ¤t.key_actions {
if let KeyAction::PressedOs(key_code) = action {
if key_code.as_ref() == check_key {
return true;
}
}
}
}
false
}
pub fn key_released_logical(&self, check_key: Key<&str>) -> bool {
if let Some(current) = &self.current {
for action in ¤t.key_actions {
if let KeyAction::Released(key_code) = action {
if key_code.as_ref() == check_key {
return true;
}
}
}
}
false
}
pub fn key_held_logical(&self, check_key: Key<&str>) -> bool {
match &self.current {
Some(current) => current.key_held.iter().any(|x| x.as_ref() == check_key),
None => false,
}
}
pub fn mouse_pressed(&self, mouse_button: MouseButton) -> bool {
if let Some(current) = &self.current {
for action in ¤t.mouse_actions {
if let MouseAction::Pressed(key_code) = *action {
if key_code == mouse_button {
return true;
}
}
}
}
false
}
pub fn mouse_released(&self, mouse_button: MouseButton) -> bool {
if let Some(current) = &self.current {
for action in ¤t.mouse_actions {
if let MouseAction::Released(key_code) = *action {
if key_code == mouse_button {
return true;
}
}
}
}
false
}
pub fn mouse_held(&self, mouse_button: MouseButton) -> bool {
match &self.current {
Some(current) => current.mouse_held[mouse_button_to_int(&mouse_button)],
None => false,
}
}
pub fn scroll_diff(&self) -> (f32, f32) {
match &self.current {
Some(current) => (current.x_scroll_diff, current.y_scroll_diff),
None => (0.0, 0.0),
}
}
pub fn cursor(&self) -> Option<(f32, f32)> {
match &self.current {
Some(current) => current.cursor_point,
None => None,
}
}
pub fn cursor_diff(&self) -> (f32, f32) {
if let Some(current_input) = &self.current {
if let Some(cur) = current_input.cursor_point {
if let Some(prev) = current_input.cursor_point_prev {
return (cur.0 - prev.0, cur.1 - prev.1);
}
}
}
(0.0, 0.0)
}
pub fn mouse_diff(&self) -> (f32, f32) {
if let Some(current_input) = &self.current {
if let Some(diff) = current_input.mouse_diff {
return diff;
}
}
(0.0, 0.0)
}
pub fn text(&self) -> &[Key] {
match &self.current {
Some(current) => ¤t.text,
None => &[],
}
}
pub fn dropped_file(&self) -> Option<PathBuf> {
self.dropped_file.clone()
}
pub fn window_resized(&self) -> Option<PhysicalSize<u32>> {
self.window_resized
}
pub fn resolution(&self) -> Option<(u32, u32)> {
self.window_size
}
pub fn scale_factor_changed(&self) -> Option<f64> {
self.scale_factor_changed
}
pub fn scale_factor(&self) -> Option<f64> {
self.scale_factor
}
pub fn destroyed(&self) -> bool {
self.destroyed
}
pub fn close_requested(&self) -> bool {
self.close_requested
}
pub fn delta_time(&self) -> Option<Duration> {
self.step_duration
}
}