blob: 6bc6ffd82376575d64480e9aa9f00c7e0314d2c9 [file] [log] [blame]
// Copyright 2020 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 {
crate::input_device,
crate::input_handler::UnhandledInputHandler,
crate::keyboard_binding,
anyhow::Error,
async_trait::async_trait,
fidl_fuchsia_ui_input3::{self as fidl_ui_input3, LockState, Modifiers},
fuchsia_component::client::connect_to_protocol,
fuchsia_syslog::{fx_log_debug, fx_log_err},
fuchsia_zircon as zx,
keymaps::{self, LockStateChecker, ModifierChecker},
std::rc::Rc,
};
#[derive(Debug)]
pub struct FrozenLockState {
lock_state: LockState,
}
impl From<LockState> for FrozenLockState {
fn from(lock_state: LockState) -> Self {
FrozenLockState { lock_state }
}
}
impl LockStateChecker for FrozenLockState {
fn test(&self, value: LockState) -> bool {
self.lock_state.contains(value)
}
}
/// Modifier state plus a tester method.
#[derive(Debug)]
pub struct FrozenModifierState {
state: Modifiers,
}
impl From<fidl_fuchsia_ui_input3::Modifiers> for FrozenModifierState {
fn from(state: Modifiers) -> Self {
FrozenModifierState { state }
}
}
impl ModifierChecker for FrozenModifierState {
fn test(&self, value: Modifiers) -> bool {
self.state.contains(value)
}
}
/// [`ImeHandler`] is responsible for dispatching key events to the IME service, thus making sure
/// that key events are delivered to application runtimes (e.g., web, Flutter).
///
/// > NOTE: The [ImeHandler] requires [ModifierHandler] to be installed upstream to apply the keymaps correctly.
pub struct ImeHandler {
/// The FIDL proxy (client-side stub) to the service for key event injection.
key_event_injector: fidl_ui_input3::KeyEventInjectorProxy,
}
#[async_trait(?Send)]
impl UnhandledInputHandler for ImeHandler {
async fn handle_unhandled_input_event(
self: Rc<Self>,
unhandled_input_event: input_device::UnhandledInputEvent,
) -> Vec<input_device::InputEvent> {
match unhandled_input_event {
input_device::UnhandledInputEvent {
device_event: input_device::InputDeviceEvent::Keyboard(ref keyboard_device_event),
device_descriptor: input_device::InputDeviceDescriptor::Keyboard(_),
event_time,
trace_id: _,
} => {
let key_event = create_key_event(&keyboard_device_event, event_time);
self.dispatch_key(key_event).await;
// Consume the input event.
vec![input_device::InputEvent::from(unhandled_input_event).into_handled()]
}
_ => vec![input_device::InputEvent::from(unhandled_input_event)],
}
}
}
#[allow(dead_code)]
impl ImeHandler {
/// Creates a new [`ImeHandler`] by connecting out to the key event injector.
pub async fn new() -> Result<Rc<Self>, Error> {
let key_event_injector = connect_to_protocol::<fidl_ui_input3::KeyEventInjectorMarker>()?;
Self::new_handler(key_event_injector).await
}
/// Creates a new [`ImeHandler`].
///
/// # Parameters
/// `key_event_injector`: A proxy (FIDL client-side stub) to the key event
/// injector FIDL service.
async fn new_handler(
key_event_injector: fidl_ui_input3::KeyEventInjectorProxy,
) -> Result<Rc<Self>, Error> {
let handler = ImeHandler { key_event_injector };
Ok(Rc::new(handler))
}
/// Dispatches key events to IME and returns KeyboardEvents for unhandled events.
///
/// # Parameters
/// `key_events`: The key events to dispatch.
/// `event_time`: The time in nanoseconds when the events were first recorded.
async fn dispatch_key(self: &Rc<Self>, key_event: fidl_ui_input3::KeyEvent) {
assert!(
key_event.timestamp.is_some(),
"dispatch_key: got a key_event without a timestamp: {:?}",
&key_event
);
match self.key_event_injector.inject(key_event).await {
Err(err) => fx_log_err!("Failed to dispatch key to IME: {:?}", err),
_ => {}
};
}
}
/// Returns a KeyEvent with the given parameters.
///
/// # Parameters
/// * `event`: The keyboard event to process.
/// * `event_time`: The time in nanoseconds when the event was first recorded.
fn create_key_event(
event: &keyboard_binding::KeyboardEvent,
event_time: zx::Time,
) -> fidl_ui_input3::KeyEvent {
let modifier_state: FrozenModifierState =
event.get_modifiers().unwrap_or(Modifiers::from_bits_allow_unknown(0)).into();
let lock_state: FrozenLockState =
event.get_lock_state().unwrap_or(LockState::from_bits_allow_unknown(0)).into();
fx_log_debug!(
"ImeHandler::create_key_event: key:{:?}, modifier_state: {:?}, lock_state: {:?}, event_type: {:?}",
event.get_key(),
modifier_state,
lock_state,
event.get_event_type(),
);
// Don't override the key meaning if already set, e.g. by prior stage.
let key_meaning = event.get_key_meaning().or(keymaps::US_QWERTY.apply(
event.get_key(),
&modifier_state,
&lock_state,
));
// Don't insert a spurious Some(0).
let repeat_sequence = match event.get_repeat_sequence() {
0 => None,
s => Some(s),
};
fidl_ui_input3::KeyEvent {
timestamp: Some(event_time.into_nanos()),
type_: event.get_event_type().into(),
key: event.get_key().into(),
modifiers: event.get_modifiers(),
lock_state: event.get_lock_state(),
key_meaning,
repeat_sequence,
..fidl_ui_input3::KeyEvent::EMPTY
}
}
#[cfg(test)]
mod tests {
use {
super::*,
crate::keyboard_binding::{self, KeyboardEvent},
crate::testing_utilities,
assert_matches::assert_matches,
fidl_fuchsia_input as fidl_input, fidl_fuchsia_ui_input3 as fidl_ui_input3,
fuchsia_async as fasync, fuchsia_zircon as zx,
futures::StreamExt,
std::convert::TryFrom as _,
test_case::test_case,
};
fn handle_events(
ime_handler: Rc<ImeHandler>,
input_events: Vec<input_device::UnhandledInputEvent>,
) {
fasync::Task::local(async move {
for input_event in input_events {
assert_matches!(
ime_handler.clone().handle_unhandled_input_event(input_event).await.as_slice(),
[input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
);
}
})
.detach();
}
async fn assert_ime_receives_events(
expected_events: Vec<fidl_ui_input3::KeyEvent>,
mut request_stream: fidl_ui_input3::KeyEventInjectorRequestStream,
) {
let mut expected_events_iter = expected_events.iter().peekable();
while let Some(Ok(fidl_ui_input3::KeyEventInjectorRequest::Inject {
key_event,
responder,
..
})) = request_stream.next().await
{
pretty_assertions::assert_eq!(&key_event, expected_events_iter.next().unwrap());
// All the expected events have been received, so make sure no more events
// are present before returning.
if expected_events_iter.peek().is_none() {
responder
.send(fidl_ui_input3::KeyEventStatus::Handled)
.expect("error responding to DispatchKey");
return;
}
responder
.send(fidl_ui_input3::KeyEventStatus::Handled)
.expect("error responding to DispatchKey");
}
assert!(false);
}
fn connect_to_key_event_injector(
) -> (fidl_ui_input3::KeyEventInjectorProxy, fidl_ui_input3::KeyEventInjectorRequestStream)
{
fidl::endpoints::create_proxy_and_stream::<fidl_ui_input3::KeyEventInjectorMarker>()
.expect("Failed to create proxy and stream for fuchsia.ui.input3.KeyEventInjector")
}
fn create_unhandled_keyboard_event(
key: fidl_fuchsia_input::Key,
event_type: fidl_fuchsia_ui_input3::KeyEventType,
modifiers: Option<fidl_ui_input3::Modifiers>,
event_time: zx::Time,
device_descriptor: &input_device::InputDeviceDescriptor,
keymap: Option<String>,
) -> input_device::UnhandledInputEvent {
create_unhandled_keyboard_event_with_key_meaning(
key,
event_type,
modifiers,
event_time,
device_descriptor,
keymap,
/* key_meaning */ None,
)
}
fn create_unhandled_keyboard_event_with_key_meaning(
key: fidl_fuchsia_input::Key,
event_type: fidl_fuchsia_ui_input3::KeyEventType,
modifiers: Option<fidl_ui_input3::Modifiers>,
event_time: zx::Time,
device_descriptor: &input_device::InputDeviceDescriptor,
keymap: Option<String>,
key_meaning: Option<fidl_fuchsia_ui_input3::KeyMeaning>,
) -> input_device::UnhandledInputEvent {
input_device::UnhandledInputEvent::try_from(
testing_utilities::create_keyboard_event_with_key_meaning(
key,
event_type,
modifiers,
event_time,
device_descriptor,
keymap,
key_meaning,
),
)
.unwrap()
}
fn create_unhandled_input_event(
keyboard_event: keyboard_binding::KeyboardEvent,
device_descriptor: &input_device::InputDeviceDescriptor,
event_time: zx::Time,
) -> input_device::UnhandledInputEvent {
input_device::UnhandledInputEvent {
device_event: input_device::InputDeviceEvent::Keyboard(keyboard_event),
device_descriptor: device_descriptor.clone(),
event_time,
trace_id: None,
}
}
/// Tests that a pressed key event is dispatched.
///
/// > NOTE: The `device_descriptor` used in this test case and elsewhere
/// *must* be of type `KeyboardDeviceDescriptor` as this is required by the
/// pattern matching in `ImeHandler`.
#[fasync::run_singlethreaded(test)]
async fn pressed_key() {
let (proxy, request_stream) = connect_to_key_event_injector();
let ime_handler =
ImeHandler::new_handler(proxy).await.expect("Failed to create ImeHandler.");
let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
keyboard_binding::KeyboardDeviceDescriptor { keys: vec![fidl_input::Key::A] },
);
let (event_time_i64, event_time_u64) = testing_utilities::event_times();
let input_events = vec![create_unhandled_keyboard_event(
fidl_input::Key::A,
fidl_fuchsia_ui_input3::KeyEventType::Pressed,
None,
event_time_u64,
&device_descriptor,
/* keymap= */ None,
)];
let expected_events = vec![fidl_ui_input3::KeyEvent {
timestamp: Some(event_time_i64),
type_: Some(fidl_ui_input3::KeyEventType::Pressed),
key: Some(fidl_input::Key::A),
// A key "A" without shift is a lowercase 'a'.
key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(97)),
..fidl_ui_input3::KeyEvent::EMPTY
}];
handle_events(ime_handler, input_events);
assert_ime_receives_events(expected_events, request_stream).await;
}
/// Tests that a released key event is dispatched.
#[fasync::run_singlethreaded(test)]
async fn released_key() {
let (proxy, request_stream) = connect_to_key_event_injector();
let ime_handler =
ImeHandler::new_handler(proxy).await.expect("Failed to create ImeHandler.");
let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
keyboard_binding::KeyboardDeviceDescriptor { keys: vec![fidl_input::Key::A] },
);
let (event_time_i64, event_time_u64) = testing_utilities::event_times();
let input_events = vec![create_unhandled_keyboard_event(
fidl_input::Key::A,
fidl_fuchsia_ui_input3::KeyEventType::Released,
None,
event_time_u64,
&device_descriptor,
/* keymap= */ None,
)];
let expected_events = vec![fidl_ui_input3::KeyEvent {
timestamp: Some(event_time_i64),
type_: Some(fidl_ui_input3::KeyEventType::Released),
key: Some(fidl_input::Key::A),
key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(97)),
..fidl_ui_input3::KeyEvent::EMPTY
}];
handle_events(ime_handler, input_events);
assert_ime_receives_events(expected_events, request_stream).await;
}
/// Tests that both pressed and released keys are dispatched appropriately.
#[fasync::run_singlethreaded(test)]
async fn pressed_and_released_key() {
let (proxy, request_stream) = connect_to_key_event_injector();
let ime_handler =
ImeHandler::new_handler(proxy).await.expect("Failed to create ImeHandler.");
let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
keyboard_binding::KeyboardDeviceDescriptor {
keys: vec![fidl_input::Key::A, fidl_input::Key::B],
},
);
let (event_time_i64, event_time_u64) = testing_utilities::event_times();
let input_events = vec![
create_unhandled_keyboard_event(
fidl_input::Key::A,
fidl_fuchsia_ui_input3::KeyEventType::Pressed,
None,
event_time_u64,
&device_descriptor,
/* keymap= */ None,
),
create_unhandled_keyboard_event(
fidl_input::Key::A,
fidl_fuchsia_ui_input3::KeyEventType::Released,
None,
event_time_u64,
&device_descriptor,
/* keymap= */ None,
),
create_unhandled_keyboard_event(
fidl_input::Key::B,
fidl_fuchsia_ui_input3::KeyEventType::Pressed,
None,
event_time_u64,
&device_descriptor,
/* keymap= */ None,
),
create_unhandled_keyboard_event_with_key_meaning(
fidl_input::Key::C,
fidl_fuchsia_ui_input3::KeyEventType::Pressed,
None,
event_time_u64,
&device_descriptor,
/* keymap= */ None,
Some(fidl_fuchsia_ui_input3::KeyMeaning::Codepoint(42)),
),
];
let expected_events = vec![
fidl_ui_input3::KeyEvent {
timestamp: Some(event_time_i64),
type_: Some(fidl_ui_input3::KeyEventType::Pressed),
key: Some(fidl_input::Key::A),
key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(97)),
..fidl_ui_input3::KeyEvent::EMPTY
},
fidl_ui_input3::KeyEvent {
timestamp: Some(event_time_i64),
type_: Some(fidl_ui_input3::KeyEventType::Released),
key: Some(fidl_input::Key::A),
key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(97)),
..fidl_ui_input3::KeyEvent::EMPTY
},
fidl_ui_input3::KeyEvent {
timestamp: Some(event_time_i64),
type_: Some(fidl_ui_input3::KeyEventType::Pressed),
key: Some(fidl_input::Key::B),
key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(98)),
..fidl_ui_input3::KeyEvent::EMPTY
},
fidl_ui_input3::KeyEvent {
timestamp: Some(event_time_i64),
type_: Some(fidl_ui_input3::KeyEventType::Pressed),
key: Some(fidl_input::Key::C),
key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(42)),
..fidl_ui_input3::KeyEvent::EMPTY
},
];
handle_events(ime_handler, input_events);
assert_ime_receives_events(expected_events, request_stream).await;
}
// Tests that modifier keys are dispatched appropriately.
//
// This test depends on the incoming event having correct modifier and lock
// state. Typically you'd do this by installing a ModifierHandler upstream
// of this pipeline stage.
#[fasync::run_singlethreaded(test)]
async fn repeated_modifier_key() {
let (proxy, request_stream) = connect_to_key_event_injector();
let ime_handler =
ImeHandler::new_handler(proxy).await.expect("Failed to create ImeHandler.");
let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
keyboard_binding::KeyboardDeviceDescriptor {
keys: vec![fidl_input::Key::A, fidl_input::Key::CapsLock],
},
);
let (event_time_i64, event_time_u64) = testing_utilities::event_times();
let input_events = vec![
create_unhandled_input_event(
KeyboardEvent::new(
fidl_input::Key::CapsLock,
fidl_fuchsia_ui_input3::KeyEventType::Pressed,
)
.into_with_modifiers(Some(fidl_ui_input3::Modifiers::CAPS_LOCK))
.into_with_lock_state(Some(fidl_ui_input3::LockState::CAPS_LOCK)),
&device_descriptor,
event_time_u64,
),
create_unhandled_input_event(
KeyboardEvent::new(
fidl_input::Key::A,
fidl_fuchsia_ui_input3::KeyEventType::Pressed,
)
.into_with_modifiers(Some(fidl_ui_input3::Modifiers::CAPS_LOCK))
.into_with_lock_state(Some(fidl_ui_input3::LockState::CAPS_LOCK)),
&device_descriptor,
event_time_u64,
),
create_unhandled_input_event(
KeyboardEvent::new(
fidl_input::Key::CapsLock,
fidl_fuchsia_ui_input3::KeyEventType::Released,
)
.into_with_lock_state(Some(fidl_ui_input3::LockState::CAPS_LOCK)),
&device_descriptor,
event_time_u64,
),
];
let expected_events = vec![
fidl_ui_input3::KeyEvent {
timestamp: Some(event_time_i64),
type_: Some(fidl_ui_input3::KeyEventType::Pressed),
key: Some(fidl_input::Key::CapsLock),
modifiers: Some(fidl_ui_input3::Modifiers::CAPS_LOCK),
lock_state: Some(fidl_ui_input3::LockState::CAPS_LOCK),
key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(0)),
..fidl_ui_input3::KeyEvent::EMPTY
},
fidl_ui_input3::KeyEvent {
timestamp: Some(event_time_i64),
type_: Some(fidl_ui_input3::KeyEventType::Pressed),
key: Some(fidl_input::Key::A),
modifiers: Some(fidl_ui_input3::Modifiers::CAPS_LOCK),
lock_state: Some(fidl_ui_input3::LockState::CAPS_LOCK),
key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(65)),
..fidl_ui_input3::KeyEvent::EMPTY
},
fidl_ui_input3::KeyEvent {
timestamp: Some(event_time_i64),
type_: Some(fidl_ui_input3::KeyEventType::Released),
key: Some(fidl_input::Key::CapsLock),
lock_state: Some(fidl_ui_input3::LockState::CAPS_LOCK),
key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(0)),
..fidl_ui_input3::KeyEvent::EMPTY
},
];
handle_events(ime_handler, input_events);
assert_ime_receives_events(expected_events, request_stream).await;
}
#[fasync::run_singlethreaded(test)]
async fn nonprintable_key_meanings_set_correctly() {
let (proxy, request_stream) = connect_to_key_event_injector();
let ime_handler =
ImeHandler::new_handler(proxy).await.expect("Failed to create ImeHandler.");
let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
keyboard_binding::KeyboardDeviceDescriptor {
keys: vec![
fidl_input::Key::Enter,
fidl_input::Key::Tab,
fidl_input::Key::Backspace,
],
},
);
let (event_time_i64, event_time_u64) = testing_utilities::event_times();
let input_events = vec![
create_unhandled_keyboard_event(
fidl_input::Key::Enter,
fidl_fuchsia_ui_input3::KeyEventType::Pressed,
None,
event_time_u64,
&device_descriptor,
/* keymap= */ None,
),
create_unhandled_keyboard_event(
fidl_input::Key::Tab,
fidl_fuchsia_ui_input3::KeyEventType::Pressed,
None,
event_time_u64,
&device_descriptor,
/* keymap= */ None,
),
create_unhandled_keyboard_event(
fidl_input::Key::Backspace,
fidl_fuchsia_ui_input3::KeyEventType::Released,
None,
event_time_u64,
&device_descriptor,
/* keymap= */ None,
),
];
let expected_events = vec![
fidl_ui_input3::KeyEvent {
timestamp: Some(event_time_i64),
type_: Some(fidl_ui_input3::KeyEventType::Pressed),
key: Some(fidl_input::Key::Enter),
key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
fidl_ui_input3::NonPrintableKey::Enter,
)),
..fidl_ui_input3::KeyEvent::EMPTY
},
fidl_ui_input3::KeyEvent {
timestamp: Some(event_time_i64),
type_: Some(fidl_ui_input3::KeyEventType::Pressed),
key: Some(fidl_input::Key::Tab),
key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
fidl_ui_input3::NonPrintableKey::Tab,
)),
..fidl_ui_input3::KeyEvent::EMPTY
},
fidl_ui_input3::KeyEvent {
timestamp: Some(event_time_i64),
// Test that things also work when a key is released.
type_: Some(fidl_ui_input3::KeyEventType::Released),
key: Some(fidl_input::Key::Backspace),
key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
fidl_ui_input3::NonPrintableKey::Backspace,
)),
..fidl_ui_input3::KeyEvent::EMPTY
},
];
handle_events(ime_handler, input_events);
assert_ime_receives_events(expected_events, request_stream).await;
}
#[fasync::run_singlethreaded(test)]
async fn tab() {
let (proxy, request_stream) = connect_to_key_event_injector();
let ime_handler =
ImeHandler::new_handler(proxy).await.expect("Failed to create ImeHandler.");
let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
keyboard_binding::KeyboardDeviceDescriptor {
keys: vec![
fidl_input::Key::Enter,
fidl_input::Key::Tab,
fidl_input::Key::Backspace,
],
},
);
let (event_time_i64, event_time_u64) = testing_utilities::event_times();
let input_events = vec![create_unhandled_keyboard_event(
fidl_input::Key::Tab,
fidl_fuchsia_ui_input3::KeyEventType::Pressed,
None,
event_time_u64,
&device_descriptor,
/* keymap= */ None,
)];
let expected_events = vec![fidl_ui_input3::KeyEvent {
timestamp: Some(event_time_i64),
type_: Some(fidl_ui_input3::KeyEventType::Pressed),
key: Some(fidl_input::Key::Tab),
key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
fidl_ui_input3::NonPrintableKey::Tab,
)),
..fidl_ui_input3::KeyEvent::EMPTY
}];
handle_events(ime_handler, input_events);
assert_ime_receives_events(expected_events, request_stream).await;
}
#[fasync::run_singlethreaded(test)]
async fn shift_shift_a() {
let (proxy, request_stream) = connect_to_key_event_injector();
let ime_handler =
ImeHandler::new_handler(proxy).await.expect("Failed to create ImeHandler.");
let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
keyboard_binding::KeyboardDeviceDescriptor {
keys: vec![fidl_input::Key::LeftCtrl, fidl_input::Key::Tab],
},
);
let (event_time_i64, event_time_u64) = testing_utilities::event_times();
let input_events = vec![
create_unhandled_keyboard_event(
fidl_input::Key::LeftShift,
fidl_fuchsia_ui_input3::KeyEventType::Pressed,
Some(Modifiers::LEFT_SHIFT | Modifiers::SHIFT),
event_time_u64,
&device_descriptor,
/* keymap= */ None,
),
create_unhandled_keyboard_event(
fidl_input::Key::RightShift,
fidl_fuchsia_ui_input3::KeyEventType::Pressed,
Some(Modifiers::LEFT_SHIFT | Modifiers::RIGHT_SHIFT | Modifiers::SHIFT),
event_time_u64,
&device_descriptor,
/* keymap= */ None,
),
create_unhandled_keyboard_event(
fidl_input::Key::A,
fidl_fuchsia_ui_input3::KeyEventType::Pressed,
Some(Modifiers::LEFT_SHIFT | Modifiers::RIGHT_SHIFT | Modifiers::SHIFT),
event_time_u64,
&device_descriptor,
/* keymap= */ None,
),
];
let expected_events = vec![
fidl_ui_input3::KeyEvent {
timestamp: Some(event_time_i64),
type_: Some(fidl_ui_input3::KeyEventType::Pressed),
key: Some(fidl_input::Key::LeftShift),
modifiers: Some(Modifiers::LEFT_SHIFT | Modifiers::SHIFT),
key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(0)),
..fidl_ui_input3::KeyEvent::EMPTY
},
fidl_ui_input3::KeyEvent {
timestamp: Some(event_time_i64),
type_: Some(fidl_ui_input3::KeyEventType::Pressed),
key: Some(fidl_input::Key::RightShift),
modifiers: Some(Modifiers::RIGHT_SHIFT | Modifiers::LEFT_SHIFT | Modifiers::SHIFT),
key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(0)),
..fidl_ui_input3::KeyEvent::EMPTY
},
fidl_ui_input3::KeyEvent {
timestamp: Some(event_time_i64),
type_: Some(fidl_ui_input3::KeyEventType::Pressed),
key: Some(fidl_input::Key::A),
modifiers: Some(Modifiers::RIGHT_SHIFT | Modifiers::LEFT_SHIFT | Modifiers::SHIFT),
key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(65)), // "A"
..fidl_ui_input3::KeyEvent::EMPTY
},
];
handle_events(ime_handler, input_events);
assert_ime_receives_events(expected_events, request_stream).await;
}
#[fasync::run_singlethreaded(test)]
async fn ctrl_tab() {
let (proxy, request_stream) = connect_to_key_event_injector();
let ime_handler =
ImeHandler::new_handler(proxy).await.expect("Failed to create ImeHandler.");
let device_descriptor = input_device::InputDeviceDescriptor::Keyboard(
keyboard_binding::KeyboardDeviceDescriptor {
keys: vec![fidl_input::Key::LeftCtrl, fidl_input::Key::Tab],
},
);
let (event_time_i64, event_time_u64) = testing_utilities::event_times();
let input_events = vec![
create_unhandled_keyboard_event(
fidl_input::Key::LeftCtrl,
fidl_fuchsia_ui_input3::KeyEventType::Pressed,
None,
event_time_u64,
&device_descriptor,
/* keymap= */ None,
),
create_unhandled_keyboard_event(
fidl_input::Key::Tab,
fidl_fuchsia_ui_input3::KeyEventType::Pressed,
None,
event_time_u64,
&device_descriptor,
/* keymap= */ None,
),
];
let expected_events = vec![
fidl_ui_input3::KeyEvent {
timestamp: Some(event_time_i64),
type_: Some(fidl_ui_input3::KeyEventType::Pressed),
key: Some(fidl_input::Key::LeftCtrl),
key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(0)),
..fidl_ui_input3::KeyEvent::EMPTY
},
fidl_ui_input3::KeyEvent {
timestamp: Some(event_time_i64),
type_: Some(fidl_ui_input3::KeyEventType::Pressed),
key: Some(fidl_input::Key::Tab),
key_meaning: Some(fidl_ui_input3::KeyMeaning::NonPrintableKey(
fidl_ui_input3::NonPrintableKey::Tab,
)),
..fidl_ui_input3::KeyEvent::EMPTY
},
];
handle_events(ime_handler, input_events);
assert_ime_receives_events(expected_events, request_stream).await;
}
#[test_case(
keyboard_binding::KeyboardEvent::new(
fidl_input::Key::A,
fidl_ui_input3::KeyEventType::Pressed),
zx::Time::from_nanos(42) => fidl_ui_input3::KeyEvent{
timestamp: Some(42),
type_: Some(fidl_ui_input3::KeyEventType::Pressed),
key: Some(fidl_input::Key::A),
key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(97)),
..fidl_ui_input3::KeyEvent::EMPTY}; "basic value copy")]
#[test_case(
keyboard_binding::KeyboardEvent::new(
fidl_input::Key::A,
fidl_ui_input3::KeyEventType::Pressed)
.into_with_repeat_sequence(13),
zx::Time::from_nanos(42) => fidl_ui_input3::KeyEvent{
timestamp: Some(42),
type_: Some(fidl_ui_input3::KeyEventType::Pressed),
key: Some(fidl_input::Key::A),
key_meaning: Some(fidl_ui_input3::KeyMeaning::Codepoint(97)),
repeat_sequence: Some(13),
..fidl_ui_input3::KeyEvent::EMPTY}; "repeat_sequence is honored")]
fn test_create_key_event(
event: keyboard_binding::KeyboardEvent,
event_time: zx::Time,
) -> fidl_ui_input3::KeyEvent {
super::create_key_event(&event, event_time)
}
}