blob: 59858a670019b1231498bbe354282f23455cf7a0 [file] [log] [blame]
// Copyright 2021 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.
// TODO(fxbug.dev/89234): Check what happens with the modifier keys - we should perhaps maintain
// them.
//! Implements hardware key autorepeat.
//!
//! The [Autorepeater] is a bit of an exception among the stages of the input pipeline. This
//! handler does not implement [input_pipeline::InputHandler], as it requires a different approach
//! to event processing.
//!
//! Specifically, it requires the ability to interleave the events it generates into the
//! flow of "regular" events through the input pipeline. While the [input_pipeline::InputHandler]
//! trait could in principle be modified to admit this sort of approach to event processing, in
//! practice the [Autorepeater] is for now the only stage that requires this approach, so it is
//! not cost effective to retrofit all other handlers just for the sake of this one. We may
//! revisit this decision if we grow more stages that need autorepeat.
use crate::input_device::{self, Handled, InputDeviceDescriptor, InputDeviceEvent, InputEvent};
use crate::keyboard_binding::KeyboardEvent;
use anyhow::{anyhow, Context, Result};
use fidl_fuchsia_settings as fsettings;
use fidl_fuchsia_ui_input3::{KeyEventType, KeyMeaning};
use fuchsia_async::{Task, Time, Timer};
use fuchsia_syslog::{fx_log_debug, fx_log_err, fx_log_info, fx_log_warn};
use fuchsia_zircon as zx;
use fuchsia_zircon::Duration;
use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
use futures::StreamExt;
use std::cell::RefCell;
use std::convert::TryInto;
use std::rc::Rc;
/// Typed autorepeat settings. Use [Default::default()] and the `into_with_*`
/// to create a new instance.
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Settings {
// The time delay before autorepeat kicks in.
delay: Duration,
// The average period between two successive autorepeats. A reciprocal of
// the autorepeat rate.
period: Duration,
}
impl Default for Settings {
fn default() -> Self {
Settings { delay: Duration::from_millis(250), period: Duration::from_millis(50) }
}
}
impl From<fsettings::Autorepeat> for Settings {
/// Conversion, since [fsettings::Autorepeat] has untyped delay and period.
fn from(s: fsettings::Autorepeat) -> Self {
Self { delay: Duration::from_nanos(s.delay), period: Duration::from_nanos(s.period) }
}
}
impl Settings {
/// Modifies the delay.
pub fn into_with_delay(self, delay: Duration) -> Self {
Self { delay, ..self }
}
/// Modifies the period.
pub fn into_with_period(self, period: Duration) -> Self {
Self { period, ..self }
}
}
// Whether the key is repeatable.
enum Repeatability {
// The key may autorepeat.
Yes,
// The key may not autorepeat.
No,
}
// Determines whether the given key meaning corresponds to a key that should be repeated.
//
// Roughly, the criterion is: if the key may contribute to text editing, it should be repeatable.
// The decisions taken below are a bit pragmatic, since our specification in the FIDL API is not
// exactly clear on when a key is repeatable. Instead our rules are implicit in the way the key
// meaning is defined.
//
// To wit, nonzero code points are printable and therefore may repeat.
// NonPrintableKey are, paradoxically, repeatable, since the current examples of keys that are
// nonprintable are empirically repeatable. Keys that are not repeatable have a zero as the
// codepoint - this is not an API requirement, but stems from the way we currently use it, so we
// may as well make it official. The decisions may become obsolete as KeyMeaning evolves.
//
// TODO(fxbug.dev/89736): Sort out whether Left, Right, Up, Down etc should be nonprintable keys
// or keys with codepoint zero.
fn repeatability(key_meaning: Option<KeyMeaning>) -> Repeatability {
match key_meaning {
Some(KeyMeaning::Codepoint(0)) => Repeatability::No, // e.g. Shift
Some(KeyMeaning::Codepoint(_)) => Repeatability::Yes, // A code point.
// This will need to be extended when more nonprintable keys are introduced.
Some(KeyMeaning::NonPrintableKey(_)) => Repeatability::Yes, // Tab, Enter, Backspace...
None => Repeatability::Yes, // Printable with US QWERTY keymap.
}
}
// An events multiplexer.
#[derive(Debug, Clone)]
enum AnyEvent {
// A keyboard input event.
Keyboard(KeyboardEvent, InputDeviceDescriptor, zx::Time, Handled),
// An input event other than keyboard.
NonKeyboard(InputEvent),
// A timer event.
Timeout,
}
impl TryInto<InputEvent> for AnyEvent {
type Error = anyhow::Error;
fn try_into(self) -> Result<InputEvent> {
match self {
AnyEvent::NonKeyboard(ev) => Ok(ev),
AnyEvent::Keyboard(ev, device_descriptor, event_time, handled) => Ok(InputEvent {
device_event: InputDeviceEvent::Keyboard(ev.clone().into_with_folded_event()),
device_descriptor: device_descriptor.clone(),
event_time,
handled,
trace_id: None,
}),
_ => Err(anyhow!("not an InputEvent: {:?}", &self)),
}
}
}
// The state of the autorepeat generator.
#[derive(Debug, Clone)]
enum State {
/// Autorepeat is not active.
Dormant,
/// Autorepeat is armed, we are waiting for a timer event to expire, and when
/// it does, we generate a repeat event.
Armed {
// The keyboard event that caused the state to become Armed.
armed_event: KeyboardEvent,
// The descriptor is used to reconstruct an InputEvent when needed.
armed_descriptor: InputDeviceDescriptor,
// The autorepeat timer is used in the various stages of autorepeat
// waits.
// Not used directly, but rather kept because of its side effect.
_delay_timer: Rc<Task<()>>,
},
}
impl Default for State {
fn default() -> Self {
State::Dormant
}
}
// Logs an `event` before sending to `sink` for debugging.
fn unbounded_send_logged<T>(sink: &UnboundedSender<T>, event: T) -> Result<()>
where
for<'a> &'a T: std::fmt::Debug,
T: 'static + Sync + Send,
{
fx_log_debug!("unbounded_send_logged: {:?}", &event);
sink.unbounded_send(event)?;
Ok(())
}
/// Creates a new autorepeat timer task.
///
/// The task will wait for the amount of time given in `delay`, and then send
/// a [AnyEvent::Timeout] to `sink`; unless it is canceled.
fn new_autorepeat_timer(sink: UnboundedSender<AnyEvent>, delay: Duration) -> Rc<Task<()>> {
let task = Task::local(async move {
Timer::new(Time::after(delay)).await;
fx_log_debug!("autorepeat timeout");
unbounded_send_logged(&sink, AnyEvent::Timeout)
.unwrap_or_else(|e| fx_log_err!("could not fire autorepeat timer: {:?}", e));
});
Rc::new(task)
}
/// Maintains the internal autorepeat state.
///
/// The autorepeat tracks key presses and generates autorepeat key events for
/// the keys that are eligible for autorepeat.
pub struct Autorepeater {
// Internal events are multiplexed into this sender. We may make multiple
// clones to serialize async events.
event_sink: UnboundedSender<AnyEvent>,
// This end is consumed to get the multiplexed ordered events.
event_source: RefCell<UnboundedReceiver<AnyEvent>>,
// The current autorepeat state.
state: RefCell<State>,
// The autorepeat settings.
settings: Settings,
// The task that feeds input events into the processing loop.
_event_feeder: Task<()>,
}
impl Autorepeater {
/// Creates a new [Autorepeater]. The `source` is a receiver end through which
/// the input pipeline events are sent. You must submit [Autorepeater::run]
/// to an executor to start the event processing.
pub fn new(source: UnboundedReceiver<InputEvent>) -> Rc<Self> {
Self::new_with_settings(source, Default::default())
}
fn new_with_settings(
mut source: UnboundedReceiver<InputEvent>,
settings: Settings,
) -> Rc<Self> {
let (event_sink, event_source) = mpsc::unbounded();
// We need a task to feed input events into the channel read by `run()`.
// The task will run until there is at least one sender. When there
// are no more senders, `source.next().await` will return None, and
// this task will exit. The task will close the `event_sink` to
// signal to the other end that it will send no more events, which can
// be used for orderly shutdown.
let event_feeder = {
let event_sink = event_sink.clone();
Task::local(async move {
while let Some(event) = source.next().await {
match event {
InputEvent {
device_event: InputDeviceEvent::Keyboard(k),
device_descriptor,
event_time,
handled,
trace_id: _,
} if handled == Handled::No => unbounded_send_logged(
&event_sink,
AnyEvent::Keyboard(k, device_descriptor, event_time, handled),
)
.context("while forwarding a keyboard event"),
InputEvent {
device_event: _,
device_descriptor: _,
event_time: _,
handled: _,
trace_id: _,
} => unbounded_send_logged(&event_sink, AnyEvent::NonKeyboard(event))
.context("while forwarding a non-keyboard event"),
}
.unwrap_or_else(|e| fx_log_err!("could not run autorepeat: {:?}", e));
}
event_sink.close_channel();
})
};
Rc::new(Autorepeater {
event_sink,
event_source: RefCell::new(event_source),
state: RefCell::new(Default::default()),
settings,
_event_feeder: event_feeder,
})
}
/// Run this function in an executor to start processing events. The
/// transformed event stream is available in `output`.
pub async fn run(self: &Rc<Self>, output: UnboundedSender<InputEvent>) -> Result<()> {
fx_log_info!("key autorepeater installed");
let src = &mut *(self.event_source.borrow_mut());
while let Some(event) = src.next().await {
match event {
// Anything not a keyboard or any handled event gets forwarded as is.
AnyEvent::NonKeyboard(input_event) => unbounded_send_logged(&output, input_event)?,
AnyEvent::Keyboard(_, _, _, _) | AnyEvent::Timeout => {
self.process_event(event, &output).await?
}
}
}
// If we got to here, that means `src` was closed.
// Ensure that the channel closure is propagated correctly.
output.close_channel();
// In production we never expect `src` to close as the autorepeater
// should be operating continuously, so if we're here and we're in prod
// this is unexpected. That is why we return an error.
//
// But, in tests it is acceptable to ignore this error and let the
// function return. An orderly shutdown will result.
Err(anyhow!("recv loop is never supposed to terminate"))
}
// Replace the autorepeater state with a new one.
fn set_state(self: &Rc<Self>, state: State) {
fx_log_debug!("set state: {:?}", &state);
self.state.replace(state);
}
// Get a copy of the current autorepeater state.
fn get_state(self: &Rc<Self>) -> State {
self.state.borrow().clone()
}
// Process a single `event`. Any forwarded or generated events are emitted
// into `output.
async fn process_event(
self: &Rc<Self>,
event: AnyEvent,
output: &UnboundedSender<InputEvent>,
) -> Result<()> {
let old_state = self.get_state();
fx_log_debug!("process_event: current state: {:?}", &old_state);
fx_log_debug!("process_event: inbound event: {:?}", &event);
match (old_state, event.clone()) {
// This is the initial state. We wait for a key event with a printable
// character, since those are autorepeatable.
(State::Dormant, AnyEvent::Keyboard(ev, descriptor, ..)) => {
match (ev.get_event_type_folded(), repeatability(ev.get_key_meaning())) {
// Only a printable key is a candidate for repeating.
// We start a delay timer and go to waiting.
(KeyEventType::Pressed, Repeatability::Yes) => {
let _delay_timer =
new_autorepeat_timer(self.event_sink.clone(), self.settings.delay);
self.set_state(State::Armed {
armed_event: ev,
armed_descriptor: descriptor,
_delay_timer,
});
}
// Any other key type or key event does not get repeated.
(_, _) => {}
}
unbounded_send_logged(&output, event.try_into()?)?;
}
// A timeout comes while we are in dormant state. We expect
// no timeouts in this state. Perhaps this is a timer task
// that fired after it was canceled? In any case, do not act on it,
// but issue a warning.
(State::Dormant, AnyEvent::Timeout) => {
// This is unexpected, but not fatal. If you see this in the
// logs, we probably need to revisit the fuchsia_async::Task
// semantics.
fx_log_warn!("spurious timeout in the autorepeater");
}
// A keyboard event comes in while autorepeat is armed.
//
// If the keyboard event comes in about the same key that was armed, we
// restart the repeat timer, to ensure repeated keypresses on the
// same key don't generate even more repetitions.
//
// If the keyboard event is about a different repeatable key, we
// restart the autorepeat timer with the new key. This means that
// an autorepeated sequence 'aaaaaabbbbbb' will pause for an
// additional repeat delay between the last 'a' and the first 'b'
// in the sequence.
//
// In all cases, pass the event onwards. No events are dropped
// from the event stream.
(State::Armed { armed_event, .. }, AnyEvent::Keyboard(ev, descriptor, ..)) => {
let ev = ev.clone();
match (ev.get_event_type_folded(), repeatability(ev.get_key_meaning())) {
(KeyEventType::Pressed, Repeatability::Yes) => {
let _delay_timer =
new_autorepeat_timer(self.event_sink.clone(), self.settings.delay);
self.set_state(State::Armed {
armed_event: ev,
armed_descriptor: descriptor,
_delay_timer,
});
}
(KeyEventType::Released, Repeatability::Yes) => {
// If the armed key was released, stop autorepeat.
// If the release was for another key, remain in the
// armed state.
if KeyboardEvent::same_key(&armed_event, &ev) {
self.set_state(State::Dormant);
}
}
// Any other event causes nothing special to happen.
_ => {}
}
unbounded_send_logged(&output, event.try_into()?)?;
}
// The timeout triggered while we are armed. This is an autorepeat!
(State::Armed { armed_event, armed_descriptor, .. }, AnyEvent::Timeout) => {
let _delay_timer =
new_autorepeat_timer(self.event_sink.clone(), self.settings.period);
let new_event = armed_event
.clone()
.into_with_repeat_sequence(armed_event.get_repeat_sequence() + 1);
let new_event_time = input_device::event_time_or_now(None);
self.set_state(State::Armed {
armed_event: new_event.clone(),
armed_descriptor: armed_descriptor.clone(),
_delay_timer,
});
// Generate a new autorepeat event and ship it out.
let autorepeat_event =
AnyEvent::Keyboard(new_event, armed_descriptor, new_event_time, Handled::No);
unbounded_send_logged(&output, autorepeat_event.try_into()?)?;
}
// Forward all other events unmodified.
(_, AnyEvent::NonKeyboard(event)) => {
unbounded_send_logged(&output, event)?;
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::testing_utilities;
use fidl_fuchsia_input::Key;
use fuchsia_async::TestExecutor;
use fuchsia_zircon as zx;
use futures::Future;
use pin_utils::pin_mut;
use pretty_assertions::assert_eq;
use std::task::Poll;
// Default autorepeat settings used for test. If these settings are changed,
// any tests may fail, since the tests are tuned to the precise timing that
// is set here.
fn default_settings() -> Settings {
Settings { delay: Duration::from_millis(500), period: Duration::from_seconds(1) }
}
// Creates a new keyboard event for testing.
fn new_event(
key: Key,
event_type: KeyEventType,
key_meaning: Option<KeyMeaning>,
repeat_sequence: u32,
) -> InputEvent {
testing_utilities::create_keyboard_event_with_key_meaning_and_repeat_sequence(
key,
event_type,
/*modifiers=*/ None,
/*event_time*/ zx::Time::ZERO,
&InputDeviceDescriptor::Fake,
/*keymap=*/ None,
key_meaning,
repeat_sequence,
)
}
fn new_handled_event(
key: Key,
event_type: KeyEventType,
key_meaning: Option<KeyMeaning>,
repeat_sequence: u32,
) -> InputEvent {
let event = new_event(key, event_type, key_meaning, repeat_sequence);
// Somewhat surprisingly, this works.
InputEvent { handled: Handled::Yes, ..event }
}
// A shorthand for blocking the specified number of milliseconds, asynchronously.
async fn wait_for_millis(millis: i64) {
wait_for_duration(zx::Duration::from_millis(millis)).await;
}
async fn wait_for_duration(duration: Duration) {
fuchsia_async::Timer::new(Time::after(duration)).await;
}
// Strip event time for these events, for comparison. The event times are
// unpredictable since they are read off of the real time monotonic clock,
// and will be different in every run.
fn remove_event_time(events: Vec<InputEvent>) -> Vec<InputEvent> {
events
.into_iter()
.map(
|InputEvent {
device_event,
device_descriptor,
event_time: _,
handled,
trace_id: _,
}| {
InputEvent {
device_event,
device_descriptor,
event_time: zx::Time::ZERO,
handled,
trace_id: None,
}
},
)
.collect()
}
// Wait for this long (in fake time) before asserting events to ensure
// that all events have been drained and all timers have fired.
const SLACK_DURATION: Duration = zx::Duration::from_millis(5000);
// Checks whether the events read from `output` match supplied `expected` events.
async fn assert_events(output: UnboundedReceiver<InputEvent>, expected: Vec<InputEvent>) {
// Spends a little while longer in the processing loop to ensure that all events have been
// drained before we take the events out. The wait is in fake time, so it does not
// introduce nondeterminism into the tests.
wait_for_duration(SLACK_DURATION).await;
assert_eq!(
remove_event_time(output.take(expected.len()).collect::<Vec<InputEvent>>().await),
expected
);
}
// Run the future `main_fut` in fake time. The fake time is being advanced
// in relatively small increments until a specified `total_duration` has
// elapsed.
//
// This complication is needed to ensure that any expired
// timers are awoken in the correct sequence because the test executor does
// not automatically wake the timers. For the fake time execution to
// be comparable to a real time execution, we need each timer to have the
// chance of waking up, so that we can properly process the consequences
// of that timer firing.
//
// We require that `main_fut` has completed at `total_duration`, and panic
// if it has not. This ensures that we never block forever in fake time.
//
// This method could possibly be implemented in [TestExecutor] for those
// test executor users who do not care to wake the timers in any special
// way.
fn run_in_fake_time<F>(executor: &mut TestExecutor, main_fut: &mut F, total_duration: Duration)
where
F: Future<Output = ()> + Unpin,
{
const INCREMENT: Duration = zx::Duration::from_millis(13);
// Run the loop for a bit longer than the fake time needed to pump all
// the events, to allow the event queue to drain.
let total_duration = total_duration + SLACK_DURATION;
let mut current = zx::Duration::from_millis(0);
let mut poll_status = Poll::Pending;
// We run until either the future completes or the timeout is reached,
// whichever comes first.
// Running the future after it returns Poll::Ready is not allowed, so
// we must exit the loop then.
while current < total_duration && poll_status == Poll::Pending {
executor.set_fake_time(Time::after(INCREMENT));
executor.wake_expired_timers();
poll_status = executor.run_until_stalled(main_fut);
current = current + INCREMENT;
}
assert_eq!(
poll_status,
Poll::Ready(()),
"the main future did not complete, perhaps increase total_duration?"
);
}
// A general note for all the tests here.
//
// The autorepeat generator is tightly coupled with the real time clock. Such
// a system would be hard to test robustly if we relied on the passage of
// real time, since we can not do precise pauses, and are sensitive to
// the scheduling delays in the emulators that run the tests.
//
// Instead, we use an executor with fake time: we have to advance the fake
// time manually, and poke the executor such that we eventually run through
// the predictable sequence of scheduled asynchronous events.
//
// The first few tests in this suite will have extra comments that explain
// the general testing techniques. Repeated uses of the same techniques
// will not be specially pointed out in the later tests.
// This test pushes a regular key press and release through the autorepeat
// handler. It is used more to explain how the event processing works, than
// it is exercising a specific feature of the autorepeat handler.
#[test]
fn basic_press_and_release_only() {
// TestExecutor puts itself as the thread local executor. Any local
// task spawned from here on will run on the test executor in fake time,
// and will need `run_with_fake_time` to drive it to completion.
let mut executor = TestExecutor::new_with_fake_time().unwrap();
// `input` is where the test fixture will inject the fake input events.
// `receiver` is where the autorepeater will read these events from.
let (input, receiver) = mpsc::unbounded();
// The autorepeat handler takes a receiver end of one channel to get
// the input from, and the send end of another channel to place the
// output into. Since we must formally start the handling process in
// an async task, the API requires you to call `run` to
// start the process and supply the sender side of the output.
//
// This API ensures that the handler is fully configured when started,
// all the while leaving the user with an option of when and how exactly
// to start the handler, including not immediately upon creation.
let handler = Autorepeater::new_with_settings(receiver, default_settings());
// `sender` is where the autorepeat handler will send processed input
// events into. `output` is where we will read the results of the
// autorepeater's work.
let (sender, output) = mpsc::unbounded();
// It is up to the caller to decide where to spawn the handler task.
let handler_task = Task::local(async move { handler.run(sender).await });
// `main_fut` is the task that exercises the handler.
let main_fut = async move {
// Inject a keyboard event into the autorepeater.
//
// The mpsc channel of which 'input' is the receiver will be closed when all consumers
// go out of scope.
input
.unbounded_send(new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
))
.unwrap();
// This will wait in fake time. The tests are not actually delayed because of this
// call.
wait_for_millis(1).await;
input
.unbounded_send(new_event(
Key::A,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
))
.unwrap();
// Assertions are also here in the async domain since reading from
// output must be asynchronous.
assert_events(
output,
vec![
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
),
new_event(
Key::A,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
),
],
)
.await;
};
// Drive both the test fixture task and the handler task in parallel,
// and both in fake time. `run_in_fake_time` advances the fake time from
// zero in increments of about 10ms until all futures complete.
let joined_fut = Task::local(async move {
let _r = futures::join!(handler_task, main_fut);
});
pin_mut!(joined_fut);
run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
}
#[test]
fn basic_sync_and_cancel_only() {
let mut executor = TestExecutor::new_with_fake_time().unwrap();
let (input, receiver) = mpsc::unbounded();
let handler = Autorepeater::new_with_settings(receiver, default_settings());
let (sender, output) = mpsc::unbounded();
let handler_task = Task::local(async move { handler.run(sender).await });
let main_fut = async move {
input
.unbounded_send(new_event(
Key::A,
KeyEventType::Sync,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
))
.unwrap();
wait_for_millis(1).await;
input
.unbounded_send(new_event(
Key::A,
KeyEventType::Cancel,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
))
.unwrap();
assert_events(
output,
vec![
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
),
new_event(
Key::A,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
),
],
)
.await;
};
let joined_fut = Task::local(async move {
let _r = futures::join!(handler_task, main_fut);
});
pin_mut!(joined_fut);
run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
}
// Ensures that we forward but not act on handled events.
#[test]
fn handled_events_are_forwarded() {
let mut executor = TestExecutor::new_with_fake_time().unwrap();
let (input, receiver) = mpsc::unbounded();
let handler = Autorepeater::new_with_settings(receiver, default_settings());
let (sender, output) = mpsc::unbounded();
let handler_task = Task::local(async move { handler.run(sender).await });
let main_fut = async move {
input
.unbounded_send(new_handled_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
))
.unwrap();
wait_for_millis(2000).await;
input
.unbounded_send(new_handled_event(
Key::A,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
))
.unwrap();
assert_events(
output,
vec![
new_handled_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
),
new_handled_event(
Key::A,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
),
],
)
.await;
};
let joined_fut = Task::local(async move {
let _r = futures::join!(handler_task, main_fut);
});
pin_mut!(joined_fut);
run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
}
// In this test, we wait with a pressed key for long enough that the default
// settings should trigger the autorepeat.
#[test]
fn autorepeat_simple() {
let mut executor = TestExecutor::new_with_fake_time().unwrap();
let (input, receiver) = mpsc::unbounded();
let handler = Autorepeater::new_with_settings(receiver, default_settings());
let (sender, output) = mpsc::unbounded();
let handler_task = Task::local(async move { handler.run(sender).await });
let main_fut = async move {
input
.unbounded_send(new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
))
.unwrap();
wait_for_millis(2000).await;
input
.unbounded_send(new_event(
Key::A,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
))
.unwrap();
// The total fake time during which the autorepeat key was actuated
// was 2 seconds. By default the delay to first autorepeat is 500ms,
// then 1000ms for each additional autorepeat. This means we should
// see three `Pressed` events: one at the outset, a second one after
// 500ms, and a third one after 1500ms.
assert_events(
output,
vec![
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
),
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
1,
),
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
2,
),
new_event(
Key::A,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
),
],
)
.await;
};
let joined_fut = Task::local(async move {
let _r = futures::join!(handler_task, main_fut);
});
pin_mut!(joined_fut);
run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
}
// This test is the same as above, but we hold the autorepeat for a little
// while longer and check that the autorepeat event stream has grown
// accordingly.
#[test]
fn autorepeat_simple_longer() {
let mut executor = TestExecutor::new_with_fake_time().unwrap();
let (input, receiver) = mpsc::unbounded();
let handler = Autorepeater::new_with_settings(receiver, default_settings());
let (sender, output) = mpsc::unbounded();
let handler_task = Task::local(async move { handler.run(sender).await });
let main_fut = async move {
input
.unbounded_send(new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
))
.unwrap();
wait_for_millis(3000).await;
input
.unbounded_send(new_event(
Key::A,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
))
.unwrap();
assert_events(
output,
vec![
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
),
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
1,
),
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
2,
),
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
3,
),
new_event(
Key::A,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
),
],
)
.await;
};
let joined_fut = Task::local(async move {
let _r = futures::join!(handler_task, main_fut);
});
pin_mut!(joined_fut);
run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
}
// In this test, keys A and B compete for autorepeat:
//
// @0ms ->|<- 1.6s ->|<- 2s ->|<- 1s ->|
// A """""""""\___________________/"""""""""""""
// : : :
// B """"""""""""""""""""\_________________/""""
#[test]
fn autorepeat_takeover() {
let mut executor = TestExecutor::new_with_fake_time().unwrap();
let (input, receiver) = mpsc::unbounded();
let handler = Autorepeater::new_with_settings(receiver, default_settings());
let (sender, output) = mpsc::unbounded();
let handler_task = Task::local(async move { handler.run(sender).await });
let main_fut = async move {
input
.unbounded_send(new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
))
.unwrap();
wait_for_millis(1600).await;
input
.unbounded_send(new_event(
Key::B,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('b' as u32)),
0,
))
.unwrap();
wait_for_millis(2000).await;
input
.unbounded_send(new_event(
Key::A,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
))
.unwrap();
wait_for_millis(1000).await;
input
.unbounded_send(new_event(
Key::B,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('b' as u32)),
0,
))
.unwrap();
assert_events(
output,
vec![
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
),
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
1,
),
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
2,
),
new_event(
Key::B,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('b' as u32)),
0,
),
new_event(
Key::B,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('b' as u32)),
1,
),
new_event(
Key::B,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('b' as u32)),
2,
),
new_event(
Key::A,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
),
new_event(
Key::B,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('b' as u32)),
3,
),
new_event(
Key::B,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('b' as u32)),
0,
),
],
)
.await;
};
let joined_fut = Task::local(async move {
let _r = futures::join!(handler_task, main_fut);
});
pin_mut!(joined_fut);
run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
}
// In this test, keys A and B compete for autorepeat:
//
// @0ms ->|<- 2s ->|<- 2s ->|<- 2s ->|
// A """""""""\__________________________/""""
// : : : :
// B """"""""""""""""""\________/"""""""""""""
#[test]
fn autorepeat_takeover_and_back() {
let mut executor = TestExecutor::new_with_fake_time().unwrap();
let (input, receiver) = mpsc::unbounded();
let handler = Autorepeater::new_with_settings(receiver, default_settings());
let (sender, output) = mpsc::unbounded();
let handler_task = Task::local(async move { handler.run(sender).await });
let main_fut = async move {
input
.unbounded_send(new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
))
.unwrap();
wait_for_millis(2000).await;
input
.unbounded_send(new_event(
Key::B,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('b' as u32)),
0,
))
.unwrap();
wait_for_millis(2000).await;
input
.unbounded_send(new_event(
Key::B,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('b' as u32)),
0,
))
.unwrap();
wait_for_millis(2000).await;
input
.unbounded_send(new_event(
Key::A,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
))
.unwrap();
// Try to elicit autorepeat. There won't be any.
wait_for_millis(2000).await;
assert_events(
output,
vec![
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
),
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
1,
),
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('a' as u32)),
2,
),
new_event(
Key::B,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('b' as u32)),
0,
),
new_event(
Key::B,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('b' as u32)),
1,
),
new_event(
Key::B,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('b' as u32)),
2,
),
new_event(
Key::B,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('b' as u32)),
0,
),
// No autorepeat after B is released.
new_event(
Key::A,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('a' as u32)),
0,
),
],
)
.await;
};
let joined_fut = Task::local(async move {
let _r = futures::join!(handler_task, main_fut);
});
pin_mut!(joined_fut);
run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
}
#[test]
fn no_autorepeat_for_left_shift() {
let mut executor = TestExecutor::new_with_fake_time().unwrap();
let (input, receiver) = mpsc::unbounded();
let handler = Autorepeater::new_with_settings(receiver, default_settings());
let (sender, output) = mpsc::unbounded();
let handler_task = Task::local(async move { handler.run(sender).await });
let main_fut = async move {
input
.unbounded_send(new_event(
Key::LeftShift,
KeyEventType::Pressed,
// Keys that do not contribute to text editing have code
// point set to zero. We use this as a discriminator for
// which keys may or may not repeat.
Some(KeyMeaning::Codepoint(0)),
0,
))
.unwrap();
wait_for_millis(5000).await;
input
.unbounded_send(new_event(
Key::LeftShift,
KeyEventType::Released,
Some(KeyMeaning::Codepoint(0)),
0,
))
.unwrap();
assert_events(
output,
vec![
new_event(
Key::LeftShift,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint(0)),
0,
),
new_event(
Key::LeftShift,
KeyEventType::Released,
Some(KeyMeaning::Codepoint(0)),
0,
),
],
)
.await;
};
let joined_fut = Task::local(async move {
let _r = futures::join!(handler_task, main_fut);
});
pin_mut!(joined_fut);
run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
}
// @0ms ->|<- 2s ->|<- 2s ->|<- 2s ->|
// A """"""""""""\________/"""""""""""""
// LeftShift """\__________________________/""""
#[test]
fn shift_a_encapsulated() {
let mut executor = TestExecutor::new_with_fake_time().unwrap();
let (input, receiver) = mpsc::unbounded();
let handler = Autorepeater::new_with_settings(receiver, default_settings());
let (sender, output) = mpsc::unbounded();
let handler_task = Task::local(async move { handler.run(sender).await });
let main_fut = async move {
input
.unbounded_send(new_event(
Key::LeftShift,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint(0)),
0,
))
.unwrap();
wait_for_millis(2000).await;
input
.unbounded_send(new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('A' as u32)),
0,
))
.unwrap();
wait_for_millis(2000).await;
input
.unbounded_send(new_event(
Key::A,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('A' as u32)),
0,
))
.unwrap();
wait_for_millis(2000).await;
input
.unbounded_send(new_event(
Key::LeftShift,
KeyEventType::Released,
Some(KeyMeaning::Codepoint(0)),
0,
))
.unwrap();
assert_events(
output,
vec![
new_event(
Key::LeftShift,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint(0)),
0,
),
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('A' as u32)),
0,
),
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('A' as u32)),
1,
),
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('A' as u32)),
2,
),
new_event(
Key::A,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('A' as u32)),
0,
),
new_event(
Key::LeftShift,
KeyEventType::Released,
Some(KeyMeaning::Codepoint(0)),
0,
),
],
)
.await;
};
let joined_fut = Task::local(async move {
let _r = futures::join!(handler_task, main_fut);
});
pin_mut!(joined_fut);
run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
}
// @0ms ->|<- 2s ->|<- 2s ->|<- 2s ->|
// A """"""""""""\_________________/""
// LeftShift """\_________________/"""""""""""
#[test]
fn shift_a_interleaved() {
let mut executor = TestExecutor::new_with_fake_time().unwrap();
let (input, receiver) = mpsc::unbounded();
let handler = Autorepeater::new_with_settings(receiver, default_settings());
let (sender, output) = mpsc::unbounded();
let handler_task = Task::local(async move { handler.run(sender).await });
let main_fut = async move {
input
.unbounded_send(new_event(
Key::LeftShift,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint(0)),
0,
))
.unwrap();
wait_for_millis(2000).await;
input
.unbounded_send(new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('A' as u32)),
0,
))
.unwrap();
wait_for_millis(2000).await;
input
.unbounded_send(new_event(
Key::LeftShift,
KeyEventType::Released,
Some(KeyMeaning::Codepoint(0)),
0,
))
.unwrap();
wait_for_millis(2000).await;
input
.unbounded_send(new_event(
Key::A,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('A' as u32)),
0,
))
.unwrap();
assert_events(
output,
vec![
new_event(
Key::LeftShift,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint(0)),
0,
),
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('A' as u32)),
0,
),
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('A' as u32)),
1,
),
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('A' as u32)),
2,
),
new_event(
Key::LeftShift,
KeyEventType::Released,
Some(KeyMeaning::Codepoint(0)),
0,
),
// This will continue autorepeating capital A, but we'd need
// to autorepeat 'a'. May need to reapply the keymap at
// this point, but this may require redoing the keymap stage.
// Alternative - stop autorepeat, would be easier.
// The current behavior may be enough, however.
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('A' as u32)),
3,
),
new_event(
Key::A,
KeyEventType::Pressed,
Some(KeyMeaning::Codepoint('A' as u32)),
4,
),
new_event(
Key::A,
KeyEventType::Released,
Some(KeyMeaning::Codepoint('A' as u32)),
0,
),
],
)
.await;
};
let joined_fut = async move {
let _r = futures::join!(main_fut, handler_task);
};
pin_mut!(joined_fut);
run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
}
}