diff --git a/.ok b/.ok index 5bea62b..91c34e8 100644 --- a/.ok +++ b/.ok @@ -1,3 +1 @@ install: cargo build --release; rm c:/dev/tools/neovide.* -ErrorAction SilentlyContinue; cp ./target/release/neovide.exe c:/dev/tools/neovide.exe -check: cargo fmt --all -- --check -code: code . -g {0}:{1}:{2} diff --git a/Cargo.lock b/Cargo.lock index bc1cf57..c86cb28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "ab_glyph_rasterizer" version = "0.1.4" @@ -267,22 +269,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "cocoa" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54201c07dcf3a5ca33fececb8042aed767ee4bfd5a0235a8ceabcda956044b2" -dependencies = [ - "bitflags", - "block", - "cocoa-foundation", - "core-foundation 0.9.1", - "core-graphics 0.22.2", - "foreign-types", - "libc", - "objc", -] - [[package]] name = "cocoa" version = "0.24.0" @@ -443,10 +429,24 @@ dependencies = [ "crossbeam-channel 0.4.4", "crossbeam-deque 0.7.3", "crossbeam-epoch 0.8.2", - "crossbeam-queue", + "crossbeam-queue 0.2.3", "crossbeam-utils 0.7.2", ] +[[package]] +name = "crossbeam" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd01a6eb3daaafa260f6fc94c3a6c36390abc2080e38e3e34ced87393fb77d80" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-channel 0.5.1", + "crossbeam-deque 0.8.0", + "crossbeam-epoch 0.9.4", + "crossbeam-queue 0.3.1", + "crossbeam-utils 0.8.4", +] + [[package]] name = "crossbeam-channel" version = "0.4.4" @@ -528,6 +528,16 @@ dependencies = [ "maybe-uninit", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f6cb3c7f5b8e51bc3ebb73a2327ad4abdbd119dc13223f14f961d2f38486756" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils 0.8.4", +] + [[package]] name = "crossbeam-utils" version = "0.7.2" @@ -557,7 +567,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8434f61eb40fc72030b18a370f7a06b428d27de66b0281977967216312b14dc7" dependencies = [ "async-trait", - "crossbeam", + "crossbeam 0.7.3", "futures 0.3.15", ] @@ -986,12 +996,11 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "glutin" version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ae1cbb9176b9151c4ce03f012e3cd1c6c18c4be79edeaeb3d99f5d8085c5fa3" +source = "git+https://github.com/Kethku/glutin?branch=new-keyboard-all#72e148c299afe3570ab1990c553b03b4d7fdadf2" dependencies = [ "android_glue", "cgl", - "cocoa 0.23.0", + "cocoa", "core-foundation 0.9.1", "glutin_egl_sys", "glutin_emscripten_sys", @@ -999,7 +1008,7 @@ dependencies = [ "glutin_glx_sys", "glutin_wgl_sys", "lazy_static", - "libloading 0.6.7", + "libloading 0.7.0", "log", "objc", "osmesa-sys", @@ -1013,8 +1022,7 @@ dependencies = [ [[package]] name = "glutin_egl_sys" version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2abb6aa55523480c4adc5a56bbaa249992e2dddb2fc63dc96e04a3355364c211" +source = "git+https://github.com/Kethku/glutin?branch=new-keyboard-all#72e148c299afe3570ab1990c553b03b4d7fdadf2" dependencies = [ "gl_generator", "winapi 0.3.9", @@ -1023,14 +1031,12 @@ dependencies = [ [[package]] name = "glutin_emscripten_sys" version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80de4146df76e8a6c32b03007bc764ff3249dcaeb4f675d68a06caf1bac363f1" +source = "git+https://github.com/Kethku/glutin?branch=new-keyboard-all#72e148c299afe3570ab1990c553b03b4d7fdadf2" [[package]] name = "glutin_gles2_sys" version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094e708b730a7c8a1954f4f8a31880af00eb8a1c5b5bf85d28a0a3c6d69103" +source = "git+https://github.com/Kethku/glutin?branch=new-keyboard-all#72e148c299afe3570ab1990c553b03b4d7fdadf2" dependencies = [ "gl_generator", "objc", @@ -1039,8 +1045,7 @@ dependencies = [ [[package]] name = "glutin_glx_sys" version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e393c8fc02b807459410429150e9c4faffdb312d59b8c038566173c81991351" +source = "git+https://github.com/Kethku/glutin?branch=new-keyboard-all#72e148c299afe3570ab1990c553b03b4d7fdadf2" dependencies = [ "gl_generator", "x11-dl", @@ -1049,8 +1054,7 @@ dependencies = [ [[package]] name = "glutin_wgl_sys" version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5951a1569dbab865c6f2a863efafff193a93caf05538d193e9e3816d21696" +source = "git+https://github.com/Kethku/glutin?branch=new-keyboard-all#72e148c299afe3570ab1990c553b03b4d7fdadf2" dependencies = [ "gl_generator", ] @@ -1312,6 +1316,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memmap2" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "723e3ebdcdc5c023db1df315364573789f8857c11b631a2fdfad7c00f5c046b4" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.5.6" @@ -1360,15 +1373,28 @@ dependencies = [ ] [[package]] -name = "mio-extras" -version = "2.0.6" +name = "mio" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" +checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956" dependencies = [ - "lazycell", + "libc", "log", - "mio", - "slab", + "miow 0.3.7", + "ntapi", + "winapi 0.3.9", +] + +[[package]] +name = "mio-misc" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ddf05411bb159cdb5801bb10002afb66cb4572be656044315e363460ce69dc2" +dependencies = [ + "crossbeam 0.8.0", + "crossbeam-queue 0.3.1", + "log", + "mio 0.7.11", ] [[package]] @@ -1378,7 +1404,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" dependencies = [ "log", - "mio", + "mio 0.6.23", "miow 0.3.7", "winapi 0.3.9", ] @@ -1391,7 +1417,7 @@ checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" dependencies = [ "iovec", "libc", - "mio", + "mio 0.6.23", ] [[package]] @@ -1442,11 +1468,17 @@ dependencies = [ "syn 1.0.72", ] +[[package]] +name = "nameof" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba896fb4d7fe86433ebaf18c532bd9202e54c450a1bf7723855220e0e76d71d1" + [[package]] name = "ndk" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eb167c1febed0a496639034d0c76b3b74263636045db5489eee52143c246e73" +checksum = "8794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab" dependencies = [ "jni-sys", "ndk-sys", @@ -1456,9 +1488,9 @@ dependencies = [ [[package]] name = "ndk-glue" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf399b8b7a39c6fb153c4ec32c72fd5fe789df24a647f229c239aa7adb15241" +checksum = "c5caf0c24d51ac1c905c27d4eda4fa0635bbe0de596b8f79235e0b17a4d29385" dependencies = [ "lazy_static", "libc", @@ -1521,6 +1553,7 @@ dependencies = [ "unicode-segmentation", "which 4.1.0", "winapi 0.3.9", + "winit", "winres", ] @@ -1593,6 +1626,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "num-derive" version = "0.2.5" @@ -1657,9 +1699,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.4.3" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca565a7df06f3d4b485494f25ba05da1435950f4dc263440eda7a6fa9b8e36e4" +checksum = "226b45a5c2ac4dd696ed30fa6b94b057ad909c7b7fc2e0d0808192bced894066" dependencies = [ "derivative", "num_enum_derive", @@ -1667,9 +1709,9 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.4.3" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffa5a33ddddfee04c0283a7653987d634e880347e96b5b2ed64de07efb59db9d" +checksum = "1c0fd9eba1d5db0994a239e09c1be402d35622277e35468ba891aa5e3188ce7e" dependencies = [ "proc-macro-crate", "proc-macro2 1.0.26", @@ -2285,7 +2327,7 @@ dependencies = [ "dlib 0.4.2", "lazy_static", "log", - "memmap2", + "memmap2 0.1.0", "nix 0.18.0", "wayland-client", "wayland-cursor", @@ -2449,7 +2491,7 @@ dependencies = [ "lazy_static", "libc", "memchr", - "mio", + "mio 0.6.23", "mio-named-pipes", "mio-uds", "num_cpus", @@ -2845,11 +2887,10 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winit" version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da4eda6fce0eb84bd0a33e3c8794eb902e1033d0a1d5a31bc4f19b1b4bbff597" +source = "git+https://github.com/Kethku/winit?branch=new-keyboard-all#3b5462ec315aae8d95b9440ff6c52a5412c2cca4" dependencies = [ "bitflags", - "cocoa 0.24.0", + "cocoa", "core-foundation 0.9.1", "core-graphics 0.22.2", "core-video-sys", @@ -2858,8 +2899,10 @@ dependencies = [ "lazy_static", "libc", "log", - "mio", - "mio-extras", + "memmap2 0.2.3", + "mio 0.7.11", + "mio-misc", + "nameof", "ndk", "ndk-glue", "ndk-sys", @@ -2867,10 +2910,13 @@ dependencies = [ "parking_lot 0.11.1", "percent-encoding", "raw-window-handle", + "scopeguard", "smithay-client-toolkit", + "unicode-segmentation", "wayland-client", "winapi 0.3.9", "x11-dl", + "xkbcommon-dl", ] [[package]] @@ -2928,6 +2974,18 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" +[[package]] +name = "xkbcommon-dl" +version = "0.1.0" +source = "git+https://github.com/maroider/xkbcommon-dl?rev=900832888ad6f11011d1369befb344a9aa8a9610#900832888ad6f11011d1369befb344a9aa8a9610" +dependencies = [ + "bitflags", + "dlib 0.5.0", + "lazy_static", + "log", + "x11-dl", +] + [[package]] name = "xml-rs" version = "0.8.3" diff --git a/Cargo.toml b/Cargo.toml index 11f3497..c84a764 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,8 @@ dirs = "2" rand = "0.7" pin-project = "0.4.27" futures = "0.3.12" -glutin = "0.26" +glutin = { git = "https://github.com/Kethku/glutin", branch = "new-keyboard-all" } +winit = { git = "https://github.com/Kethku/winit", branch = "new-keyboard-all", default-features = false } gl = "0.14.0" regex = "1.5.4" swash = "0.1.2" diff --git a/src/bridge/events.rs b/src/bridge/events.rs index dc7643f..34262e7 100644 --- a/src/bridge/events.rs +++ b/src/bridge/events.rs @@ -127,6 +127,7 @@ pub enum EditorMode { Normal, Insert, Visual, + Replace, CmdLine, Unknown(String), } @@ -477,6 +478,7 @@ fn parse_mode_change(mode_change_arguments: Vec) -> Result { "normal" => EditorMode::Normal, "insert" => EditorMode::Insert, "visual" => EditorMode::Visual, + "replace" => EditorMode::Replace, "cmdline_normal" => EditorMode::CmdLine, _ => EditorMode::Unknown(mode_name), }, diff --git a/src/editor/cursor.rs b/src/editor/cursor.rs index 4040e5a..14514a9 100644 --- a/src/editor/cursor.rs +++ b/src/editor/cursor.rs @@ -33,7 +33,7 @@ pub struct CursorMode { pub blinkoff: Option, } -#[derive(Clone, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub struct Cursor { pub grid_position: (u64, u64), pub parent_window_id: u64, diff --git a/src/editor/mod.rs b/src/editor/mod.rs index e35b0f4..9efb4e4 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -5,7 +5,6 @@ mod style; mod window; use std::collections::HashMap; -use std::fmt; use std::sync::Arc; use std::thread; @@ -47,6 +46,7 @@ impl WindowAnchor { } } +#[derive(Debug)] pub enum DrawCommand { CloseWindow(u64), Window { @@ -65,21 +65,6 @@ pub enum WindowCommand { SetMouseEnabled(bool), } -impl fmt::Debug for DrawCommand { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - DrawCommand::CloseWindow(_) => write!(formatter, "CloseWindow"), - DrawCommand::Window { grid_id, command } => { - write!(formatter, "Window {} {:?}", grid_id, command) - } - DrawCommand::UpdateCursor(_) => write!(formatter, "UpdateCursor"), - DrawCommand::FontChanged(_) => write!(formatter, "FontChanged"), - DrawCommand::DefaultStyleChanged(_) => write!(formatter, "DefaultStyleChanged"), - DrawCommand::ModeChanged(_) => write!(formatter, "ModeChanged"), - } - } -} - pub struct Editor { pub windows: HashMap, pub cursor: Cursor, diff --git a/src/main.rs b/src/main.rs index 8c122d2..24c9924 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,7 +41,7 @@ use editor::start_editor; use renderer::{cursor_renderer::CursorSettings, RendererSettings}; #[cfg(not(test))] use settings::SETTINGS; -use window::{create_window, window_geometry, KeyboardSettings, WindowSettings}; +use window::{create_window, window_geometry, WindowSettings}; pub use channel_utils::*; pub const INITIAL_DIMENSIONS: (u64, u64) = (100, 50); @@ -162,7 +162,6 @@ fn main() { } } - KeyboardSettings::register(); WindowSettings::register(); RendererSettings::register(); CursorSettings::register(); diff --git a/src/window/keyboard/layout.rs b/src/window/keyboard/layout.rs deleted file mode 100644 index cdc7641..0000000 --- a/src/window/keyboard/layout.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::settings::{FromValue, Value}; - -#[derive(Clone)] -pub enum KeyboardLayout { - Qwerty, -} - -impl FromValue for KeyboardLayout { - fn from_value(&mut self, value: Value) { - match value.as_str() { - Some("qwerty") => *self = KeyboardLayout::Qwerty, - _ => log::error!( - "keyboard_layout setting expected a known keyboard layout name, but received: {}", - value - ), - } - } -} - -impl From for Value { - fn from(layout: KeyboardLayout) -> Self { - match layout { - KeyboardLayout::Qwerty => "qwerty".into(), - } - } -} diff --git a/src/window/keyboard/mod.rs b/src/window/keyboard/mod.rs deleted file mode 100644 index 6087221..0000000 --- a/src/window/keyboard/mod.rs +++ /dev/null @@ -1,49 +0,0 @@ -mod layout; -mod modifiers; -mod settings; -mod token; - -use crate::settings::SETTINGS; - -pub use self::{ - layout::KeyboardLayout, modifiers::Modifiers, settings::KeyboardSettings, token::Token, -}; - -type KeycodeToTokenFn = fn(T, bool) -> Option>; - -pub fn neovim_keybinding_string( - keycode: Option, - keytext: Option, - modifiers: T, - keycode_to_token: KeycodeToTokenFn, -) -> Option -where - T: Into, -{ - let modifiers: Modifiers = modifiers.into(); - if let Some(text) = keytext { - Some( - if text == "<" { - Token::new("lt", true, true) - } else { - Token::new(&text, false, false) - } - .into_string(modifiers), - ) - } else if let Some(keycode) = keycode { - match SETTINGS.get::().layout { - KeyboardLayout::Qwerty => keycode_to_token(keycode, modifiers.shift), - } - .map(|e| e.into_string(modifiers)) - } else { - None - } -} - -pub fn unsupported_key(keycode: T) -> Option -where - T: std::fmt::Debug, -{ - log::trace!("Unsupported key: {:?}", keycode); - None -} diff --git a/src/window/keyboard/modifiers.rs b/src/window/keyboard/modifiers.rs deleted file mode 100644 index fb35ed1..0000000 --- a/src/window/keyboard/modifiers.rs +++ /dev/null @@ -1,15 +0,0 @@ -/// The keyboard modifiers associated with a keystroke -#[derive(Debug, Copy, Clone)] -pub struct Modifiers { - /// Shift key - pub shift: bool, - - /// Control key - pub control: bool, - - /// Alt on Windows, option on Mac - pub meta: bool, - - /// Windows key on PC, command key on Mac - pub logo: bool, -} diff --git a/src/window/keyboard/settings.rs b/src/window/keyboard/settings.rs deleted file mode 100644 index 4ec57ea..0000000 --- a/src/window/keyboard/settings.rs +++ /dev/null @@ -1,17 +0,0 @@ -use super::KeyboardLayout; -use crate::settings::FromValue; - -#[derive(SettingGroup)] -#[setting_prefix = "keyboard"] -#[derive(Clone)] -pub struct KeyboardSettings { - pub layout: KeyboardLayout, -} - -impl Default for KeyboardSettings { - fn default() -> Self { - Self { - layout: KeyboardLayout::Qwerty, - } - } -} diff --git a/src/window/keyboard/token.rs b/src/window/keyboard/token.rs deleted file mode 100644 index 5b7d75a..0000000 --- a/src/window/keyboard/token.rs +++ /dev/null @@ -1,53 +0,0 @@ -use super::Modifiers; - -/// Information about how to translate keyboard into Vim input -#[derive(Debug, Clone)] -pub struct Token<'a> { - /// The name of the key in Vimscript. - /// See `:help key-notation` for more details. - key_name: &'a str, - - /// Whether the token should be enclosed in brackets, such as or - special: bool, - - /// Whether the shift key should be considered for inclusion in the token. - use_shift: bool, -} - -impl<'a> Token<'a> { - pub const fn new(key_name: &'a str, special: bool, use_shift: bool) -> Self { - Self { - key_name, - special, - use_shift, - } - } - - /// Converts the keypress to a Neovim input - pub fn into_string(self, mods: Modifiers) -> String { - let shift = self.use_shift && mods.shift; - let special = self.special || shift || mods.control || mods.meta || use_logo(mods.logo); - let open = if special { "<" } else { "" }; - let command = if use_logo(mods.logo) { "D-" } else { "" }; - let shift = if shift { "S-" } else { "" }; - let control = if mods.control { "C-" } else { "" }; - let meta = if mods.meta { "M-" } else { "" }; - let close = if special { ">" } else { "" }; - format!( - "{}{}{}{}{}{}{}", - open, command, shift, control, meta, self.key_name, close - ) - } -} - -#[cfg(not(target_os = "windows"))] -fn use_logo(logo: bool) -> bool { - logo -} - -// The Windows key is used for OS-level shortcuts, -// so we want to ignore the logo key on this platform. -#[cfg(target_os = "windows")] -fn use_logo(_: bool) -> bool { - false -} diff --git a/src/window/mod.rs b/src/window/mod.rs index ecde1fd..e454d0a 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -1,4 +1,3 @@ -mod keyboard; mod settings; mod window_wrapper; diff --git a/src/window/settings.rs b/src/window/settings.rs index e822991..05de4e9 100644 --- a/src/window/settings.rs +++ b/src/window/settings.rs @@ -1,7 +1,5 @@ use crate::{cmd_line::CmdLineSettings, settings::*}; -pub use super::keyboard::KeyboardSettings; - #[derive(Clone, SettingGroup)] pub struct WindowSettings { pub refresh_rate: u64, diff --git a/src/window/window_wrapper/keyboard_manager.rs b/src/window/window_wrapper/keyboard_manager.rs new file mode 100644 index 0000000..5121265 --- /dev/null +++ b/src/window/window_wrapper/keyboard_manager.rs @@ -0,0 +1,131 @@ +use glutin::event::{ElementState, Event, WindowEvent}; +use glutin::keyboard::Key; + +use crate::bridge::UiCommand; +use crate::channel_utils::LoggingTx; + +pub struct KeyboardManager { + command_sender: LoggingTx, + shift: bool, + ctrl: bool, + alt: bool, + logo: bool, +} + +#[cfg(not(target_os = "windows"))] +fn use_logo(logo: bool) -> bool { + logo +} + +// The Windows key is used for OS-level shortcuts, +// so we want to ignore the logo key on this platform. +#[cfg(target_os = "windows")] +fn use_logo(_: bool) -> bool { + false +} + +fn or_empty(condition: bool, text: &str) -> &str { + if condition { + text + } else { + "" + } +} + +fn get_key_text(key: Key<'static>) -> Option<(&str, bool)> { + match key { + Key::Character(character_text) => match character_text { + " " => Some(("Space", true)), + "<" => Some(("lt", true)), + "\\" => Some(("Bslash", true)), + "|" => Some(("Bar", true)), + " " => Some(("Tab", true)), + "\n" => Some(("CR", true)), + _ => Some((character_text, false)), + }, + Key::Backspace => Some(("BS", true)), + Key::Tab => Some(("Tab", true)), + Key::Enter => Some(("CR", true)), + Key::Escape => Some(("Esc", true)), + Key::Space => Some(("Space", true)), + Key::Delete => Some(("Del", true)), + Key::ArrowUp => Some(("Up", true)), + Key::ArrowDown => Some(("Down", true)), + Key::ArrowLeft => Some(("Left", true)), + Key::ArrowRight => Some(("Right", true)), + Key::F1 => Some(("F1", true)), + Key::F2 => Some(("F2", true)), + Key::F3 => Some(("F3", true)), + Key::F4 => Some(("F4", true)), + Key::F5 => Some(("F5", true)), + Key::F6 => Some(("F6", true)), + Key::F7 => Some(("F7", true)), + Key::F8 => Some(("F8", true)), + Key::F9 => Some(("F9", true)), + Key::F10 => Some(("F10", true)), + Key::F11 => Some(("F11", true)), + Key::F12 => Some(("F12", true)), + Key::Insert => Some(("Insert", true)), + Key::Home => Some(("Home", true)), + Key::End => Some(("End", true)), + Key::PageUp => Some(("PageUp", true)), + Key::PageDown => Some(("PageDown", true)), + _ => None, + } +} + +impl KeyboardManager { + pub fn new(command_sender: LoggingTx) -> KeyboardManager { + KeyboardManager { + command_sender, + shift: false, + ctrl: false, + alt: false, + logo: false, + } + } + + fn format_keybinding_string(&self, special: bool, text: &str) -> String { + let special = special || self.shift || self.ctrl || self.alt || self.logo; + + let open = or_empty(special, "<"); + let shift = or_empty(self.shift, "S-"); + let ctrl = or_empty(self.ctrl, "C-"); + let alt = or_empty(self.alt, "M-"); + let logo = or_empty(use_logo(self.logo), "D-"); + let close = or_empty(special, ">"); + + format!("{}{}{}{}{}{}{}", open, shift, ctrl, alt, logo, text, close) + } + + pub fn handle_event(&mut self, event: &Event<()>) { + match event { + Event::WindowEvent { + event: WindowEvent::KeyboardInput { + event: key_event, .. + }, + .. + } => { + if key_event.state == ElementState::Pressed { + if let Some((key_text, special)) = get_key_text(key_event.logical_key) { + let keybinding_string = self.format_keybinding_string(special, key_text); + + self.command_sender + .send(UiCommand::Keyboard(keybinding_string)) + .expect("Could not send keyboard ui command"); + } + } + }, + Event::WindowEvent { + event: WindowEvent::ModifiersChanged(modifiers), + .. + } => { + self.shift = modifiers.shift_key(); + self.ctrl = modifiers.control_key(); + self.alt = modifiers.alt_key(); + self.logo = modifiers.super_key(); + }, + _ => { } + } + } +} diff --git a/src/window/window_wrapper/layouts/mod.rs b/src/window/window_wrapper/layouts/mod.rs deleted file mode 100644 index 90e73da..0000000 --- a/src/window/window_wrapper/layouts/mod.rs +++ /dev/null @@ -1,26 +0,0 @@ -mod qwerty; - -use crate::window::keyboard::Modifiers; -use glutin::event::ModifiersState; - -pub use qwerty::handle_qwerty_layout; - -impl From> for Modifiers { - fn from(state: Option) -> Modifiers { - if let Some(modifiers) = state { - Modifiers { - shift: modifiers.shift(), - control: modifiers.ctrl(), - meta: modifiers.alt(), - logo: modifiers.logo(), - } - } else { - Modifiers { - shift: false, - control: false, - meta: false, - logo: false, - } - } - } -} diff --git a/src/window/window_wrapper/layouts/qwerty.rs b/src/window/window_wrapper/layouts/qwerty.rs deleted file mode 100644 index ddbf04f..0000000 --- a/src/window/window_wrapper/layouts/qwerty.rs +++ /dev/null @@ -1,138 +0,0 @@ -use crate::window::keyboard::{unsupported_key, Token}; -use glutin::event::VirtualKeyCode::{self, *}; - -/// Maps winit keyboard events to Vim tokens -pub fn handle_qwerty_layout(keycode: VirtualKeyCode, shift: bool) -> Option> { - let special = |text| Some(Token::new(text, true, true)); - let normal = |text| Some(Token::new(text, false, true)); - let partial = |text| Some(Token::new(text, false, false)); - match (keycode, shift) { - (Back, _) => special("BS"), - (Tab, _) => special("Tab"), - (Return, _) => special("Enter"), - (Escape, _) => special("Esc"), - (Space, _) => normal(" "), - (Apostrophe, false) => partial("'"), - (Apostrophe, true) => partial("\""), - (Comma, false) => normal(","), - (Comma, true) => special("lt"), - (Minus, false) => partial("-"), - (Minus, true) => partial("_"), - (Period, false) => partial("."), - (Period, true) => partial(">"), - (Slash, false) => partial("/"), - (Slash, true) => partial("?"), - (Key0, false) => normal("0"), - (Key0, true) => partial(")"), - (Key1, false) => normal("1"), - (Key1, true) => partial("!"), - (Key2, false) => partial("2"), - (Key2, true) => partial("@"), - (Key3, false) => partial("3"), - (Key3, true) => partial("#"), - (Key4, false) => partial("4"), - (Key4, true) => partial("$"), - (Key5, false) => partial("5"), - (Key5, true) => partial("%"), - (Key6, false) => partial("6"), - (Key6, true) => partial("^"), - (Key7, false) => partial("7"), - (Key7, true) => partial("&"), - (Key8, false) => partial("8"), - (Key8, true) => partial("*"), - (Key9, false) => partial("9"), - (Key9, true) => partial("("), - (Colon, _) => normal(":"), - (Semicolon, false) => partial(";"), - (Semicolon, true) => partial(":"), - (Equals, false) => partial("="), - (Equals, true) => partial("+"), - (At, _) => normal("@"), - (LBracket, false) => partial("["), - (LBracket, true) => partial("{"), - (Backslash, false) => partial("\\"), - (Backslash, true) => partial("|"), - (RBracket, false) => partial("]"), - (RBracket, true) => partial("}"), - (Caret, _) => normal("^"), - (Grave, false) => partial("`"), - (Grave, true) => partial("~"), - (A, _) => normal("a"), - (B, _) => normal("b"), - (C, _) => normal("c"), - (D, _) => normal("d"), - (E, _) => normal("e"), - (F, _) => normal("f"), - (G, _) => normal("g"), - (H, _) => normal("h"), - (I, _) => normal("i"), - (J, _) => normal("j"), - (K, _) => normal("k"), - (L, _) => normal("l"), - (M, _) => normal("m"), - (N, _) => normal("n"), - (O, _) => normal("o"), - (P, _) => normal("p"), - (Q, _) => normal("q"), - (R, _) => normal("r"), - (S, _) => normal("s"), - (T, _) => normal("t"), - (U, _) => normal("u"), - (V, _) => normal("v"), - (W, _) => normal("w"), - (X, _) => normal("x"), - (Y, _) => normal("y"), - (Z, _) => normal("z"), - (Delete, _) => special("Delete"), - (F1, _) => special("F1"), - (F2, _) => special("F2"), - (F3, _) => special("F3"), - (F4, _) => special("F4"), - (F5, _) => special("F5"), - (F6, _) => special("F6"), - (F7, _) => special("F7"), - (F8, _) => special("F8"), - (F9, _) => special("F9"), - (F10, _) => special("F10"), - (F11, _) => special("F11"), - (F12, _) => special("F12"), - (Insert, _) => special("Insert"), - (Home, _) => special("Home"), - (PageUp, _) => special("PageUp"), - (End, _) => special("End"), - (PageDown, _) => special("PageDown"), - (Right, _) => special("Right"), - (Left, _) => special("Left"), - (Down, _) => special("Down"), - (Up, _) => special("Up"), - (Numpad0, _) => normal("0"), - (Numpad1, _) => normal("1"), - (Numpad2, _) => normal("2"), - (Numpad3, _) => normal("3"), - (Numpad4, _) => normal("4"), - (Numpad5, _) => normal("5"), - (Numpad6, _) => normal("6"), - (Numpad7, _) => normal("7"), - (Numpad8, _) => normal("8"), - (Numpad9, _) => normal("9"), - (F13, _) => special("F13"), - (F14, _) => special("F14"), - (F15, _) => special("F15"), - (F16, _) => special("F16"), - (F17, _) => special("F17"), - (F18, _) => special("F18"), - (F19, _) => special("F19"), - (F20, _) => special("F20"), - (F21, _) => special("F21"), - (F22, _) => special("F22"), - (F23, _) => special("F23"), - (F24, _) => special("F24"), - (LControl, _) => None, - (LShift, _) => None, - (LAlt, _) => None, - (RControl, _) => None, - (RShift, _) => None, - (RAlt, _) => None, - (keycode, _) => unsupported_key(keycode), - } -} diff --git a/src/window/window_wrapper/mod.rs b/src/window/window_wrapper/mod.rs index 0569c74..f24f0e1 100644 --- a/src/window/window_wrapper/mod.rs +++ b/src/window/window_wrapper/mod.rs @@ -1,35 +1,34 @@ -#[macro_use] -mod layouts; +mod keyboard_manager; +mod mouse_manager; mod renderer; -use super::{handle_new_grid_size, keyboard::neovim_keybinding_string, settings::WindowSettings}; -use crate::{ - bridge::UiCommand, channel_utils::*, cmd_line::CmdLineSettings, editor::WindowCommand, - error_handling::ResultPanicExplanation, redraw_scheduler::REDRAW_SCHEDULER, renderer::Renderer, - settings::SETTINGS, +use std::{ + sync::{ + atomic::{AtomicBool, Ordering}, + mpsc::Receiver, + Arc, + }, + time::{Duration, Instant}, }; + use glutin::{ self, dpi::{LogicalPosition, LogicalSize, PhysicalSize}, - event::{ - ElementState, Event, ModifiersState, MouseButton, MouseScrollDelta, - VirtualKeyCode as Keycode, WindowEvent, - }, + event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{self, Fullscreen, Icon}, ContextBuilder, GlProfile, WindowedContext, }; + +use super::{handle_new_grid_size, settings::WindowSettings}; +use crate::{ + bridge::UiCommand, channel_utils::*, cmd_line::CmdLineSettings, editor::WindowCommand, + redraw_scheduler::REDRAW_SCHEDULER, renderer::Renderer, settings::SETTINGS, +}; use image::{load_from_memory, GenericImageView, Pixel}; -use layouts::handle_qwerty_layout; +use keyboard_manager::KeyboardManager; +use mouse_manager::MouseManager; use renderer::SkiaRenderer; -use std::{ - sync::{ - atomic::{AtomicBool, Ordering}, - mpsc::Receiver, - Arc, - }, - time::{Duration, Instant}, -}; #[derive(RustEmbed)] #[folder = "assets/"] @@ -39,11 +38,8 @@ pub struct GlutinWindowWrapper { windowed_context: WindowedContext, skia_renderer: SkiaRenderer, renderer: Renderer, - mouse_down: bool, - mouse_position: LogicalPosition, - mouse_enabled: bool, - grid_id_under_mouse: u64, - current_modifiers: Option, + keyboard_manager: KeyboardManager, + mouse_manager: MouseManager, title: String, previous_size: PhysicalSize, fullscreen: bool, @@ -95,7 +91,9 @@ impl GlutinWindowWrapper { for window_command in window_commands.into_iter() { match window_command { WindowCommand::TitleChanged(new_title) => self.handle_title_changed(new_title), - WindowCommand::SetMouseEnabled(mouse_enabled) => self.mouse_enabled = mouse_enabled, + WindowCommand::SetMouseEnabled(mouse_enabled) => { + self.mouse_manager.enabled = mouse_enabled + } } } } @@ -115,160 +113,6 @@ impl GlutinWindowWrapper { } } - pub fn handle_keyboard_input( - &mut self, - keycode: Option, - modifiers: Option, - ) { - if keycode.is_some() { - log::trace!( - "Keyboard Input Received: keycode-{:?} modifiers-{:?} ", - keycode, - modifiers - ); - } - - if let Some(keybinding_string) = - neovim_keybinding_string(keycode, None, modifiers, handle_qwerty_layout) - { - self.ui_command_sender - .send(UiCommand::Keyboard(keybinding_string)) - .unwrap_or_explained_panic( - "Could not send UI command from the window system to the neovim process.", - ); - } - } - - pub fn handle_pointer_motion(&mut self, x: i32, y: i32) { - let size = self.windowed_context.window().inner_size(); - if x < 0 || x as u32 >= size.width || y < 0 || y as u32 >= size.height { - return; - } - - let previous_position = self.mouse_position; - - let logical_position: LogicalSize = PhysicalSize::new(x as u32, y as u32) - .to_logical(self.windowed_context.window().scale_factor()); - - let mut top_window_position = (0.0, 0.0); - let mut top_grid_position = None; - - for details in self.renderer.window_regions.iter() { - if logical_position.width >= details.region.left as u32 - && logical_position.width < details.region.right as u32 - && logical_position.height >= details.region.top as u32 - && logical_position.height < details.region.bottom as u32 - { - top_window_position = (details.region.left, details.region.top); - top_grid_position = Some(( - details.id, - LogicalSize::::new( - logical_position.width - details.region.left as u32, - logical_position.height - details.region.top as u32, - ), - details.floating_order.is_some(), - )); - } - } - - if let Some((grid_id, grid_position, grid_floating)) = top_grid_position { - self.grid_id_under_mouse = grid_id; - self.mouse_position = LogicalPosition::new( - (grid_position.width as u64 / self.renderer.font_width) as u32, - (grid_position.height as u64 / self.renderer.font_height) as u32, - ); - - if self.mouse_enabled && self.mouse_down && previous_position != self.mouse_position { - let (window_left, window_top) = top_window_position; - - // Until https://github.com/neovim/neovim/pull/12667 is merged, we have to special - // case non floating windows. Floating windows correctly transform mouse positions - // into grid coordinates, but non floating windows do not. - let position = if grid_floating { - (self.mouse_position.x, self.mouse_position.y) - } else { - let adjusted_drag_left = self.mouse_position.x - + (window_left / self.renderer.font_width as f32) as u32; - let adjusted_drag_top = self.mouse_position.y - + (window_top / self.renderer.font_height as f32) as u32; - (adjusted_drag_left, adjusted_drag_top) - }; - - self.ui_command_sender - .send(UiCommand::Drag { - grid_id: self.grid_id_under_mouse, - position, - }) - .ok(); - } - } - } - - pub fn handle_pointer_down(&mut self) { - if self.mouse_enabled { - self.ui_command_sender - .send(UiCommand::MouseButton { - action: String::from("press"), - grid_id: self.grid_id_under_mouse, - position: (self.mouse_position.x, self.mouse_position.y), - }) - .ok(); - } - self.mouse_down = true; - } - - pub fn handle_pointer_up(&mut self) { - if self.mouse_enabled { - self.ui_command_sender - .send(UiCommand::MouseButton { - action: String::from("release"), - grid_id: self.grid_id_under_mouse, - position: (self.mouse_position.x, self.mouse_position.y), - }) - .ok(); - } - self.mouse_down = false; - } - - pub fn handle_mouse_wheel(&mut self, x: f32, y: f32) { - let scroll_dead_zone = SETTINGS.get::().scroll_dead_zone; - if !self.mouse_enabled { - return; - } - - let vertical_input_type = match y { - _ if y > scroll_dead_zone => Some("up"), - _ if y < -scroll_dead_zone => Some("down"), - _ => None, - }; - - if let Some(input_type) = vertical_input_type { - self.ui_command_sender - .send(UiCommand::Scroll { - direction: input_type.to_string(), - grid_id: self.grid_id_under_mouse, - position: (self.mouse_position.x, self.mouse_position.y), - }) - .ok(); - } - - let horizontal_input_type = match x { - _ if x > scroll_dead_zone => Some("right"), - _ if x < -scroll_dead_zone => Some("left"), - _ => None, - }; - - if let Some(input_type) = horizontal_input_type { - self.ui_command_sender - .send(UiCommand::Scroll { - direction: input_type.to_string(), - grid_id: self.grid_id_under_mouse, - position: (self.mouse_position.x, self.mouse_position.y), - }) - .ok(); - } - } - pub fn handle_focus_lost(&mut self) { self.ui_command_sender.send(UiCommand::FocusLost).ok(); } @@ -279,9 +123,9 @@ impl GlutinWindowWrapper { } pub fn handle_event(&mut self, event: Event<()>, running: &Arc) { - let mut keycode = None; - let mut ignore_text_this_frame = false; - + self.keyboard_manager.handle_event(&event); + self.mouse_manager + .handle_event(&event, &self.renderer, &self.windowed_context); match event { Event::LoopDestroyed => { self.handle_quit(running); @@ -302,61 +146,11 @@ impl GlutinWindowWrapper { )) .ok(); } - Event::WindowEvent { - event: WindowEvent::KeyboardInput { input, .. }, - .. - } => { - if input.state == ElementState::Pressed { - keycode = input.virtual_keycode; - } - } - Event::WindowEvent { - event: WindowEvent::ModifiersChanged(m), - .. - } => { - self.current_modifiers = Some(m); - } - Event::WindowEvent { - event: WindowEvent::CursorMoved { position, .. }, - .. - } => self.handle_pointer_motion(position.x as i32, position.y as i32), - Event::WindowEvent { - event: - WindowEvent::MouseWheel { - delta: MouseScrollDelta::LineDelta(x, y), - .. - }, - .. - } => self.handle_mouse_wheel(x as f32, y as f32), - Event::WindowEvent { - event: - WindowEvent::MouseWheel { - delta: MouseScrollDelta::PixelDelta(logical_position), - .. - }, - .. - } => self.handle_mouse_wheel(logical_position.x as f32, logical_position.y as f32), - Event::WindowEvent { - event: - WindowEvent::MouseInput { - button: MouseButton::Left, - state, - .. - }, - .. - } => { - if state == ElementState::Pressed { - self.handle_pointer_down(); - } else { - self.handle_pointer_up(); - } - } Event::WindowEvent { event: WindowEvent::Focused(focus), .. } => { if focus { - ignore_text_this_frame = true; // Ignore any text events on the first frame when focus is regained. https://github.com/Kethku/neovide/issues/193 self.handle_focus_gained(); } else { self.handle_focus_lost(); @@ -365,10 +159,6 @@ impl GlutinWindowWrapper { Event::WindowEvent { .. } => REDRAW_SCHEDULER.queue_next_frame(), _ => {} } - - if !ignore_text_this_frame { - self.handle_keyboard_input(keycode, self.current_modifiers); - } } pub fn draw_frame(&mut self, dt: f32) { @@ -461,11 +251,8 @@ pub fn start_loop( windowed_context, skia_renderer, renderer, - mouse_down: false, - mouse_position: LogicalPosition::new(0, 0), - mouse_enabled: true, - grid_id_under_mouse: 0, - current_modifiers: None, + keyboard_manager: KeyboardManager::new(ui_command_sender.clone()), + mouse_manager: MouseManager::new(ui_command_sender.clone()), title: String::from("Neovide"), previous_size, fullscreen: false, diff --git a/src/window/window_wrapper/mouse_manager.rs b/src/window/window_wrapper/mouse_manager.rs new file mode 100644 index 0000000..7088ce8 --- /dev/null +++ b/src/window/window_wrapper/mouse_manager.rs @@ -0,0 +1,213 @@ +use glutin::{ + self, + WindowedContext, + dpi::{ + LogicalPosition, + LogicalSize, + PhysicalSize + }, + event::{ + ElementState, + Event, + MouseButton, + MouseScrollDelta, + WindowEvent, + }, + PossiblyCurrent +}; + +use crate::channel_utils::LoggingTx; +use crate::bridge::UiCommand; +use crate::renderer::Renderer; + +pub struct MouseManager { + command_sender: LoggingTx, + button_down: bool, + position: LogicalPosition, + grid_id_under_mouse: u64, + pub enabled: bool, +} + +impl MouseManager { + pub fn new(command_sender: LoggingTx) -> MouseManager { + MouseManager { + command_sender, + button_down: false, + position: LogicalPosition::new(0, 0), + grid_id_under_mouse: 0, + enabled: true, + } + } + + fn handle_pointer_motion(&mut self, x: i32, y: i32, renderer: &Renderer, windowed_context: &WindowedContext) { + let size = windowed_context.window().inner_size(); + if x < 0 || x as u32 >= size.width || y < 0 || y as u32 >= size.height { + return; + } + + let previous_position = self.position; + + let logical_position: LogicalSize = PhysicalSize::new(x as u32, y as u32) + .to_logical(windowed_context.window().scale_factor()); + + let mut top_window_position = (0.0, 0.0); + let mut top_grid_position = None; + + for details in renderer.window_regions.iter() { + if logical_position.width >= details.region.left as u32 + && logical_position.width < details.region.right as u32 + && logical_position.height >= details.region.top as u32 + && logical_position.height < details.region.bottom as u32 + { + top_window_position = (details.region.left, details.region.top); + top_grid_position = Some(( + details.id, + LogicalSize::::new( + logical_position.width - details.region.left as u32, + logical_position.height - details.region.top as u32, + ), + details.floating_order.is_some(), + )); + } + } + + if let Some((grid_id, grid_position, grid_floating)) = top_grid_position { + self.grid_id_under_mouse = grid_id; + self.position = LogicalPosition::new( + (grid_position.width as u64 / renderer.font_width) as u32, + (grid_position.height as u64 / renderer.font_height) as u32, + ); + + if self.enabled && self.button_down && previous_position != self.position { + let (window_left, window_top) = top_window_position; + + // Until https://github.com/neovim/neovim/pull/12667 is merged, we have to special + // case non floating windows. Floating windows correctly transform mouse positions + // into grid coordinates, but non floating windows do not. + let position = if grid_floating { + (self.position.x, self.position.y) + } else { + let adjusted_drag_left = self.position.x + + (window_left / renderer.font_width as f32) as u32; + let adjusted_drag_top = self.position.y + + (window_top / renderer.font_height as f32) as u32; + (adjusted_drag_left, adjusted_drag_top) + }; + + self.command_sender + .send(UiCommand::Drag { + grid_id: self.grid_id_under_mouse, + position, + }) + .ok(); + } + } + } + + fn handle_pointer_down(&mut self) { + if self.enabled { + self.command_sender + .send(UiCommand::MouseButton { + action: String::from("press"), + grid_id: self.grid_id_under_mouse, + position: (self.position.x, self.position.y), + }) + .ok(); + } + self.button_down = true; + } + + fn handle_pointer_up(&mut self) { + if self.enabled { + self.command_sender + .send(UiCommand::MouseButton { + action: String::from("release"), + grid_id: self.grid_id_under_mouse, + position: (self.position.x, self.position.y), + }) + .ok(); + } + self.button_down = false; + } + + fn handle_mouse_wheel(&mut self, x: f32, y: f32) { + if !self.enabled { + return; + } + + let vertical_input_type = match y { + _ if y > 1.8 => Some("up"), + _ if y < -1.8 => Some("down"), + _ => None, + }; + + if let Some(input_type) = vertical_input_type { + self.command_sender + .send(UiCommand::Scroll { + direction: input_type.to_string(), + grid_id: self.grid_id_under_mouse, + position: (self.position.x, self.position.y), + }) + .ok(); + } + + let horizontal_input_type = match x { + _ if x > 1.8 => Some("right"), + _ if x < -1.8 => Some("left"), + _ => None, + }; + + if let Some(input_type) = horizontal_input_type { + self.command_sender + .send(UiCommand::Scroll { + direction: input_type.to_string(), + grid_id: self.grid_id_under_mouse, + position: (self.position.x, self.position.y), + }) + .ok(); + } + } + + pub fn handle_event(&mut self, event: &Event<()>, renderer: &Renderer, windowed_context: &WindowedContext) { + match event { + Event::WindowEvent { + event: WindowEvent::CursorMoved { position, .. }, + .. + } => self.handle_pointer_motion( + position.x as i32, position.y as i32, + renderer, windowed_context), + Event::WindowEvent { + event: + WindowEvent::MouseWheel { + delta: MouseScrollDelta::LineDelta(x, y), + .. + }, + .. + } => self.handle_mouse_wheel(*x as f32, *y as f32), + Event::WindowEvent { + event: + WindowEvent::MouseWheel { + delta: MouseScrollDelta::PixelDelta(logical_position), + .. + }, + .. + } => self.handle_mouse_wheel(logical_position.x as f32, logical_position.y as f32), + Event::WindowEvent { + event: + WindowEvent::MouseInput { + button: MouseButton::Left, + state, + .. + }, + .. + } => { + if state == &ElementState::Pressed { + self.handle_pointer_down(); + } else { + self.handle_pointer_up(); + } + }, + _ => {} + } + } +}