Another project
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 8.9 kB View raw
1use bone_app::{InputEvent, KeyDown, NavKey, ScrollDelta, WindowPoint}; 2use bone_render::{ViewportExtent, ViewportPx}; 3use bone_ui::input::{KeyChar, KeyCode as UiKeyCode, ModifierMask, NamedKey, PointerButton}; 4use winit::{ 5 dpi::PhysicalSize, 6 event::{ElementState, KeyEvent, MouseButton, MouseScrollDelta, WindowEvent}, 7 keyboard::{Key, KeyCode, ModifiersState, NamedKey as WinitNamed, PhysicalKey, SmolStr}, 8}; 9 10pub enum AppEvent { 11 Input(InputEvent), 12 Redraw, 13 Close, 14 Ignored, 15} 16 17impl AppEvent { 18 pub fn from_winit(event: WindowEvent) -> Self { 19 match event { 20 WindowEvent::CloseRequested => Self::Close, 21 WindowEvent::RedrawRequested => Self::Redraw, 22 WindowEvent::Resized(size) => Self::Input(InputEvent::Resize(viewport_extent(size))), 23 WindowEvent::Focused(focused) => Self::Input(InputEvent::Focus(focused)), 24 WindowEvent::ModifiersChanged(mods) => { 25 Self::Input(InputEvent::Modifiers(modifier_mask(mods.state()))) 26 } 27 WindowEvent::CursorMoved { position, .. } => Self::Input(InputEvent::CursorMove( 28 WindowPoint::new(position.x, position.y), 29 )), 30 WindowEvent::CursorLeft { .. } => Self::Input(InputEvent::CursorLeft), 31 WindowEvent::CursorEntered { .. } => Self::Input(InputEvent::CursorEntered), 32 WindowEvent::MouseInput { state, button, .. } => match pointer_button(button) { 33 Some(button) => Self::Input(InputEvent::Pointer { 34 button, 35 pressed: state == ElementState::Pressed, 36 }), 37 None => Self::Ignored, 38 }, 39 WindowEvent::MouseWheel { delta, .. } => { 40 Self::Input(InputEvent::Wheel(scroll_delta(delta))) 41 } 42 WindowEvent::KeyboardInput { 43 event: 44 KeyEvent { 45 state: ElementState::Pressed, 46 physical_key, 47 logical_key, 48 text, 49 repeat, 50 .. 51 }, 52 .. 53 } => Self::Input(InputEvent::KeyDown(key_down( 54 physical_key, 55 &logical_key, 56 text, 57 repeat, 58 ))), 59 WindowEvent::KeyboardInput { .. } 60 | WindowEvent::ActivationTokenDone { .. } 61 | WindowEvent::Moved(_) 62 | WindowEvent::Destroyed 63 | WindowEvent::DroppedFile(_) 64 | WindowEvent::HoveredFile(_) 65 | WindowEvent::HoveredFileCancelled 66 | WindowEvent::Ime(_) 67 | WindowEvent::PinchGesture { .. } 68 | WindowEvent::PanGesture { .. } 69 | WindowEvent::DoubleTapGesture { .. } 70 | WindowEvent::RotationGesture { .. } 71 | WindowEvent::TouchpadPressure { .. } 72 | WindowEvent::AxisMotion { .. } 73 | WindowEvent::Touch(_) 74 | WindowEvent::ScaleFactorChanged { .. } 75 | WindowEvent::ThemeChanged(_) 76 | WindowEvent::Occluded(_) => Self::Ignored, 77 } 78 } 79} 80 81pub fn viewport_extent(size: PhysicalSize<u32>) -> ViewportExtent { 82 ViewportExtent::new( 83 ViewportPx::new(size.width.max(1)), 84 ViewportPx::new(size.height.max(1)), 85 ) 86} 87 88fn modifier_mask(state: ModifiersState) -> ModifierMask { 89 let bits = [ 90 (state.control_key(), ModifierMask::CTRL), 91 (state.shift_key(), ModifierMask::SHIFT), 92 (state.alt_key(), ModifierMask::ALT), 93 (state.super_key(), ModifierMask::META), 94 ]; 95 bits.iter() 96 .filter(|(active, _)| *active) 97 .fold(ModifierMask::NONE, |acc, (_, m)| acc.union(*m)) 98} 99 100const fn pointer_button(button: MouseButton) -> Option<PointerButton> { 101 match button { 102 MouseButton::Left => Some(PointerButton::Primary), 103 MouseButton::Right => Some(PointerButton::Secondary), 104 MouseButton::Middle => Some(PointerButton::Middle), 105 MouseButton::Back | MouseButton::Forward | MouseButton::Other(_) => None, 106 } 107} 108 109fn scroll_delta(delta: MouseScrollDelta) -> ScrollDelta { 110 match delta { 111 MouseScrollDelta::LineDelta(x, y) => ScrollDelta::Lines { x, y }, 112 MouseScrollDelta::PixelDelta(p) => ScrollDelta::Pixels { x: p.x, y: p.y }, 113 } 114} 115 116fn key_down( 117 physical_key: PhysicalKey, 118 logical_key: &Key, 119 text: Option<SmolStr>, 120 repeat: bool, 121) -> KeyDown { 122 let physical_code = match physical_key { 123 PhysicalKey::Code(c) => Some(c), 124 PhysicalKey::Unidentified(_) => None, 125 }; 126 let logical_named = match logical_key { 127 Key::Named(nk) => winit_named_to_ui(*nk), 128 _ => None, 129 }; 130 let named = logical_named.or_else(|| physical_code.and_then(keycode_to_named)); 131 let code = named.map(UiKeyCode::Named).or_else(|| { 132 physical_code 133 .and_then(keycode_to_char) 134 .map(|c| UiKeyCode::Char(KeyChar::from_char(c))) 135 }); 136 KeyDown { 137 code, 138 nav: physical_code.and_then(keycode_to_nav), 139 text: text.map(|t| t.to_string()), 140 repeat, 141 } 142} 143 144const fn keycode_to_nav(code: KeyCode) -> Option<NavKey> { 145 match code { 146 KeyCode::ArrowLeft => Some(NavKey::Left), 147 KeyCode::ArrowRight => Some(NavKey::Right), 148 KeyCode::ArrowUp => Some(NavKey::Up), 149 KeyCode::ArrowDown => Some(NavKey::Down), 150 KeyCode::KeyZ => Some(NavKey::Zoom), 151 KeyCode::Equal => Some(NavKey::ZoomIn), 152 KeyCode::Minus => Some(NavKey::ZoomOut), 153 _ => None, 154 } 155} 156 157fn keycode_to_named(code: KeyCode) -> Option<NamedKey> { 158 match code { 159 KeyCode::Tab => Some(NamedKey::Tab), 160 KeyCode::Enter | KeyCode::NumpadEnter => Some(NamedKey::Enter), 161 KeyCode::Escape => Some(NamedKey::Escape), 162 KeyCode::Backspace => Some(NamedKey::Backspace), 163 KeyCode::Delete => Some(NamedKey::Delete), 164 KeyCode::Space => Some(NamedKey::Space), 165 KeyCode::ArrowUp => Some(NamedKey::ArrowUp), 166 KeyCode::ArrowDown => Some(NamedKey::ArrowDown), 167 KeyCode::ArrowLeft => Some(NamedKey::ArrowLeft), 168 KeyCode::ArrowRight => Some(NamedKey::ArrowRight), 169 KeyCode::Home => Some(NamedKey::Home), 170 KeyCode::End => Some(NamedKey::End), 171 KeyCode::PageUp => Some(NamedKey::PageUp), 172 KeyCode::PageDown => Some(NamedKey::PageDown), 173 KeyCode::F2 => Some(NamedKey::F2), 174 _ => None, 175 } 176} 177 178fn winit_named_to_ui(named: WinitNamed) -> Option<NamedKey> { 179 match named { 180 WinitNamed::Tab => Some(NamedKey::Tab), 181 WinitNamed::Enter => Some(NamedKey::Enter), 182 WinitNamed::Escape => Some(NamedKey::Escape), 183 WinitNamed::Backspace => Some(NamedKey::Backspace), 184 WinitNamed::Delete => Some(NamedKey::Delete), 185 WinitNamed::Space => Some(NamedKey::Space), 186 WinitNamed::ArrowUp => Some(NamedKey::ArrowUp), 187 WinitNamed::ArrowDown => Some(NamedKey::ArrowDown), 188 WinitNamed::ArrowLeft => Some(NamedKey::ArrowLeft), 189 WinitNamed::ArrowRight => Some(NamedKey::ArrowRight), 190 WinitNamed::Home => Some(NamedKey::Home), 191 WinitNamed::End => Some(NamedKey::End), 192 WinitNamed::PageUp => Some(NamedKey::PageUp), 193 WinitNamed::PageDown => Some(NamedKey::PageDown), 194 WinitNamed::F2 => Some(NamedKey::F2), 195 _ => None, 196 } 197} 198 199fn keycode_to_char(code: KeyCode) -> Option<char> { 200 match code { 201 KeyCode::KeyA => Some('a'), 202 KeyCode::KeyB => Some('b'), 203 KeyCode::KeyC => Some('c'), 204 KeyCode::KeyD => Some('d'), 205 KeyCode::KeyE => Some('e'), 206 KeyCode::KeyF => Some('f'), 207 KeyCode::KeyG => Some('g'), 208 KeyCode::KeyH => Some('h'), 209 KeyCode::KeyI => Some('i'), 210 KeyCode::KeyJ => Some('j'), 211 KeyCode::KeyK => Some('k'), 212 KeyCode::KeyL => Some('l'), 213 KeyCode::KeyM => Some('m'), 214 KeyCode::KeyN => Some('n'), 215 KeyCode::KeyO => Some('o'), 216 KeyCode::KeyP => Some('p'), 217 KeyCode::KeyQ => Some('q'), 218 KeyCode::KeyR => Some('r'), 219 KeyCode::KeyS => Some('s'), 220 KeyCode::KeyT => Some('t'), 221 KeyCode::KeyU => Some('u'), 222 KeyCode::KeyV => Some('v'), 223 KeyCode::KeyW => Some('w'), 224 KeyCode::KeyX => Some('x'), 225 KeyCode::KeyY => Some('y'), 226 KeyCode::KeyZ => Some('z'), 227 KeyCode::Digit0 => Some('0'), 228 KeyCode::Digit1 => Some('1'), 229 KeyCode::Digit2 => Some('2'), 230 KeyCode::Digit3 => Some('3'), 231 KeyCode::Digit4 => Some('4'), 232 KeyCode::Digit5 => Some('5'), 233 KeyCode::Digit6 => Some('6'), 234 KeyCode::Digit7 => Some('7'), 235 KeyCode::Digit8 => Some('8'), 236 KeyCode::Digit9 => Some('9'), 237 _ => None, 238 } 239}