use std::{collections::HashMap, fmt};
use crate::event::*;
use zng_layout::unit::euclid;
use zng_var::{Var, var};
use zng_view_api::{
keyboard::{KeyCode, KeyState},
mouse::{ButtonId, ButtonState, MouseScrollDelta},
};
pub use zng_view_api::AxisId;
pub use zng_view_api::raw_input::{InputDeviceCapability, InputDeviceInfo};
use once_cell::sync::Lazy;
zng_unique_id::unique_id_64! {
pub struct InputDeviceId;
}
zng_unique_id::impl_unique_id_bytemuck!(InputDeviceId);
impl InputDeviceId {
pub fn virtual_keyboard() -> InputDeviceId {
static ID: Lazy<InputDeviceId> = Lazy::new(InputDeviceId::new_unique);
*ID
}
pub fn virtual_mouse() -> InputDeviceId {
static ID: Lazy<InputDeviceId> = Lazy::new(InputDeviceId::new_unique);
*ID
}
pub fn virtual_generic() -> InputDeviceId {
static ID: Lazy<InputDeviceId> = Lazy::new(InputDeviceId::new_unique);
*ID
}
}
impl fmt::Debug for InputDeviceId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
f.debug_struct("InputDeviceId")
.field("id", &self.get())
.field("sequential", &self.sequential())
.finish()
} else {
write!(f, "InputDeviceId({})", self.sequential())
}
}
}
impl fmt::Display for InputDeviceId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "InputDeviceId({})", self.get())
}
}
event_args! {
pub struct InputDevicesChangedArgs {
pub devices: HashMap<InputDeviceId, InputDeviceInfo>,
..
fn is_in_target(&self, id: WidgetId) -> bool {
true
}
}
pub struct PointerMotionArgs {
pub device_id: InputDeviceId,
pub delta: euclid::Vector2D<f64, ()>,
..
fn is_in_target(&self, id: WidgetId) -> bool {
true
}
}
pub struct ScrollMotionArgs {
pub device_id: InputDeviceId,
pub delta: MouseScrollDelta,
..
fn is_in_target(&self, id: WidgetId) -> bool {
true
}
}
pub struct AxisMotionArgs {
pub device_id: InputDeviceId,
pub axis: AxisId,
pub value: f64,
..
fn is_in_target(&self, id: WidgetId) -> bool {
true
}
}
pub struct ButtonArgs {
pub device_id: InputDeviceId,
pub button: ButtonId,
pub state: ButtonState,
..
fn is_in_target(&self, id: WidgetId) -> bool {
true
}
}
pub struct KeyArgs {
pub device_id: InputDeviceId,
pub key_code: KeyCode,
pub state: KeyState,
..
fn is_in_target(&self, id: WidgetId) -> bool {
true
}
}
}
event! {
pub static INPUT_DEVICES_CHANGED_EVENT: InputDevicesChangedArgs;
pub static POINTER_MOTION_EVENT: PointerMotionArgs;
pub static SCROLL_MOTION_EVENT: ScrollMotionArgs;
pub static AXIS_MOTION_EVENT: AxisMotionArgs;
pub static BUTTON_EVENT: ButtonArgs;
pub static KEY_EVENT: KeyArgs;
}
#[allow(non_camel_case_types)]
pub struct INPUT_DEVICES;
impl INPUT_DEVICES {
pub fn available_devices(&self) -> Var<HashMap<InputDeviceId, InputDeviceInfo>> {
INPUT_DEVICES_SV.read().devices.read_only()
}
pub fn device(&self, id: InputDeviceId) -> Var<InputDeviceInfo> {
INPUT_DEVICES_SV.read().devices.map(move |m| {
m.get(&id)
.cloned()
.unwrap_or_else(|| InputDeviceInfo::new("Unknown Input Device", InputDeviceCapability::empty()))
})
}
pub(crate) fn update(&self, devices: HashMap<InputDeviceId, InputDeviceInfo>) {
INPUT_DEVICES_SV.read().devices.set(devices);
}
}
struct InputDevicesSv {
devices: Var<HashMap<InputDeviceId, InputDeviceInfo>>,
}
app_local! {
static INPUT_DEVICES_SV: InputDevicesSv = InputDevicesSv {
devices: var(HashMap::new()),
};
}