diff options
author | Thomas Linford <tlinford@users.noreply.github.com> | 2022-03-10 13:14:02 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-10 13:14:02 +0100 |
commit | 9961a28cb5b5e4a029e237d4e72157a0c1f1b23e (patch) | |
tree | 77a16ea7dc2a4d298aa075b8231d379e55421bc2 | |
parent | c38981c655dae4fc94e1a001b169d3ab1eda6c5e (diff) |
feature(mouse): forward mouse events (#1191)
* handle sgr mouse mode enable by applications
* forward mouse events
* fix scroll events not forwarded to floating panes
* improve mouse hold/release with floating panes
-rw-r--r-- | zellij-server/src/panes/grid.rs | 8 | ||||
-rw-r--r-- | zellij-server/src/panes/plugin_pane.rs | 3 | ||||
-rw-r--r-- | zellij-server/src/panes/terminal_pane.rs | 4 | ||||
-rw-r--r-- | zellij-server/src/tab/mod.rs | 145 |
4 files changed, 132 insertions, 28 deletions
diff --git a/zellij-server/src/panes/grid.rs b/zellij-server/src/panes/grid.rs index dedf93412..fe1a81ea0 100644 --- a/zellij-server/src/panes/grid.rs +++ b/zellij-server/src/panes/grid.rs @@ -306,6 +306,7 @@ pub struct Grid { pub link_handler: Rc<RefCell<LinkHandler>>, pub ring_bell: bool, scrollback_buffer_lines: usize, + pub mouse_mode: bool, } impl Debug for Grid { @@ -363,6 +364,7 @@ impl Grid { link_handler, ring_bell: false, scrollback_buffer_lines: 0, + mouse_mode: false, } } pub fn render_full_viewport(&mut self) { @@ -1773,6 +1775,9 @@ impl Perform for Grid { Some(7) => { self.disable_linewrap = true; } + Some(1006) => { + self.mouse_mode = false; + } _ => {} }; } else if let Some(4) = params_iter.next().map(|param| param[0]) { @@ -1826,6 +1831,9 @@ impl Perform for Grid { Some(7) => { self.disable_linewrap = false; } + Some(1006) => { + self.mouse_mode = true; + } _ => {} }; } else if let Some(4) = params_iter.next().map(|param| param[0]) { diff --git a/zellij-server/src/panes/plugin_pane.rs b/zellij-server/src/panes/plugin_pane.rs index f5a11c845..8b21c8333 100644 --- a/zellij-server/src/panes/plugin_pane.rs +++ b/zellij-server/src/panes/plugin_pane.rs @@ -401,4 +401,7 @@ impl Pane for PluginPane { )) .unwrap(); } + fn mouse_mode(&self) -> bool { + false + } } diff --git a/zellij-server/src/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs index eca769869..5ac94c4f3 100644 --- a/zellij-server/src/panes/terminal_pane.rs +++ b/zellij-server/src/panes/terminal_pane.rs @@ -472,6 +472,10 @@ impl Pane for TerminalPane { fn borderless(&self) -> bool { self.borderless } + + fn mouse_mode(&self) -> bool { + self.grid.mouse_mode + } } impl TerminalPane { diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs index d304aa61c..e33141f61 100644 --- a/zellij-server/src/tab/mod.rs +++ b/zellij-server/src/tab/mod.rs @@ -289,6 +289,7 @@ pub trait Pane { fn set_borderless(&mut self, borderless: bool); fn borderless(&self) -> bool; fn handle_right_click(&mut self, _to: &Position, _client_id: ClientId) {} + fn mouse_mode(&self) -> bool; } impl Tab { @@ -975,6 +976,20 @@ impl Tab { }; self.write_to_pane_id(input_bytes, pane_id); } + pub fn write_to_terminal_at(&mut self, input_bytes: Vec<u8>, position: &Position) { + if self.floating_panes.panes_are_visible() { + let pane_id = self.floating_panes.get_pane_id_at(position, false); + if let Some(pane_id) = pane_id { + self.write_to_pane_id(input_bytes, pane_id); + return; + } + } + + let pane_id = self.get_pane_id_at(position, false); + if let Some(pane_id) = pane_id { + self.write_to_pane_id(input_bytes, pane_id); + } + } pub fn write_to_pane_id(&mut self, input_bytes: Vec<u8>, pane_id: PaneId) { match pane_id { PaneId::Terminal(active_terminal_id) => { @@ -2288,15 +2303,35 @@ impl Tab { } pub fn scroll_terminal_up(&mut self, point: &Position, lines: usize, client_id: ClientId) { if let Some(pane) = self.get_pane_at(point, false) { - pane.scroll_up(lines, client_id); + if pane.mouse_mode() { + let relative_position = pane.relative_position(point); + let mouse_event = format!( + "\u{1b}[<64;{:?};{:?}M", + relative_position.column.0 + 1, + relative_position.line.0 + 1 + ); + self.write_to_terminal_at(mouse_event.into_bytes(), point); + } else { + pane.scroll_up(lines, client_id); + } } } pub fn scroll_terminal_down(&mut self, point: &Position, lines: usize, client_id: ClientId) { if let Some(pane) = self.get_pane_at(point, false) { - pane.scroll_down(lines, client_id); - if !pane.is_scrolled() { - if let PaneId::Terminal(pid) = pane.pid() { - self.process_pending_vte_events(pid); + if pane.mouse_mode() { + let relative_position = pane.relative_position(point); + let mouse_event = format!( + "\u{1b}[<65;{:?};{:?}M", + relative_position.column.0 + 1, + relative_position.line.0 + 1 + ); + self.write_to_terminal_at(mouse_event.into_bytes(), point); + } else { + pane.scroll_down(lines, client_id); + if !pane.is_scrolled() { + if let PaneId::Terminal(pid) = pane.pid() { + self.process_pending_vte_events(pid); + } } } } @@ -2348,8 +2383,18 @@ impl Tab { if let Some(pane) = self.get_pane_at(position, false) { let relative_position = pane.relative_position(position); - pane.start_selection(&relative_position, client_id); - self.selecting_with_mouse = true; + + if pane.mouse_mode() { + let mouse_event = format!( + "\u{1b}[<0;{:?};{:?}M", + relative_position.column.0 + 1, + relative_position.line.0 + 1 + ); + self.write_to_active_terminal(mouse_event.into_bytes(), client_id); + } else { + pane.start_selection(&relative_position, client_id); + self.selecting_with_mouse = true; + } }; } pub fn handle_right_click(&mut self, position: &Position, client_id: ClientId) { @@ -2357,7 +2402,16 @@ impl Tab { if let Some(pane) = self.get_pane_at(position, false) { let relative_position = pane.relative_position(position); - pane.handle_right_click(&relative_position, client_id); + if pane.mouse_mode() { + let mouse_event = format!( + "\u{1b}[<2;{:?};{:?}M", + relative_position.column.0 + 1, + relative_position.line.0 + 1 + ); + self.write_to_active_terminal(mouse_event.into_bytes(), client_id); + } else { + pane.handle_right_click(&relative_position, client_id); + } }; } fn focus_pane_at(&mut self, point: &Position, client_id: ClientId) { @@ -2392,38 +2446,73 @@ impl Tab { } } pub fn handle_mouse_release(&mut self, position: &Position, client_id: ClientId) { - if self.selecting_with_mouse { - let mut selected_text = None; - let active_pane = self.get_active_pane_or_floating_pane_mut(client_id); - if let Some(active_pane) = active_pane { - let relative_position = active_pane.relative_position(position); + if self.floating_panes.panes_are_visible() + && self.floating_panes.pane_is_being_moved_with_mouse() + { + self.floating_panes.stop_moving_pane_with_mouse(*position); + return; + } + + let selecting = self.selecting_with_mouse; + let active_pane = self.get_active_pane_or_floating_pane_mut(client_id); + + if let Some(active_pane) = active_pane { + let relative_position = active_pane.relative_position(position); + if active_pane.mouse_mode() { + // ensure that coordinates are valid + let col = (relative_position.column.0 + 1) + .max(1) + .min(active_pane.get_content_columns()); + + let line = (relative_position.line.0 + 1) + .max(1) + .min(active_pane.get_content_rows() as isize); + let mouse_event = format!("\u{1b}[<0;{:?};{:?}m", col, line); + self.write_to_active_terminal(mouse_event.into_bytes(), client_id); + } else if selecting { active_pane.end_selection(&relative_position, client_id); - selected_text = active_pane.get_selected_text(); + let selected_text = active_pane.get_selected_text(); active_pane.reset_selection(); + if let Some(selected_text) = selected_text { + self.write_selection_to_clipboard(&selected_text); + } + self.selecting_with_mouse = false; } - - if let Some(selected_text) = selected_text { - self.write_selection_to_clipboard(&selected_text); - } - self.selecting_with_mouse = false; - } else if self.floating_panes.panes_are_visible() { - self.floating_panes.stop_moving_pane_with_mouse(*position); } } pub fn handle_mouse_hold(&mut self, position_on_screen: &Position, client_id: ClientId) { let search_selectable = true; - if self.selecting_with_mouse { - let active_pane = self.get_active_pane_or_floating_pane_mut(client_id); - if let Some(active_pane) = active_pane { - let relative_position = active_pane.relative_position(position_on_screen); - active_pane.update_selection(&relative_position, client_id); - } - } else if self.floating_panes.panes_are_visible() + + if self.floating_panes.panes_are_visible() + && self.floating_panes.pane_is_being_moved_with_mouse() && self .floating_panes .move_pane_with_mouse(*position_on_screen, search_selectable) { self.set_force_render(); + return; + } + + let selecting = self.selecting_with_mouse; + let active_pane = self.get_active_pane_or_floating_pane_mut(client_id); + + if let Some(active_pane) = active_pane { + let relative_position = active_pane.relative_position(position_on_screen); + if active_pane.mouse_mode() { + // ensure that coordinates are valid + let col = (relative_position.column.0 + 1) + .max(1) + .min(active_pane.get_content_columns()); + + let line = (relative_position.line.0 + 1) + .max(1) + .min(active_pane.get_content_rows() as isize); + + let mouse_event = format!("\u{1b}[<32;{:?};{:?}M", col, line); + self.write_to_active_terminal(mouse_event.into_bytes(), client_id); + } else if selecting { + active_pane.update_selection(&relative_position, client_id); + } } } |