From 6252d36a14399153af09be2b9572edda3c14043e Mon Sep 17 00:00:00 2001 From: Paul Rouget Date: Mon, 13 Jul 2020 14:04:06 +0200 Subject: [PATCH] Unfocus input when virtual keyboard is dismissed --- components/compositing/lib.rs | 3 ++ components/compositing/windowing.rs | 3 ++ components/constellation/constellation.rs | 36 +++++++++++++++++++ components/script/dom/document.rs | 7 ++++ components/script/script_thread.rs | 12 +++++-- components/script_traits/lib.rs | 2 ++ components/servo/lib.rs | 10 ++++++ ports/libsimpleservo/api/src/lib.rs | 5 +++ ports/libsimpleservo/capi/src/lib.rs | 8 +++++ .../hololens/ServoApp/ServoControl/Servo.h | 1 + .../ServoApp/ServoControl/ServoControl.cpp | 6 ++++ 11 files changed, 91 insertions(+), 2 deletions(-) diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs index cc4f86922ff..3a7634e3f57 100644 --- a/components/compositing/lib.rs +++ b/components/compositing/lib.rs @@ -109,6 +109,8 @@ pub enum ConstellationMsg { MediaSessionAction(MediaSessionActionType), /// Toggle browser visibility. ChangeBrowserVisibility(TopLevelBrowsingContextId, bool), + /// Virtual keyboard was dismissed + IMEDismissed, } impl fmt::Debug for ConstellationMsg { @@ -140,6 +142,7 @@ impl fmt::Debug for ConstellationMsg { ExitFullScreen(..) => "ExitFullScreen", MediaSessionAction(..) => "MediaSessionAction", ChangeBrowserVisibility(..) => "ChangeBrowserVisibility", + IMEDismissed => "IMEDismissed", }; write!(formatter, "ConstellationMsg::{}", variant) } diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index ac481486d37..c308bf196f6 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -102,6 +102,8 @@ pub enum WindowEvent { MediaSessionAction(MediaSessionActionType), /// Set browser visibility. A hidden browser will not tick the animations. ChangeBrowserVisibility(TopLevelBrowsingContextId, bool), + /// Virtual keyboard was dismissed + IMEDismissed, } impl Debug for WindowEvent { @@ -134,6 +136,7 @@ impl Debug for WindowEvent { WindowEvent::ExitFullScreen(..) => write!(f, "ExitFullScreen"), WindowEvent::MediaSessionAction(..) => write!(f, "MediaSessionAction"), WindowEvent::ChangeBrowserVisibility(..) => write!(f, "ChangeBrowserVisibility"), + WindowEvent::IMEDismissed => write!(f, "IMEDismissed"), } } } diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 1fe8bb034f2..4d94533ffae 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -1470,6 +1470,9 @@ where FromCompositorMsg::Keyboard(key_event) => { self.handle_key_msg(key_event); }, + FromCompositorMsg::IMEDismissed => { + self.handle_ime_dismissed(); + }, // Perform a navigation previously requested by script, if approved by the embedder. // If there is already a pending page (self.pending_changes), it will not be overridden; // However, if the id is not encompassed by another change, it will be. @@ -4074,6 +4077,39 @@ where session_history.replace_history_state(pipeline_id, history_state_id, url); } + fn handle_ime_dismissed(&mut self) { + // Send to the focused browsing contexts' current pipeline. + let focused_browsing_context_id = self + .active_browser_id + .and_then(|browser_id| self.browsers.get(&browser_id)) + .map(|browser| browser.focused_browsing_context_id); + if let Some(browsing_context_id) = focused_browsing_context_id { + let pipeline_id = match self.browsing_contexts.get(&browsing_context_id) { + Some(ctx) => ctx.pipeline_id, + None => { + return warn!( + "Got IME dismissed event for nonexistent browsing context {}.", + browsing_context_id, + ); + }, + }; + let msg = + ConstellationControlMsg::SendEvent(pipeline_id, CompositorEvent::IMEDismissedEvent); + let result = match self.pipelines.get(&pipeline_id) { + Some(pipeline) => pipeline.event_loop.send(msg), + None => { + return debug!( + "Pipeline {:?} got IME dismissed event after closure.", + pipeline_id + ); + }, + }; + if let Err(e) = result { + self.handle_send_error(pipeline_id, e); + } + } + } + fn handle_key_msg(&mut self, event: KeyboardEvent) { // Send to the focused browsing contexts' current pipeline. If it // doesn't exist, fall back to sending to the compositor. diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 437b147678d..8244f4af31f 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -1722,6 +1722,13 @@ impl Document { self.window.reflow(ReflowGoal::Full, ReflowReason::KeyEvent); } + pub fn ime_dismissed(&self) { + self.request_focus( + self.GetBody().as_ref().map(|e| &*e.upcast()), + FocusType::Element, + ) + } + pub fn dispatch_composition_event( &self, composition_event: ::keyboard_types::CompositionEvent, diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 7a439e0dcd6..dda8699b9f2 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -129,8 +129,8 @@ use profile_traits::time::{self as profile_time, profile, ProfilerCategory}; use script_layout_interface::message::{self, LayoutThreadInit, Msg, ReflowGoal}; use script_traits::webdriver_msg::WebDriverScriptCommand; use script_traits::CompositorEvent::{ - CompositionEvent, KeyboardEvent, MouseButtonEvent, MouseMoveEvent, ResizeEvent, TouchEvent, - WheelEvent, + CompositionEvent, IMEDismissedEvent, KeyboardEvent, MouseButtonEvent, MouseMoveEvent, + ResizeEvent, TouchEvent, WheelEvent, }; use script_traits::{ AnimationTickType, CompositorEvent, ConstellationControlMsg, DiscardBrowsingContext, @@ -3583,6 +3583,14 @@ impl ScriptThread { document.dispatch_key_event(key_event); }, + IMEDismissedEvent => { + let document = match self.documents.borrow().find_document(pipeline_id) { + Some(document) => document, + None => return warn!("Message sent to closed pipeline {}.", pipeline_id), + }; + document.ime_dismissed(); + }, + CompositionEvent(composition_event) => { let document = match self.documents.borrow().find_document(pipeline_id) { Some(document) => document, diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index f885a042ddd..13dc9c32fa3 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -570,6 +570,8 @@ pub enum CompositorEvent { KeyboardEvent(KeyboardEvent), /// An event from the IME is dispatched. CompositionEvent(CompositionEvent), + /// Virtual keyboard was dismissed + IMEDismissedEvent, } /// Requests a TimerEvent-Message be sent after the given duration. diff --git a/components/servo/lib.rs b/components/servo/lib.rs index b2a8ebc12fb..aa71c8f3309 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -663,6 +663,16 @@ where } }, + WindowEvent::IMEDismissed => { + let msg = ConstellationMsg::IMEDismissed; + if let Err(e) = self.constellation_chan.send(msg) { + warn!( + "Sending IMEDismissed event to constellation failed ({:?}).", + e + ); + } + }, + WindowEvent::Quit => { self.compositor.maybe_start_shutting_down(); }, diff --git a/ports/libsimpleservo/api/src/lib.rs b/ports/libsimpleservo/api/src/lib.rs index adf7cfe15d4..fc9ce60b8f9 100644 --- a/ports/libsimpleservo/api/src/lib.rs +++ b/ports/libsimpleservo/api/src/lib.rs @@ -560,6 +560,11 @@ impl ServoGlue { } } + pub fn ime_dismissed(&mut self) -> Result<(), &'static str> { + info!("ime_dismissed"); + self.process_event(WindowEvent::IMEDismissed) + } + pub fn on_context_menu_closed( &mut self, result: ContextMenuResult, diff --git a/ports/libsimpleservo/capi/src/lib.rs b/ports/libsimpleservo/capi/src/lib.rs index 6af857c352c..01044cf70c2 100644 --- a/ports/libsimpleservo/capi/src/lib.rs +++ b/ports/libsimpleservo/capi/src/lib.rs @@ -766,6 +766,14 @@ pub extern "C" fn change_visibility(visible: bool) { }); } +#[no_mangle] +pub extern "C" fn ime_dismissed() { + catch_any_panic(|| { + debug!("ime_dismissed"); + call(|s| s.ime_dismissed()); + }); +} + pub struct WakeupCallback(extern "C" fn()); impl WakeupCallback { diff --git a/support/hololens/ServoApp/ServoControl/Servo.h b/support/hololens/ServoApp/ServoControl/Servo.h index 2be93581b22..2d8e3b0f091 100644 --- a/support/hololens/ServoApp/ServoControl/Servo.h +++ b/support/hololens/ServoApp/ServoControl/Servo.h @@ -88,6 +88,7 @@ public: void ContextMenuClosed(CContextMenuResult res, unsigned int idx) { on_context_menu_closed(res, idx); } + void IMEDismissed() { ime_dismissed(); } private: ServoDelegate &mDelegate; diff --git a/support/hololens/ServoApp/ServoControl/ServoControl.cpp b/support/hololens/ServoApp/ServoControl/ServoControl.cpp index f83aef32941..db4710f0606 100644 --- a/support/hololens/ServoApp/ServoControl/ServoControl.cpp +++ b/support/hololens/ServoApp/ServoControl/ServoControl.cpp @@ -91,6 +91,12 @@ void ServoControl::OnLoaded(IInspectable const &, RoutedEventArgs const &) { void ServoControl::InitializeTextController() { mInputPane = Windows::UI::ViewManagement::InputPane::GetForCurrentView(); + mInputPane->Hiding([=](const auto &, const auto &) { + if (mLooping) { + RunOnGLThread([=] { mServo->IMEDismissed(); }); + } + }); + auto manager = CoreTextServicesManager::GetForCurrentView(); mEditContext = manager.CreateEditContext(); mEditContext->InputPaneDisplayPolicy(CoreTextInputPaneDisplayPolicy::Manual);