mirror of
https://github.com/microsoft/edit.git
synced 2025-12-23 07:07:25 +00:00
Move keyboard definitions into their own file
This commit is contained in:
parent
8e48ae3d60
commit
873fd03c1d
9 changed files with 401 additions and 339 deletions
|
|
@ -6,7 +6,7 @@ use std::num::ParseIntError;
|
|||
use edit::framebuffer::IndexedColor;
|
||||
use edit::helpers::*;
|
||||
use edit::icu;
|
||||
use edit::input::{kbmod, vk};
|
||||
use edit::kbd::*;
|
||||
use edit::tui::*;
|
||||
|
||||
use crate::localization::*;
|
||||
|
|
@ -68,7 +68,7 @@ fn draw_search(ctx: &mut Context, state: &mut State) {
|
|||
ctx.attr_background_rgba(ctx.indexed(IndexedColor::White));
|
||||
ctx.attr_foreground_rgba(ctx.indexed(IndexedColor::Black));
|
||||
{
|
||||
if ctx.contains_focus() && ctx.consume_shortcut(vk::ESCAPE) {
|
||||
if ctx.contains_focus() && ctx.consume_shortcut(VK_ESCAPE) {
|
||||
state.wants_search.kind = StateSearchKind::Hidden;
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ fn draw_search(ctx: &mut Context, state: &mut State) {
|
|||
if focus == StateSearchKind::Search {
|
||||
ctx.steal_focus();
|
||||
}
|
||||
if ctx.is_focused() && ctx.consume_shortcut(vk::RETURN) {
|
||||
if ctx.is_focused() && ctx.consume_shortcut(VK_RETURN) {
|
||||
action = Some(SearchAction::Search);
|
||||
}
|
||||
}
|
||||
|
|
@ -105,9 +105,9 @@ fn draw_search(ctx: &mut Context, state: &mut State) {
|
|||
ctx.steal_focus();
|
||||
}
|
||||
if ctx.is_focused() {
|
||||
if ctx.consume_shortcut(vk::RETURN) {
|
||||
if ctx.consume_shortcut(VK_RETURN) {
|
||||
action = Some(SearchAction::Replace);
|
||||
} else if ctx.consume_shortcut(kbmod::CTRL_ALT | vk::RETURN) {
|
||||
} else if ctx.consume_shortcut(MOD_CTRL | MOD_ALT | VK_RETURN) {
|
||||
action = Some(SearchAction::ReplaceAll);
|
||||
}
|
||||
}
|
||||
|
|
@ -271,9 +271,9 @@ pub fn draw_handle_wants_close(ctx: &mut Context, state: &mut State) {
|
|||
|
||||
// Handle accelerator shortcuts
|
||||
if contains_focus {
|
||||
if ctx.consume_shortcut(vk::S) {
|
||||
if ctx.consume_shortcut(VK_S) {
|
||||
action = Action::Save;
|
||||
} else if ctx.consume_shortcut(vk::N) {
|
||||
} else if ctx.consume_shortcut(VK_N) {
|
||||
action = Action::Discard;
|
||||
}
|
||||
}
|
||||
|
|
@ -319,7 +319,7 @@ pub fn draw_goto_menu(ctx: &mut Context, state: &mut State) {
|
|||
ctx.attr_intrinsic_size(Size { width: 24, height: 1 });
|
||||
ctx.steal_focus();
|
||||
|
||||
if ctx.consume_shortcut(vk::RETURN) {
|
||||
if ctx.consume_shortcut(VK_RETURN) {
|
||||
match validate_goto_point(&state.goto_target) {
|
||||
Ok(point) => {
|
||||
let mut buf = doc.buffer.borrow_mut();
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use std::path::{Path, PathBuf};
|
|||
use edit::arena::scratch_arena;
|
||||
use edit::framebuffer::IndexedColor;
|
||||
use edit::helpers::*;
|
||||
use edit::input::{kbmod, vk};
|
||||
use edit::kbd::*;
|
||||
use edit::tui::*;
|
||||
use edit::{icu, path};
|
||||
|
||||
|
|
@ -75,9 +75,9 @@ pub fn draw_file_picker(ctx: &mut Context, state: &mut State) {
|
|||
if !state.file_picker_autocomplete.is_empty() {
|
||||
let bg = ctx.indexed_alpha(IndexedColor::Background, 3, 4);
|
||||
let fg = ctx.contrasted(bg);
|
||||
let focus_list_beg = ctx.is_focused() && ctx.consume_shortcut(vk::DOWN);
|
||||
let focus_list_end = ctx.is_focused() && ctx.consume_shortcut(vk::UP);
|
||||
let mut autocomplete_done = ctx.consume_shortcut(vk::ESCAPE);
|
||||
let focus_list_beg = ctx.is_focused() && ctx.consume_shortcut(VK_DOWN);
|
||||
let focus_list_end = ctx.is_focused() && ctx.consume_shortcut(VK_UP);
|
||||
let mut autocomplete_done = ctx.consume_shortcut(VK_ESCAPE);
|
||||
|
||||
ctx.list_begin("suggestions");
|
||||
ctx.attr_float(FloatSpec {
|
||||
|
|
@ -105,8 +105,8 @@ pub fn draw_file_picker(ctx: &mut Context, state: &mut State) {
|
|||
if (is_first && focus_list_beg) || (is_last && focus_list_end) {
|
||||
ctx.list_item_steal_focus();
|
||||
} else if ctx.is_focused()
|
||||
&& ((is_first && ctx.consume_shortcut(vk::UP))
|
||||
|| (is_last && ctx.consume_shortcut(vk::DOWN)))
|
||||
&& ((is_first && ctx.consume_shortcut(VK_UP))
|
||||
|| (is_last && ctx.consume_shortcut(VK_DOWN)))
|
||||
{
|
||||
ctx.toss_focus_up();
|
||||
}
|
||||
|
|
@ -126,7 +126,7 @@ pub fn draw_file_picker(ctx: &mut Context, state: &mut State) {
|
|||
}
|
||||
}
|
||||
|
||||
if ctx.is_focused() && ctx.consume_shortcut(vk::RETURN) {
|
||||
if ctx.is_focused() && ctx.consume_shortcut(VK_RETURN) {
|
||||
activated = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -170,7 +170,7 @@ pub fn draw_file_picker(ctx: &mut Context, state: &mut State) {
|
|||
ctx.scrollarea_end();
|
||||
|
||||
if contains_focus
|
||||
&& (ctx.consume_shortcut(vk::BACK) || ctx.consume_shortcut(kbmod::ALT | vk::UP))
|
||||
&& (ctx.consume_shortcut(VK_BACK) || ctx.consume_shortcut(MOD_ALT | VK_UP))
|
||||
{
|
||||
state.file_picker_pending_name = "..".into();
|
||||
activated = true;
|
||||
|
|
@ -224,8 +224,8 @@ pub fn draw_file_picker(ctx: &mut Context, state: &mut State) {
|
|||
ctx.table_end();
|
||||
|
||||
if contains_focus {
|
||||
save |= ctx.consume_shortcut(vk::Y);
|
||||
if ctx.consume_shortcut(vk::N) {
|
||||
save |= ctx.consume_shortcut(VK_Y);
|
||||
if ctx.consume_shortcut(VK_N) {
|
||||
state.file_picker_overwrite_warning = None;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
use edit::arena_format;
|
||||
use edit::helpers::*;
|
||||
use edit::input::{kbmod, vk};
|
||||
use edit::kbd::*;
|
||||
use edit::tui::*;
|
||||
|
||||
use crate::localization::*;
|
||||
|
|
@ -19,7 +19,7 @@ pub fn draw_menubar(ctx: &mut Context, state: &mut State) {
|
|||
if ctx.menubar_menu_begin(loc(LocId::File), 'F') {
|
||||
draw_menu_file(ctx, state);
|
||||
}
|
||||
if !contains_focus && ctx.consume_shortcut(vk::F10) {
|
||||
if !contains_focus && ctx.consume_shortcut(VK_F10) {
|
||||
ctx.steal_focus();
|
||||
}
|
||||
if state.documents.active().is_some() {
|
||||
|
|
@ -38,24 +38,24 @@ pub fn draw_menubar(ctx: &mut Context, state: &mut State) {
|
|||
}
|
||||
|
||||
fn draw_menu_file(ctx: &mut Context, state: &mut State) {
|
||||
if ctx.menubar_menu_button(loc(LocId::FileNew), 'N', kbmod::CTRL | vk::N) {
|
||||
if ctx.menubar_menu_button(loc(LocId::FileNew), 'N', MOD_CTRL | VK_N) {
|
||||
draw_add_untitled_document(ctx, state);
|
||||
}
|
||||
if ctx.menubar_menu_button(loc(LocId::FileOpen), 'O', kbmod::CTRL | vk::O) {
|
||||
if ctx.menubar_menu_button(loc(LocId::FileOpen), 'O', MOD_CTRL | VK_O) {
|
||||
state.wants_file_picker = StateFilePicker::Open;
|
||||
}
|
||||
if state.documents.active().is_some() {
|
||||
if ctx.menubar_menu_button(loc(LocId::FileSave), 'S', kbmod::CTRL | vk::S) {
|
||||
if ctx.menubar_menu_button(loc(LocId::FileSave), 'S', MOD_CTRL | VK_S) {
|
||||
state.wants_save = true;
|
||||
}
|
||||
if ctx.menubar_menu_button(loc(LocId::FileSaveAs), 'A', vk::NULL) {
|
||||
if ctx.menubar_menu_button(loc(LocId::FileSaveAs), 'A', VK_NULL) {
|
||||
state.wants_file_picker = StateFilePicker::SaveAs;
|
||||
}
|
||||
if ctx.menubar_menu_button(loc(LocId::FileClose), 'C', kbmod::CTRL | vk::W) {
|
||||
if ctx.menubar_menu_button(loc(LocId::FileClose), 'C', MOD_CTRL | VK_W) {
|
||||
state.wants_close = true;
|
||||
}
|
||||
}
|
||||
if ctx.menubar_menu_button(loc(LocId::FileExit), 'X', kbmod::CTRL | vk::Q) {
|
||||
if ctx.menubar_menu_button(loc(LocId::FileExit), 'X', MOD_CTRL | VK_Q) {
|
||||
state.wants_exit = true;
|
||||
}
|
||||
ctx.menubar_menu_end();
|
||||
|
|
@ -65,37 +65,37 @@ fn draw_menu_edit(ctx: &mut Context, state: &mut State) {
|
|||
let doc = state.documents.active().unwrap();
|
||||
let mut tb = doc.buffer.borrow_mut();
|
||||
|
||||
if ctx.menubar_menu_button(loc(LocId::EditUndo), 'U', kbmod::CTRL | vk::Z) {
|
||||
if ctx.menubar_menu_button(loc(LocId::EditUndo), 'U', MOD_CTRL | VK_Z) {
|
||||
tb.undo();
|
||||
ctx.needs_rerender();
|
||||
}
|
||||
if ctx.menubar_menu_button(loc(LocId::EditRedo), 'R', kbmod::CTRL | vk::Y) {
|
||||
if ctx.menubar_menu_button(loc(LocId::EditRedo), 'R', MOD_CTRL | VK_Y) {
|
||||
tb.redo();
|
||||
ctx.needs_rerender();
|
||||
}
|
||||
if ctx.menubar_menu_button(loc(LocId::EditCut), 'T', kbmod::CTRL | vk::X) {
|
||||
if ctx.menubar_menu_button(loc(LocId::EditCut), 'T', MOD_CTRL | VK_X) {
|
||||
tb.cut(ctx.clipboard_mut());
|
||||
ctx.needs_rerender();
|
||||
}
|
||||
if ctx.menubar_menu_button(loc(LocId::EditCopy), 'C', kbmod::CTRL | vk::C) {
|
||||
if ctx.menubar_menu_button(loc(LocId::EditCopy), 'C', MOD_CTRL | VK_C) {
|
||||
tb.copy(ctx.clipboard_mut());
|
||||
ctx.needs_rerender();
|
||||
}
|
||||
if ctx.menubar_menu_button(loc(LocId::EditPaste), 'P', kbmod::CTRL | vk::V) {
|
||||
if ctx.menubar_menu_button(loc(LocId::EditPaste), 'P', MOD_CTRL | VK_V) {
|
||||
tb.paste(ctx.clipboard_ref());
|
||||
ctx.needs_rerender();
|
||||
}
|
||||
if state.wants_search.kind != StateSearchKind::Disabled {
|
||||
if ctx.menubar_menu_button(loc(LocId::EditFind), 'F', kbmod::CTRL | vk::F) {
|
||||
if ctx.menubar_menu_button(loc(LocId::EditFind), 'F', MOD_CTRL | VK_F) {
|
||||
state.wants_search.kind = StateSearchKind::Search;
|
||||
state.wants_search.focus = true;
|
||||
}
|
||||
if ctx.menubar_menu_button(loc(LocId::EditReplace), 'L', kbmod::CTRL | vk::R) {
|
||||
if ctx.menubar_menu_button(loc(LocId::EditReplace), 'L', MOD_CTRL | VK_R) {
|
||||
state.wants_search.kind = StateSearchKind::Replace;
|
||||
state.wants_search.focus = true;
|
||||
}
|
||||
}
|
||||
if ctx.menubar_menu_button(loc(LocId::EditSelectAll), 'A', kbmod::CTRL | vk::A) {
|
||||
if ctx.menubar_menu_button(loc(LocId::EditSelectAll), 'A', MOD_CTRL | VK_A) {
|
||||
tb.select_all();
|
||||
ctx.needs_rerender();
|
||||
}
|
||||
|
|
@ -108,16 +108,16 @@ fn draw_menu_view(ctx: &mut Context, state: &mut State) {
|
|||
let word_wrap = tb.is_word_wrap_enabled();
|
||||
|
||||
// All values on the statusbar are currently document specific.
|
||||
if ctx.menubar_menu_button(loc(LocId::ViewFocusStatusbar), 'S', vk::NULL) {
|
||||
if ctx.menubar_menu_button(loc(LocId::ViewFocusStatusbar), 'S', VK_NULL) {
|
||||
state.wants_statusbar_focus = true;
|
||||
}
|
||||
if ctx.menubar_menu_button(loc(LocId::ViewGoToFile), 'F', kbmod::CTRL | vk::P) {
|
||||
if ctx.menubar_menu_button(loc(LocId::ViewGoToFile), 'F', MOD_CTRL | VK_P) {
|
||||
state.wants_go_to_file = true;
|
||||
}
|
||||
if ctx.menubar_menu_button(loc(LocId::FileGoto), 'G', kbmod::CTRL | vk::G) {
|
||||
if ctx.menubar_menu_button(loc(LocId::FileGoto), 'G', MOD_CTRL | VK_G) {
|
||||
state.wants_goto = true;
|
||||
}
|
||||
if ctx.menubar_menu_checkbox(loc(LocId::ViewWordWrap), 'W', kbmod::ALT | vk::Z, word_wrap) {
|
||||
if ctx.menubar_menu_checkbox(loc(LocId::ViewWordWrap), 'W', MOD_ALT | VK_Z, word_wrap) {
|
||||
tb.set_word_wrap(!word_wrap);
|
||||
ctx.needs_rerender();
|
||||
}
|
||||
|
|
@ -127,7 +127,7 @@ fn draw_menu_view(ctx: &mut Context, state: &mut State) {
|
|||
}
|
||||
|
||||
fn draw_menu_help(ctx: &mut Context, state: &mut State) {
|
||||
if ctx.menubar_menu_button(loc(LocId::HelpAbout), 'A', vk::NULL) {
|
||||
if ctx.menubar_menu_button(loc(LocId::HelpAbout), 'A', VK_NULL) {
|
||||
state.wants_about = true;
|
||||
}
|
||||
ctx.menubar_menu_end();
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use edit::arena::scratch_arena;
|
|||
use edit::framebuffer::{Attributes, IndexedColor};
|
||||
use edit::fuzzy::score_fuzzy;
|
||||
use edit::helpers::*;
|
||||
use edit::input::vk;
|
||||
use edit::kbd::*;
|
||||
use edit::tui::*;
|
||||
use edit::{arena_format, icu};
|
||||
|
||||
|
|
@ -97,7 +97,7 @@ pub fn draw_statusbar(ctx: &mut Context, state: &mut State) {
|
|||
ctx.attr_padding(Rect::two(0, 1));
|
||||
ctx.table_set_cell_gap(Size { width: 1, height: 0 });
|
||||
{
|
||||
if ctx.contains_focus() && ctx.consume_shortcut(vk::RETURN) {
|
||||
if ctx.contains_focus() && ctx.consume_shortcut(VK_RETURN) {
|
||||
ctx.toss_focus_up();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,11 +25,11 @@ use draw_statusbar::*;
|
|||
use edit::arena::{self, Arena, ArenaString, scratch_arena};
|
||||
use edit::framebuffer::{self, IndexedColor};
|
||||
use edit::helpers::{CoordType, KIBI, MEBI, MetricFormatter, Rect, Size};
|
||||
use edit::input::{self, kbmod, vk};
|
||||
use edit::kbd::*;
|
||||
use edit::oklab::oklab_blend;
|
||||
use edit::tui::*;
|
||||
use edit::vt::{self, Token};
|
||||
use edit::{apperr, arena_format, base64, path, sys, unicode};
|
||||
use edit::{apperr, arena_format, base64, input, path, sys, unicode};
|
||||
use localization::*;
|
||||
use state::*;
|
||||
|
||||
|
|
@ -322,31 +322,29 @@ fn draw(ctx: &mut Context, state: &mut State) {
|
|||
if let Some(key) = ctx.keyboard_input() {
|
||||
// Shortcuts that are not handled as part of the textarea, etc.
|
||||
|
||||
if key == kbmod::CTRL | vk::N {
|
||||
if key == MOD_CTRL | VK_N {
|
||||
draw_add_untitled_document(ctx, state);
|
||||
} else if key == kbmod::CTRL | vk::O {
|
||||
} else if key == MOD_CTRL | VK_O {
|
||||
state.wants_file_picker = StateFilePicker::Open;
|
||||
} else if key == kbmod::CTRL | vk::S {
|
||||
} else if key == MOD_CTRL | VK_S {
|
||||
state.wants_save = true;
|
||||
} else if key == kbmod::CTRL_SHIFT | vk::S {
|
||||
} else if key == MOD_CTRL | MOD_SHIFT | VK_S {
|
||||
state.wants_file_picker = StateFilePicker::SaveAs;
|
||||
} else if key == kbmod::CTRL | vk::W {
|
||||
} else if key == MOD_CTRL | VK_W {
|
||||
state.wants_close = true;
|
||||
} else if key == kbmod::CTRL | vk::P {
|
||||
} else if key == MOD_CTRL | VK_P {
|
||||
state.wants_go_to_file = true;
|
||||
} else if key == kbmod::CTRL | vk::Q {
|
||||
} else if key == MOD_CTRL | VK_Q {
|
||||
state.wants_exit = true;
|
||||
} else if key == kbmod::CTRL | vk::G {
|
||||
} else if key == MOD_CTRL | VK_G {
|
||||
state.wants_goto = true;
|
||||
} else if key == kbmod::CTRL | vk::F && state.wants_search.kind != StateSearchKind::Disabled
|
||||
{
|
||||
} else if key == MOD_CTRL | VK_F && state.wants_search.kind != StateSearchKind::Disabled {
|
||||
state.wants_search.kind = StateSearchKind::Search;
|
||||
state.wants_search.focus = true;
|
||||
} else if key == kbmod::CTRL | vk::R && state.wants_search.kind != StateSearchKind::Disabled
|
||||
{
|
||||
} else if key == MOD_CTRL | VK_R && state.wants_search.kind != StateSearchKind::Disabled {
|
||||
state.wants_search.kind = StateSearchKind::Replace;
|
||||
state.wants_search.focus = true;
|
||||
} else if key == vk::F3 {
|
||||
} else if key == VK_F3 {
|
||||
search_execute(ctx, state, SearchAction::Search);
|
||||
} else {
|
||||
return;
|
||||
|
|
|
|||
317
src/input.rs
317
src/input.rs
|
|
@ -6,14 +6,16 @@
|
|||
//! In the future this allows us to take apart the application and
|
||||
//! support input schemes that aren't VT, such as UEFI, or GUI.
|
||||
|
||||
use std::mem;
|
||||
use std::ops::{BitOr, BitOrAssign};
|
||||
use std::{fmt, mem};
|
||||
|
||||
use crate::helpers::{CoordType, Point, Size};
|
||||
use crate::kbd::*;
|
||||
use crate::vt;
|
||||
|
||||
/// Represents a key/modifier combination.
|
||||
///
|
||||
/// TODO: Is this a good idea? I did it to allow typing `kbmod::CTRL | vk::A`.
|
||||
/// TODO: Is this a good idea? I did it to allow typing `MOD_CTRL | VK_A`.
|
||||
/// The reason it's an awkward u32 and not a struct is to hopefully make ABIs easier later.
|
||||
/// Of course you could just translate on the ABI boundary, but my hope is that this
|
||||
/// design lets me realize some restrictions early on that I can't foresee yet.
|
||||
|
|
@ -32,7 +34,7 @@ impl InputKey {
|
|||
} else if ch >= 'a' && ch <= 'z' {
|
||||
Some(Self(ch as u32 & !0x20)) // Shift a-z to A-Z
|
||||
} else if ch >= 'A' && ch <= 'Z' {
|
||||
Some(Self(kbmod::SHIFT.0 | ch as u32))
|
||||
Some(Self(MOD_SHIFT.0 | ch as u32))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
@ -59,13 +61,62 @@ impl InputKey {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for InputKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(match self.0 {
|
||||
0x00 => "NULL",
|
||||
0x08 => "BACK",
|
||||
0x09 => "TAB",
|
||||
0x0D => "RETURN",
|
||||
0x1B => "ESCAPE",
|
||||
0x20 => "SPACE",
|
||||
0x21 => "PRIOR",
|
||||
0x22 => "NEXT",
|
||||
|
||||
0x23 => "END",
|
||||
0x24 => "HOME",
|
||||
|
||||
0x25 => "LEFT",
|
||||
0x26 => "UP",
|
||||
0x27 => "RIGHT",
|
||||
0x28 => "DOWN",
|
||||
|
||||
0x2D => "INSERT",
|
||||
0x2E => "DELETE",
|
||||
|
||||
0x6A => "MULTIPLY",
|
||||
0x6B => "ADD",
|
||||
0x6C => "SEPARATOR",
|
||||
0x6D => "SUBTRACT",
|
||||
0x6E => "DECIMAL",
|
||||
0x6F => "DIVIDE",
|
||||
_ => {
|
||||
return {
|
||||
if matches!(self.0, 0x30..=0x39 | 0x41..=0x5A) {
|
||||
// 0-9, A-Z
|
||||
write!(f, "{}", char::from_u32(self.0).unwrap_or('\0'))
|
||||
} else if matches!(self.0, 0x70..=0x87) {
|
||||
// F1-F24
|
||||
write!(f, "F{}", self.0 - 0x70 + 1)
|
||||
} else if matches!(self.0, 0x60..=0x69) {
|
||||
// NUMPAD0-NUMPAD9
|
||||
write!(f, "NUMPAD{}", self.0 - 0x60)
|
||||
} else {
|
||||
write!(f, "VK_{:02X}", self.0)
|
||||
}
|
||||
};
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A keyboard modifier. Ctrl/Alt/Shift.
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub struct InputKeyMod(u32);
|
||||
|
||||
impl InputKeyMod {
|
||||
const fn new(v: u32) -> Self {
|
||||
pub(crate) const fn new(v: u32) -> Self {
|
||||
Self(v)
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +125,7 @@ impl InputKeyMod {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOr<InputKeyMod> for InputKey {
|
||||
impl BitOr<InputKeyMod> for InputKeyMod {
|
||||
type Output = Self;
|
||||
|
||||
fn bitor(self, rhs: InputKeyMod) -> Self {
|
||||
|
|
@ -82,7 +133,15 @@ impl std::ops::BitOr<InputKeyMod> for InputKey {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOr<InputKey> for InputKeyMod {
|
||||
impl BitOr<InputKeyMod> for InputKey {
|
||||
type Output = Self;
|
||||
|
||||
fn bitor(self, rhs: InputKeyMod) -> Self {
|
||||
Self(self.0 | rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOr<InputKey> for InputKeyMod {
|
||||
type Output = InputKey;
|
||||
|
||||
fn bitor(self, rhs: InputKey) -> InputKey {
|
||||
|
|
@ -90,137 +149,30 @@ impl std::ops::BitOr<InputKey> for InputKeyMod {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOrAssign for InputKeyMod {
|
||||
impl BitOrAssign for InputKeyMod {
|
||||
fn bitor_assign(&mut self, rhs: Self) {
|
||||
self.0 |= rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Keyboard keys.
|
||||
///
|
||||
/// The codes defined here match the VK_* constants on Windows.
|
||||
/// It's a convenient way to handle keyboard input, even on other platforms.
|
||||
pub mod vk {
|
||||
use super::InputKey;
|
||||
|
||||
pub const NULL: InputKey = InputKey::new('\0' as u32);
|
||||
pub const BACK: InputKey = InputKey::new(0x08);
|
||||
pub const TAB: InputKey = InputKey::new('\t' as u32);
|
||||
pub const RETURN: InputKey = InputKey::new('\r' as u32);
|
||||
pub const ESCAPE: InputKey = InputKey::new(0x1B);
|
||||
pub const SPACE: InputKey = InputKey::new(' ' as u32);
|
||||
pub const PRIOR: InputKey = InputKey::new(0x21);
|
||||
pub const NEXT: InputKey = InputKey::new(0x22);
|
||||
|
||||
pub const END: InputKey = InputKey::new(0x23);
|
||||
pub const HOME: InputKey = InputKey::new(0x24);
|
||||
|
||||
pub const LEFT: InputKey = InputKey::new(0x25);
|
||||
pub const UP: InputKey = InputKey::new(0x26);
|
||||
pub const RIGHT: InputKey = InputKey::new(0x27);
|
||||
pub const DOWN: InputKey = InputKey::new(0x28);
|
||||
|
||||
pub const INSERT: InputKey = InputKey::new(0x2D);
|
||||
pub const DELETE: InputKey = InputKey::new(0x2E);
|
||||
|
||||
pub const N0: InputKey = InputKey::new('0' as u32);
|
||||
pub const N1: InputKey = InputKey::new('1' as u32);
|
||||
pub const N2: InputKey = InputKey::new('2' as u32);
|
||||
pub const N3: InputKey = InputKey::new('3' as u32);
|
||||
pub const N4: InputKey = InputKey::new('4' as u32);
|
||||
pub const N5: InputKey = InputKey::new('5' as u32);
|
||||
pub const N6: InputKey = InputKey::new('6' as u32);
|
||||
pub const N7: InputKey = InputKey::new('7' as u32);
|
||||
pub const N8: InputKey = InputKey::new('8' as u32);
|
||||
pub const N9: InputKey = InputKey::new('9' as u32);
|
||||
|
||||
pub const A: InputKey = InputKey::new('A' as u32);
|
||||
pub const B: InputKey = InputKey::new('B' as u32);
|
||||
pub const C: InputKey = InputKey::new('C' as u32);
|
||||
pub const D: InputKey = InputKey::new('D' as u32);
|
||||
pub const E: InputKey = InputKey::new('E' as u32);
|
||||
pub const F: InputKey = InputKey::new('F' as u32);
|
||||
pub const G: InputKey = InputKey::new('G' as u32);
|
||||
pub const H: InputKey = InputKey::new('H' as u32);
|
||||
pub const I: InputKey = InputKey::new('I' as u32);
|
||||
pub const J: InputKey = InputKey::new('J' as u32);
|
||||
pub const K: InputKey = InputKey::new('K' as u32);
|
||||
pub const L: InputKey = InputKey::new('L' as u32);
|
||||
pub const M: InputKey = InputKey::new('M' as u32);
|
||||
pub const N: InputKey = InputKey::new('N' as u32);
|
||||
pub const O: InputKey = InputKey::new('O' as u32);
|
||||
pub const P: InputKey = InputKey::new('P' as u32);
|
||||
pub const Q: InputKey = InputKey::new('Q' as u32);
|
||||
pub const R: InputKey = InputKey::new('R' as u32);
|
||||
pub const S: InputKey = InputKey::new('S' as u32);
|
||||
pub const T: InputKey = InputKey::new('T' as u32);
|
||||
pub const U: InputKey = InputKey::new('U' as u32);
|
||||
pub const V: InputKey = InputKey::new('V' as u32);
|
||||
pub const W: InputKey = InputKey::new('W' as u32);
|
||||
pub const X: InputKey = InputKey::new('X' as u32);
|
||||
pub const Y: InputKey = InputKey::new('Y' as u32);
|
||||
pub const Z: InputKey = InputKey::new('Z' as u32);
|
||||
|
||||
pub const NUMPAD0: InputKey = InputKey::new(0x60);
|
||||
pub const NUMPAD1: InputKey = InputKey::new(0x61);
|
||||
pub const NUMPAD2: InputKey = InputKey::new(0x62);
|
||||
pub const NUMPAD3: InputKey = InputKey::new(0x63);
|
||||
pub const NUMPAD4: InputKey = InputKey::new(0x64);
|
||||
pub const NUMPAD5: InputKey = InputKey::new(0x65);
|
||||
pub const NUMPAD6: InputKey = InputKey::new(0x66);
|
||||
pub const NUMPAD7: InputKey = InputKey::new(0x67);
|
||||
pub const NUMPAD8: InputKey = InputKey::new(0x68);
|
||||
pub const NUMPAD9: InputKey = InputKey::new(0x69);
|
||||
pub const MULTIPLY: InputKey = InputKey::new(0x6A);
|
||||
pub const ADD: InputKey = InputKey::new(0x6B);
|
||||
pub const SEPARATOR: InputKey = InputKey::new(0x6C);
|
||||
pub const SUBTRACT: InputKey = InputKey::new(0x6D);
|
||||
pub const DECIMAL: InputKey = InputKey::new(0x6E);
|
||||
pub const DIVIDE: InputKey = InputKey::new(0x6F);
|
||||
|
||||
pub const F1: InputKey = InputKey::new(0x70);
|
||||
pub const F2: InputKey = InputKey::new(0x71);
|
||||
pub const F3: InputKey = InputKey::new(0x72);
|
||||
pub const F4: InputKey = InputKey::new(0x73);
|
||||
pub const F5: InputKey = InputKey::new(0x74);
|
||||
pub const F6: InputKey = InputKey::new(0x75);
|
||||
pub const F7: InputKey = InputKey::new(0x76);
|
||||
pub const F8: InputKey = InputKey::new(0x77);
|
||||
pub const F9: InputKey = InputKey::new(0x78);
|
||||
pub const F10: InputKey = InputKey::new(0x79);
|
||||
pub const F11: InputKey = InputKey::new(0x7A);
|
||||
pub const F12: InputKey = InputKey::new(0x7B);
|
||||
pub const F13: InputKey = InputKey::new(0x7C);
|
||||
pub const F14: InputKey = InputKey::new(0x7D);
|
||||
pub const F15: InputKey = InputKey::new(0x7E);
|
||||
pub const F16: InputKey = InputKey::new(0x7F);
|
||||
pub const F17: InputKey = InputKey::new(0x80);
|
||||
pub const F18: InputKey = InputKey::new(0x81);
|
||||
pub const F19: InputKey = InputKey::new(0x82);
|
||||
pub const F20: InputKey = InputKey::new(0x83);
|
||||
pub const F21: InputKey = InputKey::new(0x84);
|
||||
pub const F22: InputKey = InputKey::new(0x85);
|
||||
pub const F23: InputKey = InputKey::new(0x86);
|
||||
pub const F24: InputKey = InputKey::new(0x87);
|
||||
}
|
||||
|
||||
/// Keyboard modifiers.
|
||||
pub mod kbmod {
|
||||
use super::InputKeyMod;
|
||||
|
||||
pub const NONE: InputKeyMod = InputKeyMod::new(0x00000000);
|
||||
pub const CTRL: InputKeyMod = InputKeyMod::new(0x01000000);
|
||||
pub const ALT: InputKeyMod = InputKeyMod::new(0x02000000);
|
||||
pub const SHIFT: InputKeyMod = InputKeyMod::new(0x04000000);
|
||||
|
||||
pub const CTRL_ALT: InputKeyMod = InputKeyMod::new(0x03000000);
|
||||
pub const CTRL_SHIFT: InputKeyMod = InputKeyMod::new(0x05000000);
|
||||
pub const ALT_SHIFT: InputKeyMod = InputKeyMod::new(0x06000000);
|
||||
pub const CTRL_ALT_SHIFT: InputKeyMod = InputKeyMod::new(0x07000000);
|
||||
impl fmt::Debug for InputKeyMod {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut sep = "";
|
||||
for (modifier, name) in [(MOD_CTRL, "CTRL"), (MOD_ALT, "ALT"), (MOD_SHIFT, "SHIFT")] {
|
||||
if self.contains(modifier) {
|
||||
write!(f, "{}{}", sep, name)?;
|
||||
sep = " | ";
|
||||
}
|
||||
}
|
||||
if sep.is_empty() {
|
||||
f.write_str("NONE")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Mouse input state. Up/Down, Left/Right, etc.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum InputMouseState {
|
||||
#[default]
|
||||
None,
|
||||
|
|
@ -236,7 +188,7 @@ pub enum InputMouseState {
|
|||
}
|
||||
|
||||
/// Mouse input.
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct InputMouse {
|
||||
/// The state of the mouse.Up/Down, Left/Right, etc.
|
||||
pub state: InputMouseState,
|
||||
|
|
@ -316,14 +268,14 @@ impl<'input> Iterator for Stream<'_, '_, 'input> {
|
|||
}
|
||||
|
||||
const KEYPAD_LUT: [u8; 8] = [
|
||||
vk::UP.value() as u8, // A
|
||||
vk::DOWN.value() as u8, // B
|
||||
vk::RIGHT.value() as u8, // C
|
||||
vk::LEFT.value() as u8, // D
|
||||
0, // E
|
||||
vk::END.value() as u8, // F
|
||||
0, // G
|
||||
vk::HOME.value() as u8, // H
|
||||
VK_UP.value() as u8, // A
|
||||
VK_DOWN.value() as u8, // B
|
||||
VK_RIGHT.value() as u8, // C
|
||||
VK_LEFT.value() as u8, // D
|
||||
0, // E
|
||||
VK_END.value() as u8, // F
|
||||
0, // G
|
||||
VK_HOME.value() as u8, // H
|
||||
];
|
||||
|
||||
match self.stream.next()? {
|
||||
|
|
@ -332,24 +284,24 @@ impl<'input> Iterator for Stream<'_, '_, 'input> {
|
|||
}
|
||||
vt::Token::Ctrl(ch) => match ch {
|
||||
'\0' | '\t' | '\r' => return Some(Input::Keyboard(InputKey::new(ch as u32))),
|
||||
'\n' => return Some(Input::Keyboard(kbmod::CTRL | vk::RETURN)),
|
||||
'\n' => return Some(Input::Keyboard(MOD_CTRL | VK_RETURN)),
|
||||
..='\x1a' => {
|
||||
// Shift control code to A-Z
|
||||
let key = ch as u32 | 0x40;
|
||||
return Some(Input::Keyboard(kbmod::CTRL | InputKey::new(key)));
|
||||
return Some(Input::Keyboard(MOD_CTRL | InputKey::new(key)));
|
||||
}
|
||||
'\x7f' => return Some(Input::Keyboard(vk::BACK)),
|
||||
'\x7f' => return Some(Input::Keyboard(VK_BACK)),
|
||||
_ => {}
|
||||
},
|
||||
vt::Token::Esc(ch) => {
|
||||
match ch {
|
||||
'\0' => return Some(Input::Keyboard(vk::ESCAPE)),
|
||||
'\n' => return Some(Input::Keyboard(kbmod::CTRL_ALT | vk::RETURN)),
|
||||
'\0' => return Some(Input::Keyboard(VK_ESCAPE)),
|
||||
'\n' => return Some(Input::Keyboard(MOD_CTRL | MOD_ALT | VK_RETURN)),
|
||||
' '..='~' => {
|
||||
let ch = ch as u32;
|
||||
let key = ch & !0x20; // Shift a-z to A-Z
|
||||
let modifiers =
|
||||
if (ch & 0x20) != 0 { kbmod::ALT } else { kbmod::ALT_SHIFT };
|
||||
if (ch & 0x20) != 0 { MOD_ALT } else { MOD_ALT | MOD_SHIFT };
|
||||
return Some(Input::Keyboard(modifiers | InputKey::new(key)));
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -363,7 +315,7 @@ impl<'input> Iterator for Stream<'_, '_, 'input> {
|
|||
}
|
||||
}
|
||||
'P'..='S' => {
|
||||
let key = vk::F1.value() + ch as u32 - 'P' as u32;
|
||||
let key = VK_F1.value() + ch as u32 - 'P' as u32;
|
||||
return Some(Input::Keyboard(InputKey::new(key)));
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -378,16 +330,16 @@ impl<'input> Iterator for Stream<'_, '_, 'input> {
|
|||
));
|
||||
}
|
||||
}
|
||||
'Z' => return Some(Input::Keyboard(kbmod::SHIFT | vk::TAB)),
|
||||
'Z' => return Some(Input::Keyboard(MOD_SHIFT | VK_TAB)),
|
||||
'~' => {
|
||||
const LUT: [u8; 35] = [
|
||||
0,
|
||||
vk::HOME.value() as u8, // 1
|
||||
vk::INSERT.value() as u8, // 2
|
||||
vk::DELETE.value() as u8, // 3
|
||||
vk::END.value() as u8, // 4
|
||||
vk::PRIOR.value() as u8, // 5
|
||||
vk::NEXT.value() as u8, // 6
|
||||
VK_HOME.value() as u8, // 1
|
||||
VK_INSERT.value() as u8, // 2
|
||||
VK_DELETE.value() as u8, // 3
|
||||
VK_END.value() as u8, // 4
|
||||
VK_PRIOR.value() as u8, // 5
|
||||
VK_NEXT.value() as u8, // 6
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
|
@ -396,26 +348,26 @@ impl<'input> Iterator for Stream<'_, '_, 'input> {
|
|||
0,
|
||||
0,
|
||||
0,
|
||||
vk::F5.value() as u8, // 15
|
||||
VK_F5.value() as u8, // 15
|
||||
0,
|
||||
vk::F6.value() as u8, // 17
|
||||
vk::F7.value() as u8, // 18
|
||||
vk::F8.value() as u8, // 19
|
||||
vk::F9.value() as u8, // 20
|
||||
vk::F10.value() as u8, // 21
|
||||
VK_F6.value() as u8, // 17
|
||||
VK_F7.value() as u8, // 18
|
||||
VK_F8.value() as u8, // 19
|
||||
VK_F9.value() as u8, // 20
|
||||
VK_F10.value() as u8, // 21
|
||||
0,
|
||||
vk::F11.value() as u8, // 23
|
||||
vk::F12.value() as u8, // 24
|
||||
vk::F13.value() as u8, // 25
|
||||
vk::F14.value() as u8, // 26
|
||||
VK_F11.value() as u8, // 23
|
||||
VK_F12.value() as u8, // 24
|
||||
VK_F13.value() as u8, // 25
|
||||
VK_F14.value() as u8, // 26
|
||||
0,
|
||||
vk::F15.value() as u8, // 28
|
||||
vk::F16.value() as u8, // 29
|
||||
VK_F15.value() as u8, // 28
|
||||
VK_F16.value() as u8, // 29
|
||||
0,
|
||||
vk::F17.value() as u8, // 31
|
||||
vk::F18.value() as u8, // 32
|
||||
vk::F19.value() as u8, // 33
|
||||
vk::F20.value() as u8, // 34
|
||||
VK_F17.value() as u8, // 31
|
||||
VK_F18.value() as u8, // 32
|
||||
VK_F19.value() as u8, // 33
|
||||
VK_F20.value() as u8, // 34
|
||||
];
|
||||
const LUT_LEN: u16 = LUT.len() as u16;
|
||||
|
||||
|
|
@ -436,7 +388,7 @@ impl<'input> Iterator for Stream<'_, '_, 'input> {
|
|||
let btn = csi.params[0];
|
||||
let mut mouse = InputMouse {
|
||||
state: InputMouseState::None,
|
||||
modifiers: kbmod::NONE,
|
||||
modifiers: MOD_NONE,
|
||||
position: Default::default(),
|
||||
scroll: Default::default(),
|
||||
};
|
||||
|
|
@ -455,13 +407,10 @@ impl<'input> Iterator for Stream<'_, '_, 'input> {
|
|||
mouse.state = STATES[(btn as usize) & 0x03];
|
||||
}
|
||||
|
||||
mouse.modifiers = kbmod::NONE;
|
||||
mouse.modifiers |=
|
||||
if (btn & 0x04) != 0 { kbmod::SHIFT } else { kbmod::NONE };
|
||||
mouse.modifiers |=
|
||||
if (btn & 0x08) != 0 { kbmod::ALT } else { kbmod::NONE };
|
||||
mouse.modifiers |=
|
||||
if (btn & 0x10f) != 0 { kbmod::CTRL } else { kbmod::NONE };
|
||||
mouse.modifiers = MOD_NONE;
|
||||
mouse.modifiers |= if (btn & 0x04) != 0 { MOD_SHIFT } else { MOD_NONE };
|
||||
mouse.modifiers |= if (btn & 0x08) != 0 { MOD_ALT } else { MOD_NONE };
|
||||
mouse.modifiers |= if (btn & 0x10) != 0 { MOD_CTRL } else { MOD_NONE };
|
||||
|
||||
mouse.position.x = csi.params[1] as CoordType - 1;
|
||||
mouse.position.y = csi.params[2] as CoordType - 1;
|
||||
|
|
@ -552,10 +501,10 @@ impl<'input> Stream<'_, '_, 'input> {
|
|||
_ => InputMouseState::None,
|
||||
};
|
||||
let modifiers = match modifier {
|
||||
4 => kbmod::SHIFT,
|
||||
8 => kbmod::ALT,
|
||||
16 => kbmod::CTRL,
|
||||
_ => kbmod::NONE,
|
||||
4 => MOD_SHIFT,
|
||||
8 => MOD_ALT,
|
||||
16 => MOD_CTRL,
|
||||
_ => MOD_NONE,
|
||||
};
|
||||
|
||||
self.parser.x10_mouse_want = false;
|
||||
|
|
@ -570,16 +519,16 @@ impl<'input> Stream<'_, '_, 'input> {
|
|||
}
|
||||
|
||||
fn parse_modifiers(csi: &vt::Csi) -> InputKeyMod {
|
||||
let mut modifiers = kbmod::NONE;
|
||||
let mut modifiers = MOD_NONE;
|
||||
let p1 = csi.params[1].saturating_sub(1);
|
||||
if (p1 & 0x01) != 0 {
|
||||
modifiers |= kbmod::SHIFT;
|
||||
modifiers |= MOD_SHIFT;
|
||||
}
|
||||
if (p1 & 0x02) != 0 {
|
||||
modifiers |= kbmod::ALT;
|
||||
modifiers |= MOD_ALT;
|
||||
}
|
||||
if (p1 & 0x04) != 0 {
|
||||
modifiers |= kbmod::CTRL;
|
||||
modifiers |= MOD_CTRL;
|
||||
}
|
||||
modifiers
|
||||
}
|
||||
|
|
|
|||
114
src/kbd.rs
Normal file
114
src/kbd.rs
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
//! The VK_* codes defined here match the VK_* constants on Windows.
|
||||
//! It's a convenient way to handle keyboard input, even on other platforms.
|
||||
|
||||
use crate::input::{InputKey, InputKeyMod};
|
||||
|
||||
pub const VK_NULL: InputKey = InputKey::new('\0' as u32);
|
||||
pub const VK_BACK: InputKey = InputKey::new(0x08);
|
||||
pub const VK_TAB: InputKey = InputKey::new('\t' as u32);
|
||||
pub const VK_RETURN: InputKey = InputKey::new('\r' as u32);
|
||||
pub const VK_ESCAPE: InputKey = InputKey::new(0x1B);
|
||||
pub const VK_SPACE: InputKey = InputKey::new(' ' as u32);
|
||||
pub const VK_PRIOR: InputKey = InputKey::new(0x21);
|
||||
pub const VK_NEXT: InputKey = InputKey::new(0x22);
|
||||
|
||||
pub const VK_END: InputKey = InputKey::new(0x23);
|
||||
pub const VK_HOME: InputKey = InputKey::new(0x24);
|
||||
|
||||
pub const VK_LEFT: InputKey = InputKey::new(0x25);
|
||||
pub const VK_UP: InputKey = InputKey::new(0x26);
|
||||
pub const VK_RIGHT: InputKey = InputKey::new(0x27);
|
||||
pub const VK_DOWN: InputKey = InputKey::new(0x28);
|
||||
|
||||
pub const VK_INSERT: InputKey = InputKey::new(0x2D);
|
||||
pub const VK_DELETE: InputKey = InputKey::new(0x2E);
|
||||
|
||||
pub const VK_0: InputKey = InputKey::new('0' as u32);
|
||||
pub const VK_1: InputKey = InputKey::new('1' as u32);
|
||||
pub const VK_2: InputKey = InputKey::new('2' as u32);
|
||||
pub const VK_3: InputKey = InputKey::new('3' as u32);
|
||||
pub const VK_4: InputKey = InputKey::new('4' as u32);
|
||||
pub const VK_5: InputKey = InputKey::new('5' as u32);
|
||||
pub const VK_6: InputKey = InputKey::new('6' as u32);
|
||||
pub const VK_7: InputKey = InputKey::new('7' as u32);
|
||||
pub const VK_8: InputKey = InputKey::new('8' as u32);
|
||||
pub const VK_9: InputKey = InputKey::new('9' as u32);
|
||||
|
||||
pub const VK_A: InputKey = InputKey::new('A' as u32);
|
||||
pub const VK_B: InputKey = InputKey::new('B' as u32);
|
||||
pub const VK_C: InputKey = InputKey::new('C' as u32);
|
||||
pub const VK_D: InputKey = InputKey::new('D' as u32);
|
||||
pub const VK_E: InputKey = InputKey::new('E' as u32);
|
||||
pub const VK_F: InputKey = InputKey::new('F' as u32);
|
||||
pub const VK_G: InputKey = InputKey::new('G' as u32);
|
||||
pub const VK_H: InputKey = InputKey::new('H' as u32);
|
||||
pub const VK_I: InputKey = InputKey::new('I' as u32);
|
||||
pub const VK_J: InputKey = InputKey::new('J' as u32);
|
||||
pub const VK_K: InputKey = InputKey::new('K' as u32);
|
||||
pub const VK_L: InputKey = InputKey::new('L' as u32);
|
||||
pub const VK_M: InputKey = InputKey::new('M' as u32);
|
||||
pub const VK_N: InputKey = InputKey::new('N' as u32);
|
||||
pub const VK_O: InputKey = InputKey::new('O' as u32);
|
||||
pub const VK_P: InputKey = InputKey::new('P' as u32);
|
||||
pub const VK_Q: InputKey = InputKey::new('Q' as u32);
|
||||
pub const VK_R: InputKey = InputKey::new('R' as u32);
|
||||
pub const VK_S: InputKey = InputKey::new('S' as u32);
|
||||
pub const VK_T: InputKey = InputKey::new('T' as u32);
|
||||
pub const VK_U: InputKey = InputKey::new('U' as u32);
|
||||
pub const VK_V: InputKey = InputKey::new('V' as u32);
|
||||
pub const VK_W: InputKey = InputKey::new('W' as u32);
|
||||
pub const VK_X: InputKey = InputKey::new('X' as u32);
|
||||
pub const VK_Y: InputKey = InputKey::new('Y' as u32);
|
||||
pub const VK_Z: InputKey = InputKey::new('Z' as u32);
|
||||
|
||||
pub const VK_NUMPAD0: InputKey = InputKey::new(0x60);
|
||||
pub const VK_NUMPAD1: InputKey = InputKey::new(0x61);
|
||||
pub const VK_NUMPAD2: InputKey = InputKey::new(0x62);
|
||||
pub const VK_NUMPAD3: InputKey = InputKey::new(0x63);
|
||||
pub const VK_NUMPAD4: InputKey = InputKey::new(0x64);
|
||||
pub const VK_NUMPAD5: InputKey = InputKey::new(0x65);
|
||||
pub const VK_NUMPAD6: InputKey = InputKey::new(0x66);
|
||||
pub const VK_NUMPAD7: InputKey = InputKey::new(0x67);
|
||||
pub const VK_NUMPAD8: InputKey = InputKey::new(0x68);
|
||||
pub const VK_NUMPAD9: InputKey = InputKey::new(0x69);
|
||||
pub const VK_MULTIPLY: InputKey = InputKey::new(0x6A);
|
||||
pub const VK_ADD: InputKey = InputKey::new(0x6B);
|
||||
pub const VK_SEPARATOR: InputKey = InputKey::new(0x6C);
|
||||
pub const VK_SUBTRACT: InputKey = InputKey::new(0x6D);
|
||||
pub const VK_DECIMAL: InputKey = InputKey::new(0x6E);
|
||||
pub const VK_DIVIDE: InputKey = InputKey::new(0x6F);
|
||||
|
||||
pub const VK_F1: InputKey = InputKey::new(0x70);
|
||||
pub const VK_F2: InputKey = InputKey::new(0x71);
|
||||
pub const VK_F3: InputKey = InputKey::new(0x72);
|
||||
pub const VK_F4: InputKey = InputKey::new(0x73);
|
||||
pub const VK_F5: InputKey = InputKey::new(0x74);
|
||||
pub const VK_F6: InputKey = InputKey::new(0x75);
|
||||
pub const VK_F7: InputKey = InputKey::new(0x76);
|
||||
pub const VK_F8: InputKey = InputKey::new(0x77);
|
||||
pub const VK_F9: InputKey = InputKey::new(0x78);
|
||||
pub const VK_F10: InputKey = InputKey::new(0x79);
|
||||
pub const VK_F11: InputKey = InputKey::new(0x7A);
|
||||
pub const VK_F12: InputKey = InputKey::new(0x7B);
|
||||
pub const VK_F13: InputKey = InputKey::new(0x7C);
|
||||
pub const VK_F14: InputKey = InputKey::new(0x7D);
|
||||
pub const VK_F15: InputKey = InputKey::new(0x7E);
|
||||
pub const VK_F16: InputKey = InputKey::new(0x7F);
|
||||
pub const VK_F17: InputKey = InputKey::new(0x80);
|
||||
pub const VK_F18: InputKey = InputKey::new(0x81);
|
||||
pub const VK_F19: InputKey = InputKey::new(0x82);
|
||||
pub const VK_F20: InputKey = InputKey::new(0x83);
|
||||
pub const VK_F21: InputKey = InputKey::new(0x84);
|
||||
pub const VK_F22: InputKey = InputKey::new(0x85);
|
||||
pub const VK_F23: InputKey = InputKey::new(0x86);
|
||||
pub const VK_F24: InputKey = InputKey::new(0x87);
|
||||
|
||||
pub const MOD_NONE: InputKeyMod = InputKeyMod::new(0x00000000);
|
||||
pub const MOD_CTRL: InputKeyMod = InputKeyMod::new(0x01000000);
|
||||
pub const MOD_ALT: InputKeyMod = InputKeyMod::new(0x02000000);
|
||||
pub const MOD_SHIFT: InputKeyMod = InputKeyMod::new(0x04000000);
|
||||
|
||||
pub const MOD_CTRL_ALT: InputKeyMod = InputKeyMod::new(0x03000000);
|
||||
pub const MOD_CTRL_SHIFT: InputKeyMod = InputKeyMod::new(0x05000000);
|
||||
pub const MOD_ALT_SHIFT: InputKeyMod = InputKeyMod::new(0x06000000);
|
||||
pub const MOD_CTRL_ALT_SHIFT: InputKeyMod = InputKeyMod::new(0x07000000);
|
||||
|
|
@ -32,6 +32,7 @@ pub mod hash;
|
|||
pub mod helpers;
|
||||
pub mod icu;
|
||||
pub mod input;
|
||||
pub mod kbd;
|
||||
pub mod oklab;
|
||||
pub mod path;
|
||||
pub mod simd;
|
||||
|
|
|
|||
198
src/tui.rs
198
src/tui.rs
|
|
@ -157,13 +157,13 @@ use crate::document::WriteableDocument;
|
|||
use crate::framebuffer::{Attributes, Framebuffer, INDEXED_COLORS_COUNT, IndexedColor};
|
||||
use crate::hash::*;
|
||||
use crate::helpers::*;
|
||||
use crate::input::{InputKeyMod, kbmod, vk};
|
||||
use crate::input::InputKeyMod;
|
||||
use crate::kbd::*;
|
||||
use crate::{apperr, arena_format, input, simd, unicode};
|
||||
|
||||
const ROOT_ID: u64 = 0x14057B7EF767814F; // Knuth's MMIX constant
|
||||
const SHIFT_TAB: InputKey = vk::TAB.with_modifiers(kbmod::SHIFT);
|
||||
const KBMOD_FOR_WORD_NAV: InputKeyMod =
|
||||
if cfg!(target_os = "macos") { kbmod::ALT } else { kbmod::CTRL };
|
||||
const SHIFT_TAB: InputKey = VK_TAB.with_modifiers(MOD_SHIFT);
|
||||
const KBMOD_FOR_WORD_NAV: InputKeyMod = if cfg!(target_os = "macos") { MOD_ALT } else { MOD_CTRL };
|
||||
|
||||
type Input<'input> = input::Input<'input>;
|
||||
type InputKey = input::InputKey;
|
||||
|
|
@ -520,7 +520,7 @@ impl Tui {
|
|||
let now = std::time::Instant::now();
|
||||
let mut input_text = None;
|
||||
let mut input_keyboard = None;
|
||||
let mut input_mouse_modifiers = kbmod::NONE;
|
||||
let mut input_mouse_modifiers = MOD_NONE;
|
||||
let mut input_mouse_click = 0;
|
||||
let mut input_scroll_delta = Point { x: 0, y: 0 };
|
||||
// `input_consumed` should be `true` if we're in the settling phase which is indicated by
|
||||
|
|
@ -556,7 +556,7 @@ impl Tui {
|
|||
let clipboard = self.clipboard_mut();
|
||||
clipboard.write(paste);
|
||||
clipboard.mark_as_synchronized();
|
||||
input_keyboard = Some(kbmod::CTRL | vk::V);
|
||||
input_keyboard = Some(MOD_CTRL | VK_V);
|
||||
}
|
||||
Some(Input::Keyboard(keyboard)) => {
|
||||
input_keyboard = Some(keyboard);
|
||||
|
|
@ -743,7 +743,7 @@ impl Tui {
|
|||
|
||||
let mut focus_path_pop_min = 0;
|
||||
// If the user pressed Escape, we move the focus to a parent node.
|
||||
if !ctx.input_consumed && ctx.consume_shortcut(vk::ESCAPE) {
|
||||
if !ctx.input_consumed && ctx.consume_shortcut(VK_ESCAPE) {
|
||||
focus_path_pop_min = 1;
|
||||
}
|
||||
|
||||
|
|
@ -1463,11 +1463,11 @@ impl<'a> Context<'a, '_> {
|
|||
let Some(input) = self.input_keyboard else {
|
||||
return;
|
||||
};
|
||||
if !matches!(input, SHIFT_TAB | vk::TAB) {
|
||||
if !matches!(input, SHIFT_TAB | VK_TAB) {
|
||||
return;
|
||||
}
|
||||
|
||||
let forward = input == vk::TAB;
|
||||
let forward = input == VK_TAB;
|
||||
let mut focused_start = focused;
|
||||
let mut focused_next = focused;
|
||||
|
||||
|
|
@ -1749,7 +1749,7 @@ impl<'a> Context<'a, '_> {
|
|||
// Consume the input unconditionally, so that the root (the "main window")
|
||||
// doesn't accidentally receive any input via `consume_shortcut()`.
|
||||
if self.contains_focus() {
|
||||
let exit = !self.input_consumed && self.input_keyboard == Some(vk::ESCAPE);
|
||||
let exit = !self.input_consumed && self.input_keyboard == Some(VK_ESCAPE);
|
||||
self.set_input_consumed_unchecked();
|
||||
exit
|
||||
} else {
|
||||
|
|
@ -1820,7 +1820,7 @@ impl<'a> Context<'a, '_> {
|
|||
}
|
||||
|
||||
fn table_end_row(&mut self) {
|
||||
self.table_move_focus(vk::LEFT, vk::RIGHT);
|
||||
self.table_move_focus(VK_LEFT, VK_RIGHT);
|
||||
}
|
||||
|
||||
/// Ends the current table block.
|
||||
|
|
@ -1835,7 +1835,7 @@ impl<'a> Context<'a, '_> {
|
|||
}
|
||||
|
||||
self.block_end(); // table
|
||||
self.table_move_focus(vk::UP, vk::DOWN);
|
||||
self.table_move_focus(VK_UP, VK_DOWN);
|
||||
}
|
||||
|
||||
fn table_move_focus(&mut self, prev_key: InputKey, next_key: InputKey) {
|
||||
|
|
@ -2031,8 +2031,8 @@ impl<'a> Context<'a, '_> {
|
|||
fn button_activated(&mut self) -> bool {
|
||||
if !self.input_consumed
|
||||
&& ((self.input_mouse_click != 0 && self.contains_mouse_down())
|
||||
|| self.input_keyboard == Some(vk::RETURN)
|
||||
|| self.input_keyboard == Some(vk::SPACE))
|
||||
|| self.input_keyboard == Some(VK_RETURN)
|
||||
|| self.input_keyboard == Some(VK_SPACE))
|
||||
&& self.is_focused()
|
||||
{
|
||||
self.set_input_consumed();
|
||||
|
|
@ -2267,7 +2267,7 @@ impl<'a> Context<'a, '_> {
|
|||
2 => tb.select_word(),
|
||||
_ => match self.tui.mouse_state {
|
||||
InputMouseState::Left => {
|
||||
if self.input_mouse_modifiers.contains(kbmod::SHIFT) {
|
||||
if self.input_mouse_modifiers.contains(MOD_SHIFT) {
|
||||
// TODO: Untested because Windows Terminal surprisingly doesn't support Shift+Click.
|
||||
tb.selection_update_visual(pos);
|
||||
} else {
|
||||
|
|
@ -2321,29 +2321,29 @@ impl<'a> Context<'a, '_> {
|
|||
make_cursor_visible = true;
|
||||
|
||||
match key {
|
||||
vk::BACK => {
|
||||
let granularity = if modifiers == kbmod::CTRL {
|
||||
VK_BACK => {
|
||||
let granularity = if modifiers == MOD_CTRL {
|
||||
CursorMovement::Word
|
||||
} else {
|
||||
CursorMovement::Grapheme
|
||||
};
|
||||
tb.delete(granularity, -1);
|
||||
}
|
||||
vk::TAB => {
|
||||
VK_TAB => {
|
||||
if single_line {
|
||||
// If this is just a simple input field, don't consume Tab (= early return).
|
||||
return false;
|
||||
}
|
||||
tb.indent_change(if modifiers == kbmod::SHIFT { -1 } else { 1 });
|
||||
tb.indent_change(if modifiers == MOD_SHIFT { -1 } else { 1 });
|
||||
}
|
||||
vk::RETURN => {
|
||||
VK_RETURN => {
|
||||
if single_line {
|
||||
// If this is just a simple input field, don't consume Enter (= early return).
|
||||
return false;
|
||||
}
|
||||
write = b"\n";
|
||||
}
|
||||
vk::ESCAPE => {
|
||||
VK_ESCAPE => {
|
||||
// If there was a selection, clear it and show the cursor (= fallthrough).
|
||||
if !tb.clear_selection() {
|
||||
if single_line {
|
||||
|
|
@ -2357,7 +2357,7 @@ impl<'a> Context<'a, '_> {
|
|||
make_cursor_visible = false;
|
||||
}
|
||||
}
|
||||
vk::PRIOR => {
|
||||
VK_PRIOR => {
|
||||
let height = node_prev.inner.height() - 1;
|
||||
|
||||
// If the cursor was already on the first line,
|
||||
|
|
@ -2366,7 +2366,7 @@ impl<'a> Context<'a, '_> {
|
|||
tc.preferred_column = 0;
|
||||
}
|
||||
|
||||
if modifiers == kbmod::SHIFT {
|
||||
if modifiers == MOD_SHIFT {
|
||||
tb.selection_update_visual(Point {
|
||||
x: tc.preferred_column,
|
||||
y: tb.cursor_visual_pos().y - height,
|
||||
|
|
@ -2378,7 +2378,7 @@ impl<'a> Context<'a, '_> {
|
|||
});
|
||||
}
|
||||
}
|
||||
vk::NEXT => {
|
||||
VK_NEXT => {
|
||||
let height = node_prev.inner.height() - 1;
|
||||
|
||||
// If the cursor was already on the last line,
|
||||
|
|
@ -2387,7 +2387,7 @@ impl<'a> Context<'a, '_> {
|
|||
tc.preferred_column = CoordType::MAX;
|
||||
}
|
||||
|
||||
if modifiers == kbmod::SHIFT {
|
||||
if modifiers == MOD_SHIFT {
|
||||
tb.selection_update_visual(Point {
|
||||
x: tc.preferred_column,
|
||||
y: tb.cursor_visual_pos().y + height,
|
||||
|
|
@ -2403,28 +2403,28 @@ impl<'a> Context<'a, '_> {
|
|||
tc.preferred_column = tb.cursor_visual_pos().x;
|
||||
}
|
||||
}
|
||||
vk::END => {
|
||||
VK_END => {
|
||||
let logical_before = tb.cursor_logical_pos();
|
||||
let destination = if modifiers.contains(kbmod::CTRL) {
|
||||
let destination = if modifiers.contains(MOD_CTRL) {
|
||||
Point::MAX
|
||||
} else {
|
||||
Point { x: CoordType::MAX, y: tb.cursor_visual_pos().y }
|
||||
};
|
||||
|
||||
if modifiers.contains(kbmod::SHIFT) {
|
||||
if modifiers.contains(MOD_SHIFT) {
|
||||
tb.selection_update_visual(destination);
|
||||
} else {
|
||||
tb.cursor_move_to_visual(destination);
|
||||
}
|
||||
|
||||
if !modifiers.contains(kbmod::CTRL) {
|
||||
if !modifiers.contains(MOD_CTRL) {
|
||||
let logical_after = tb.cursor_logical_pos();
|
||||
|
||||
// If word-wrap is enabled and the user presses End the first time,
|
||||
// it moves to the start of the visual line. The second time they
|
||||
// press it, it moves to the start of the logical line.
|
||||
if tb.is_word_wrap_enabled() && logical_after == logical_before {
|
||||
if modifiers == kbmod::SHIFT {
|
||||
if modifiers == MOD_SHIFT {
|
||||
tb.selection_update_logical(Point {
|
||||
x: CoordType::MAX,
|
||||
y: tb.cursor_logical_pos().y,
|
||||
|
|
@ -2438,28 +2438,28 @@ impl<'a> Context<'a, '_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
vk::HOME => {
|
||||
VK_HOME => {
|
||||
let logical_before = tb.cursor_logical_pos();
|
||||
let destination = if modifiers.contains(kbmod::CTRL) {
|
||||
let destination = if modifiers.contains(MOD_CTRL) {
|
||||
Default::default()
|
||||
} else {
|
||||
Point { x: 0, y: tb.cursor_visual_pos().y }
|
||||
};
|
||||
|
||||
if modifiers.contains(kbmod::SHIFT) {
|
||||
if modifiers.contains(MOD_SHIFT) {
|
||||
tb.selection_update_visual(destination);
|
||||
} else {
|
||||
tb.cursor_move_to_visual(destination);
|
||||
}
|
||||
|
||||
if !modifiers.contains(kbmod::CTRL) {
|
||||
if !modifiers.contains(MOD_CTRL) {
|
||||
let mut logical_after = tb.cursor_logical_pos();
|
||||
|
||||
// If word-wrap is enabled and the user presses Home the first time,
|
||||
// it moves to the start of the visual line. The second time they
|
||||
// press it, it moves to the start of the logical line.
|
||||
if tb.is_word_wrap_enabled() && logical_after == logical_before {
|
||||
if modifiers == kbmod::SHIFT {
|
||||
if modifiers == MOD_SHIFT {
|
||||
tb.selection_update_logical(Point {
|
||||
x: 0,
|
||||
y: tb.cursor_logical_pos().y,
|
||||
|
|
@ -2483,7 +2483,7 @@ impl<'a> Context<'a, '_> {
|
|||
&& let indent_end = tb.indent_end_logical_pos()
|
||||
&& (logical_before > indent_end || logical_before.x == 0)
|
||||
{
|
||||
if modifiers == kbmod::SHIFT {
|
||||
if modifiers == MOD_SHIFT {
|
||||
tb.selection_update_logical(indent_end);
|
||||
} else {
|
||||
tb.cursor_move_to_logical(indent_end);
|
||||
|
|
@ -2491,13 +2491,13 @@ impl<'a> Context<'a, '_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
vk::LEFT => {
|
||||
VK_LEFT => {
|
||||
let granularity = if modifiers.contains(KBMOD_FOR_WORD_NAV) {
|
||||
CursorMovement::Word
|
||||
} else {
|
||||
CursorMovement::Grapheme
|
||||
};
|
||||
if modifiers.contains(kbmod::SHIFT) {
|
||||
if modifiers.contains(MOD_SHIFT) {
|
||||
tb.selection_update_delta(granularity, -1);
|
||||
} else if let Some((beg, _)) = tb.selection_range() {
|
||||
unsafe { tb.set_cursor(beg) };
|
||||
|
|
@ -2505,12 +2505,12 @@ impl<'a> Context<'a, '_> {
|
|||
tb.cursor_move_delta(granularity, -1);
|
||||
}
|
||||
}
|
||||
vk::UP => {
|
||||
VK_UP => {
|
||||
if single_line {
|
||||
return false;
|
||||
}
|
||||
match modifiers {
|
||||
kbmod::NONE => {
|
||||
MOD_NONE => {
|
||||
let mut x = tc.preferred_column;
|
||||
let mut y = tb.cursor_visual_pos().y - 1;
|
||||
|
||||
|
|
@ -2530,11 +2530,11 @@ impl<'a> Context<'a, '_> {
|
|||
|
||||
tb.cursor_move_to_visual(Point { x, y });
|
||||
}
|
||||
kbmod::CTRL => {
|
||||
MOD_CTRL => {
|
||||
tc.scroll_offset.y -= 1;
|
||||
make_cursor_visible = false;
|
||||
}
|
||||
kbmod::SHIFT => {
|
||||
MOD_SHIFT => {
|
||||
// If the cursor was already on the first line,
|
||||
// move it to the start of the buffer.
|
||||
if tb.cursor_visual_pos().y == 0 {
|
||||
|
|
@ -2546,20 +2546,20 @@ impl<'a> Context<'a, '_> {
|
|||
y: tb.cursor_visual_pos().y - 1,
|
||||
});
|
||||
}
|
||||
kbmod::ALT => tb.move_selected_lines(MoveLineDirection::Up),
|
||||
kbmod::CTRL_ALT => {
|
||||
MOD_ALT => tb.move_selected_lines(MoveLineDirection::Up),
|
||||
MOD_CTRL_ALT => {
|
||||
// TODO: Add cursor above
|
||||
}
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
vk::RIGHT => {
|
||||
VK_RIGHT => {
|
||||
let granularity = if modifiers.contains(KBMOD_FOR_WORD_NAV) {
|
||||
CursorMovement::Word
|
||||
} else {
|
||||
CursorMovement::Grapheme
|
||||
};
|
||||
if modifiers.contains(kbmod::SHIFT) {
|
||||
if modifiers.contains(MOD_SHIFT) {
|
||||
tb.selection_update_delta(granularity, 1);
|
||||
} else if let Some((_, end)) = tb.selection_range() {
|
||||
unsafe { tb.set_cursor(end) };
|
||||
|
|
@ -2567,12 +2567,12 @@ impl<'a> Context<'a, '_> {
|
|||
tb.cursor_move_delta(granularity, 1);
|
||||
}
|
||||
}
|
||||
vk::DOWN => {
|
||||
VK_DOWN => {
|
||||
if single_line {
|
||||
return false;
|
||||
}
|
||||
match modifiers {
|
||||
kbmod::NONE => {
|
||||
MOD_NONE => {
|
||||
let mut x = tc.preferred_column;
|
||||
let mut y = tb.cursor_visual_pos().y + 1;
|
||||
|
||||
|
|
@ -2597,11 +2597,11 @@ impl<'a> Context<'a, '_> {
|
|||
tc.preferred_column = tb.cursor_visual_pos().x;
|
||||
}
|
||||
}
|
||||
kbmod::CTRL => {
|
||||
MOD_CTRL => {
|
||||
tc.scroll_offset.y += 1;
|
||||
make_cursor_visible = false;
|
||||
}
|
||||
kbmod::SHIFT => {
|
||||
MOD_SHIFT => {
|
||||
// If the cursor was already on the last line,
|
||||
// move it to the end of the buffer.
|
||||
if tb.cursor_visual_pos().y >= tb.visual_line_count() - 1 {
|
||||
|
|
@ -2617,77 +2617,77 @@ impl<'a> Context<'a, '_> {
|
|||
tc.preferred_column = tb.cursor_visual_pos().x;
|
||||
}
|
||||
}
|
||||
kbmod::ALT => tb.move_selected_lines(MoveLineDirection::Down),
|
||||
kbmod::CTRL_ALT => {
|
||||
MOD_ALT => tb.move_selected_lines(MoveLineDirection::Down),
|
||||
MOD_CTRL_ALT => {
|
||||
// TODO: Add cursor above
|
||||
}
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
vk::INSERT => match modifiers {
|
||||
kbmod::SHIFT => tb.paste(self.clipboard_ref()),
|
||||
kbmod::CTRL => tb.copy(self.clipboard_mut()),
|
||||
VK_INSERT => match modifiers {
|
||||
MOD_SHIFT => tb.paste(self.clipboard_ref()),
|
||||
MOD_CTRL => tb.copy(self.clipboard_mut()),
|
||||
_ => tb.set_overtype(!tb.is_overtype()),
|
||||
},
|
||||
vk::DELETE => match modifiers {
|
||||
kbmod::SHIFT => tb.cut(self.clipboard_mut()),
|
||||
kbmod::CTRL => tb.delete(CursorMovement::Word, 1),
|
||||
VK_DELETE => match modifiers {
|
||||
MOD_SHIFT => tb.cut(self.clipboard_mut()),
|
||||
MOD_CTRL => tb.delete(CursorMovement::Word, 1),
|
||||
_ => tb.delete(CursorMovement::Grapheme, 1),
|
||||
},
|
||||
vk::A => match modifiers {
|
||||
kbmod::CTRL => tb.select_all(),
|
||||
VK_A => match modifiers {
|
||||
MOD_CTRL => tb.select_all(),
|
||||
_ => return false,
|
||||
},
|
||||
vk::B => match modifiers {
|
||||
kbmod::ALT if cfg!(target_os = "macos") => {
|
||||
VK_B => match modifiers {
|
||||
MOD_ALT if cfg!(target_os = "macos") => {
|
||||
// On macOS, terminals commonly emit the Emacs style
|
||||
// Alt+B (ESC b) sequence for Alt+Left.
|
||||
tb.cursor_move_delta(CursorMovement::Word, -1);
|
||||
}
|
||||
_ => return false,
|
||||
},
|
||||
vk::F => match modifiers {
|
||||
kbmod::ALT if cfg!(target_os = "macos") => {
|
||||
VK_F => match modifiers {
|
||||
MOD_ALT if cfg!(target_os = "macos") => {
|
||||
// On macOS, terminals commonly emit the Emacs style
|
||||
// Alt+F (ESC f) sequence for Alt+Right.
|
||||
tb.cursor_move_delta(CursorMovement::Word, 1);
|
||||
}
|
||||
_ => return false,
|
||||
},
|
||||
vk::H => match modifiers {
|
||||
kbmod::CTRL => tb.delete(CursorMovement::Word, -1),
|
||||
VK_H => match modifiers {
|
||||
MOD_CTRL => tb.delete(CursorMovement::Word, -1),
|
||||
_ => return false,
|
||||
},
|
||||
vk::L => match modifiers {
|
||||
kbmod::CTRL => tb.select_line(),
|
||||
VK_L => match modifiers {
|
||||
MOD_CTRL => tb.select_line(),
|
||||
_ => return false,
|
||||
},
|
||||
vk::X => match modifiers {
|
||||
kbmod::CTRL => tb.cut(self.clipboard_mut()),
|
||||
VK_X => match modifiers {
|
||||
MOD_CTRL => tb.cut(self.clipboard_mut()),
|
||||
_ => return false,
|
||||
},
|
||||
vk::C => match modifiers {
|
||||
kbmod::CTRL => tb.copy(self.clipboard_mut()),
|
||||
VK_C => match modifiers {
|
||||
MOD_CTRL => tb.copy(self.clipboard_mut()),
|
||||
_ => return false,
|
||||
},
|
||||
vk::V => match modifiers {
|
||||
kbmod::CTRL => tb.paste(self.clipboard_ref()),
|
||||
VK_V => match modifiers {
|
||||
MOD_CTRL => tb.paste(self.clipboard_ref()),
|
||||
_ => return false,
|
||||
},
|
||||
vk::Y => match modifiers {
|
||||
kbmod::CTRL => tb.redo(),
|
||||
VK_Y => match modifiers {
|
||||
MOD_CTRL => tb.redo(),
|
||||
_ => return false,
|
||||
},
|
||||
vk::Z => match modifiers {
|
||||
kbmod::CTRL => tb.undo(),
|
||||
kbmod::CTRL_SHIFT => tb.redo(),
|
||||
kbmod::ALT => tb.set_word_wrap(!tb.is_word_wrap_enabled()),
|
||||
VK_Z => match modifiers {
|
||||
MOD_CTRL => tb.undo(),
|
||||
MOD_CTRL_SHIFT => tb.redo(),
|
||||
MOD_ALT => tb.set_word_wrap(!tb.is_word_wrap_enabled()),
|
||||
_ => return false,
|
||||
},
|
||||
_ => return false,
|
||||
}
|
||||
|
||||
change_preferred_column = !matches!(key, vk::PRIOR | vk::NEXT | vk::UP | vk::DOWN);
|
||||
change_preferred_column = !matches!(key, VK_PRIOR | VK_NEXT | VK_UP | VK_DOWN);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2863,10 +2863,10 @@ impl<'a> Context<'a, '_> {
|
|||
&& let Some(key) = self.input_keyboard
|
||||
{
|
||||
match key {
|
||||
vk::PRIOR => sc.scroll_offset.y -= prev_container.inner_clipped.height(),
|
||||
vk::NEXT => sc.scroll_offset.y += prev_container.inner_clipped.height(),
|
||||
vk::END => sc.scroll_offset.y = CoordType::MAX,
|
||||
vk::HOME => sc.scroll_offset.y = 0,
|
||||
VK_PRIOR => sc.scroll_offset.y -= prev_container.inner_clipped.height(),
|
||||
VK_NEXT => sc.scroll_offset.y += prev_container.inner_clipped.height(),
|
||||
VK_END => sc.scroll_offset.y = CoordType::MAX,
|
||||
VK_HOME => sc.scroll_offset.y = 0,
|
||||
_ => return,
|
||||
}
|
||||
self.set_input_consumed();
|
||||
|
|
@ -2956,7 +2956,7 @@ impl<'a> Context<'a, '_> {
|
|||
let entered = focused
|
||||
&& selected_before
|
||||
&& !self.input_consumed
|
||||
&& matches!(self.input_keyboard, Some(vk::RETURN));
|
||||
&& matches!(self.input_keyboard, Some(VK_RETURN));
|
||||
let activated = clicked || entered;
|
||||
if activated {
|
||||
self.set_input_consumed();
|
||||
|
|
@ -3020,7 +3020,7 @@ impl<'a> Context<'a, '_> {
|
|||
let mut consumed = true;
|
||||
|
||||
match key {
|
||||
vk::PRIOR => {
|
||||
VK_PRIOR => {
|
||||
selected_next = selected_now;
|
||||
for _ in 0..prev_container.borrow().inner_clipped.height() - 1 {
|
||||
let node = selected_next.borrow();
|
||||
|
|
@ -3030,7 +3030,7 @@ impl<'a> Context<'a, '_> {
|
|||
};
|
||||
}
|
||||
}
|
||||
vk::NEXT => {
|
||||
VK_NEXT => {
|
||||
selected_next = selected_now;
|
||||
for _ in 0..prev_container.borrow().inner_clipped.height() - 1 {
|
||||
let node = selected_next.borrow();
|
||||
|
|
@ -3040,13 +3040,13 @@ impl<'a> Context<'a, '_> {
|
|||
};
|
||||
}
|
||||
}
|
||||
vk::END => {
|
||||
VK_END => {
|
||||
selected_next = list.children.last.unwrap_or(selected_next);
|
||||
}
|
||||
vk::HOME => {
|
||||
VK_HOME => {
|
||||
selected_next = list.children.first.unwrap_or(selected_next);
|
||||
}
|
||||
vk::UP => {
|
||||
VK_UP => {
|
||||
selected_next = selected_now
|
||||
.borrow()
|
||||
.siblings
|
||||
|
|
@ -3054,7 +3054,7 @@ impl<'a> Context<'a, '_> {
|
|||
.or(list.children.last)
|
||||
.unwrap_or(selected_next);
|
||||
}
|
||||
vk::DOWN => {
|
||||
VK_DOWN => {
|
||||
selected_next = selected_now
|
||||
.borrow()
|
||||
.siblings
|
||||
|
|
@ -3122,7 +3122,7 @@ impl<'a> Context<'a, '_> {
|
|||
let contains_focus = self.contains_focus();
|
||||
let keyboard_focus = accelerator != '\0'
|
||||
&& !contains_focus
|
||||
&& self.consume_shortcut(kbmod::ALT | InputKey::new(accelerator as u32));
|
||||
&& self.consume_shortcut(MOD_ALT | InputKey::new(accelerator as u32));
|
||||
|
||||
if contains_focus || keyboard_focus {
|
||||
self.attr_background_rgba(self.tui.floater_default_bg);
|
||||
|
|
@ -3212,15 +3212,15 @@ impl<'a> Context<'a, '_> {
|
|||
|
||||
if !self.input_consumed
|
||||
&& let Some(key) = self.input_keyboard
|
||||
&& matches!(key, vk::ESCAPE | vk::UP | vk::DOWN)
|
||||
&& matches!(key, VK_ESCAPE | VK_UP | VK_DOWN)
|
||||
{
|
||||
if matches!(key, vk::UP | vk::DOWN) {
|
||||
if matches!(key, VK_UP | VK_DOWN) {
|
||||
// If the focus is on the menubar, and the user presses up/down,
|
||||
// focus the first/last item of the flyout respectively.
|
||||
let ln = self.tree.last_node.borrow();
|
||||
if self.tui.is_node_focused(ln.parent.map_or(0, |n| n.borrow().id)) {
|
||||
let selected_next =
|
||||
if key == vk::UP { ln.children.last } else { ln.children.first };
|
||||
if key == VK_UP { ln.children.last } else { ln.children.first };
|
||||
if let Some(selected_next) = selected_next {
|
||||
self.steal_focus_for(selected_next);
|
||||
self.set_input_consumed();
|
||||
|
|
@ -3303,15 +3303,15 @@ impl<'a> Context<'a, '_> {
|
|||
let shortcut_letter = shortcut.value() as u8 as char;
|
||||
if shortcut_letter.is_ascii_uppercase() {
|
||||
let mut shortcut_text = ArenaString::new_in(self.arena());
|
||||
if shortcut.modifiers_contains(kbmod::CTRL) {
|
||||
if shortcut.modifiers_contains(MOD_CTRL) {
|
||||
shortcut_text.push_str(self.tui.modifier_translations.ctrl);
|
||||
shortcut_text.push('+');
|
||||
}
|
||||
if shortcut.modifiers_contains(kbmod::ALT) {
|
||||
if shortcut.modifiers_contains(MOD_ALT) {
|
||||
shortcut_text.push_str(self.tui.modifier_translations.alt);
|
||||
shortcut_text.push('+');
|
||||
}
|
||||
if shortcut.modifiers_contains(kbmod::SHIFT) {
|
||||
if shortcut.modifiers_contains(MOD_SHIFT) {
|
||||
shortcut_text.push_str(self.tui.modifier_translations.shift);
|
||||
shortcut_text.push('+');
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue