Emit focus events (#689)
This commit is contained in:
		
							parent
							
								
									c6a8952201
								
							
						
					
					
						commit
						069497b43b
					
				| @ -7,7 +7,10 @@ use std::io::stdout; | |||||||
| use crossterm::event::poll; | use crossterm::event::poll; | ||||||
| use crossterm::{ | use crossterm::{ | ||||||
|     cursor::position, |     cursor::position, | ||||||
|     event::{read, DisableMouseCapture, EnableMouseCapture, Event, KeyCode}, |     event::{ | ||||||
|  |         read, DisableFocusChange, DisableMouseCapture, EnableFocusChange, EnableMouseCapture, | ||||||
|  |         Event, KeyCode, | ||||||
|  |     }, | ||||||
|     execute, |     execute, | ||||||
|     terminal::{disable_raw_mode, enable_raw_mode}, |     terminal::{disable_raw_mode, enable_raw_mode}, | ||||||
|     Result, |     Result, | ||||||
| @ -15,7 +18,7 @@ use crossterm::{ | |||||||
| use std::time::Duration; | use std::time::Duration; | ||||||
| 
 | 
 | ||||||
| const HELP: &str = r#"Blocking read()
 | const HELP: &str = r#"Blocking read()
 | ||||||
|  - Keyboard, mouse and terminal resize events enabled |  - Keyboard, mouse, focus and terminal resize events enabled | ||||||
|  - Hit "c" to print current cursor position |  - Hit "c" to print current cursor position | ||||||
|  - Use Esc to quit |  - Use Esc to quit | ||||||
| "#;
 | "#;
 | ||||||
| @ -67,13 +70,13 @@ fn main() -> Result<()> { | |||||||
|     enable_raw_mode()?; |     enable_raw_mode()?; | ||||||
| 
 | 
 | ||||||
|     let mut stdout = stdout(); |     let mut stdout = stdout(); | ||||||
|     execute!(stdout, EnableMouseCapture)?; |     execute!(stdout, EnableFocusChange, EnableMouseCapture)?; | ||||||
| 
 | 
 | ||||||
|     if let Err(e) = print_events() { |     if let Err(e) = print_events() { | ||||||
|         println!("Error: {:?}\r", e); |         println!("Error: {:?}\r", e); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     execute!(stdout, DisableMouseCapture)?; |     execute!(stdout, DisableFocusChange, DisableMouseCapture)?; | ||||||
| 
 | 
 | ||||||
|     disable_raw_mode() |     disable_raw_mode() | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										45
									
								
								src/event.rs
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								src/event.rs
									
									
									
									
									
								
							| @ -34,6 +34,8 @@ | |||||||
| //!     loop {
 | //!     loop {
 | ||||||
| //!         // `read()` blocks until an `Event` is available
 | //!         // `read()` blocks until an `Event` is available
 | ||||||
| //!         match read()? {
 | //!         match read()? {
 | ||||||
|  | //!             Event::FocusGained => println!("FocusGained"),
 | ||||||
|  | //!             Event::FocusLost => println!("FocusLost"),
 | ||||||
| //!             Event::Key(event) => println!("{:?}", event),
 | //!             Event::Key(event) => println!("{:?}", event),
 | ||||||
| //!             Event::Mouse(event) => println!("{:?}", event),
 | //!             Event::Mouse(event) => println!("{:?}", event),
 | ||||||
| //!             Event::Resize(width, height) => println!("New size {}x{}", width, height),
 | //!             Event::Resize(width, height) => println!("New size {}x{}", width, height),
 | ||||||
| @ -57,6 +59,8 @@ | |||||||
| //!             // It's guaranteed that the `read()` won't block when the `poll()`
 | //!             // It's guaranteed that the `read()` won't block when the `poll()`
 | ||||||
| //!             // function returns `true`
 | //!             // function returns `true`
 | ||||||
| //!             match read()? {
 | //!             match read()? {
 | ||||||
|  | //!                 Event::FocusGained => println!("FocusGained"),
 | ||||||
|  | //!                 Event::FocusLost => println!("FocusLost"),
 | ||||||
| //!                 Event::Key(event) => println!("{:?}", event),
 | //!                 Event::Key(event) => println!("{:?}", event),
 | ||||||
| //!                 Event::Mouse(event) => println!("{:?}", event),
 | //!                 Event::Mouse(event) => println!("{:?}", event),
 | ||||||
| //!                 Event::Resize(width, height) => println!("New size {}x{}", width, height),
 | //!                 Event::Resize(width, height) => println!("New size {}x{}", width, height),
 | ||||||
| @ -74,6 +78,7 @@ | |||||||
| 
 | 
 | ||||||
| use std::fmt; | use std::fmt; | ||||||
| use std::hash::{Hash, Hasher}; | use std::hash::{Hash, Hasher}; | ||||||
|  | #[cfg(windows)] | ||||||
| use std::io; | use std::io; | ||||||
| use std::time::Duration; | use std::time::Duration; | ||||||
| 
 | 
 | ||||||
| @ -409,10 +414,50 @@ impl Command for PopKeyboardEnhancementFlags { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// A command that enables focus event emission.
 | ||||||
|  | ///
 | ||||||
|  | /// Focus events can be captured with [read](./fn.read.html)/[poll](./fn.poll.html).
 | ||||||
|  | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||||||
|  | pub struct EnableFocusChange; | ||||||
|  | 
 | ||||||
|  | impl Command for EnableFocusChange { | ||||||
|  |     fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result { | ||||||
|  |         f.write_str(csi!("?1004h")) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[cfg(windows)] | ||||||
|  |     fn execute_winapi(&self) -> Result<()> { | ||||||
|  |         // Focus events are always enabled on Windows
 | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// A command that disables focus event emission.
 | ||||||
|  | ///
 | ||||||
|  | /// Focus events can be captured with [read](./fn.read.html)/[poll](./fn.poll.html).
 | ||||||
|  | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||||||
|  | pub struct DisableFocusChange; | ||||||
|  | 
 | ||||||
|  | impl Command for DisableFocusChange { | ||||||
|  |     fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result { | ||||||
|  |         f.write_str(csi!("?1004l")) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[cfg(windows)] | ||||||
|  |     fn execute_winapi(&self) -> Result<()> { | ||||||
|  |         // Focus events can't be disabled on Windows
 | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /// Represents an event.
 | /// Represents an event.
 | ||||||
| #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||||||
| #[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] | #[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] | ||||||
| pub enum Event { | pub enum Event { | ||||||
|  |     /// The terminal gained focus
 | ||||||
|  |     FocusGained, | ||||||
|  |     /// The terminal lost focus
 | ||||||
|  |     FocusLost, | ||||||
|     /// A single key event with additional pressed modifiers.
 |     /// A single key event with additional pressed modifiers.
 | ||||||
|     Key(KeyEvent), |     Key(KeyEvent), | ||||||
|     /// A single mouse event with additional pressed modifiers.
 |     /// A single mouse event with additional pressed modifiers.
 | ||||||
|  | |||||||
| @ -66,6 +66,14 @@ impl EventSource for WindowsEventSource { | |||||||
|                         InputRecord::WindowBufferSizeEvent(record) => { |                         InputRecord::WindowBufferSizeEvent(record) => { | ||||||
|                             Some(Event::Resize(record.size.x as u16, record.size.y as u16)) |                             Some(Event::Resize(record.size.x as u16, record.size.y as u16)) | ||||||
|                         } |                         } | ||||||
|  |                         InputRecord::FocusEvent(record) => { | ||||||
|  |                             let event = if record.set_focus { | ||||||
|  |                                 Event::FocusGained | ||||||
|  |                             } else { | ||||||
|  |                                 Event::FocusLost | ||||||
|  |                             }; | ||||||
|  |                             Some(event) | ||||||
|  |                         } | ||||||
|                         _ => None, |                         _ => None, | ||||||
|                     }; |                     }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -167,6 +167,8 @@ pub(crate) fn parse_csi(buffer: &[u8]) -> Result<Option<InternalEvent>> { | |||||||
|         })), |         })), | ||||||
|         b'M' => return parse_csi_normal_mouse(buffer), |         b'M' => return parse_csi_normal_mouse(buffer), | ||||||
|         b'<' => return parse_csi_sgr_mouse(buffer), |         b'<' => return parse_csi_sgr_mouse(buffer), | ||||||
|  |         b'I' => Some(Event::FocusGained), | ||||||
|  |         b'O' => Some(Event::FocusLost), | ||||||
|         b'0'..=b'9' => { |         b'0'..=b'9' => { | ||||||
|             // Numbered escape code.
 |             // Numbered escape code.
 | ||||||
|             if buffer.len() == 3 { |             if buffer.len() == 3 { | ||||||
| @ -745,6 +747,14 @@ mod tests { | |||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn test_parse_csi_focus() { | ||||||
|  |         assert_eq!( | ||||||
|  |             parse_csi(b"\x1B[O").unwrap(), | ||||||
|  |             Some(InternalEvent::Event(Event::FocusLost)) | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_parse_csi_rxvt_mouse() { |     fn test_parse_csi_rxvt_mouse() { | ||||||
|         assert_eq!( |         assert_eq!( | ||||||
|  | |||||||
| @ -350,7 +350,6 @@ pub struct SetStyle(pub ContentStyle); | |||||||
| 
 | 
 | ||||||
| impl Command for SetStyle { | impl Command for SetStyle { | ||||||
|     fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result { |     fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result { | ||||||
| 
 |  | ||||||
|         if let Some(bg) = self.0.background_color { |         if let Some(bg) = self.0.background_color { | ||||||
|             execute_fmt(f, SetBackgroundColor(bg)).map_err(|_| fmt::Error)?; |             execute_fmt(f, SetBackgroundColor(bg)).map_err(|_| fmt::Error)?; | ||||||
|         } |         } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user