From 36c36d8215280c880666600fe79b4bacc4c6a6f8 Mon Sep 17 00:00:00 2001 From: Antoine POPINEAU Date: Sun, 29 Oct 2023 10:33:55 +0100 Subject: [PATCH] Limit UI refresh frame rate. --- src/event.rs | 13 +- src/keyboard.rs | 331 ++++++++++++++++++++++++------------------------ src/main.rs | 8 +- 3 files changed, 179 insertions(+), 173 deletions(-) diff --git a/src/event.rs b/src/event.rs index 4c31ee6..64f3735 100644 --- a/src/event.rs +++ b/src/event.rs @@ -4,10 +4,12 @@ use crossterm::event::{Event as TermEvent, EventStream, KeyEvent}; use futures::{future::FutureExt, StreamExt}; use tokio::sync::mpsc; -const TICK_RATE: u64 = 250; +const TICK_RATE: u64 = 150; +const FRAME_RATE: f64 = 60.0; pub enum Event { Key(KeyEvent), + Render, Tick, } @@ -21,10 +23,12 @@ impl Events { tokio::task::spawn(async move { let mut stream = EventStream::new(); - let mut interval = tokio::time::interval(Duration::from_millis(TICK_RATE)); + let mut render_interval = tokio::time::interval(Duration::from_secs_f64(1.0 / FRAME_RATE)); + let mut tick_interval = tokio::time::interval(Duration::from_millis(TICK_RATE)); loop { - let delay = interval.tick(); + let tick = tick_interval.tick(); + let render = render_interval.tick(); let event = stream.next().fuse(); tokio::select! { @@ -34,7 +38,8 @@ impl Events { } } - _ = delay => { let _ = tx.send(Event::Tick).await; }, + _ = render => { let _ = tx.send(Event::Render).await; }, + _ = tick => { let _ = tx.send(Event::Tick).await; }, } } }); diff --git a/src/keyboard.rs b/src/keyboard.rs index d058709..77f84ea 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -5,7 +5,6 @@ use greetd_ipc::Request; use tokio::sync::RwLock; use crate::{ - event::{Event, Events}, info::{delete_last_session_path, get_last_user_session, get_last_user_session_path, write_last_session, write_last_session_path}, ipc::Ipc, power::power, @@ -13,229 +12,227 @@ use crate::{ Greeter, Mode, }; -pub async fn handle(greeter: Arc>, events: &mut Events, ipc: Ipc) -> Result<(), Box> { - if let Some(Event::Key(input)) = events.next().await { - let mut greeter = greeter.write().await; - - match input { - KeyEvent { - code: KeyCode::Char('u'), - modifiers: KeyModifiers::CONTROL, - .. - } => match greeter.mode { - Mode::Username => greeter.username = String::new(), - Mode::Password => greeter.answer = String::new(), - Mode::Command => greeter.new_command = String::new(), - _ => {} - }, - - #[cfg(debug_assertions)] - KeyEvent { - code: KeyCode::Char('x'), - modifiers: KeyModifiers::CONTROL, - .. - } => { - use crate::greeter::AuthStatus; - - crate::exit(&mut greeter, AuthStatus::Cancel).await; - } - - KeyEvent { code: KeyCode::Esc, .. } => match greeter.mode { - Mode::Users | Mode::Command | Mode::Sessions | Mode::Power => { - greeter.mode = greeter.previous_mode; - } +pub async fn handle(greeter: Arc>, input: KeyEvent, ipc: Ipc) -> Result<(), Box> { + let mut greeter = greeter.write().await; + + match input { + KeyEvent { + code: KeyCode::Char('u'), + modifiers: KeyModifiers::CONTROL, + .. + } => match greeter.mode { + Mode::Username => greeter.username = String::new(), + Mode::Password => greeter.answer = String::new(), + Mode::Command => greeter.new_command = String::new(), + _ => {} + }, - _ => { - Ipc::cancel(&mut greeter).await; - greeter.reset(false).await; - } - }, + #[cfg(debug_assertions)] + KeyEvent { + code: KeyCode::Char('x'), + modifiers: KeyModifiers::CONTROL, + .. + } => { + use crate::greeter::AuthStatus; - KeyEvent { code: KeyCode::Left, .. } => greeter.cursor_offset -= 1, - KeyEvent { code: KeyCode::Right, .. } => greeter.cursor_offset += 1, + crate::exit(&mut greeter, AuthStatus::Cancel).await; + } - KeyEvent { code: KeyCode::F(2), .. } => { - greeter.previous_mode = match greeter.mode { - Mode::Users | Mode::Command | Mode::Sessions | Mode::Power => greeter.previous_mode, - _ => greeter.mode, - }; + KeyEvent { code: KeyCode::Esc, .. } => match greeter.mode { + Mode::Users | Mode::Command | Mode::Sessions | Mode::Power => { + greeter.mode = greeter.previous_mode; + } - greeter.new_command = greeter.command.clone().unwrap_or_default(); - greeter.mode = Mode::Command; + _ => { + Ipc::cancel(&mut greeter).await; + greeter.reset(false).await; } + }, - KeyEvent { code: KeyCode::F(3), .. } => { - greeter.previous_mode = match greeter.mode { - Mode::Users | Mode::Command | Mode::Sessions | Mode::Power => greeter.previous_mode, - _ => greeter.mode, - }; + KeyEvent { code: KeyCode::Left, .. } => greeter.cursor_offset -= 1, + KeyEvent { code: KeyCode::Right, .. } => greeter.cursor_offset += 1, - greeter.mode = Mode::Sessions; - } + KeyEvent { code: KeyCode::F(2), .. } => { + greeter.previous_mode = match greeter.mode { + Mode::Users | Mode::Command | Mode::Sessions | Mode::Power => greeter.previous_mode, + _ => greeter.mode, + }; - KeyEvent { code: KeyCode::F(12), .. } => { - greeter.previous_mode = match greeter.mode { - Mode::Users | Mode::Command | Mode::Sessions | Mode::Power => greeter.previous_mode, - _ => greeter.mode, - }; + greeter.new_command = greeter.command.clone().unwrap_or_default(); + greeter.mode = Mode::Command; + } - greeter.mode = Mode::Power; - } + KeyEvent { code: KeyCode::F(3), .. } => { + greeter.previous_mode = match greeter.mode { + Mode::Users | Mode::Command | Mode::Sessions | Mode::Power => greeter.previous_mode, + _ => greeter.mode, + }; - KeyEvent { code: KeyCode::Up, .. } => { - if let Mode::Users = greeter.mode { - if greeter.users.selected > 0 { - greeter.users.selected -= 1; - } - } + greeter.mode = Mode::Sessions; + } - if let Mode::Sessions = greeter.mode { - if greeter.sessions.selected > 0 { - greeter.sessions.selected -= 1; - } - } + KeyEvent { code: KeyCode::F(12), .. } => { + greeter.previous_mode = match greeter.mode { + Mode::Users | Mode::Command | Mode::Sessions | Mode::Power => greeter.previous_mode, + _ => greeter.mode, + }; - if let Mode::Power = greeter.mode { - if greeter.powers.selected > 0 { - greeter.powers.selected -= 1; - } + greeter.mode = Mode::Power; + } + + KeyEvent { code: KeyCode::Up, .. } => { + if let Mode::Users = greeter.mode { + if greeter.users.selected > 0 { + greeter.users.selected -= 1; } } - KeyEvent { code: KeyCode::Down, .. } => { - if let Mode::Users = greeter.mode { - if greeter.users.selected < greeter.users.options.len() - 1 { - greeter.users.selected += 1; - } + if let Mode::Sessions = greeter.mode { + if greeter.sessions.selected > 0 { + greeter.sessions.selected -= 1; } + } - if let Mode::Sessions = greeter.mode { - if greeter.sessions.selected < greeter.sessions.options.len() - 1 { - greeter.sessions.selected += 1; - } + if let Mode::Power = greeter.mode { + if greeter.powers.selected > 0 { + greeter.powers.selected -= 1; } + } + } - if let Mode::Power = greeter.mode { - if greeter.powers.selected < greeter.powers.options.len() - 1 { - greeter.powers.selected += 1; - } + KeyEvent { code: KeyCode::Down, .. } => { + if let Mode::Users = greeter.mode { + if greeter.users.selected < greeter.users.options.len() - 1 { + greeter.users.selected += 1; } } - KeyEvent { - code: KeyCode::Char('a'), - modifiers: KeyModifiers::CONTROL, - .. - } => { - let value = { - match greeter.mode { - Mode::Username => &greeter.username, - _ => &greeter.answer, - } - }; + if let Mode::Sessions = greeter.mode { + if greeter.sessions.selected < greeter.sessions.options.len() - 1 { + greeter.sessions.selected += 1; + } + } - greeter.cursor_offset = -(value.chars().count() as i16); + if let Mode::Power = greeter.mode { + if greeter.powers.selected < greeter.powers.options.len() - 1 { + greeter.powers.selected += 1; + } } + } - KeyEvent { - code: KeyCode::Char('e'), - modifiers: KeyModifiers::CONTROL, - .. - } => greeter.cursor_offset = 0, + KeyEvent { + code: KeyCode::Char('a'), + modifiers: KeyModifiers::CONTROL, + .. + } => { + let value = { + match greeter.mode { + Mode::Username => &greeter.username, + _ => &greeter.answer, + } + }; - KeyEvent { code: KeyCode::Tab, .. } => match greeter.mode { - Mode::Username if !greeter.username.is_empty() => validate_username(&mut greeter, &ipc).await, - _ => {} - }, + greeter.cursor_offset = -(value.chars().count() as i16); + } - KeyEvent { code: KeyCode::Enter, .. } => match greeter.mode { - Mode::Username if !greeter.username.is_empty() => validate_username(&mut greeter, &ipc).await, + KeyEvent { + code: KeyCode::Char('e'), + modifiers: KeyModifiers::CONTROL, + .. + } => greeter.cursor_offset = 0, - Mode::Username if greeter.user_menu => { - greeter.previous_mode = match greeter.mode { - Mode::Users | Mode::Command | Mode::Sessions | Mode::Power => greeter.previous_mode, - _ => greeter.mode, - }; + KeyEvent { code: KeyCode::Tab, .. } => match greeter.mode { + Mode::Username if !greeter.username.is_empty() => validate_username(&mut greeter, &ipc).await, + _ => {} + }, - greeter.mode = Mode::Users; - } + KeyEvent { code: KeyCode::Enter, .. } => match greeter.mode { + Mode::Username if !greeter.username.is_empty() => validate_username(&mut greeter, &ipc).await, - Mode::Username => {} + Mode::Username if greeter.user_menu => { + greeter.previous_mode = match greeter.mode { + Mode::Users | Mode::Command | Mode::Sessions | Mode::Power => greeter.previous_mode, + _ => greeter.mode, + }; - Mode::Password => { - greeter.working = true; - greeter.message = None; + greeter.mode = Mode::Users; + } - ipc - .send(Request::PostAuthMessageResponse { - response: Some(greeter.answer.clone()), - }) - .await; + Mode::Username => {} - greeter.answer = String::new(); - } + Mode::Password => { + greeter.working = true; + greeter.message = None; - Mode::Command => { - greeter.sessions.selected = 0; - greeter.command = Some(greeter.new_command.clone()); + ipc + .send(Request::PostAuthMessageResponse { + response: Some(greeter.answer.clone()), + }) + .await; - if greeter.remember_session { - write_last_session(&greeter.new_command); - delete_last_session_path(); - } + greeter.answer = String::new(); + } - greeter.mode = greeter.previous_mode; + Mode::Command => { + greeter.sessions.selected = 0; + greeter.command = Some(greeter.new_command.clone()); + + if greeter.remember_session { + write_last_session(&greeter.new_command); + delete_last_session_path(); } - Mode::Users => { - let username = greeter.users.options.get(greeter.users.selected).cloned(); + greeter.mode = greeter.previous_mode; + } - if let Some(User { username, name }) = username { - greeter.username = username; - greeter.username_mask = name; - } + Mode::Users => { + let username = greeter.users.options.get(greeter.users.selected).cloned(); - validate_username(&mut greeter, &ipc).await; + if let Some(User { username, name }) = username { + greeter.username = username; + greeter.username_mask = name; } - Mode::Sessions => { - let session = greeter.sessions.options.get(greeter.sessions.selected).cloned(); + validate_username(&mut greeter, &ipc).await; + } - if let Some(Session { path, command, .. }) = session { - if greeter.remember_session { - if let Some(ref path) = path { - write_last_session_path(path); - } + Mode::Sessions => { + let session = greeter.sessions.options.get(greeter.sessions.selected).cloned(); - write_last_session(&command); + if let Some(Session { path, command, .. }) = session { + if greeter.remember_session { + if let Some(ref path) = path { + write_last_session_path(path); } - greeter.session_path = path.clone(); - greeter.command = Some(command.clone()); + write_last_session(&command); } - greeter.mode = greeter.previous_mode; + greeter.session_path = path.clone(); + greeter.command = Some(command.clone()); } - Mode::Power => { - let power_command = greeter.powers.options.get(greeter.powers.selected).cloned(); + greeter.mode = greeter.previous_mode; + } - if let Some(command) = power_command { - power(&mut greeter, command.action); - } + Mode::Power => { + let power_command = greeter.powers.options.get(greeter.powers.selected).cloned(); - greeter.mode = greeter.previous_mode; + if let Some(command) = power_command { + power(&mut greeter, command.action); } - Mode::Processing => {} - }, + greeter.mode = greeter.previous_mode; + } + + Mode::Processing => {} + }, - KeyEvent { code: KeyCode::Char(c), .. } => insert_key(&mut greeter, c).await, + KeyEvent { code: KeyCode::Char(c), .. } => insert_key(&mut greeter, c).await, - KeyEvent { code: KeyCode::Backspace, .. } | KeyEvent { code: KeyCode::Delete, .. } => delete_key(&mut greeter, input.code).await, + KeyEvent { code: KeyCode::Backspace, .. } | KeyEvent { code: KeyCode::Delete, .. } => delete_key(&mut greeter, input.code).await, - _ => {} - } + _ => {} } Ok(()) diff --git a/src/main.rs b/src/main.rs index f5a201d..6043c02 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,7 @@ use crossterm::{ execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, }; +use event::Event; use greetd_ipc::Request; use tokio::sync::RwLock; use tui::{backend::CrosstermBackend, Terminal}; @@ -92,8 +93,11 @@ async fn run() -> Result<(), Box> { return Err(status.into()); } - ui::draw(greeter.clone(), &mut terminal).await?; - keyboard::handle(greeter.clone(), &mut events, ipc.clone()).await?; + match events.next().await { + Some(Event::Render) => ui::draw(greeter.clone(), &mut terminal).await?, + Some(Event::Key(key)) => keyboard::handle(greeter.clone(), key, ipc.clone()).await?, + Some(Event::Tick) | None => {} + } } }