use std::sync::{Arc, RwLock};
use crate::application::prelude::{LifecycleListener, LifecycleListenerHandle};
use crate::window::prelude::{Event, EventListener, EventListenerHandle};
use super::events::InputEvent;
use super::keyboard::{Key, Keyboard};
use super::mouse::{Mouse, MouseButton};
use super::touchpad::{GesturePan, GestureTap, TouchPad, TouchState};
use super::InputParams;
use crate::math::prelude::Vector2;
pub struct InputSystem {
events: EventListenerHandle,
lifecycle: LifecycleListenerHandle,
state: Arc<InputState>,
}
struct InputState {
touch_emulation: bool,
touch_emulation_button: RwLock<Option<MouseButton>>,
mouse: RwLock<Mouse>,
keyboard: RwLock<Keyboard>,
touchpad: RwLock<TouchPad>,
}
impl EventListener for Arc<InputState> {
fn on(&mut self, v: &Event) -> Result<(), failure::Error> {
if let Event::InputDevice(v) = *v {
match v {
InputEvent::MouseMoved { position } => {
if self.touch_emulation_button.read().unwrap().is_some() {
self.touchpad.write().unwrap().on_touch(
255,
TouchState::Move,
self.mouse.read().unwrap().position(),
);
}
self.mouse.write().unwrap().on_move(position)
}
InputEvent::MousePressed { button } => {
if self.touch_emulation {
*self.touch_emulation_button.write().unwrap() = Some(button);
self.touchpad.write().unwrap().on_touch(
255,
TouchState::Start,
self.mouse.read().unwrap().position(),
);
}
self.mouse.write().unwrap().on_button_pressed(button)
}
InputEvent::MouseReleased { button } => {
if *self.touch_emulation_button.read().unwrap() == Some(button) {
*self.touch_emulation_button.write().unwrap() = None;
self.touchpad.write().unwrap().on_touch(
255,
TouchState::End,
self.mouse.read().unwrap().position(),
);
}
self.mouse.write().unwrap().on_button_released(button)
}
InputEvent::MouseWheel { delta } => {
self.mouse.write().unwrap().on_wheel_scroll(delta)
}
InputEvent::KeyboardPressed { key } => {
self.keyboard.write().unwrap().on_key_pressed(key)
}
InputEvent::KeyboardReleased { key } => {
self.keyboard.write().unwrap().on_key_released(key)
}
InputEvent::ReceivedCharacter { character } => {
self.keyboard.write().unwrap().on_char(character)
}
InputEvent::Touch {
id,
state,
position,
} => {
self.touchpad.write().unwrap().on_touch(id, state, position);
}
}
}
Ok(())
}
}
impl LifecycleListener for Arc<InputState> {
fn on_post_update(&mut self) -> Result<(), failure::Error> {
self.mouse.write().unwrap().advance();
self.keyboard.write().unwrap().advance();
self.touchpad.write().unwrap().advance();
Ok(())
}
}
impl Drop for InputSystem {
fn drop(&mut self) {
crate::application::detach(self.lifecycle);
crate::window::detach(self.events);
}
}
impl InputSystem {
pub fn new(setup: InputParams) -> Self {
debug_assert!(crate::application::valid(), "");
let state = Arc::new(InputState {
touch_emulation: setup.touch_emulation,
touch_emulation_button: RwLock::new(None),
mouse: RwLock::new(Mouse::new(setup.mouse)),
keyboard: RwLock::new(Keyboard::new(setup.keyboard)),
touchpad: RwLock::new(TouchPad::new(setup.touchpad)),
});
InputSystem {
state: state.clone(),
lifecycle: crate::application::attach(state.clone()),
events: crate::window::attach(state),
}
}
pub fn reset(&self) {
self.state.mouse.write().unwrap().reset();
self.state.keyboard.write().unwrap().reset();
self.state.touchpad.write().unwrap().reset();
*self.state.touch_emulation_button.write().unwrap() = None;
}
#[inline]
pub fn has_keyboard_attached(&self) -> bool {
true
}
#[inline]
pub fn is_key_down(&self, key: Key) -> bool {
self.state.keyboard.read().unwrap().is_key_down(key)
}
#[inline]
pub fn is_key_press(&self, key: Key) -> bool {
self.state.keyboard.read().unwrap().is_key_press(key)
}
#[inline]
pub fn is_key_release(&self, key: Key) -> bool {
self.state.keyboard.read().unwrap().is_key_release(key)
}
#[inline]
pub fn is_key_repeat(&self, key: Key) -> bool {
self.state.keyboard.read().unwrap().is_key_repeat(key)
}
#[inline]
pub fn text(&self) -> String {
use std::iter::FromIterator;
String::from_iter(self.state.keyboard.read().unwrap().captured_chars())
}
#[inline]
pub fn has_mouse_attached(&self) -> bool {
true
}
#[inline]
pub fn is_mouse_down(&self, button: MouseButton) -> bool {
self.state.mouse.read().unwrap().is_button_down(button)
}
#[inline]
pub fn is_mouse_press(&self, button: MouseButton) -> bool {
self.state.mouse.read().unwrap().is_button_press(button)
}
#[inline]
pub fn is_mouse_release(&self, button: MouseButton) -> bool {
self.state.mouse.read().unwrap().is_button_release(button)
}
#[inline]
pub fn is_mouse_click(&self, button: MouseButton) -> bool {
self.state.mouse.read().unwrap().is_button_click(button)
}
#[inline]
pub fn is_mouse_double_click(&self, button: MouseButton) -> bool {
self.state
.mouse
.read()
.unwrap()
.is_button_double_click(button)
}
#[inline]
pub fn mouse_position(&self) -> Vector2<f32> {
self.state.mouse.read().unwrap().position()
}
#[inline]
pub fn mouse_movement(&self) -> Vector2<f32> {
self.state.mouse.read().unwrap().movement()
}
#[inline]
pub fn mouse_scroll(&self) -> Vector2<f32> {
self.state.mouse.read().unwrap().scroll()
}
#[inline]
pub fn has_touchpad_attached(&self) -> bool {
true
}
#[inline]
pub fn is_finger_touched(&self, n: usize) -> bool {
self.state.touchpad.read().unwrap().is_touched(n)
}
#[inline]
pub fn finger_position(&self, n: usize) -> Option<Vector2<f32>> {
self.state.touchpad.read().unwrap().position(n)
}
#[inline]
pub fn finger_tap(&self) -> GestureTap {
self.state.touchpad.read().unwrap().tap()
}
#[inline]
pub fn finger_double_tap(&self) -> GestureTap {
self.state.touchpad.read().unwrap().double_tap()
}
#[inline]
pub fn finger_pan(&self) -> GesturePan {
self.state.touchpad.read().unwrap().pan()
}
}