pub struct Key {
pub name: String,
pub text: Option<String>,
pub ctrl: bool,
pub alt: bool,
pub shift: bool,
pub meta: bool,
}Expand description
One key press, or a paste (name "paste" with its text).
Fields§
§name: StringThe key: a lowercase character ("a", "é"), "space", a named key
("enter", "up", "f5", …) or "paste".
text: Option<String>What the key types, when it types something.
ctrl: boolControl held.
alt: boolAlt (Option) held.
shift: boolShift held.
meta: boolCmd on macOS, Super elsewhere.
Implementations§
Source§impl Key
impl Key
Sourcepub fn is(&self, chord: &str) -> bool
pub fn is(&self, chord: &str) -> bool
Whether this is the chord chord: modifiers and a name joined by +
("ctrl+c", "shift+tab", "escape", "ctrl++"), every modifier
matching exactly.
§Example
use tern_sdk::keys::Key;
let key = Key { ctrl: true, ..Key::named("c") };
assert!(key.is("ctrl+c"));
assert!(!key.is("c"));Examples found in repository?
More examples
examples/dashboard.rs (line 1139)
1121fn main() -> Result<(), tern_sdk::Error> {
1122 let mut dash = Dash::new();
1123 let Some(mut session) = Session::connect(Options::new().app("dashboard"))? else {
1124 print!("{}", dash.view(true).plain(100));
1125 return Ok(());
1126 };
1127 let sf = session.open(SurfaceOptions::screen().title("Fleet").font(Font::Sans))?;
1128 session.render(sf, dash.view(false))?;
1129 let mut next = Instant::now() + TICK;
1130 loop {
1131 let left = next.saturating_duration_since(Instant::now());
1132 match session.next(Some(left))? {
1133 None => {
1134 dash.tick();
1135 next = Instant::now() + TICK;
1136 },
1137 Some(Input::Msg(msg, _)) => dash.update(msg),
1138 Some(Input::Key(key)) => {
1139 if key.is("escape") && dash.confirming.is_some() {
1140 dash.update(Msg::Keep);
1141 } else if key.is("enter") && dash.confirming.is_some() {
1142 dash.update(Msg::Confirm);
1143 } else if key.is("escape") || key.is("q") || key.is("ctrl+c") {
1144 break;
1145 } else if key.is("tab") || key.is("]") {
1146 dash.page = dash.page.turn(false);
1147 } else if key.is("shift+tab") || key.is("[") {
1148 dash.page = dash.page.turn(true);
1149 } else if key.is("up") || key.is("k") {
1150 dash.pick(dash.page, -1);
1151 } else if key.is("down") || key.is("j") {
1152 dash.pick(dash.page, 1);
1153 } else if key.is("r") {
1154 dash.update(Msg::Refresh);
1155 } else if key.is("a") {
1156 dash.act_selected();
1157 } else if key.is("enter") {
1158 if let Some(id) = dash.selected[dash.page.index()] {
1159 dash.update(Msg::Open(dash.page, id.into()));
1160 }
1161 } else {
1162 continue;
1163 }
1164 },
1165 Some(Input::Event(_) | Input::Clipboard(_)) => continue,
1166 }
1167 session.render(sf, dash.view(false))?;
1168 }
1169 session.close()?;
1170 Ok(())
1171}examples/chat.rs (line 139)
128fn main() -> Result<(), tern_sdk::Error> {
129 let Some(mut session) = Session::connect(Options::new().feature(feature::SEND))? else {
130 return plain();
131 };
132 let sf = session.open(SurfaceOptions::inline().title("chat"))?;
133 let mut chat = Chat::default();
134 session.render(sf, chat.view())?;
135 session.focus(sf, Some(EDITOR))?;
136 while let Some(input) = session.next(None)? {
137 match input {
138 Input::Key(key) => {
139 if key.is("escape") || key.is("ctrl+c") || key.is("ctrl+d") {
140 break;
141 }
142 match key.name.as_str() {
143 "enter" if !key.shift && !key.alt => {
144 let text = std::mem::take(&mut chat.draft);
145 chat.cursor = 0;
146 chat.send(text);
147 },
148 "enter" => chat.insert("\n"),
149 "backspace" if chat.cursor > 0 => {
150 let at = chat.byte(chat.cursor - 1);
151 chat.draft.remove(at);
152 chat.cursor -= 1;
153 },
154 "delete" if chat.cursor < chat.draft.chars().count() => {
155 let at = chat.byte(chat.cursor);
156 chat.draft.remove(at);
157 },
158 "left" => chat.cursor = chat.cursor.saturating_sub(1),
159 "right" => chat.cursor = (chat.cursor + 1).min(chat.draft.chars().count()),
160 "home" => chat.cursor = 0,
161 "end" => chat.cursor = chat.draft.chars().count(),
162 "paste" => chat.insert(key.text.as_deref().unwrap_or_default()),
163 _ => match key.typed() {
164 Some(text) => chat.insert(text),
165 None => continue,
166 },
167 }
168 },
169 Input::Msg(Msg::Send(text), _) => chat.send(text),
170 Input::Msg(Msg::Focus, _) => session.focus(sf, Some(EDITOR))?,
171 Input::Event(_) | Input::Clipboard(_) => continue,
172 }
173 session.render(sf, chat.view())?;
174 }
175 session.close()?;
176 println!("Chat closed after {} messages.", chat.transcript.len());
177 Ok(())
178}Sourcepub fn typed(&self) -> Option<&str>
pub fn typed(&self) -> Option<&str>
Whether the key types text without Control, Alt or Meta held.
Examples found in repository?
examples/chat.rs (line 163)
128fn main() -> Result<(), tern_sdk::Error> {
129 let Some(mut session) = Session::connect(Options::new().feature(feature::SEND))? else {
130 return plain();
131 };
132 let sf = session.open(SurfaceOptions::inline().title("chat"))?;
133 let mut chat = Chat::default();
134 session.render(sf, chat.view())?;
135 session.focus(sf, Some(EDITOR))?;
136 while let Some(input) = session.next(None)? {
137 match input {
138 Input::Key(key) => {
139 if key.is("escape") || key.is("ctrl+c") || key.is("ctrl+d") {
140 break;
141 }
142 match key.name.as_str() {
143 "enter" if !key.shift && !key.alt => {
144 let text = std::mem::take(&mut chat.draft);
145 chat.cursor = 0;
146 chat.send(text);
147 },
148 "enter" => chat.insert("\n"),
149 "backspace" if chat.cursor > 0 => {
150 let at = chat.byte(chat.cursor - 1);
151 chat.draft.remove(at);
152 chat.cursor -= 1;
153 },
154 "delete" if chat.cursor < chat.draft.chars().count() => {
155 let at = chat.byte(chat.cursor);
156 chat.draft.remove(at);
157 },
158 "left" => chat.cursor = chat.cursor.saturating_sub(1),
159 "right" => chat.cursor = (chat.cursor + 1).min(chat.draft.chars().count()),
160 "home" => chat.cursor = 0,
161 "end" => chat.cursor = chat.draft.chars().count(),
162 "paste" => chat.insert(key.text.as_deref().unwrap_or_default()),
163 _ => match key.typed() {
164 Some(text) => chat.insert(text),
165 None => continue,
166 },
167 }
168 },
169 Input::Msg(Msg::Send(text), _) => chat.send(text),
170 Input::Msg(Msg::Focus, _) => session.focus(sf, Some(EDITOR))?,
171 Input::Event(_) | Input::Clipboard(_) => continue,
172 }
173 session.render(sf, chat.view())?;
174 }
175 session.close()?;
176 println!("Chat closed after {} messages.", chat.transcript.len());
177 Ok(())
178}Trait Implementations§
impl Eq for Key
impl StructuralPartialEq for Key
Auto Trait Implementations§
impl Freeze for Key
impl RefUnwindSafe for Key
impl Send for Key
impl Sync for Key
impl Unpin for Key
impl UnsafeUnpin for Key
impl UnwindSafe for Key
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
Compare self to
key and return true if they are equal.