use crate::Vec2;
use std::cell::Cell;
use std::rc::Rc;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct PointerId(pub u64);
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PointerKind {
Mouse,
Touch,
Pen,
}
#[derive(Clone, Copy, Debug)]
pub enum PointerButton {
Primary, Secondary, Tertiary, }
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PointerEventPass {
Initial,
Main,
Final,
}
#[derive(Clone, Copy, Debug)]
pub enum PointerEventKind {
Down(PointerButton),
Up(PointerButton),
Move,
Cancel,
Enter,
Leave,
}
#[derive(Clone, Debug)]
pub struct PointerEvent {
pub id: PointerId,
pub kind: PointerKind,
pub event: PointerEventKind,
pub position: Vec2,
pub origin: Vec2,
pub pressure: f32,
pub modifiers: Modifiers,
pub consumed: Rc<Cell<bool>>,
}
impl PointerEvent {
pub fn new(
id: PointerId,
kind: PointerKind,
event: PointerEventKind,
position: Vec2,
pressure: f32,
modifiers: Modifiers,
) -> Self {
Self {
id,
kind,
event,
position,
origin: Vec2::ZERO,
pressure,
modifiers,
consumed: Rc::new(Cell::new(false)),
}
}
pub fn position_in_window(&self) -> Vec2 {
self.position + self.origin
}
pub fn consume(&self) {
self.consumed.set(true);
}
pub fn is_consumed(&self) -> bool {
self.consumed.get()
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct Modifiers {
pub shift: bool,
pub ctrl: bool,
pub alt: bool,
pub meta: bool, pub command: bool, }
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Key {
Character(char),
Enter,
Tab,
Backspace,
Delete,
Insert,
Escape,
ArrowLeft,
ArrowRight,
ArrowUp,
ArrowDown,
Home,
End,
PageUp,
PageDown,
Space,
F(u8), Unknown,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum KeyEventType {
Down,
Up,
Unknown,
}
#[derive(Clone, Debug)]
pub struct KeyEvent {
pub key: Key,
pub modifiers: Modifiers,
pub is_repeat: bool,
pub event_type: KeyEventType,
pub utf16_code_point: u16,
}
#[derive(Clone, Debug)]
pub struct TextInputEvent {
pub text: String,
}
#[derive(Clone, Debug)]
pub enum ImeEvent {
Start,
Update {
text: String,
cursor: Option<(usize, usize)>, },
Commit(String),
Cancel,
}
#[derive(Clone, Debug)]
pub enum InputEvent {
Pointer(PointerEvent),
Key(KeyEvent),
Text(TextInputEvent),
Ime(ImeEvent),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
pub enum InputMode {
#[default]
Touch,
Keyboard,
}
thread_local! {
static INPUT_MODE: Cell<InputMode> = const { Cell::new(InputMode::Touch) };
}
#[inline]
pub fn input_mode() -> InputMode {
crate::locals::local_input_mode().unwrap_or_else(|| INPUT_MODE.get())
}
#[inline]
pub fn set_input_mode_default(mode: InputMode) {
INPUT_MODE.set(mode);
}
pub fn request_input_mode(mode: InputMode) -> bool {
let prev = INPUT_MODE.get();
if prev == mode {
return false;
}
INPUT_MODE.set(mode);
crate::frame_clock::request_frame();
true
}
#[inline]
pub fn is_focus_visible(focused: bool) -> bool {
focused && input_mode() == InputMode::Keyboard
}
#[cfg(test)]
mod input_mode_tests {
use super::*;
use crate::frame_clock::take_frame_request;
use crate::modifier::{Interaction, MutableInteractionSource};
#[test]
fn request_input_mode_changes_and_requests_frame() {
set_input_mode_default(InputMode::Touch);
let _ = take_frame_request();
assert!(!request_input_mode(InputMode::Touch));
assert!(!take_frame_request());
assert!(request_input_mode(InputMode::Keyboard));
assert_eq!(input_mode(), InputMode::Keyboard);
assert!(take_frame_request());
assert!(request_input_mode(InputMode::Touch));
assert_eq!(input_mode(), InputMode::Touch);
set_input_mode_default(InputMode::Touch);
}
#[test]
fn focus_visible_requires_keyboard_mode() {
set_input_mode_default(InputMode::Touch);
let src = MutableInteractionSource::new();
src.emit(Interaction::Focus);
assert!(src.source().collect_is_focused());
assert!(!src.source().collect_is_focus_visible());
set_input_mode_default(InputMode::Keyboard);
assert!(src.source().collect_is_focus_visible());
set_input_mode_default(InputMode::Touch);
src.emit(Interaction::Unfocus);
}
#[test]
fn with_input_mode_overrides_global() {
set_input_mode_default(InputMode::Touch);
crate::locals::with_input_mode(InputMode::Keyboard, || {
assert_eq!(input_mode(), InputMode::Keyboard);
});
assert_eq!(input_mode(), InputMode::Touch);
}
}