mirror of https://github.com/sgoudham/neovide.git
integrate new keyboard api (#736)
* use new keyboard api using my fork of in progress winit keyboard pr branches * attempt fix for modifiers stuck bugmacos-click-through
parent
113a3f421c
commit
76237c6d47
@ -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<KeyboardLayout> for Value {
|
|
||||||
fn from(layout: KeyboardLayout) -> Self {
|
|
||||||
match layout {
|
|
||||||
KeyboardLayout::Qwerty => "qwerty".into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<T> = fn(T, bool) -> Option<Token<'static>>;
|
|
||||||
|
|
||||||
pub fn neovim_keybinding_string<T, U>(
|
|
||||||
keycode: Option<U>,
|
|
||||||
keytext: Option<String>,
|
|
||||||
modifiers: T,
|
|
||||||
keycode_to_token: KeycodeToTokenFn<U>,
|
|
||||||
) -> Option<String>
|
|
||||||
where
|
|
||||||
T: Into<Modifiers>,
|
|
||||||
{
|
|
||||||
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::<KeyboardSettings>().layout {
|
|
||||||
KeyboardLayout::Qwerty => keycode_to_token(keycode, modifiers.shift),
|
|
||||||
}
|
|
||||||
.map(|e| e.into_string(modifiers))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unsupported_key<T, R>(keycode: T) -> Option<R>
|
|
||||||
where
|
|
||||||
T: std::fmt::Debug,
|
|
||||||
{
|
|
||||||
log::trace!("Unsupported key: {:?}", keycode);
|
|
||||||
None
|
|
||||||
}
|
|
@ -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,
|
|
||||||
}
|
|
@ -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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 <Esc> or <BS>
|
|
||||||
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
|
|
||||||
}
|
|
@ -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<UiCommand>,
|
||||||
|
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<UiCommand>) -> 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();
|
||||||
|
},
|
||||||
|
_ => { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,26 +0,0 @@
|
|||||||
mod qwerty;
|
|
||||||
|
|
||||||
use crate::window::keyboard::Modifiers;
|
|
||||||
use glutin::event::ModifiersState;
|
|
||||||
|
|
||||||
pub use qwerty::handle_qwerty_layout;
|
|
||||||
|
|
||||||
impl From<Option<ModifiersState>> for Modifiers {
|
|
||||||
fn from(state: Option<ModifiersState>) -> 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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<Token<'static>> {
|
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<UiCommand>,
|
||||||
|
button_down: bool,
|
||||||
|
position: LogicalPosition<u32>,
|
||||||
|
grid_id_under_mouse: u64,
|
||||||
|
pub enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MouseManager {
|
||||||
|
pub fn new(command_sender: LoggingTx<UiCommand>) -> 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<PossiblyCurrent>) {
|
||||||
|
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<u32> = 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::<u32>::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<PossiblyCurrent>) {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue