diff --git a/src/screenreader.rs b/src/screenreader.rs index 108098c..9fe371d 100644 --- a/src/screenreader.rs +++ b/src/screenreader.rs @@ -225,20 +225,15 @@ impl<'dbus> OrcaManager<'dbus> { match mode { ScreenReaderMode::Focus => { self.keyboard.key_down(Key::Insert)?; - self.keyboard.key_down(Key::A)?; - self.keyboard.key_up(Key::A)?; - self.keyboard.key_down(Key::A)?; - self.keyboard.key_up(Key::A)?; + self.keyboard.key_press(Key::A)?; + self.keyboard.key_press(Key::A)?; self.keyboard.key_up(Key::Insert)?; } ScreenReaderMode::Browse => { self.keyboard.key_down(Key::Insert)?; - self.keyboard.key_down(Key::A)?; - self.keyboard.key_up(Key::A)?; - self.keyboard.key_down(Key::A)?; - self.keyboard.key_up(Key::A)?; - self.keyboard.key_down(Key::A)?; - self.keyboard.key_up(Key::A)?; + self.keyboard.key_press(Key::A)?; + self.keyboard.key_press(Key::A)?; + self.keyboard.key_press(Key::A)?; self.keyboard.key_up(Key::Insert)?; } } @@ -261,48 +256,39 @@ impl<'dbus> OrcaManager<'dbus> { } ScreenReaderAction::ReadNextWord => { self.keyboard.key_down(Key::LeftCtrl)?; - self.keyboard.key_down(Key::Right)?; - self.keyboard.key_up(Key::Right)?; + self.keyboard.key_press(Key::Right)?; self.keyboard.key_up(Key::LeftCtrl)?; } ScreenReaderAction::ReadPreviousWord => { self.keyboard.key_down(Key::LeftCtrl)?; - self.keyboard.key_down(Key::Left)?; - self.keyboard.key_up(Key::Left)?; + self.keyboard.key_press(Key::Left)?; self.keyboard.key_up(Key::LeftCtrl)?; } ScreenReaderAction::ReadNextItem => { - self.keyboard.key_down(Key::Down)?; - self.keyboard.key_up(Key::Down)?; + self.keyboard.key_press(Key::Down)?; } ScreenReaderAction::ReadPreviousItem => { - self.keyboard.key_down(Key::Up)?; - self.keyboard.key_up(Key::Up)?; + self.keyboard.key_press(Key::Up)?; } ScreenReaderAction::MoveToNextLandmark => { - self.keyboard.key_down(Key::M)?; - self.keyboard.key_up(Key::M)?; + self.keyboard.key_press(Key::M)?; } ScreenReaderAction::MoveToPreviousLandmark => { self.keyboard.key_down(Key::LeftShift)?; - self.keyboard.key_down(Key::M)?; - self.keyboard.key_up(Key::M)?; + self.keyboard.key_press(Key::M)?; self.keyboard.key_up(Key::LeftShift)?; } ScreenReaderAction::MoveToNextHeading => { - self.keyboard.key_down(Key::H)?; - self.keyboard.key_up(Key::H)?; + self.keyboard.key_press(Key::H)?; } ScreenReaderAction::MoveToPreviousHeading => { self.keyboard.key_down(Key::LeftShift)?; - self.keyboard.key_down(Key::H)?; - self.keyboard.key_up(Key::H)?; + self.keyboard.key_press(Key::H)?; self.keyboard.key_up(Key::LeftShift)?; } ScreenReaderAction::ToggleMode => { self.keyboard.key_down(Key::Insert)?; - self.keyboard.key_down(Key::A)?; - self.keyboard.key_up(Key::A)?; + self.keyboard.key_press(Key::A)?; self.keyboard.key_up(Key::Insert)?; // TODO: I guess we should emit that the mode changed here... match self.mode { @@ -476,6 +462,7 @@ mod test { use crate::systemd::test::{MockManager, MockUnit}; use crate::systemd::EnableState; use crate::testing; + use input_linux::{Key, KeyState}; use std::time::Duration; use tokio::fs::{copy, remove_file}; use tokio::time::sleep; @@ -622,4 +609,459 @@ mod test { assert_eq!(manager.volume(), 5.0); assert!(nofile_result.is_err()); } + + #[tokio::test] + async fn test_read_next_word() { + let mut h = testing::start(); + copy(TEST_ORCA_SETTINGS, h.test.path().join(ORCA_SETTINGS)) + .await + .unwrap(); + let mut manager = OrcaManager::new(&h.new_dbus().await.expect("new_dbus")) + .await + .expect("OrcaManager::new"); + manager + .trigger_action(ScreenReaderAction::ReadNextWord, 0) + .await + .unwrap(); + + manager + .keyboard + .expect_key(Key::LeftCtrl, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::Right, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::Right, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::LeftCtrl, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager.keyboard.expect_empty().unwrap(); + } + + #[tokio::test] + async fn test_read_previous_word() { + let mut h = testing::start(); + copy(TEST_ORCA_SETTINGS, h.test.path().join(ORCA_SETTINGS)) + .await + .unwrap(); + let mut manager = OrcaManager::new(&h.new_dbus().await.expect("new_dbus")) + .await + .expect("OrcaManager::new"); + manager + .trigger_action(ScreenReaderAction::ReadPreviousWord, 0) + .await + .unwrap(); + + manager + .keyboard + .expect_key(Key::LeftCtrl, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::Left, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::Left, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::LeftCtrl, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager.keyboard.expect_empty().unwrap(); + } + + #[tokio::test] + async fn test_read_next_item() { + let mut h = testing::start(); + copy(TEST_ORCA_SETTINGS, h.test.path().join(ORCA_SETTINGS)) + .await + .unwrap(); + let mut manager = OrcaManager::new(&h.new_dbus().await.expect("new_dbus")) + .await + .expect("OrcaManager::new"); + manager + .trigger_action(ScreenReaderAction::ReadNextItem, 0) + .await + .unwrap(); + + manager + .keyboard + .expect_key(Key::Down, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::Down, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager.keyboard.expect_empty().unwrap(); + } + + #[tokio::test] + async fn test_read_previous_item() { + let mut h = testing::start(); + copy(TEST_ORCA_SETTINGS, h.test.path().join(ORCA_SETTINGS)) + .await + .unwrap(); + let mut manager = OrcaManager::new(&h.new_dbus().await.expect("new_dbus")) + .await + .expect("OrcaManager::new"); + manager + .trigger_action(ScreenReaderAction::ReadPreviousItem, 0) + .await + .unwrap(); + + manager + .keyboard + .expect_key(Key::Up, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::Up, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager.keyboard.expect_empty().unwrap(); + } + + #[tokio::test] + async fn test_move_to_next_landmark() { + let mut h = testing::start(); + copy(TEST_ORCA_SETTINGS, h.test.path().join(ORCA_SETTINGS)) + .await + .unwrap(); + let mut manager = OrcaManager::new(&h.new_dbus().await.expect("new_dbus")) + .await + .expect("OrcaManager::new"); + manager + .trigger_action(ScreenReaderAction::MoveToNextLandmark, 0) + .await + .unwrap(); + + manager + .keyboard + .expect_key(Key::M, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::M, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager.keyboard.expect_empty().unwrap(); + } + + #[tokio::test] + async fn test_move_to_previous_landmark() { + let mut h = testing::start(); + copy(TEST_ORCA_SETTINGS, h.test.path().join(ORCA_SETTINGS)) + .await + .unwrap(); + let mut manager = OrcaManager::new(&h.new_dbus().await.expect("new_dbus")) + .await + .expect("OrcaManager::new"); + manager + .trigger_action(ScreenReaderAction::MoveToPreviousLandmark, 0) + .await + .unwrap(); + + manager + .keyboard + .expect_key(Key::LeftShift, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::M, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::M, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::LeftShift, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager.keyboard.expect_empty().unwrap(); + } + + #[tokio::test] + async fn test_move_to_next_heading() { + let mut h = testing::start(); + copy(TEST_ORCA_SETTINGS, h.test.path().join(ORCA_SETTINGS)) + .await + .unwrap(); + let mut manager = OrcaManager::new(&h.new_dbus().await.expect("new_dbus")) + .await + .expect("OrcaManager::new"); + manager + .trigger_action(ScreenReaderAction::MoveToNextHeading, 0) + .await + .unwrap(); + + manager + .keyboard + .expect_key(Key::H, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::H, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager.keyboard.expect_empty().unwrap(); + } + + #[tokio::test] + async fn test_move_to_previous_heading() { + let mut h = testing::start(); + copy(TEST_ORCA_SETTINGS, h.test.path().join(ORCA_SETTINGS)) + .await + .unwrap(); + let mut manager = OrcaManager::new(&h.new_dbus().await.expect("new_dbus")) + .await + .expect("OrcaManager::new"); + manager + .trigger_action(ScreenReaderAction::MoveToPreviousHeading, 0) + .await + .unwrap(); + + manager + .keyboard + .expect_key(Key::LeftShift, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::H, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::H, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::LeftShift, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager.keyboard.expect_empty().unwrap(); + } + + #[tokio::test] + async fn test_toggle_mode_to_focus() { + let mut h = testing::start(); + copy(TEST_ORCA_SETTINGS, h.test.path().join(ORCA_SETTINGS)) + .await + .unwrap(); + let mut manager = OrcaManager::new(&h.new_dbus().await.expect("new_dbus")) + .await + .expect("OrcaManager::new"); + manager.mode = ScreenReaderMode::Browse; + manager + .trigger_action(ScreenReaderAction::ToggleMode, 0) + .await + .unwrap(); + + manager + .keyboard + .expect_key(Key::Insert, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::A, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::A, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::Insert, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager.keyboard.expect_empty().unwrap(); + + assert_eq!(manager.mode, ScreenReaderMode::Focus); + } + + #[tokio::test] + async fn test_toggle_mode_to_browse() { + let mut h = testing::start(); + copy(TEST_ORCA_SETTINGS, h.test.path().join(ORCA_SETTINGS)) + .await + .unwrap(); + let mut manager = OrcaManager::new(&h.new_dbus().await.expect("new_dbus")) + .await + .expect("OrcaManager::new"); + manager.mode = ScreenReaderMode::Focus; + manager + .trigger_action(ScreenReaderAction::ToggleMode, 0) + .await + .unwrap(); + + manager + .keyboard + .expect_key(Key::Insert, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::A, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::A, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::Insert, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager.keyboard.expect_empty().unwrap(); + + assert_eq!(manager.mode, ScreenReaderMode::Browse); + } + + #[tokio::test] + async fn test_set_mode_to_focus() { + let mut h = testing::start(); + copy(TEST_ORCA_SETTINGS, h.test.path().join(ORCA_SETTINGS)) + .await + .unwrap(); + let mut manager = OrcaManager::new(&h.new_dbus().await.expect("new_dbus")) + .await + .expect("OrcaManager::new"); + manager.mode = ScreenReaderMode::Browse; + manager.set_mode(ScreenReaderMode::Focus).await.unwrap(); + + manager + .keyboard + .expect_key(Key::Insert, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::A, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::A, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::A, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::A, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::Insert, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager.keyboard.expect_empty().unwrap(); + + assert_eq!(manager.mode, ScreenReaderMode::Focus); + } + + #[tokio::test] + async fn test_set_mode_to_browse() { + let mut h = testing::start(); + copy(TEST_ORCA_SETTINGS, h.test.path().join(ORCA_SETTINGS)) + .await + .unwrap(); + let mut manager = OrcaManager::new(&h.new_dbus().await.expect("new_dbus")) + .await + .expect("OrcaManager::new"); + manager.mode = ScreenReaderMode::Focus; + manager.set_mode(ScreenReaderMode::Browse).await.unwrap(); + + manager + .keyboard + .expect_key(Key::Insert, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::A, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::A, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::A, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::A, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::A, KeyState::PRESSED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::A, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager + .keyboard + .expect_key(Key::Insert, KeyState::RELEASED) + .unwrap(); + manager.keyboard.expect_sync().unwrap(); + manager.keyboard.expect_empty().unwrap(); + + assert_eq!(manager.mode, ScreenReaderMode::Browse); + } + + #[tokio::test] + async fn test_set_mode_same() { + let mut h = testing::start(); + copy(TEST_ORCA_SETTINGS, h.test.path().join(ORCA_SETTINGS)) + .await + .unwrap(); + let mut manager = OrcaManager::new(&h.new_dbus().await.expect("new_dbus")) + .await + .expect("OrcaManager::new"); + manager.mode = ScreenReaderMode::Browse; + manager.set_mode(ScreenReaderMode::Browse).await.unwrap(); + manager.keyboard.expect_empty().unwrap(); + assert_eq!(manager.mode, ScreenReaderMode::Browse); + } } diff --git a/src/uinput.rs b/src/uinput.rs index 98774eb..5b03828 100644 --- a/src/uinput.rs +++ b/src/uinput.rs @@ -8,9 +8,9 @@ use anyhow::{ensure, Result}; #[cfg(test)] use input_linux::InputEvent; +use input_linux::{EventKind, EventTime, Key, KeyEvent, KeyState, SynchronizeEvent}; #[cfg(not(test))] -use input_linux::{EventKind, InputId, UInputHandle}; -use input_linux::{EventTime, Key, KeyEvent, KeyState, SynchronizeEvent}; +use input_linux::{InputId, UInputHandle}; #[cfg(not(test))] use nix::fcntl::{fcntl, FcntlArg, OFlag}; #[cfg(test)] @@ -133,4 +133,40 @@ impl UInputDevice { pub(crate) fn key_up(&mut self, key: Key) -> Result<()> { self.send_key_event(key, KeyState::RELEASED) } + + pub(crate) fn key_press(&mut self, key: Key) -> Result<()> { + self.send_key_event(key, KeyState::PRESSED)?; + self.send_key_event(key, KeyState::RELEASED)?; + Ok(()) + } + + #[cfg(test)] + pub(crate) fn expect_sync(&mut self) -> Result<()> { + let event = self.queue.pop_front().unwrap(); + ensure!( + event.kind == EventKind::Synchronize, + "event.kind is {:?}", + event.kind + ); + Ok(()) + } + + #[cfg(test)] + pub(crate) fn expect_key(&mut self, key: Key, state: KeyState) -> Result<()> { + let event = self.queue.pop_front().unwrap(); + ensure!( + event.kind == EventKind::Key, + "event.kind is {:?}", + event.kind + ); + ensure!(event.code == key as u16, "event.code is {}", event.code); + ensure!(event.value == state.value, "event.value is {}", event.value); + Ok(()) + } + + #[cfg(test)] + pub(crate) fn expect_empty(&mut self) -> Result<()> { + ensure!(self.queue.is_empty(), "queue not empty"); + Ok(()) + } }