From 0321f3dcfb576763625a74392332e627ad5ece1b Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 29 May 2017 12:51:49 -0400 Subject: [PATCH] Implement FocusIn/FocusOut reports (#589) Implements sending FocusIn/FocusOut events, as defined at http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-FocusIn_FocusOut --- src/ansi.rs | 3 +++ src/event.rs | 13 +++++++++---- src/input.rs | 13 +++++++++++++ src/term/mod.rs | 27 +++++++++++++++------------ 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/ansi.rs b/src/ansi.rs index a2adcf90..cca8fe28 100644 --- a/src/ansi.rs +++ b/src/ansi.rs @@ -302,6 +302,8 @@ pub enum Mode { ReportMouseClicks = 1000, /// ?1002 ReportMouseMotion = 1002, + /// ?1004 + ReportFocusInOut = 1004, /// ?1006 SgrMouse = 1006, /// ?1049 @@ -325,6 +327,7 @@ impl Mode { 25 => Mode::ShowCursor, 1000 => Mode::ReportMouseClicks, 1002 => Mode::ReportMouseMotion, + 1004 => Mode::ReportFocusInOut, 1006 => Mode::SgrMouse, 1049 => Mode::SwapScreenAndSetRestoreCursor, 2004 => Mode::BracketedPaste, diff --git a/src/event.rs b/src/event.rs index 32b0e9d6..2d50234d 100644 --- a/src/event.rs +++ b/src/event.rs @@ -251,14 +251,19 @@ impl Processor { *hide_cursor = false; processor.on_mouse_wheel(scroll_delta, touch_phase); }, - glutin::Event::Focused(true) | glutin::Event::Refresh | glutin::Event::Awakened => { processor.ctx.terminal.dirty = true; }, - glutin::Event::Focused(false) => { - *hide_cursor = false; - }, + glutin::Event::Focused(is_focused) => { + if is_focused { + processor.ctx.terminal.dirty = true; + } else { + *hide_cursor = false; + } + + processor.on_focus_change(is_focused); + } _ => (), } } diff --git a/src/input.rs b/src/input.rs index 47374e47..f3efdf14 100644 --- a/src/input.rs +++ b/src/input.rs @@ -381,6 +381,19 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { } } + pub fn on_focus_change(&mut self, is_focused: bool) { + if self.ctx.terminal_mode().contains(mode::FOCUS_IN_OUT) { + let chr = if is_focused { + "I" + } else { + "O" + }; + + let msg = format!("\x1b[{}", chr); + self.ctx.write_to_pty(msg.into_bytes()); + } + } + pub fn mouse_input(&mut self, state: ElementState, button: MouseButton) { if let MouseButton::Left = button { let state = mem::replace(&mut self.ctx.mouse_mut().left_button_state, state); diff --git a/src/term/mod.rs b/src/term/mod.rs index f600347b..1316ac20 100644 --- a/src/term/mod.rs +++ b/src/term/mod.rs @@ -252,18 +252,19 @@ impl<'a> Iterator for RenderableCellsIter<'a> { pub mod mode { bitflags! { pub flags TermMode: u16 { - const SHOW_CURSOR = 0b00000000001, - const APP_CURSOR = 0b00000000010, - const APP_KEYPAD = 0b00000000100, - const MOUSE_REPORT_CLICK = 0b00000001000, - const BRACKETED_PASTE = 0b00000010000, - const SGR_MOUSE = 0b00000100000, - const MOUSE_MOTION = 0b00001000000, - const LINE_WRAP = 0b00010000000, - const LINE_FEED_NEW_LINE = 0b00100000000, - const ORIGIN = 0b01000000000, - const INSERT = 0b10000000000, - const ANY = 0b11111111111, + const SHOW_CURSOR = 0b000000000001, + const APP_CURSOR = 0b000000000010, + const APP_KEYPAD = 0b000000000100, + const MOUSE_REPORT_CLICK = 0b000000001000, + const BRACKETED_PASTE = 0b000000010000, + const SGR_MOUSE = 0b000000100000, + const MOUSE_MOTION = 0b000001000000, + const LINE_WRAP = 0b000010000000, + const LINE_FEED_NEW_LINE = 0b000100000000, + const ORIGIN = 0b001000000000, + const INSERT = 0b010000000000, + const FOCUS_IN_OUT = 0b100000000000, + const ANY = 0b111111111111, const NONE = 0, } } @@ -1631,6 +1632,7 @@ impl ansi::Handler for Term { ansi::Mode::CursorKeys => self.mode.insert(mode::APP_CURSOR), ansi::Mode::ReportMouseClicks => self.mode.insert(mode::MOUSE_REPORT_CLICK), ansi::Mode::ReportMouseMotion => self.mode.insert(mode::MOUSE_MOTION), + ansi::Mode::ReportFocusInOut => self.mode.insert(mode::FOCUS_IN_OUT), ansi::Mode::BracketedPaste => self.mode.insert(mode::BRACKETED_PASTE), ansi::Mode::SgrMouse => self.mode.insert(mode::SGR_MOUSE), ansi::Mode::LineWrap => self.mode.insert(mode::LINE_WRAP), @@ -1657,6 +1659,7 @@ impl ansi::Handler for Term { ansi::Mode::CursorKeys => self.mode.remove(mode::APP_CURSOR), ansi::Mode::ReportMouseClicks => self.mode.remove(mode::MOUSE_REPORT_CLICK), ansi::Mode::ReportMouseMotion => self.mode.remove(mode::MOUSE_MOTION), + ansi::Mode::ReportFocusInOut => self.mode.remove(mode::FOCUS_IN_OUT), ansi::Mode::BracketedPaste => self.mode.remove(mode::BRACKETED_PASTE), ansi::Mode::SgrMouse => self.mode.remove(mode::SGR_MOUSE), ansi::Mode::LineWrap => self.mode.remove(mode::LINE_WRAP),