From 9ca88ea9c303dda93370f440a7f343ca47940281 Mon Sep 17 00:00:00 2001 From: wjian23 Date: Fri, 27 Oct 2023 15:12:56 +0800 Subject: [PATCH] =?UTF-8?q?refactor(core):=20=F0=9F=92=A1key=20event?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/builtin_widgets/focus_scope.rs | 14 ++-- core/src/events.rs | 2 +- core/src/events/dispatcher.rs | 36 ++++---- core/src/events/keyboard.rs | 106 ++++++++++++++++-------- core/src/window.rs | 54 +++++++----- examples/wordle_game/src/ui.rs | 2 +- ribir/src/app.rs | 33 +++++++- widgets/src/checkbox.rs | 2 +- widgets/src/input/handle.rs | 4 +- widgets/src/input/text_selectable.rs | 4 +- 10 files changed, 163 insertions(+), 94 deletions(-) diff --git a/core/src/builtin_widgets/focus_scope.rs b/core/src/builtin_widgets/focus_scope.rs index e3d3c3a4e..e0b6dd5c3 100644 --- a/core/src/builtin_widgets/focus_scope.rs +++ b/core/src/builtin_widgets/focus_scope.rs @@ -36,7 +36,7 @@ mod tests { }; use super::*; - use crate::{test_helper::*, window::DelayEvent}; + use crate::test_helper::*; #[test] fn tab_scope() { @@ -192,11 +192,13 @@ mod tests { // will deal key event twice (inner and host). wnd.draw_frame(); - wnd.add_delay_event(DelayEvent::KeyDown { - id: wnd.focusing().unwrap(), - physical_key: PhysicalKey::Code(KeyCode::Digit1), - key: VirtualKey::Character("1".into()), - }); + wnd.processes_keyboard_event( + PhysicalKey::Code(KeyCode::Digit0), + VirtualKey::Character("0".into()), + false, + KeyLocation::Standard, + ElementState::Pressed, + ); wnd.run_frame_tasks(); wnd.draw_frame(); diff --git a/core/src/events.rs b/core/src/events.rs index fc846f469..4b78ee1de 100644 --- a/core/src/events.rs +++ b/core/src/events.rs @@ -19,7 +19,7 @@ mod character; pub use character::*; mod wheel; pub use wheel::*; -pub use winit::keyboard::{Key as VirtualKey, KeyCode, ModifiersState, NamedKey, PhysicalKey}; + pub(crate) mod focus_mgr; mod listener_impl_helper; diff --git a/core/src/events/dispatcher.rs b/core/src/events/dispatcher.rs index 6a1960705..e7788ce81 100644 --- a/core/src/events/dispatcher.rs +++ b/core/src/events/dispatcher.rs @@ -2,7 +2,7 @@ use crate::{prelude::*, widget_tree::WidgetTree, window::DelayEvent}; use ribir_text::PIXELS_PER_EM; use std::rc::{Rc, Weak}; use winit::{ - event::{DeviceId, ElementState, Ime, KeyEvent, MouseButton, MouseScrollDelta, WindowEvent}, + event::{DeviceId, ElementState, MouseButton, MouseScrollDelta, WindowEvent}, keyboard::ModifiersState, }; @@ -55,38 +55,32 @@ impl Dispatcher { WindowEvent::MouseInput { state, button, device_id, .. } => { self.dispatch_mouse_input(device_id, state, button); } - WindowEvent::KeyboardInput { event, .. } => { - self.dispatch_keyboard_input(event); - } - WindowEvent::Ime(ime) => { - if let Ime::Commit(s) = ime { - self.add_chars_event(s) - } - } WindowEvent::MouseWheel { delta, .. } => self.dispatch_wheel(delta, wnd_factor), _ => log::info!("not processed event {:?}", event), } } - pub fn dispatch_keyboard_input(&mut self, event: KeyEvent) { + pub fn dispatch_keyboard_input( + &mut self, + physical_key: PhysicalKey, + key: VirtualKey, + is_repeat: bool, + location: KeyLocation, + state: ElementState, + ) { let wnd = self.window(); - if let Some(id) = wnd.focusing() { - let KeyEvent { physical_key, logical_key, text, .. } = event; - match event.state { + if let Some(focus_id) = wnd.focusing() { + let event = KeyboardEvent::new(wnd.id(), focus_id, physical_key, key, is_repeat, location); + match state { ElementState::Pressed => { - wnd.add_delay_event(DelayEvent::KeyDown { id, physical_key, key: logical_key }); - if let Some(text) = text { - self.add_chars_event(text.to_string()); - } - } - ElementState::Released => { - wnd.add_delay_event(DelayEvent::KeyUp { id, physical_key, key: logical_key }) + wnd.add_delay_event(DelayEvent::KeyDown(event)); } + ElementState::Released => wnd.add_delay_event(DelayEvent::KeyUp(event)), }; } } - pub fn add_chars_event(&mut self, chars: String) { + pub fn dispatch_receive_chars(&mut self, chars: String) { let wnd = self.window(); if let Some(focus) = wnd.focusing() { self diff --git a/core/src/events/keyboard.rs b/core/src/events/keyboard.rs index 3e053738f..c8b525b18 100644 --- a/core/src/events/keyboard.rs +++ b/core/src/events/keyboard.rs @@ -6,13 +6,33 @@ use crate::{ impl_listener, impl_multi_event_listener, prelude::*, window::WindowId, }; +pub use winit::keyboard::{ + Key as VirtualKey, KeyCode, KeyLocation, ModifiersState, NamedKey, PhysicalKey, +}; + #[derive(Debug)] pub struct KeyboardEvent { - pub physical_key: PhysicalKey, - pub key: VirtualKey, + physical_key: PhysicalKey, + key: VirtualKey, + is_repeat: bool, + location: KeyLocation, common: CommonEvent, } +impl KeyboardEvent { + #[inline] + pub fn key_code(&self) -> &PhysicalKey { &self.physical_key } + + #[inline] + pub fn key(&self) -> &VirtualKey { &self.key } + + #[inline] + pub fn is_repeat(&self) -> bool { self.is_repeat } + + #[inline] + pub fn location(&self) -> KeyLocation { self.location } +} + pub type KeyboardSubject = MutRefItemSubject<'static, AllKeyboard, Infallible>; impl_multi_event_listener! { @@ -34,10 +54,19 @@ impl_compose_child_with_focus_for_listener!(KeyboardListener); impl KeyboardEvent { #[inline] - pub fn new(physical_key: PhysicalKey, key: VirtualKey, id: WidgetId, wnd_id: WindowId) -> Self { + pub fn new( + wnd_id: WindowId, + id: WidgetId, + physical_key: PhysicalKey, + key: VirtualKey, + is_repeat: bool, + location: KeyLocation, + ) -> Self { Self { physical_key, key, + is_repeat, + location, common: CommonEvent::new(id, wnd_id), } } @@ -45,8 +74,10 @@ impl KeyboardEvent { #[cfg(test)] mod tests { + use winit::event::ElementState; + use super::*; - use crate::{test_helper::*, window::DelayEvent}; + use crate::test_helper::*; use std::{cell::RefCell, rc::Rc}; #[test] @@ -90,45 +121,50 @@ mod tests { let mut wnd = TestWindow::new(fn_widget!(w)); wnd.draw_frame(); - let focusing = wnd.focusing().unwrap(); - - wnd.add_delay_event(DelayEvent::KeyDown { - id: focusing, - physical_key: PhysicalKey::Code(KeyCode::Digit0), - key: VirtualKey::Character("Key0".into()), - }); + wnd.processes_keyboard_event( + PhysicalKey::Code(KeyCode::Digit0), + VirtualKey::Character("0".into()), + false, + KeyLocation::Standard, + ElementState::Pressed, + ); - wnd.add_delay_event(DelayEvent::KeyUp { - id: focusing, - physical_key: PhysicalKey::Code(KeyCode::Digit0), - key: VirtualKey::Character("Key0".into()), - }); + wnd.processes_keyboard_event( + PhysicalKey::Code(KeyCode::Digit0), + VirtualKey::Character("0".into()), + false, + KeyLocation::Standard, + ElementState::Released, + ); - wnd.add_delay_event(DelayEvent::KeyDown { - id: focusing, - physical_key: PhysicalKey::Code(KeyCode::Digit1), - key: VirtualKey::Character("Key1".into()), - }); + wnd.processes_keyboard_event( + PhysicalKey::Code(KeyCode::Digit1), + VirtualKey::Character("1".into()), + false, + KeyLocation::Standard, + ElementState::Pressed, + ); - wnd.add_delay_event(DelayEvent::KeyUp { - id: focusing, - physical_key: PhysicalKey::Code(KeyCode::Digit1), - key: VirtualKey::Character("Key1".into()), - }); + wnd.processes_keyboard_event( + PhysicalKey::Code(KeyCode::Digit1), + VirtualKey::Character("1".into()), + false, + KeyLocation::Standard, + ElementState::Released, + ); wnd.run_frame_tasks(); - assert_eq!( &*keys.borrow(), &[ - "key down capture Character(\"Key0\")", - "key down Character(\"Key0\")", - "key up capture Character(\"Key0\")", - "key up Character(\"Key0\")", - "key down capture Character(\"Key1\")", - "key down Character(\"Key1\")", - "key up capture Character(\"Key1\")", - "key up Character(\"Key1\")" + "key down capture Character(\"0\")", + "key down Character(\"0\")", + "key up capture Character(\"0\")", + "key up Character(\"0\")", + "key down capture Character(\"1\")", + "key down Character(\"1\")", + "key up capture Character(\"1\")", + "key up Character(\"1\")" ] ); } diff --git a/core/src/window.rs b/core/src/window.rs index b6b436edf..2fe54a7d6 100644 --- a/core/src/window.rs +++ b/core/src/window.rs @@ -24,7 +24,7 @@ use std::{ rc::Rc, time::Instant, }; -use winit::event::WindowEvent; +use winit::event::{ElementState, WindowEvent}; pub use winit::window::CursorIcon; /// Window is the root to represent. @@ -97,6 +97,27 @@ impl Window { self.dispatcher.borrow_mut().dispatch(event, ratio); } + pub fn processes_keyboard_event( + &self, + physical_key: PhysicalKey, + key: VirtualKey, + is_repeat: bool, + location: KeyLocation, + state: ElementState, + ) { + self.dispatcher.borrow_mut().dispatch_keyboard_input( + physical_key, + key, + is_repeat, + location, + state, + ); + } + + pub fn processes_receive_chars(&self, chars: String) { + self.dispatcher.borrow_mut().dispatch_receive_chars(chars) + } + /// Request switch the focus to next widget. pub fn request_next_focus(&self) { self.focus_mgr.borrow_mut().focus_next_widget(); } @@ -402,18 +423,15 @@ impl Window { let mut e = AllFocusBubble::FocusOut(e.into_inner()); self.bottom_up_emit::(&mut e, bottom, up); } - DelayEvent::KeyDown { id, physical_key, key } => { - let mut e = AllKeyboard::KeyDownCapture(KeyboardEvent::new( - physical_key, - key.clone(), - id, - self.id(), - )); + DelayEvent::KeyDown(event) => { + let id = event.id(); + + let mut e = AllKeyboard::KeyDownCapture(event); self.top_down_emit::(&mut e, id, None); let mut e = AllKeyboard::KeyDown(e.into_inner()); self.bottom_up_emit::(&mut e, id, None); - if !e.is_prevent_default() && key == VirtualKey::Named(NamedKey::Tab) { + if !e.is_prevent_default() && *e.key() == VirtualKey::Named(NamedKey::Tab) { let pressed_shift = { let dispatcher = self.dispatcher.borrow(); dispatcher.info.modifiers().contains(ModifiersState::SHIFT) @@ -427,9 +445,9 @@ impl Window { } } } - DelayEvent::KeyUp { id, physical_key, key } => { - let mut e = - AllKeyboard::KeyUpCapture(KeyboardEvent::new(physical_key, key, id, self.id())); + DelayEvent::KeyUp(event) => { + let id = event.id(); + let mut e = AllKeyboard::KeyUpCapture(event); self.top_down_emit::(&mut e, id, None); let mut e = AllKeyboard::KeyUp(e.into_inner()); self.bottom_up_emit::(&mut e, id, None); @@ -588,16 +606,8 @@ pub(crate) enum DelayEvent { bottom: WidgetId, up: Option, }, - KeyDown { - id: WidgetId, - physical_key: PhysicalKey, - key: VirtualKey, - }, - KeyUp { - id: WidgetId, - physical_key: PhysicalKey, - key: VirtualKey, - }, + KeyDown(KeyboardEvent), + KeyUp(KeyboardEvent), Chars { id: WidgetId, chars: String, diff --git a/examples/wordle_game/src/ui.rs b/examples/wordle_game/src/ui.rs index cb2eebe19..34e0d6a08 100644 --- a/examples/wordle_game/src/ui.rs +++ b/examples/wordle_game/src/ui.rs @@ -176,7 +176,7 @@ impl Compose for Wordle { e.chars.chars().for_each(|c| $this.write().guessing.enter_char(c)) }, on_key_down: move |e| { - match e.key { + match e.key() { VirtualKey::Named(NamedKey::Backspace) => $this.write().guessing.delete_back_char(), VirtualKey::Named(NamedKey::Enter) => { match $this.write().guess() { diff --git a/ribir/src/app.rs b/ribir/src/app.rs index b05ab9b7a..7b1a0b731 100644 --- a/ribir/src/app.rs +++ b/ribir/src/app.rs @@ -7,7 +7,7 @@ use std::rc::Rc; use std::{convert::Infallible, sync::Once}; use winit::platform::run_on_demand::EventLoopExtRunOnDemand; use winit::{ - event::{Event, StartCause, WindowEvent}, + event::{Event, Ime, KeyEvent, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopProxy}, }; @@ -122,8 +122,7 @@ impl App { request_redraw(&wnd) } event => { - #[allow(deprecated)] - wnd.processes_native_event(event); + App::dispatch_wnd_native_event(&wnd, event); } } wnd.run_frame_tasks(); @@ -165,6 +164,34 @@ impl App { }); } + fn dispatch_wnd_native_event(wnd: &Window, event: WindowEvent) { + match event { + WindowEvent::KeyboardInput { event, .. } => { + let KeyEvent { + physical_key, + logical_key, + text, + location, + repeat, + state, + .. + } = event; + wnd.processes_keyboard_event(physical_key, logical_key, repeat, location, state); + + if let Some(txt) = text { + wnd.processes_receive_chars(txt.to_string()); + } + } + WindowEvent::Ime(ime) => { + if let Ime::Commit(s) = ime { + wnd.processes_receive_chars(s) + } + } + #[allow(deprecated)] + _ => wnd.processes_native_event(event), + } + } + #[track_caller] fn shared() -> &'static App { unsafe { Self::shared_mut() } } diff --git a/widgets/src/checkbox.rs b/widgets/src/checkbox.rs index 577eb1eaa..74a5f7fe4 100644 --- a/widgets/src/checkbox.rs +++ b/widgets/src/checkbox.rs @@ -100,7 +100,7 @@ impl ComposeChild for Checkbox { @ $checkbox { cursor: CursorIcon::Pointer, on_tap: move |_| $this.write().switch_check(), - on_key_up: move |k| if k.key == VirtualKey::Named(NamedKey::Space) { + on_key_up: move |k| if *k.key() == VirtualKey::Named(NamedKey::Space) { $this.write().switch_check() } } diff --git a/widgets/src/input/handle.rs b/widgets/src/input/handle.rs index e3e704708..ce0bb0d3d 100644 --- a/widgets/src/input/handle.rs +++ b/widgets/src/input/handle.rs @@ -86,7 +86,7 @@ fn key_with_command(this: &mut TextEditorArea, event: &KeyboardEvent) -> bool { // use the physical key to make sure the keyboard with different // layout use the same key as shortcut. - match event.physical_key { + match event.key_code() { PhysicalKey::Code(KeyCode::KeyV) => { let clipboard = AppCtx::clipboard(); let txt = clipboard.borrow_mut().read_text(); @@ -116,7 +116,7 @@ fn key_with_command(this: &mut TextEditorArea, event: &KeyboardEvent) -> bool { } fn single_key(this: &mut TextEditorArea, key: &KeyboardEvent) -> bool { - match key.key { + match key.key() { VirtualKey::Named(NamedKey::Enter) => { if this.multi_line { InputWriter::new(this).insert_str("\r"); diff --git a/widgets/src/input/text_selectable.rs b/widgets/src/input/text_selectable.rs index fb8f10893..4a48097a4 100644 --- a/widgets/src/input/text_selectable.rs +++ b/widgets/src/input/text_selectable.rs @@ -102,7 +102,7 @@ fn key_handle(this: &mut TextSelectable, text: &CowArc, event: &KeyboardEve fn deal_with_command(this: &mut TextSelectable, text: &CowArc, event: &KeyboardEvent) -> bool { // use the physical key to make sure the keyboard with different // layout use the same key as shortcut. - match event.physical_key { + match event.key_code() { PhysicalKey::Code(KeyCode::KeyC) => { let rg = this.caret.select_range(); if !rg.is_empty() { @@ -131,7 +131,7 @@ fn is_move_by_word(event: &KeyboardEvent) -> bool { fn deal_with_selection(this: &mut TextSelectable, text: &str, event: &KeyboardEvent) { let old_caret = this.caret; - match event.key { + match event.key() { VirtualKey::Named(NamedKey::ArrowLeft) => { if is_move_by_word(event) { let cluster = select_prev_word(text, this.caret.cluster(), false).start;