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
This commit is contained in:
parent
c38981c655
commit
9961a28cb5
4 changed files with 134 additions and 30 deletions
|
|
@ -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]) {
|
||||
|
|
|
|||
|
|
@ -401,4 +401,7 @@ impl Pane for PluginPane {
|
|||
))
|
||||
.unwrap();
|
||||
}
|
||||
fn mouse_mode(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
active_pane.end_selection(&relative_position, client_id);
|
||||
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;
|
||||
} 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.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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue