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 link_handler: Rc<RefCell<LinkHandler>>,
|
||||||
pub ring_bell: bool,
|
pub ring_bell: bool,
|
||||||
scrollback_buffer_lines: usize,
|
scrollback_buffer_lines: usize,
|
||||||
|
pub mouse_mode: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Grid {
|
impl Debug for Grid {
|
||||||
|
|
@ -363,6 +364,7 @@ impl Grid {
|
||||||
link_handler,
|
link_handler,
|
||||||
ring_bell: false,
|
ring_bell: false,
|
||||||
scrollback_buffer_lines: 0,
|
scrollback_buffer_lines: 0,
|
||||||
|
mouse_mode: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn render_full_viewport(&mut self) {
|
pub fn render_full_viewport(&mut self) {
|
||||||
|
|
@ -1773,6 +1775,9 @@ impl Perform for Grid {
|
||||||
Some(7) => {
|
Some(7) => {
|
||||||
self.disable_linewrap = true;
|
self.disable_linewrap = true;
|
||||||
}
|
}
|
||||||
|
Some(1006) => {
|
||||||
|
self.mouse_mode = false;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
} else if let Some(4) = params_iter.next().map(|param| param[0]) {
|
} else if let Some(4) = params_iter.next().map(|param| param[0]) {
|
||||||
|
|
@ -1826,6 +1831,9 @@ impl Perform for Grid {
|
||||||
Some(7) => {
|
Some(7) => {
|
||||||
self.disable_linewrap = false;
|
self.disable_linewrap = false;
|
||||||
}
|
}
|
||||||
|
Some(1006) => {
|
||||||
|
self.mouse_mode = true;
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
} else if let Some(4) = params_iter.next().map(|param| param[0]) {
|
} else if let Some(4) = params_iter.next().map(|param| param[0]) {
|
||||||
|
|
|
||||||
|
|
@ -401,4 +401,7 @@ impl Pane for PluginPane {
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
fn mouse_mode(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -472,6 +472,10 @@ impl Pane for TerminalPane {
|
||||||
fn borderless(&self) -> bool {
|
fn borderless(&self) -> bool {
|
||||||
self.borderless
|
self.borderless
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mouse_mode(&self) -> bool {
|
||||||
|
self.grid.mouse_mode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TerminalPane {
|
impl TerminalPane {
|
||||||
|
|
|
||||||
|
|
@ -289,6 +289,7 @@ pub trait Pane {
|
||||||
fn set_borderless(&mut self, borderless: bool);
|
fn set_borderless(&mut self, borderless: bool);
|
||||||
fn borderless(&self) -> bool;
|
fn borderless(&self) -> bool;
|
||||||
fn handle_right_click(&mut self, _to: &Position, _client_id: ClientId) {}
|
fn handle_right_click(&mut self, _to: &Position, _client_id: ClientId) {}
|
||||||
|
fn mouse_mode(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tab {
|
impl Tab {
|
||||||
|
|
@ -975,6 +976,20 @@ impl Tab {
|
||||||
};
|
};
|
||||||
self.write_to_pane_id(input_bytes, pane_id);
|
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) {
|
pub fn write_to_pane_id(&mut self, input_bytes: Vec<u8>, pane_id: PaneId) {
|
||||||
match pane_id {
|
match pane_id {
|
||||||
PaneId::Terminal(active_terminal_id) => {
|
PaneId::Terminal(active_terminal_id) => {
|
||||||
|
|
@ -2288,11 +2303,30 @@ impl Tab {
|
||||||
}
|
}
|
||||||
pub fn scroll_terminal_up(&mut self, point: &Position, lines: usize, client_id: ClientId) {
|
pub fn scroll_terminal_up(&mut self, point: &Position, lines: usize, client_id: ClientId) {
|
||||||
if let Some(pane) = self.get_pane_at(point, false) {
|
if let Some(pane) = self.get_pane_at(point, false) {
|
||||||
|
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);
|
pane.scroll_up(lines, client_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
pub fn scroll_terminal_down(&mut self, point: &Position, lines: usize, client_id: ClientId) {
|
pub fn scroll_terminal_down(&mut self, point: &Position, lines: usize, client_id: ClientId) {
|
||||||
if let Some(pane) = self.get_pane_at(point, false) {
|
if let Some(pane) = self.get_pane_at(point, false) {
|
||||||
|
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);
|
pane.scroll_down(lines, client_id);
|
||||||
if !pane.is_scrolled() {
|
if !pane.is_scrolled() {
|
||||||
if let PaneId::Terminal(pid) = pane.pid() {
|
if let PaneId::Terminal(pid) = pane.pid() {
|
||||||
|
|
@ -2301,6 +2335,7 @@ impl Tab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
fn get_pane_at(
|
fn get_pane_at(
|
||||||
&mut self,
|
&mut self,
|
||||||
point: &Position,
|
point: &Position,
|
||||||
|
|
@ -2348,8 +2383,18 @@ impl Tab {
|
||||||
|
|
||||||
if let Some(pane) = self.get_pane_at(position, false) {
|
if let Some(pane) = self.get_pane_at(position, false) {
|
||||||
let relative_position = pane.relative_position(position);
|
let relative_position = pane.relative_position(position);
|
||||||
|
|
||||||
|
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);
|
pane.start_selection(&relative_position, client_id);
|
||||||
self.selecting_with_mouse = true;
|
self.selecting_with_mouse = true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn handle_right_click(&mut self, position: &Position, client_id: ClientId) {
|
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) {
|
if let Some(pane) = self.get_pane_at(position, false) {
|
||||||
let relative_position = pane.relative_position(position);
|
let relative_position = pane.relative_position(position);
|
||||||
|
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);
|
pane.handle_right_click(&relative_position, client_id);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
fn focus_pane_at(&mut self, point: &Position, client_id: ClientId) {
|
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) {
|
pub fn handle_mouse_release(&mut self, position: &Position, client_id: ClientId) {
|
||||||
if self.selecting_with_mouse {
|
if self.floating_panes.panes_are_visible()
|
||||||
let mut selected_text = None;
|
&& self.floating_panes.pane_is_being_moved_with_mouse()
|
||||||
let active_pane = self.get_active_pane_or_floating_pane_mut(client_id);
|
{
|
||||||
if let Some(active_pane) = active_pane {
|
self.floating_panes.stop_moving_pane_with_mouse(*position);
|
||||||
let relative_position = active_pane.relative_position(position);
|
return;
|
||||||
active_pane.end_selection(&relative_position, client_id);
|
|
||||||
selected_text = active_pane.get_selected_text();
|
|
||||||
active_pane.reset_selection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
if let Some(selected_text) = selected_text {
|
||||||
self.write_selection_to_clipboard(&selected_text);
|
self.write_selection_to_clipboard(&selected_text);
|
||||||
}
|
}
|
||||||
self.selecting_with_mouse = false;
|
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) {
|
pub fn handle_mouse_hold(&mut self, position_on_screen: &Position, client_id: ClientId) {
|
||||||
let search_selectable = true;
|
let search_selectable = true;
|
||||||
if self.selecting_with_mouse {
|
|
||||||
let active_pane = self.get_active_pane_or_floating_pane_mut(client_id);
|
if self.floating_panes.panes_are_visible()
|
||||||
if let Some(active_pane) = active_pane {
|
&& self.floating_panes.pane_is_being_moved_with_mouse()
|
||||||
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()
|
|
||||||
&& self
|
&& self
|
||||||
.floating_panes
|
.floating_panes
|
||||||
.move_pane_with_mouse(*position_on_screen, search_selectable)
|
.move_pane_with_mouse(*position_on_screen, search_selectable)
|
||||||
{
|
{
|
||||||
self.set_force_render();
|
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