blob: 50ab6b007923e00ec66af309fb64ab159525bea2 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
anyhow::{Context as _, Error},
fidl_fuchsia_ui_input as ui_input, fidl_fuchsia_ui_input3 as ui_input3,
fuchsia_syslog::{fx_log_err, fx_log_warn},
futures::{TryFutureExt, TryStreamExt},
};
use fidl_fuchsia_ui_keyboard_focus as fidl_focus;
use crate::ime_service::ImeService;
use crate::keyboard::{events::KeyEvent, keyboard3};
/// Keyboard service router.
/// Starts providers of input3.Keyboard.
/// Handles keyboard events, routing them to one of the following:
/// - other fuchsia.ui.input.ImeService events to ime_service
pub struct Service {
ime_service: ImeService,
keyboard3: keyboard3::KeyboardService,
}
impl Service {
pub async fn new(ime_service: ImeService) -> Result<Service, Error> {
let keyboard3 = keyboard3::KeyboardService::new();
Ok(Service { ime_service, keyboard3 })
}
/// Starts a task that processes `fuchsia.ui.keyboard.focus.Controller`.
/// This method returns immediately without blocking.
pub fn spawn_focus_controller(&self, mut stream: fidl_focus::ControllerRequestStream) {
let keyboard3 = self.keyboard3.clone();
fuchsia_async::Task::spawn(
async move {
while let Some(msg) = stream.try_next().await.context(concat!(
"keyboard::Service::spawn_focus_controller: ",
"error while reading the request stream for ",
"fuchsia.ui.keyboard.focus.Controller"
))? {
match msg {
fidl_focus::ControllerRequest::Notify { view_ref, responder, .. } => {
let view_ref = keyboard3::ViewRef::new(view_ref);
keyboard3.handle_focus_change(view_ref).await;
responder.send()?;
}
}
}
Ok(())
}
.unwrap_or_else(|e: anyhow::Error| fx_log_err!("couldn't run: {:?}", e)),
)
.detach();
}
/// Starts a task that processes `fuchsia.ui.input3.KeyEventInjector` requests.
/// This method returns immediately without blocking.
pub fn spawn_key_event_injector(&self, mut stream: ui_input3::KeyEventInjectorRequestStream) {
let mut keyboard3 = self.keyboard3.clone();
let mut ime_service = self.ime_service.clone();
fuchsia_async::Task::spawn(
async move {
while let Some(msg) = stream.try_next().await.context(concat!(
"keyboard::Service::spawn_key_event_injector: ",
"error while reading the request stream for ",
"fuchsia.ui.input3.KeyEventInjector"
))? {
match msg {
ui_input3::KeyEventInjectorRequest::Inject {
key_event, responder, ..
} => {
let key_event_obj =
KeyEvent::new(&key_event, keyboard3.get_keys_pressed().await)?;
ime_service.inject_input(key_event_obj.clone()).await.unwrap_or_else(
|e| {
fx_log_warn!(
concat!(
"keyboard::Service::spawn_key_event_injector: ",
"error injecting input into IME: {:?}"
),
e
)
},
);
let was_handled = if keyboard3
.handle_key_event(key_event)
.await
.context("error handling input3 keyboard event")?
{
ui_input3::KeyEventStatus::Handled
} else {
ui_input3::KeyEventStatus::NotHandled
};
responder.send(was_handled).context(concat!(
"keyboard::Service::spawn_key_event_injector: ",
"error while sending response"
))?;
}
}
}
Ok(())
}
.unwrap_or_else(|e: anyhow::Error| fx_log_err!("couldn't run: {:?}", e)),
)
.detach();
}
pub fn spawn_ime_service(&self, mut stream: ui_input::ImeServiceRequestStream) {
let mut ime_service = self.ime_service.clone();
fuchsia_async::Task::spawn(
async move {
while let Some(msg) =
stream.try_next().await.context("error running keyboard service")?
{
ime_service
.handle_ime_service_msg(msg)
.await
.context("Handle IME service messages")?;
}
Ok(())
}
.unwrap_or_else(|e: anyhow::Error| fx_log_err!("couldn't run: {:?}", e)),
)
.detach();
}
pub fn spawn_keyboard3_service(&self, stream: ui_input3::KeyboardRequestStream) {
let keyboard3 = self.keyboard3.clone();
fuchsia_async::Task::spawn(
async move { keyboard3.spawn_service(stream).await }
.unwrap_or_else(|e: anyhow::Error| fx_log_err!("couldn't run: {:?}", e)),
)
.detach();
}
}