Isolate winit imports to `app` module (#908)

This is the first step towards #907.

This doesn't split the crate yet, but adds a translation layer between
winit and Masonry to facilitate that split.
This commit is contained in:
Olivier FAURE 2025-03-23 11:21:35 +01:00 committed by GitHub
parent 125dab7949
commit 25a446029f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 889 additions and 96 deletions

15
Cargo.lock generated
View File

@ -496,6 +496,9 @@ name = "bitflags"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
dependencies = [
"serde",
]
[[package]]
name = "block"
@ -1758,6 +1761,17 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "keyboard-types"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a"
dependencies = [
"bitflags 2.8.0",
"serde",
"unicode-segmentation",
]
[[package]]
name = "khronos-egl"
version = "6.0.0"
@ -1894,6 +1908,7 @@ dependencies = [
"futures-intrusive",
"image",
"insta",
"keyboard-types",
"nv-flip",
"once_cell",
"parley",

View File

@ -58,6 +58,7 @@ nv-flip.workspace = true
tracing-tracy = { version = "0.11.3", optional = true }
wgpu-profiler = { optional = true, version = "0.19.0", default-features = false }
anymap3 = "1.0.1"
keyboard-types = "0.7.0"
[target.'cfg(target_arch = "wasm32")'.dependencies]
web-time.workspace = true

View File

@ -0,0 +1,633 @@
// Copyright 2025 the Xilem Authors
// SPDX-License-Identifier: Apache-2.0
// Most of this file is copy-pasted directly from
// https://github.com/DioxusLabs/blitz/blob/main/packages/blitz-shell/src/convert_events.rs
// Should be removed once https://github.com/rust-windowing/winit/pull/4026 is merged.
use keyboard_types::KeyState;
use keyboard_types::{Code, Key, KeyboardEvent, Location, Modifiers};
use winit::event::ElementState;
use winit::event::Force as WinitForce;
use winit::event::Ime as WinitIme;
use winit::event::KeyEvent as WinitKeyEvent;
use winit::event::MouseButton as WinitMouseButton;
use winit::keyboard::Key as WinitKey;
use winit::keyboard::KeyCode as WinitKeyCode;
use winit::keyboard::KeyLocation as WinitKeyLocation;
use winit::keyboard::ModifiersState as WinitModifiers;
use winit::keyboard::NamedKey as WinitNamedKey;
use winit::keyboard::PhysicalKey as WinitPhysicalKey;
use winit::window::ResizeDirection as WinitResizeDirection;
use crate::core::{Force, Ime, PointerButton, ResizeDirection};
pub(crate) fn winit_mouse_button_to_masonry(button: WinitMouseButton) -> PointerButton {
match button {
WinitMouseButton::Left => PointerButton::Primary,
WinitMouseButton::Right => PointerButton::Secondary,
WinitMouseButton::Middle => PointerButton::Auxiliary,
WinitMouseButton::Back => PointerButton::X1,
WinitMouseButton::Forward => PointerButton::X2,
WinitMouseButton::Other(_) => PointerButton::Other,
}
}
pub(crate) fn masonry_resize_direction_to_winit(dir: ResizeDirection) -> WinitResizeDirection {
match dir {
ResizeDirection::East => WinitResizeDirection::East,
ResizeDirection::North => WinitResizeDirection::North,
ResizeDirection::NorthEast => WinitResizeDirection::NorthEast,
ResizeDirection::NorthWest => WinitResizeDirection::NorthWest,
ResizeDirection::South => WinitResizeDirection::South,
ResizeDirection::SouthEast => WinitResizeDirection::SouthEast,
ResizeDirection::SouthWest => WinitResizeDirection::SouthWest,
ResizeDirection::West => WinitResizeDirection::West,
}
}
pub(crate) fn winit_force_to_masonry(force: WinitForce) -> Force {
match force {
WinitForce::Calibrated {
force,
max_possible_force,
altitude_angle,
} => Force::Calibrated {
force,
max_possible_force,
altitude_angle,
},
WinitForce::Normalized(value) => Force::Normalized(value),
}
}
pub(crate) fn winit_ime_to_masonry(event: WinitIme) -> Ime {
match event {
WinitIme::Enabled => Ime::Enabled,
WinitIme::Disabled => Ime::Disabled,
WinitIme::Preedit(text, cursor) => Ime::Preedit(text, cursor),
WinitIme::Commit(text) => Ime::Commit(text),
}
}
pub(crate) fn winit_key_event_to_kbt(event: &WinitKeyEvent, mods: WinitModifiers) -> KeyboardEvent {
KeyboardEvent {
key: winit_key_to_kbt_key(&event.logical_key),
code: winit_physical_key_to_kbt_code(event.physical_key),
modifiers: winit_modifiers_to_kbt_modifiers(mods),
location: winit_key_location_to_kbt_location(event.location),
is_composing: false,
state: match event.state {
ElementState::Pressed => KeyState::Down,
ElementState::Released => KeyState::Up,
},
repeat: event.repeat,
}
}
pub(crate) fn winit_modifiers_to_kbt_modifiers(winit_modifiers: WinitModifiers) -> Modifiers {
let mut modifiers = Modifiers::default();
if winit_modifiers.control_key() {
modifiers.insert(Modifiers::CONTROL);
}
if winit_modifiers.alt_key() {
modifiers.insert(Modifiers::ALT);
}
if winit_modifiers.shift_key() {
modifiers.insert(Modifiers::SHIFT);
}
if winit_modifiers.super_key() {
modifiers.insert(Modifiers::SUPER);
}
modifiers
}
pub(crate) fn winit_key_location_to_kbt_location(location: WinitKeyLocation) -> Location {
match location {
WinitKeyLocation::Standard => Location::Standard,
WinitKeyLocation::Left => Location::Left,
WinitKeyLocation::Right => Location::Right,
WinitKeyLocation::Numpad => Location::Numpad,
}
}
pub(crate) fn winit_physical_key_to_kbt_code(physical_key: WinitPhysicalKey) -> Code {
match physical_key {
WinitPhysicalKey::Unidentified(_) => Code::Unidentified,
WinitPhysicalKey::Code(key_code) => match key_code {
// Variants that don't match 1:1
WinitKeyCode::Meta => Code::Super,
WinitKeyCode::SuperLeft => Code::Super,
WinitKeyCode::SuperRight => Code::Super,
WinitKeyCode::Backquote => Code::Backquote,
WinitKeyCode::Backslash => Code::Backslash,
WinitKeyCode::BracketLeft => Code::BracketLeft,
WinitKeyCode::BracketRight => Code::BracketRight,
WinitKeyCode::Comma => Code::Comma,
WinitKeyCode::Digit0 => Code::Digit0,
WinitKeyCode::Digit1 => Code::Digit1,
WinitKeyCode::Digit2 => Code::Digit2,
WinitKeyCode::Digit3 => Code::Digit3,
WinitKeyCode::Digit4 => Code::Digit4,
WinitKeyCode::Digit5 => Code::Digit5,
WinitKeyCode::Digit6 => Code::Digit6,
WinitKeyCode::Digit7 => Code::Digit7,
WinitKeyCode::Digit8 => Code::Digit8,
WinitKeyCode::Digit9 => Code::Digit9,
WinitKeyCode::Equal => Code::Equal,
WinitKeyCode::IntlBackslash => Code::IntlBackslash,
WinitKeyCode::IntlRo => Code::IntlRo,
WinitKeyCode::IntlYen => Code::IntlYen,
WinitKeyCode::KeyA => Code::KeyA,
WinitKeyCode::KeyB => Code::KeyB,
WinitKeyCode::KeyC => Code::KeyC,
WinitKeyCode::KeyD => Code::KeyD,
WinitKeyCode::KeyE => Code::KeyE,
WinitKeyCode::KeyF => Code::KeyF,
WinitKeyCode::KeyG => Code::KeyG,
WinitKeyCode::KeyH => Code::KeyH,
WinitKeyCode::KeyI => Code::KeyI,
WinitKeyCode::KeyJ => Code::KeyJ,
WinitKeyCode::KeyK => Code::KeyK,
WinitKeyCode::KeyL => Code::KeyL,
WinitKeyCode::KeyM => Code::KeyM,
WinitKeyCode::KeyN => Code::KeyN,
WinitKeyCode::KeyO => Code::KeyO,
WinitKeyCode::KeyP => Code::KeyP,
WinitKeyCode::KeyQ => Code::KeyQ,
WinitKeyCode::KeyR => Code::KeyR,
WinitKeyCode::KeyS => Code::KeyS,
WinitKeyCode::KeyT => Code::KeyT,
WinitKeyCode::KeyU => Code::KeyU,
WinitKeyCode::KeyV => Code::KeyV,
WinitKeyCode::KeyW => Code::KeyW,
WinitKeyCode::KeyX => Code::KeyX,
WinitKeyCode::KeyY => Code::KeyY,
WinitKeyCode::KeyZ => Code::KeyZ,
WinitKeyCode::Minus => Code::Minus,
WinitKeyCode::Period => Code::Period,
WinitKeyCode::Quote => Code::Quote,
WinitKeyCode::Semicolon => Code::Semicolon,
WinitKeyCode::Slash => Code::Slash,
WinitKeyCode::AltLeft => Code::AltLeft,
WinitKeyCode::AltRight => Code::AltRight,
WinitKeyCode::Backspace => Code::Backspace,
WinitKeyCode::CapsLock => Code::CapsLock,
WinitKeyCode::ContextMenu => Code::ContextMenu,
WinitKeyCode::ControlLeft => Code::ControlLeft,
WinitKeyCode::ControlRight => Code::ControlRight,
WinitKeyCode::Enter => Code::Enter,
WinitKeyCode::ShiftLeft => Code::ShiftLeft,
WinitKeyCode::ShiftRight => Code::ShiftRight,
WinitKeyCode::Space => Code::Space,
WinitKeyCode::Tab => Code::Tab,
WinitKeyCode::Convert => Code::Convert,
WinitKeyCode::KanaMode => Code::KanaMode,
WinitKeyCode::Lang1 => Code::Lang1,
WinitKeyCode::Lang2 => Code::Lang2,
WinitKeyCode::Lang3 => Code::Lang3,
WinitKeyCode::Lang4 => Code::Lang4,
WinitKeyCode::Lang5 => Code::Lang5,
WinitKeyCode::NonConvert => Code::NonConvert,
WinitKeyCode::Delete => Code::Delete,
WinitKeyCode::End => Code::End,
WinitKeyCode::Help => Code::Help,
WinitKeyCode::Home => Code::Home,
WinitKeyCode::Insert => Code::Insert,
WinitKeyCode::PageDown => Code::PageDown,
WinitKeyCode::PageUp => Code::PageUp,
WinitKeyCode::ArrowDown => Code::ArrowDown,
WinitKeyCode::ArrowLeft => Code::ArrowLeft,
WinitKeyCode::ArrowRight => Code::ArrowRight,
WinitKeyCode::ArrowUp => Code::ArrowUp,
WinitKeyCode::NumLock => Code::NumLock,
WinitKeyCode::Numpad0 => Code::Numpad0,
WinitKeyCode::Numpad1 => Code::Numpad1,
WinitKeyCode::Numpad2 => Code::Numpad2,
WinitKeyCode::Numpad3 => Code::Numpad3,
WinitKeyCode::Numpad4 => Code::Numpad4,
WinitKeyCode::Numpad5 => Code::Numpad5,
WinitKeyCode::Numpad6 => Code::Numpad6,
WinitKeyCode::Numpad7 => Code::Numpad7,
WinitKeyCode::Numpad8 => Code::Numpad8,
WinitKeyCode::Numpad9 => Code::Numpad9,
WinitKeyCode::NumpadAdd => Code::NumpadAdd,
WinitKeyCode::NumpadBackspace => Code::NumpadBackspace,
WinitKeyCode::NumpadClear => Code::NumpadClear,
WinitKeyCode::NumpadClearEntry => Code::NumpadClearEntry,
WinitKeyCode::NumpadComma => Code::NumpadComma,
WinitKeyCode::NumpadDecimal => Code::NumpadDecimal,
WinitKeyCode::NumpadDivide => Code::NumpadDivide,
WinitKeyCode::NumpadEnter => Code::NumpadEnter,
WinitKeyCode::NumpadEqual => Code::NumpadEqual,
WinitKeyCode::NumpadHash => Code::NumpadHash,
WinitKeyCode::NumpadMemoryAdd => Code::NumpadMemoryAdd,
WinitKeyCode::NumpadMemoryClear => Code::NumpadMemoryClear,
WinitKeyCode::NumpadMemoryRecall => Code::NumpadMemoryRecall,
WinitKeyCode::NumpadMemoryStore => Code::NumpadMemoryStore,
WinitKeyCode::NumpadMemorySubtract => Code::NumpadMemorySubtract,
WinitKeyCode::NumpadMultiply => Code::NumpadMultiply,
WinitKeyCode::NumpadParenLeft => Code::NumpadParenLeft,
WinitKeyCode::NumpadParenRight => Code::NumpadParenRight,
WinitKeyCode::NumpadStar => Code::NumpadStar,
WinitKeyCode::NumpadSubtract => Code::NumpadSubtract,
WinitKeyCode::Escape => Code::Escape,
WinitKeyCode::Fn => Code::Fn,
WinitKeyCode::FnLock => Code::FnLock,
WinitKeyCode::PrintScreen => Code::PrintScreen,
WinitKeyCode::ScrollLock => Code::ScrollLock,
WinitKeyCode::Pause => Code::Pause,
WinitKeyCode::BrowserBack => Code::BrowserBack,
WinitKeyCode::BrowserFavorites => Code::BrowserFavorites,
WinitKeyCode::BrowserForward => Code::BrowserForward,
WinitKeyCode::BrowserHome => Code::BrowserHome,
WinitKeyCode::BrowserRefresh => Code::BrowserRefresh,
WinitKeyCode::BrowserSearch => Code::BrowserSearch,
WinitKeyCode::BrowserStop => Code::BrowserStop,
WinitKeyCode::Eject => Code::Eject,
WinitKeyCode::LaunchApp1 => Code::LaunchApp1,
WinitKeyCode::LaunchApp2 => Code::LaunchApp2,
WinitKeyCode::LaunchMail => Code::LaunchMail,
WinitKeyCode::MediaPlayPause => Code::MediaPlayPause,
WinitKeyCode::MediaSelect => Code::MediaSelect,
WinitKeyCode::MediaStop => Code::MediaStop,
WinitKeyCode::MediaTrackNext => Code::MediaTrackNext,
WinitKeyCode::MediaTrackPrevious => Code::MediaTrackPrevious,
WinitKeyCode::Power => Code::Power,
WinitKeyCode::Sleep => Code::Sleep,
WinitKeyCode::AudioVolumeDown => Code::AudioVolumeDown,
WinitKeyCode::AudioVolumeMute => Code::AudioVolumeMute,
WinitKeyCode::AudioVolumeUp => Code::AudioVolumeUp,
WinitKeyCode::WakeUp => Code::WakeUp,
WinitKeyCode::Hyper => Code::Hyper,
WinitKeyCode::Turbo => Code::Turbo,
WinitKeyCode::Abort => Code::Abort,
WinitKeyCode::Resume => Code::Resume,
WinitKeyCode::Suspend => Code::Suspend,
WinitKeyCode::Again => Code::Again,
WinitKeyCode::Copy => Code::Copy,
WinitKeyCode::Cut => Code::Cut,
WinitKeyCode::Find => Code::Find,
WinitKeyCode::Open => Code::Open,
WinitKeyCode::Paste => Code::Paste,
WinitKeyCode::Props => Code::Props,
WinitKeyCode::Select => Code::Select,
WinitKeyCode::Undo => Code::Undo,
WinitKeyCode::Hiragana => Code::Hiragana,
WinitKeyCode::Katakana => Code::Katakana,
WinitKeyCode::F1 => Code::F1,
WinitKeyCode::F2 => Code::F2,
WinitKeyCode::F3 => Code::F3,
WinitKeyCode::F4 => Code::F4,
WinitKeyCode::F5 => Code::F5,
WinitKeyCode::F6 => Code::F6,
WinitKeyCode::F7 => Code::F7,
WinitKeyCode::F8 => Code::F8,
WinitKeyCode::F9 => Code::F9,
WinitKeyCode::F10 => Code::F10,
WinitKeyCode::F11 => Code::F11,
WinitKeyCode::F12 => Code::F12,
WinitKeyCode::F13 => Code::F13,
WinitKeyCode::F14 => Code::F14,
WinitKeyCode::F15 => Code::F15,
WinitKeyCode::F16 => Code::F16,
WinitKeyCode::F17 => Code::F17,
WinitKeyCode::F18 => Code::F18,
WinitKeyCode::F19 => Code::F19,
WinitKeyCode::F20 => Code::F20,
WinitKeyCode::F21 => Code::F21,
WinitKeyCode::F22 => Code::F22,
WinitKeyCode::F23 => Code::F23,
WinitKeyCode::F24 => Code::F24,
WinitKeyCode::F25 => Code::F25,
WinitKeyCode::F26 => Code::F26,
WinitKeyCode::F27 => Code::F27,
WinitKeyCode::F28 => Code::F28,
WinitKeyCode::F29 => Code::F29,
WinitKeyCode::F30 => Code::F30,
WinitKeyCode::F31 => Code::F31,
WinitKeyCode::F32 => Code::F32,
WinitKeyCode::F33 => Code::F33,
WinitKeyCode::F34 => Code::F34,
WinitKeyCode::F35 => Code::F35,
_ => todo!(),
},
}
}
pub(crate) fn winit_key_to_kbt_key(winit_key: &WinitKey) -> Key {
match winit_key {
WinitKey::Character(c) => Key::Character(c.to_string()),
WinitKey::Unidentified(_) => Key::Unidentified,
WinitKey::Dead(_) => Key::Dead,
WinitKey::Named(named_key) => match named_key {
WinitNamedKey::Alt => Key::Alt,
WinitNamedKey::AltGraph => Key::AltGraph,
WinitNamedKey::CapsLock => Key::CapsLock,
WinitNamedKey::Control => Key::Control,
WinitNamedKey::Fn => Key::Fn,
WinitNamedKey::FnLock => Key::FnLock,
WinitNamedKey::NumLock => Key::NumLock,
WinitNamedKey::ScrollLock => Key::ScrollLock,
WinitNamedKey::Shift => Key::Shift,
WinitNamedKey::Symbol => Key::Symbol,
WinitNamedKey::SymbolLock => Key::SymbolLock,
WinitNamedKey::Meta => Key::Meta,
WinitNamedKey::Hyper => Key::Hyper,
WinitNamedKey::Super => Key::Super,
WinitNamedKey::Enter => Key::Enter,
WinitNamedKey::Tab => Key::Tab,
WinitNamedKey::Space => Key::Character(" ".to_string()),
WinitNamedKey::ArrowDown => Key::ArrowDown,
WinitNamedKey::ArrowLeft => Key::ArrowLeft,
WinitNamedKey::ArrowRight => Key::ArrowRight,
WinitNamedKey::ArrowUp => Key::ArrowUp,
WinitNamedKey::End => Key::End,
WinitNamedKey::Home => Key::Home,
WinitNamedKey::PageDown => Key::PageDown,
WinitNamedKey::PageUp => Key::PageUp,
WinitNamedKey::Backspace => Key::Backspace,
WinitNamedKey::Clear => Key::Clear,
WinitNamedKey::Copy => Key::Copy,
WinitNamedKey::CrSel => Key::CrSel,
WinitNamedKey::Cut => Key::Cut,
WinitNamedKey::Delete => Key::Delete,
WinitNamedKey::EraseEof => Key::EraseEof,
WinitNamedKey::ExSel => Key::ExSel,
WinitNamedKey::Insert => Key::Insert,
WinitNamedKey::Paste => Key::Paste,
WinitNamedKey::Redo => Key::Redo,
WinitNamedKey::Undo => Key::Undo,
WinitNamedKey::Accept => Key::Accept,
WinitNamedKey::Again => Key::Again,
WinitNamedKey::Attn => Key::Attn,
WinitNamedKey::Cancel => Key::Cancel,
WinitNamedKey::ContextMenu => Key::ContextMenu,
WinitNamedKey::Escape => Key::Escape,
WinitNamedKey::Execute => Key::Execute,
WinitNamedKey::Find => Key::Find,
WinitNamedKey::Help => Key::Help,
WinitNamedKey::Pause => Key::Pause,
WinitNamedKey::Play => Key::Play,
WinitNamedKey::Props => Key::Props,
WinitNamedKey::Select => Key::Select,
WinitNamedKey::ZoomIn => Key::ZoomIn,
WinitNamedKey::ZoomOut => Key::ZoomOut,
WinitNamedKey::BrightnessDown => Key::BrightnessDown,
WinitNamedKey::BrightnessUp => Key::BrightnessUp,
WinitNamedKey::Eject => Key::Eject,
WinitNamedKey::LogOff => Key::LogOff,
WinitNamedKey::Power => Key::Power,
WinitNamedKey::PowerOff => Key::PowerOff,
WinitNamedKey::PrintScreen => Key::PrintScreen,
WinitNamedKey::Hibernate => Key::Hibernate,
WinitNamedKey::Standby => Key::Standby,
WinitNamedKey::WakeUp => Key::WakeUp,
WinitNamedKey::AllCandidates => Key::AllCandidates,
WinitNamedKey::Alphanumeric => Key::Alphanumeric,
WinitNamedKey::CodeInput => Key::CodeInput,
WinitNamedKey::Compose => Key::Compose,
WinitNamedKey::Convert => Key::Convert,
WinitNamedKey::FinalMode => Key::FinalMode,
WinitNamedKey::GroupFirst => Key::GroupFirst,
WinitNamedKey::GroupLast => Key::GroupLast,
WinitNamedKey::GroupNext => Key::GroupNext,
WinitNamedKey::GroupPrevious => Key::GroupPrevious,
WinitNamedKey::ModeChange => Key::ModeChange,
WinitNamedKey::NextCandidate => Key::NextCandidate,
WinitNamedKey::NonConvert => Key::NonConvert,
WinitNamedKey::PreviousCandidate => Key::PreviousCandidate,
WinitNamedKey::Process => Key::Process,
WinitNamedKey::SingleCandidate => Key::SingleCandidate,
WinitNamedKey::HangulMode => Key::HangulMode,
WinitNamedKey::HanjaMode => Key::HanjaMode,
WinitNamedKey::JunjaMode => Key::JunjaMode,
WinitNamedKey::Eisu => Key::Eisu,
WinitNamedKey::Hankaku => Key::Hankaku,
WinitNamedKey::Hiragana => Key::Hiragana,
WinitNamedKey::HiraganaKatakana => Key::HiraganaKatakana,
WinitNamedKey::KanaMode => Key::KanaMode,
WinitNamedKey::KanjiMode => Key::KanjiMode,
WinitNamedKey::Katakana => Key::Katakana,
WinitNamedKey::Romaji => Key::Romaji,
WinitNamedKey::Zenkaku => Key::Zenkaku,
WinitNamedKey::ZenkakuHankaku => Key::ZenkakuHankaku,
WinitNamedKey::Soft1 => Key::Soft1,
WinitNamedKey::Soft2 => Key::Soft2,
WinitNamedKey::Soft3 => Key::Soft3,
WinitNamedKey::Soft4 => Key::Soft4,
WinitNamedKey::ChannelDown => Key::ChannelDown,
WinitNamedKey::ChannelUp => Key::ChannelUp,
WinitNamedKey::Close => Key::Close,
WinitNamedKey::MailForward => Key::MailForward,
WinitNamedKey::MailReply => Key::MailReply,
WinitNamedKey::MailSend => Key::MailSend,
WinitNamedKey::MediaClose => Key::MediaClose,
WinitNamedKey::MediaFastForward => Key::MediaFastForward,
WinitNamedKey::MediaPause => Key::MediaPause,
WinitNamedKey::MediaPlay => Key::MediaPlay,
WinitNamedKey::MediaPlayPause => Key::MediaPlayPause,
WinitNamedKey::MediaRecord => Key::MediaRecord,
WinitNamedKey::MediaRewind => Key::MediaRewind,
WinitNamedKey::MediaStop => Key::MediaStop,
WinitNamedKey::MediaTrackNext => Key::MediaTrackNext,
WinitNamedKey::MediaTrackPrevious => Key::MediaTrackPrevious,
WinitNamedKey::New => Key::New,
WinitNamedKey::Open => Key::Open,
WinitNamedKey::Print => Key::Print,
WinitNamedKey::Save => Key::Save,
WinitNamedKey::SpellCheck => Key::SpellCheck,
WinitNamedKey::Key11 => Key::Key11,
WinitNamedKey::Key12 => Key::Key12,
WinitNamedKey::AudioBalanceLeft => Key::AudioBalanceLeft,
WinitNamedKey::AudioBalanceRight => Key::AudioBalanceRight,
WinitNamedKey::AudioBassBoostDown => Key::AudioBassBoostDown,
WinitNamedKey::AudioBassBoostToggle => Key::AudioBassBoostToggle,
WinitNamedKey::AudioBassBoostUp => Key::AudioBassBoostUp,
WinitNamedKey::AudioFaderFront => Key::AudioFaderFront,
WinitNamedKey::AudioFaderRear => Key::AudioFaderRear,
WinitNamedKey::AudioSurroundModeNext => Key::AudioSurroundModeNext,
WinitNamedKey::AudioTrebleDown => Key::AudioTrebleDown,
WinitNamedKey::AudioTrebleUp => Key::AudioTrebleUp,
WinitNamedKey::AudioVolumeDown => Key::AudioVolumeDown,
WinitNamedKey::AudioVolumeUp => Key::AudioVolumeUp,
WinitNamedKey::AudioVolumeMute => Key::AudioVolumeMute,
WinitNamedKey::MicrophoneToggle => Key::MicrophoneToggle,
WinitNamedKey::MicrophoneVolumeDown => Key::MicrophoneVolumeDown,
WinitNamedKey::MicrophoneVolumeUp => Key::MicrophoneVolumeUp,
WinitNamedKey::MicrophoneVolumeMute => Key::MicrophoneVolumeMute,
WinitNamedKey::SpeechCorrectionList => Key::SpeechCorrectionList,
WinitNamedKey::SpeechInputToggle => Key::SpeechInputToggle,
WinitNamedKey::LaunchApplication1 => Key::LaunchApplication1,
WinitNamedKey::LaunchApplication2 => Key::LaunchApplication2,
WinitNamedKey::LaunchCalendar => Key::LaunchCalendar,
WinitNamedKey::LaunchContacts => Key::LaunchContacts,
WinitNamedKey::LaunchMail => Key::LaunchMail,
WinitNamedKey::LaunchMediaPlayer => Key::LaunchMediaPlayer,
WinitNamedKey::LaunchMusicPlayer => Key::LaunchMusicPlayer,
WinitNamedKey::LaunchPhone => Key::LaunchPhone,
WinitNamedKey::LaunchScreenSaver => Key::LaunchScreenSaver,
WinitNamedKey::LaunchSpreadsheet => Key::LaunchSpreadsheet,
WinitNamedKey::LaunchWebBrowser => Key::LaunchWebBrowser,
WinitNamedKey::LaunchWebCam => Key::LaunchWebCam,
WinitNamedKey::LaunchWordProcessor => Key::LaunchWordProcessor,
WinitNamedKey::BrowserBack => Key::BrowserBack,
WinitNamedKey::BrowserFavorites => Key::BrowserFavorites,
WinitNamedKey::BrowserForward => Key::BrowserForward,
WinitNamedKey::BrowserHome => Key::BrowserHome,
WinitNamedKey::BrowserRefresh => Key::BrowserRefresh,
WinitNamedKey::BrowserSearch => Key::BrowserSearch,
WinitNamedKey::BrowserStop => Key::BrowserStop,
WinitNamedKey::AppSwitch => Key::AppSwitch,
WinitNamedKey::Call => Key::Call,
WinitNamedKey::Camera => Key::Camera,
WinitNamedKey::CameraFocus => Key::CameraFocus,
WinitNamedKey::EndCall => Key::EndCall,
WinitNamedKey::GoBack => Key::GoBack,
WinitNamedKey::GoHome => Key::GoHome,
WinitNamedKey::HeadsetHook => Key::HeadsetHook,
WinitNamedKey::LastNumberRedial => Key::LastNumberRedial,
WinitNamedKey::Notification => Key::Notification,
WinitNamedKey::MannerMode => Key::MannerMode,
WinitNamedKey::VoiceDial => Key::VoiceDial,
WinitNamedKey::TV => Key::TV,
WinitNamedKey::TV3DMode => Key::TV3DMode,
WinitNamedKey::TVAntennaCable => Key::TVAntennaCable,
WinitNamedKey::TVAudioDescription => Key::TVAudioDescription,
WinitNamedKey::TVAudioDescriptionMixDown => Key::TVAudioDescriptionMixDown,
WinitNamedKey::TVAudioDescriptionMixUp => Key::TVAudioDescriptionMixUp,
WinitNamedKey::TVContentsMenu => Key::TVContentsMenu,
WinitNamedKey::TVDataService => Key::TVDataService,
WinitNamedKey::TVInput => Key::TVInput,
WinitNamedKey::TVInputComponent1 => Key::TVInputComponent1,
WinitNamedKey::TVInputComponent2 => Key::TVInputComponent2,
WinitNamedKey::TVInputComposite1 => Key::TVInputComposite1,
WinitNamedKey::TVInputComposite2 => Key::TVInputComposite2,
WinitNamedKey::TVInputHDMI1 => Key::TVInputHDMI1,
WinitNamedKey::TVInputHDMI2 => Key::TVInputHDMI2,
WinitNamedKey::TVInputHDMI3 => Key::TVInputHDMI3,
WinitNamedKey::TVInputHDMI4 => Key::TVInputHDMI4,
WinitNamedKey::TVInputVGA1 => Key::TVInputVGA1,
WinitNamedKey::TVMediaContext => Key::TVMediaContext,
WinitNamedKey::TVNetwork => Key::TVNetwork,
WinitNamedKey::TVNumberEntry => Key::TVNumberEntry,
WinitNamedKey::TVPower => Key::TVPower,
WinitNamedKey::TVRadioService => Key::TVRadioService,
WinitNamedKey::TVSatellite => Key::TVSatellite,
WinitNamedKey::TVSatelliteBS => Key::TVSatelliteBS,
WinitNamedKey::TVSatelliteCS => Key::TVSatelliteCS,
WinitNamedKey::TVSatelliteToggle => Key::TVSatelliteToggle,
WinitNamedKey::TVTerrestrialAnalog => Key::TVTerrestrialAnalog,
WinitNamedKey::TVTerrestrialDigital => Key::TVTerrestrialDigital,
WinitNamedKey::TVTimer => Key::TVTimer,
WinitNamedKey::AVRInput => Key::AVRInput,
WinitNamedKey::AVRPower => Key::AVRPower,
WinitNamedKey::ColorF0Red => Key::ColorF0Red,
WinitNamedKey::ColorF1Green => Key::ColorF1Green,
WinitNamedKey::ColorF2Yellow => Key::ColorF2Yellow,
WinitNamedKey::ColorF3Blue => Key::ColorF3Blue,
WinitNamedKey::ColorF4Grey => Key::ColorF4Grey,
WinitNamedKey::ColorF5Brown => Key::ColorF5Brown,
WinitNamedKey::ClosedCaptionToggle => Key::ClosedCaptionToggle,
WinitNamedKey::Dimmer => Key::Dimmer,
WinitNamedKey::DisplaySwap => Key::DisplaySwap,
WinitNamedKey::DVR => Key::DVR,
WinitNamedKey::Exit => Key::Exit,
WinitNamedKey::FavoriteClear0 => Key::FavoriteClear0,
WinitNamedKey::FavoriteClear1 => Key::FavoriteClear1,
WinitNamedKey::FavoriteClear2 => Key::FavoriteClear2,
WinitNamedKey::FavoriteClear3 => Key::FavoriteClear3,
WinitNamedKey::FavoriteRecall0 => Key::FavoriteRecall0,
WinitNamedKey::FavoriteRecall1 => Key::FavoriteRecall1,
WinitNamedKey::FavoriteRecall2 => Key::FavoriteRecall2,
WinitNamedKey::FavoriteRecall3 => Key::FavoriteRecall3,
WinitNamedKey::FavoriteStore0 => Key::FavoriteStore0,
WinitNamedKey::FavoriteStore1 => Key::FavoriteStore1,
WinitNamedKey::FavoriteStore2 => Key::FavoriteStore2,
WinitNamedKey::FavoriteStore3 => Key::FavoriteStore3,
WinitNamedKey::Guide => Key::Guide,
WinitNamedKey::GuideNextDay => Key::GuideNextDay,
WinitNamedKey::GuidePreviousDay => Key::GuidePreviousDay,
WinitNamedKey::Info => Key::Info,
WinitNamedKey::InstantReplay => Key::InstantReplay,
WinitNamedKey::Link => Key::Link,
WinitNamedKey::ListProgram => Key::ListProgram,
WinitNamedKey::LiveContent => Key::LiveContent,
WinitNamedKey::Lock => Key::Lock,
WinitNamedKey::MediaApps => Key::MediaApps,
WinitNamedKey::MediaAudioTrack => Key::MediaAudioTrack,
WinitNamedKey::MediaLast => Key::MediaLast,
WinitNamedKey::MediaSkipBackward => Key::MediaSkipBackward,
WinitNamedKey::MediaSkipForward => Key::MediaSkipForward,
WinitNamedKey::MediaStepBackward => Key::MediaStepBackward,
WinitNamedKey::MediaStepForward => Key::MediaStepForward,
WinitNamedKey::MediaTopMenu => Key::MediaTopMenu,
WinitNamedKey::NavigateIn => Key::NavigateIn,
WinitNamedKey::NavigateNext => Key::NavigateNext,
WinitNamedKey::NavigateOut => Key::NavigateOut,
WinitNamedKey::NavigatePrevious => Key::NavigatePrevious,
WinitNamedKey::NextFavoriteChannel => Key::NextFavoriteChannel,
WinitNamedKey::NextUserProfile => Key::NextUserProfile,
WinitNamedKey::OnDemand => Key::OnDemand,
WinitNamedKey::Pairing => Key::Pairing,
WinitNamedKey::PinPDown => Key::PinPDown,
WinitNamedKey::PinPMove => Key::PinPMove,
WinitNamedKey::PinPToggle => Key::PinPToggle,
WinitNamedKey::PinPUp => Key::PinPUp,
WinitNamedKey::PlaySpeedDown => Key::PlaySpeedDown,
WinitNamedKey::PlaySpeedReset => Key::PlaySpeedReset,
WinitNamedKey::PlaySpeedUp => Key::PlaySpeedUp,
WinitNamedKey::RandomToggle => Key::RandomToggle,
WinitNamedKey::RcLowBattery => Key::RcLowBattery,
WinitNamedKey::RecordSpeedNext => Key::RecordSpeedNext,
WinitNamedKey::RfBypass => Key::RfBypass,
WinitNamedKey::ScanChannelsToggle => Key::ScanChannelsToggle,
WinitNamedKey::ScreenModeNext => Key::ScreenModeNext,
WinitNamedKey::Settings => Key::Settings,
WinitNamedKey::SplitScreenToggle => Key::SplitScreenToggle,
WinitNamedKey::STBInput => Key::STBInput,
WinitNamedKey::STBPower => Key::STBPower,
WinitNamedKey::Subtitle => Key::Subtitle,
WinitNamedKey::Teletext => Key::Teletext,
WinitNamedKey::VideoModeNext => Key::VideoModeNext,
WinitNamedKey::Wink => Key::Wink,
WinitNamedKey::ZoomToggle => Key::ZoomToggle,
WinitNamedKey::F1 => Key::F1,
WinitNamedKey::F2 => Key::F2,
WinitNamedKey::F3 => Key::F3,
WinitNamedKey::F4 => Key::F4,
WinitNamedKey::F5 => Key::F5,
WinitNamedKey::F6 => Key::F6,
WinitNamedKey::F7 => Key::F7,
WinitNamedKey::F8 => Key::F8,
WinitNamedKey::F9 => Key::F9,
WinitNamedKey::F10 => Key::F10,
WinitNamedKey::F11 => Key::F11,
WinitNamedKey::F12 => Key::F12,
WinitNamedKey::F13 => Key::F13,
WinitNamedKey::F14 => Key::F14,
WinitNamedKey::F15 => Key::F15,
WinitNamedKey::F16 => Key::F16,
WinitNamedKey::F17 => Key::F17,
WinitNamedKey::F18 => Key::F18,
WinitNamedKey::F19 => Key::F19,
WinitNamedKey::F20 => Key::F20,
WinitNamedKey::F21 => Key::F21,
WinitNamedKey::F22 => Key::F22,
WinitNamedKey::F23 => Key::F23,
WinitNamedKey::F24 => Key::F24,
WinitNamedKey::F25 => Key::F25,
WinitNamedKey::F26 => Key::F26,
WinitNamedKey::F27 => Key::F27,
WinitNamedKey::F28 => Key::F28,
WinitNamedKey::F29 => Key::F29,
WinitNamedKey::F30 => Key::F30,
WinitNamedKey::F31 => Key::F31,
WinitNamedKey::F32 => Key::F32,
WinitNamedKey::F33 => Key::F33,
WinitNamedKey::F34 => Key::F34,
WinitNamedKey::F35 => Key::F35,
_ => Key::Unidentified,
},
}
}

View File

@ -23,6 +23,8 @@ use winit::window::{Window, WindowAttributes, WindowId};
use crate::app::{
AppDriver, DriverCtx, RenderRoot, RenderRootOptions, RenderRootSignal, WindowSizePolicy,
masonry_resize_direction_to_winit, winit_force_to_masonry, winit_ime_to_masonry,
winit_key_event_to_kbt, winit_modifiers_to_kbt_modifiers, winit_mouse_button_to_masonry,
};
use crate::core::{
PointerButton, PointerEvent, PointerState, TextEvent, Widget, WidgetId, WindowEvent,
@ -43,22 +45,6 @@ impl From<accesskit_winit::Event> for MasonryUserEvent {
}
}
impl From<WinitMouseButton> for PointerButton {
fn from(button: WinitMouseButton) -> Self {
match button {
WinitMouseButton::Left => Self::Primary,
WinitMouseButton::Right => Self::Secondary,
WinitMouseButton::Middle => Self::Auxiliary,
WinitMouseButton::Back => Self::X1,
WinitMouseButton::Forward => Self::X2,
WinitMouseButton::Other(other) => {
warn!("Got winit MouseButton::Other({other}) which is not yet fully supported.");
Self::Other
}
}
}
}
pub enum WindowState<'a> {
Uninitialized(WindowAttributes),
Rendering {
@ -79,6 +65,7 @@ pub struct MasonryState<'a> {
render_cx: RenderContext,
render_root: RenderRoot,
pointer_state: PointerState,
winit_mods: winit::event::Modifiers,
renderer: Option<Renderer>,
// TODO: Winit doesn't seem to let us create these proxies from within the loop
// The reasons for this are unclear
@ -247,6 +234,7 @@ impl MasonryState<'_> {
#[cfg(feature = "tracy")]
frame: None,
pointer_state: PointerState::empty(),
winit_mods: winit::event::Modifiers::default(),
proxy: event_loop.create_proxy(),
window: WindowState::Uninitialized(window),
@ -500,21 +488,26 @@ impl MasonryState<'_> {
.handle_window_event(WindowEvent::Resize(size));
}
WinitWindowEvent::ModifiersChanged(modifiers) => {
self.pointer_state.mods = modifiers;
self.pointer_state.mods = winit_modifiers_to_kbt_modifiers(modifiers.state());
self.winit_mods = modifiers;
self.render_root
.handle_text_event(TextEvent::ModifierChange(modifiers.state()));
.handle_text_event(TextEvent::ModifierChange(self.pointer_state.mods));
}
WinitWindowEvent::KeyboardInput {
device_id: _,
event,
is_synthetic: false, // TODO: Introduce an escape hatch for synthetic keys
} => {
let text = event.text.as_ref().map(|text| text.to_string());
let event = winit_key_event_to_kbt(&event, self.winit_mods.state());
self.render_root.handle_text_event(TextEvent::KeyboardKey(
event,
self.pointer_state.mods.state(),
self.pointer_state.mods,
text,
));
}
WinitWindowEvent::Ime(ime) => {
let ime = winit_ime_to_masonry(ime);
self.render_root.handle_text_event(TextEvent::Ime(ime));
}
WinitWindowEvent::Focused(new_focus) => {
@ -535,22 +528,31 @@ impl MasonryState<'_> {
self.render_root
.handle_pointer_event(PointerEvent::PointerLeave(self.pointer_state.clone()));
}
WinitWindowEvent::MouseInput { state, button, .. } => match state {
winit::event::ElementState::Pressed => {
self.render_root
.handle_pointer_event(PointerEvent::PointerDown(
button.into(),
self.pointer_state.clone(),
));
WinitWindowEvent::MouseInput { state, button, .. } => {
if let WinitMouseButton::Other(other) = button {
warn!(
"Got winit MouseButton::Other({other}) which is not yet fully supported."
);
}
winit::event::ElementState::Released => {
self.render_root
.handle_pointer_event(PointerEvent::PointerUp(
button.into(),
self.pointer_state.clone(),
));
let button = winit_mouse_button_to_masonry(button);
match state {
winit::event::ElementState::Pressed => {
self.render_root
.handle_pointer_event(PointerEvent::PointerDown(
button,
self.pointer_state.clone(),
));
}
winit::event::ElementState::Released => {
self.render_root
.handle_pointer_event(PointerEvent::PointerUp(
button,
self.pointer_state.clone(),
));
}
}
},
}
WinitWindowEvent::MouseWheel { delta, .. } => {
// TODO - This delta value doesn't quite make sense.
// Figure out and document a better standard.
@ -578,7 +580,7 @@ impl MasonryState<'_> {
// It will also interact with gesture discrimination.
self.pointer_state.physical_position = location;
self.pointer_state.position = location.to_logical(window.scale_factor());
self.pointer_state.force = force;
self.pointer_state.force = force.map(winit_force_to_masonry);
match phase {
winit::event::TouchPhase::Started => {
self.render_root
@ -725,6 +727,7 @@ impl MasonryState<'_> {
}
RenderRootSignal::DragResizeWindow(direction) => {
// TODO - Handle return value?
let direction = masonry_resize_direction_to_winit(direction);
let _ = window.drag_resize_window(direction);
}
RenderRootSignal::ToggleMaximized => {

View File

@ -4,6 +4,7 @@
//! Types needed for running a Masonry app.
mod app_driver;
mod convert_winit_event;
mod event_loop_runner;
mod render_root;
mod tracing_backend;
@ -14,5 +15,9 @@ pub use event_loop_runner::{
};
pub use render_root::{RenderRoot, RenderRootOptions, RenderRootSignal, WindowSizePolicy};
pub(crate) use convert_winit_event::{
masonry_resize_direction_to_winit, winit_force_to_masonry, winit_ime_to_masonry,
winit_key_event_to_kbt, winit_modifiers_to_kbt_modifiers, winit_mouse_button_to_masonry,
};
pub(crate) use render_root::{MutateCallback, RenderRootState};
pub(crate) use tracing_backend::{try_init_test_tracing, try_init_tracing};

View File

@ -13,7 +13,6 @@ use vello::Scene;
use vello::kurbo::{
Rect, {self},
};
use winit::window::ResizeDirection;
#[cfg(not(target_arch = "wasm32"))]
use std::time::Instant;
@ -22,8 +21,9 @@ use web_time::Instant;
use crate::Handled;
use crate::core::{
AccessEvent, Action, BrushIndex, PointerEvent, PropertiesRef, QueryCtx, TextEvent, Widget,
WidgetArena, WidgetId, WidgetMut, WidgetPod, WidgetRef, WidgetState, WindowEvent,
AccessEvent, Action, BrushIndex, Ime, PointerEvent, PropertiesRef, QueryCtx, ResizeDirection,
TextEvent, Widget, WidgetArena, WidgetId, WidgetMut, WidgetPod, WidgetRef, WidgetState,
WindowEvent,
};
use crate::dpi::{LogicalPosition, LogicalSize, PhysicalSize};
use crate::passes::accessibility::run_accessibility_pass;
@ -396,7 +396,7 @@ impl RenderRoot {
let handled = run_on_text_event_pass(self, &event);
run_update_focus_pass(self);
if matches!(event, TextEvent::Ime(winit::event::Ime::Enabled)) {
if matches!(event, TextEvent::Ime(Ime::Enabled)) {
// Reset the last sent IME area, as the platform reset the IME state and may have
// forgotten it.
self.global_state.last_sent_ime_area = INVALID_IME_AREA;

View File

@ -9,12 +9,11 @@ use dpi::LogicalPosition;
use parley::{FontContext, LayoutContext};
use tracing::{trace, warn};
use tree_arena::{ArenaMutList, ArenaRefList};
use winit::window::ResizeDirection;
use crate::app::{MutateCallback, RenderRootSignal, RenderRootState};
use crate::core::{
Action, AllowRawMut, BoxConstraints, BrushIndex, CreateWidget, FromDynWidget, PropertiesMut,
PropertiesRef, Widget, WidgetId, WidgetMut, WidgetPod, WidgetRef, WidgetState,
PropertiesRef, ResizeDirection, Widget, WidgetId, WidgetMut, WidgetPod, WidgetRef, WidgetState,
};
use crate::kurbo::{Affine, Insets, Point, Rect, Size, Vec2};
use crate::passes::layout::run_layout_on;

View File

@ -5,9 +5,8 @@
use std::path::PathBuf;
use keyboard_types::{KeyboardEvent, Modifiers};
use vello::kurbo::Point;
use winit::event::{Force, Ime, KeyEvent, Modifiers};
use winit::keyboard::ModifiersState;
use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
use crate::kurbo::Rect;
@ -228,11 +227,11 @@ pub enum PointerEvent {
#[derive(Debug, Clone)]
pub enum TextEvent {
/// A keyboard event.
KeyboardKey(KeyEvent, ModifiersState),
KeyboardKey(KeyboardEvent, Modifiers, Option<String>),
/// An IME event.
Ime(Ime),
/// Modifier keys (e.g. Shift, Ctrl, Alt) were pressed or released.
ModifierChange(ModifiersState),
ModifierChange(Modifiers),
/// The window took or lost focus.
WindowFocusChange(bool),
}
@ -474,8 +473,8 @@ impl TextEvent {
/// Short name, for debug logging.
pub fn short_name(&self) -> &'static str {
match self {
Self::KeyboardKey(KeyEvent { repeat: true, .. }, _) => "KeyboardKey(repeat)",
Self::KeyboardKey(_, _) => "KeyboardKey",
Self::KeyboardKey(KeyboardEvent { repeat: true, .. }, ..) => "KeyboardKey(repeat)",
Self::KeyboardKey(..) => "KeyboardKey",
Self::Ime(Ime::Disabled) => "Ime::Disabled",
Self::Ime(Ime::Enabled) => "Ime::Enabled",
Self::Ime(Ime::Commit(_)) => "Ime::Commit",
@ -492,7 +491,7 @@ impl TextEvent {
/// cluttering the console.
pub fn is_high_density(&self) -> bool {
match self {
Self::KeyboardKey(_, _) => false,
Self::KeyboardKey(..) => false,
Self::Ime(_) => false,
// Basically every mouse click/scroll event seems to produce a modifier change event.
Self::ModifierChange(_) => true,
@ -570,3 +569,153 @@ impl Update {
}
}
}
/// Describes [input method](https://en.wikipedia.org/wiki/Input_method) events.
///
/// Mirrors [`winit::event::Ime`](https://docs.rs/winit/latest/x86_64-unknown-linux-gnu/winit/event/enum.Ime.html).
///
/// This is also called a "composition event".
///
/// Most keypresses using a latin-like keyboard layout simply generate a
/// [`TextEvent::KeyboardKey`]. However, one couldn't possibly have a key for every single
/// unicode character that the user might want to type
/// - so the solution operating systems employ is to allow the user to type these using _a sequence
/// of keypresses_ instead.
///
/// A prominent example of this is accents - many keyboard layouts allow you to first click the
/// "accent key", and then the character you want to apply the accent to. In this case, some
/// platforms will generate the following event sequence:
///
/// ```ignore
/// // Press "`" key
/// Ime::Preedit("`", Some((0, 0)))
/// // Press "E" key
/// Ime::Preedit("", None) // Synthetic event generated by winit to clear preedit.
/// Ime::Commit("é")
/// ```
///
/// Additionally, certain input devices are configured to display a candidate box that allow the
/// user to select the desired character interactively. (To properly position this box, you must use
/// [`RenderRootSignal::ImeMoved`](crate::app::RenderRootSignal::ImeMoved).)
///
/// An example of a keyboard layout which uses candidate boxes is pinyin. On a latin keyboard the
/// following event sequence could be obtained:
///
/// ```ignore
/// // Press "A" key
/// Ime::Preedit("a", Some((1, 1)))
/// // Press "B" key
/// Ime::Preedit("a b", Some((3, 3)))
/// // Press left arrow key
/// Ime::Preedit("a b", Some((1, 1)))
/// // Press space key
/// Ime::Preedit("啊b", Some((3, 3)))
/// // Press space key
/// Ime::Preedit("", None) // Synthetic event generated by winit to clear preedit.
/// Ime::Commit("啊不")
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
//#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Ime {
/// Notifies when the IME was enabled.
///
/// After getting this event you could receive [`Preedit`][Self::Preedit] and
/// [`Commit`][Self::Commit] events. You should also start performing IME related requests
/// like [`RenderRootSignal::ImeMoved`](crate::app::RenderRootSignal::ImeMoved).
Enabled,
/// Notifies when a new composing text should be set at the cursor position.
///
/// The value represents a pair of the preedit string and the cursor begin position and end
/// position. When it's `None`, the cursor should be hidden. When `String` is an empty string
/// this indicates that preedit was cleared.
///
/// The cursor position is byte-wise indexed.
Preedit(String, Option<(usize, usize)>),
/// Notifies when text should be inserted into the editor widget.
///
/// Right before this event winit will send empty [`Self::Preedit`] event.
Commit(String),
/// Notifies when the IME was disabled.
///
/// After receiving this event you won't get any more [`Preedit`][Self::Preedit] or
/// [`Commit`][Self::Commit] events until the next [`Enabled`][Self::Enabled] event.
Disabled,
}
/// Describes the force of a touch event
///
/// Mirrors [`winit::event::Force`](https://docs.rs/winit/latest/x86_64-unknown-linux-gnu/winit/event/enum.Force.html).
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Force {
/// On iOS, the force is calibrated so that the same number corresponds to
/// roughly the same amount of pressure on the screen regardless of the
/// device.
Calibrated {
/// The force of the touch, where a value of 1.0 represents the force of
/// an average touch (predetermined by the system, not user-specific).
///
/// The force reported by Apple Pencil is measured along the axis of the
/// pencil. If you want a force perpendicular to the device, you need to
/// calculate this value using the `altitude_angle` value.
force: f64,
/// The maximum possible force for a touch.
///
/// The value of this field is sufficiently high to provide a wide
/// dynamic range for values of the `force` field.
max_possible_force: f64,
/// The altitude (in radians) of the stylus.
///
/// A value of 0 radians indicates that the stylus is parallel to the
/// surface. The value of this property is Pi/2 when the stylus is
/// perpendicular to the surface.
altitude_angle: Option<f64>,
},
/// If the platform reports the force as normalized, we have no way of
/// knowing how much pressure 1.0 corresponds to we know it's the maximum
/// amount of force, but as to how much force, you might either have to
/// press really really hard, or not hard at all, depending on the device.
Normalized(f64),
}
impl Force {
/// Returns the force normalized to the range between 0.0 and 1.0 inclusive.
///
/// Instead of normalizing the force, you should prefer to handle
/// [`Force::Calibrated`] so that the amount of force the user has to apply is
/// consistent across devices.
pub fn normalized(&self) -> f64 {
match self {
Self::Calibrated {
force,
max_possible_force,
altitude_angle,
} => {
let force = match altitude_angle {
Some(altitude_angle) => force / altitude_angle.sin(),
None => *force,
};
force / max_possible_force
}
Self::Normalized(force) => *force,
}
}
}
/// Defines the orientation that a window resize will be performed.
///
/// Mirrors [`winit::window::ResizeDirection`](https://docs.rs/winit/latest/x86_64-unknown-linux-gnu/winit/window/enum.ResizeDirection.html).
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[expect(missing_docs, reason = "Copied from winit")]
pub enum ResizeDirection {
East,
North,
NorthEast,
NorthWest,
South,
SouthEast,
SouthWest,
West,
}

View File

@ -6,7 +6,7 @@
mod action;
mod box_constraints;
mod contexts;
mod event;
mod events;
mod object_fit;
mod properties;
mod text;
@ -23,9 +23,9 @@ pub use contexts::{
AccessCtx, ComposeCtx, EventCtx, IsContext, LayoutCtx, MutateCtx, PaintCtx, QueryCtx,
RawWrapper, RawWrapperMut, RegisterCtx, UpdateCtx,
};
pub use event::{
AccessEvent, PointerButton, PointerEvent, PointerState, TextEvent, Update, WindowEvent,
WindowTheme,
pub use events::{
AccessEvent, Force, Ime, PointerButton, PointerEvent, PointerState, ResizeDirection, TextEvent,
Update, WindowEvent, WindowTheme,
};
pub use object_fit::ObjectFit;
pub use properties::{Properties, PropertiesMut, PropertiesRef};

View File

@ -2,9 +2,8 @@
// SPDX-License-Identifier: Apache-2.0
use dpi::LogicalPosition;
use keyboard_types::{Key, KeyState};
use tracing::{debug, info_span, trace};
use winit::event::ElementState;
use winit::keyboard::{KeyCode, PhysicalKey};
use crate::Handled;
use crate::app::{RenderRoot, RenderRootSignal};
@ -227,22 +226,16 @@ pub(crate) fn run_on_text_event_pass(root: &mut RenderRoot, event: &TextEvent) -
!event.is_high_density(),
);
if let TextEvent::KeyboardKey(key, mods) = event {
if let TextEvent::KeyboardKey(key, mods, _) = event {
// Handle Tab focus
if key.physical_key == PhysicalKey::Code(KeyCode::Tab)
&& key.state == ElementState::Pressed
&& handled == Handled::No
{
let forward = !mods.shift_key();
if key.key == Key::Tab && key.state == KeyState::Down && handled == Handled::No {
let forward = !mods.shift();
let next_focused_widget = root.widget_from_focus_chain(forward);
root.global_state.next_focused_widget = next_focused_widget;
handled = Handled::Yes;
}
if key.physical_key == PhysicalKey::Code(KeyCode::F11)
&& key.state == ElementState::Pressed
&& handled == Handled::No
{
if key.key == Key::F11 && key.state == KeyState::Down && handled == Handled::No {
root.global_state.inspector_state.is_picking_widget =
!root.global_state.inspector_state.is_picking_widget;
root.global_state.inspector_state.hovered_widget = None;
@ -251,10 +244,7 @@ pub(crate) fn run_on_text_event_pass(root: &mut RenderRoot, event: &TextEvent) -
handled = Handled::Yes;
}
if key.physical_key == PhysicalKey::Code(KeyCode::F12)
&& key.state == ElementState::Pressed
&& handled == Handled::No
{
if key.key == Key::F12 && key.state == KeyState::Down && handled == Handled::No {
root.debug_paint = !root.debug_paint;
root.root_state_mut().needs_paint = true;
handled = Handled::Yes;

View File

@ -10,7 +10,7 @@ use tree_arena::ArenaMut;
use crate::app::{RenderRoot, RenderRootSignal, RenderRootState};
use crate::core::{
PointerEvent, PropertiesMut, QueryCtx, RegisterCtx, TextEvent, Update, UpdateCtx, Widget,
Ime, PointerEvent, PropertiesMut, QueryCtx, RegisterCtx, TextEvent, Update, UpdateCtx, Widget,
WidgetId, WidgetState,
};
use crate::passes::event::{run_on_pointer_event_pass, run_on_text_event_pass};
@ -507,7 +507,7 @@ pub(crate) fn run_update_focus_pass(root: &mut RenderRoot) {
// IME was active, but the next focused widget is going to receive the Ime::Disabled event
// sent by the platform. Synthesize an `Ime::Disabled` event here and send it to the widget
// about to be unfocused.
run_on_text_event_pass(root, &TextEvent::Ime(winit::event::Ime::Disabled));
run_on_text_event_pass(root, &TextEvent::Ime(Ime::Disabled));
// Disable the IME, which was enabled specifically for this widget. Note that if the newly
// focused widget also requires IME, we will request it again - this resets the platform's

View File

@ -16,14 +16,13 @@ use wgpu::{
BufferDescriptor, BufferUsages, CommandEncoderDescriptor, Extent3d, ImageCopyBuffer,
TextureDescriptor, TextureFormat, TextureUsages,
};
use winit::event::Ime;
use crate::Handled;
use crate::app::{
RenderRoot, RenderRootOptions, RenderRootSignal, WindowSizePolicy, try_init_test_tracing,
};
use crate::core::{
Action, PointerButton, PointerEvent, PointerState, TextEvent, Widget, WidgetId, WidgetMut,
Action, Ime, PointerButton, PointerEvent, PointerState, TextEvent, Widget, WidgetId, WidgetMut,
WidgetRef, WindowEvent,
};
use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};

View File

@ -5,6 +5,7 @@ use std::mem::Discriminant;
use std::time::Instant;
use accesskit::{Node, NodeId, Role};
use keyboard_types::{Key, KeyState};
use parley::PlainEditor;
use parley::editor::{Generation, SplitString};
use parley::layout::Alignment;
@ -13,10 +14,9 @@ use tracing::{Span, trace_span};
use vello::Scene;
use vello::kurbo::{Affine, Point, Rect, Size, Vec2};
use vello::peniko::{Brush, Fill};
use winit::keyboard::{Key, NamedKey};
use crate::core::{
AccessCtx, AccessEvent, BoxConstraints, BrushIndex, EventCtx, LayoutCtx, PaintCtx,
AccessCtx, AccessEvent, BoxConstraints, BrushIndex, EventCtx, Ime, LayoutCtx, PaintCtx,
PointerButton, PointerEvent, PropertiesMut, PropertiesRef, QueryCtx, RegisterCtx,
StyleProperty, TextEvent, Update, UpdateCtx, Widget, WidgetId, WidgetMut, default_styles,
render_text,
@ -578,24 +578,23 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
event: &TextEvent,
) {
match event {
TextEvent::KeyboardKey(key_event, modifiers_state) => {
if !key_event.state.is_pressed() || self.editor.is_composing() {
TextEvent::KeyboardKey(key_event, modifiers_state, key_text) => {
if key_event.state != KeyState::Down || self.editor.is_composing() {
return;
}
#[allow(unused)]
let (shift, action_mod) = (
modifiers_state.shift_key(),
modifiers_state.shift(),
if cfg!(target_os = "macos") {
modifiers_state.super_key()
modifiers_state.meta()
} else {
modifiers_state.control_key()
modifiers_state.ctrl()
},
);
let (fctx, lctx) = ctx.text_contexts();
// Whether the text was changed.
let mut edited = false;
// Ideally we'd use key_without_modifiers, but that's broken
match &key_event.logical_key {
match &key_event.key {
// Cut
#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))]
Key::Character(x)
@ -640,7 +639,7 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
drv.select_all();
}
}
Key::Named(NamedKey::ArrowLeft) => {
Key::ArrowLeft => {
let mut drv = self.editor.driver(fctx, lctx);
if action_mod {
if shift {
@ -654,7 +653,7 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
drv.move_left();
}
}
Key::Named(NamedKey::ArrowRight) => {
Key::ArrowRight => {
let mut drv = self.editor.driver(fctx, lctx);
if action_mod {
if shift {
@ -668,7 +667,7 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
drv.move_right();
}
}
Key::Named(NamedKey::ArrowUp) => {
Key::ArrowUp => {
let mut drv = self.editor.driver(fctx, lctx);
if shift {
drv.select_up();
@ -676,7 +675,7 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
drv.move_up();
}
}
Key::Named(NamedKey::ArrowDown) => {
Key::ArrowDown => {
let mut drv = self.editor.driver(fctx, lctx);
if shift {
drv.select_down();
@ -684,7 +683,7 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
drv.move_down();
}
}
Key::Named(NamedKey::Home) => {
Key::Home => {
let mut drv = self.editor.driver(fctx, lctx);
if action_mod {
if shift {
@ -698,7 +697,7 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
drv.move_to_line_start();
}
}
Key::Named(NamedKey::End) => {
Key::End => {
let mut drv = self.editor.driver(fctx, lctx);
if action_mod {
if shift {
@ -712,7 +711,7 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
drv.move_to_line_end();
}
}
Key::Named(NamedKey::Delete) if EDITABLE => {
Key::Delete if EDITABLE => {
let mut drv = self.editor.driver(fctx, lctx);
if action_mod {
drv.delete_word();
@ -722,7 +721,7 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
edited = true;
}
Key::Named(NamedKey::Backspace) if EDITABLE => {
Key::Backspace if EDITABLE => {
let mut drv = self.editor.driver(fctx, lctx);
if action_mod {
drv.backdelete_word();
@ -732,13 +731,13 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
edited = true;
}
Key::Named(NamedKey::Space) if EDITABLE => {
Key::Character(sp) if EDITABLE && sp.as_str() == " " => {
self.editor
.driver(fctx, lctx)
.insert_or_replace_selection(" ");
edited = true;
}
Key::Named(NamedKey::Enter) => {
Key::Enter => {
// TODO: Multiline?
let multiline = false;
if multiline {
@ -754,12 +753,12 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
}
}
Key::Named(NamedKey::Tab) => {
Key::Tab => {
// Intentionally do nothing so that tabbing from a textbox/Prose works.
// Note that this doesn't allow input of the tab character; we need to be more clever here at some point
return;
}
_ if EDITABLE => match &key_event.text {
_ if EDITABLE => match &key_text {
Some(text) => {
self.editor
.driver(fctx, lctx)
@ -801,10 +800,10 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
// We don't send a TextChanged when the preedit changes
let mut edited = false;
match e {
winit::event::Ime::Disabled => {
Ime::Disabled => {
self.editor.driver(fctx, lctx).clear_compose();
}
winit::event::Ime::Preedit(text, cursor) => {
Ime::Preedit(text, cursor) => {
if text.is_empty() {
self.editor.driver(fctx, lctx).clear_compose();
} else {
@ -812,13 +811,13 @@ impl<const EDITABLE: bool> Widget for TextArea<EDITABLE> {
edited = true;
}
}
winit::event::Ime::Commit(text) => {
Ime::Commit(text) => {
self.editor
.driver(fctx, lctx)
.insert_or_replace_selection(text);
edited = true;
}
winit::event::Ime::Enabled => {}
Ime::Enabled => {}
}
ctx.set_handled();