use teksilo_core::gesture::GestureEvent;
use teksilo_core::pointer::{EventTime, PointerSample, ScrollSample};
use crate::window_system::WindowSystem;
#[derive(Clone, Debug)]
pub enum InputSample {
Pointer(PointerSample),
Scroll(ScrollSample),
Gesture(GestureEvent),
}
impl InputSample {
pub fn as_pointer(&self) -> Option<&PointerSample> {
match self {
Self::Pointer(sample) => Some(sample),
_ => None,
}
}
pub fn as_scroll(&self) -> Option<&ScrollSample> {
match self {
Self::Scroll(sample) => Some(sample),
_ => None,
}
}
pub fn as_gesture(&self) -> Option<&GestureEvent> {
match self {
Self::Gesture(gesture) => Some(gesture),
_ => None,
}
}
}
#[non_exhaustive]
#[derive(Debug)]
pub enum BackendEvent<'a> {
Winit(&'a winit::event::WindowEvent),
}
impl<'a> From<&'a winit::event::WindowEvent> for BackendEvent<'a> {
fn from(event: &'a winit::event::WindowEvent) -> Self {
Self::Winit(event)
}
}
pub use teksilo_core::window::SoftKeyboardSupport;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum PlatformKind {
Windows,
MacOs,
Unix,
}
impl PlatformKind {
pub const HOST: Self = {
#[cfg(target_os = "windows")]
{
Self::Windows
}
#[cfg(target_os = "macos")]
{
Self::MacOs
}
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
{
Self::Unix
}
};
}
#[non_exhaustive]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
pub struct BackendCaps {
pub reports_cancel: bool,
pub reports_pressure: bool,
pub reports_tilt: bool,
pub reports_twist: bool,
pub reports_pen_kind: bool,
pub reports_palm: bool,
pub reports_scroll_phase: bool,
pub reports_os_momentum: bool,
pub reports_os_pinch: bool,
pub synthesises_mouse_from_touch: bool,
pub touch_window_drag: bool,
pub osk: SoftKeyboardSupport,
}
impl BackendCaps {
pub const fn for_platform(platform: PlatformKind, window_system: WindowSystem) -> Self {
match platform {
PlatformKind::Windows => Self {
reports_cancel: false,
reports_pressure: true,
reports_tilt: false,
reports_twist: false,
reports_pen_kind: false,
reports_palm: false,
reports_scroll_phase: false,
reports_os_momentum: false,
reports_os_pinch: false,
synthesises_mouse_from_touch: false,
touch_window_drag: false,
osk: crate::soft_keyboard::support_for(PlatformKind::Windows),
},
PlatformKind::MacOs => Self {
reports_cancel: false,
reports_pressure: false,
reports_tilt: false,
reports_twist: false,
reports_pen_kind: false,
reports_palm: false,
reports_scroll_phase: true,
reports_os_momentum: true,
reports_os_pinch: true,
synthesises_mouse_from_touch: false,
touch_window_drag: false,
osk: crate::soft_keyboard::support_for(PlatformKind::MacOs),
},
PlatformKind::Unix => match window_system {
WindowSystem::Wayland => Self {
reports_cancel: true,
reports_pressure: false,
reports_tilt: false,
reports_twist: false,
reports_pen_kind: false,
reports_palm: false,
reports_scroll_phase: true,
reports_os_momentum: false,
reports_os_pinch: false,
synthesises_mouse_from_touch: false,
touch_window_drag: false,
osk: crate::soft_keyboard::support_for(PlatformKind::Unix),
},
WindowSystem::X11 => Self {
reports_cancel: false,
reports_pressure: false,
reports_tilt: false,
reports_twist: false,
reports_pen_kind: false,
reports_palm: false,
reports_scroll_phase: false,
reports_os_momentum: false,
reports_os_pinch: false,
synthesises_mouse_from_touch: true,
touch_window_drag: false,
osk: crate::soft_keyboard::support_for(PlatformKind::Unix),
},
WindowSystem::Unknown => Self {
reports_cancel: false,
reports_pressure: false,
reports_tilt: false,
reports_twist: false,
reports_pen_kind: false,
reports_palm: false,
reports_scroll_phase: false,
reports_os_momentum: false,
reports_os_pinch: false,
synthesises_mouse_from_touch: false,
touch_window_drag: false,
osk: crate::soft_keyboard::support_for(PlatformKind::Unix),
},
},
}
}
}
pub trait PointerBackend {
fn translate(&mut self, event: &BackendEvent<'_>, now: EventTime) -> Vec<InputSample>;
fn capabilities(&self) -> BackendCaps;
fn cancel_all(&mut self, now: EventTime) -> Vec<InputSample>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn no_platform_offers_touch_window_drag() {
for platform in [PlatformKind::Windows, PlatformKind::MacOs] {
assert!(!BackendCaps::for_platform(platform, WindowSystem::Unknown).touch_window_drag);
}
for ws in [
WindowSystem::Wayland,
WindowSystem::X11,
WindowSystem::Unknown,
] {
assert!(!BackendCaps::for_platform(PlatformKind::Unix, ws).touch_window_drag);
}
}
#[test]
fn only_wayland_reports_cancel() {
assert!(
BackendCaps::for_platform(PlatformKind::Unix, WindowSystem::Wayland).reports_cancel
);
assert!(!BackendCaps::for_platform(PlatformKind::Unix, WindowSystem::X11).reports_cancel);
assert!(
!BackendCaps::for_platform(PlatformKind::Windows, WindowSystem::Unknown).reports_cancel
);
assert!(
!BackendCaps::for_platform(PlatformKind::MacOs, WindowSystem::Unknown).reports_cancel
);
}
#[test]
fn only_x11_promotes_touch_to_mouse() {
assert!(
BackendCaps::for_platform(PlatformKind::Unix, WindowSystem::X11)
.synthesises_mouse_from_touch
);
for (platform, ws) in [
(PlatformKind::Unix, WindowSystem::Wayland),
(PlatformKind::Unix, WindowSystem::Unknown),
(PlatformKind::Windows, WindowSystem::Unknown),
(PlatformKind::MacOs, WindowSystem::Unknown),
] {
assert!(!BackendCaps::for_platform(platform, ws).synthesises_mouse_from_touch);
}
}
#[test]
fn only_macos_owns_the_momentum() {
assert!(
BackendCaps::for_platform(PlatformKind::MacOs, WindowSystem::Unknown)
.reports_os_momentum
);
assert!(
!BackendCaps::for_platform(PlatformKind::Unix, WindowSystem::Wayland)
.reports_os_momentum
);
assert!(
!BackendCaps::for_platform(PlatformKind::Windows, WindowSystem::Unknown)
.reports_os_momentum
);
}
#[test]
fn the_soft_keyboard_is_windows_only_and_explicit() {
assert_eq!(
BackendCaps::for_platform(PlatformKind::Windows, WindowSystem::Unknown).osk,
SoftKeyboardSupport::Explicit
);
assert_eq!(
BackendCaps::for_platform(PlatformKind::Unix, WindowSystem::Wayland).osk,
SoftKeyboardSupport::None
);
assert_eq!(SoftKeyboardSupport::default(), SoftKeyboardSupport::None);
}
#[test]
fn an_unknown_backend_claims_nothing() {
assert_eq!(
BackendCaps::for_platform(PlatformKind::Unix, WindowSystem::Unknown),
BackendCaps::default()
);
}
}