@@ -294,6 +294,120 @@ impl Command for DisableMouseCapture {
294
294
}
295
295
}
296
296
297
+ bitflags ! {
298
+ /// Represents special flags that tell compatible terminals to add extra information to keyboard events.
299
+ ///
300
+ /// See <https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement> for more information.
301
+ ///
302
+ /// Alternate keys and Unicode codepoints are not yet supported by crossterm.
303
+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
304
+ pub struct KeyboardEnhancementFlags : u8 {
305
+ /// Represent Escape and modified keys using CSI-u sequences, so they can be unambiguously
306
+ /// read.
307
+ const DISAMBIGUATE_ESCAPE_CODES = 0b0000_0001 ;
308
+ /// Add extra events with [`KeyEvent.kind`] set to [`KeyEventKind::Repeat`] or
309
+ /// [`KeyEventKind::Release`] when keys are autorepeated or released.
310
+ const REPORT_EVENT_TYPES = 0b0000_0010 ;
311
+ // Send [alternate keycodes](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#key-codes)
312
+ // in addition to the base keycode.
313
+ //
314
+ // *Note*: these are not yet supported by crossterm.
315
+ // const REPORT_ALTERNATE_KEYS = 0b0000_0100;
316
+ /// Represent all keyboard events as CSI-u sequences. This is required to get repeat/release
317
+ /// events for plain-text keys.
318
+ const REPORT_ALL_KEYS_AS_ESCAPE_CODES = 0b0000_1000 ;
319
+ // Send the Unicode codepoint as well as the keycode.
320
+ //
321
+ // *Note*: this is not yet supported by crossterm.
322
+ // const REPORT_ASSOCIATED_TEXT = 0b0001_0000;
323
+ }
324
+ }
325
+
326
+ /// A command that enables the [kitty keyboard protocol](https://sw.kovidgoyal.net/kitty/keyboard-protocol/), which adds extra information to keyboard events and removes ambiguity for modifier keys.
327
+ ///
328
+ /// It should be paired with [`PopKeyboardEnhancementFlags`] at the end of execution.
329
+ ///
330
+ /// Example usage:
331
+ /// ```no_run
332
+ /// use std::io::{Write, stdout};
333
+ /// use crossterm::execute;
334
+ /// use crossterm::event::{
335
+ /// KeyboardEnhancementFlags,
336
+ /// PushKeyboardEnhancementFlags,
337
+ /// PopKeyboardEnhancementFlags
338
+ /// };
339
+ ///
340
+ /// let mut stdout = stdout();
341
+ ///
342
+ /// execute!(
343
+ /// stdout,
344
+ /// PushKeyboardEnhancementFlags(
345
+ /// KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
346
+ /// )
347
+ /// );
348
+ ///
349
+ /// // ...
350
+ ///
351
+ /// execute!(stdout, PopKeyboardEnhancementFlags);
352
+ /// ```
353
+ ///
354
+ /// Note that, currently, only the following support this protocol:
355
+ /// * [kitty terminal](https://sw.kovidgoyal.net/kitty/)
356
+ /// * [foot terminal](https://codeberg.org/dnkl/foot/issues/319)
357
+ /// * [WezTerm terminal](https://wezfurlong.org/wezterm/config/lua/config/enable_kitty_keyboard.html)
358
+ /// * [notcurses library](https://github.com/dankamongmen/notcurses/issues/2131)
359
+ /// * [neovim text editor](https://github.com/neovim/neovim/pull/18181)
360
+ /// * [kakoune text editor](https://github.com/mawww/kakoune/issues/4103)
361
+ /// * [dte text editor](https://gitlab.com/craigbarnes/dte/-/issues/138)
362
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
363
+ pub struct PushKeyboardEnhancementFlags ( pub KeyboardEnhancementFlags ) ;
364
+
365
+ impl Command for PushKeyboardEnhancementFlags {
366
+ fn write_ansi ( & self , f : & mut impl fmt:: Write ) -> fmt:: Result {
367
+ write ! ( f, "{}{}u" , csi!( ">" ) , self . 0 . bits( ) )
368
+ }
369
+
370
+ #[ cfg( windows) ]
371
+ fn execute_winapi ( & self ) -> Result < ( ) > {
372
+ Err ( io:: Error :: new (
373
+ io:: ErrorKind :: Unsupported ,
374
+ "Keyboard progressive enhancement not implemented on Windows." ,
375
+ ) )
376
+ }
377
+
378
+ #[ cfg( windows) ]
379
+ fn is_ansi_code_supported ( & self ) -> bool {
380
+ false
381
+ }
382
+ }
383
+
384
+ /// A command that disables extra kinds of keyboard events.
385
+ ///
386
+ /// Specifically, it pops one level of keyboard enhancement flags.
387
+ ///
388
+ /// See [`PushKeyboardEnhancementFlags`] and <https://sw.kovidgoyal.net/kitty/keyboard-protocol/> for more information.
389
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
390
+ pub struct PopKeyboardEnhancementFlags ;
391
+
392
+ impl Command for PopKeyboardEnhancementFlags {
393
+ fn write_ansi ( & self , f : & mut impl fmt:: Write ) -> fmt:: Result {
394
+ f. write_str ( csi ! ( "<1u" ) )
395
+ }
396
+
397
+ #[ cfg( windows) ]
398
+ fn execute_winapi ( & self ) -> Result < ( ) > {
399
+ Err ( io:: Error :: new (
400
+ io:: ErrorKind :: Unsupported ,
401
+ "Keyboard progressive enhancement not implemented on Windows." ,
402
+ ) )
403
+ }
404
+
405
+ #[ cfg( windows) ]
406
+ fn is_ansi_code_supported ( & self ) -> bool {
407
+ false
408
+ }
409
+ }
410
+
297
411
/// Represents an event.
298
412
#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
299
413
#[ derive( Debug , PartialOrd , PartialEq , Eq , Clone , Copy , Hash ) ]
@@ -384,6 +498,15 @@ bitflags! {
384
498
}
385
499
}
386
500
501
+ /// Represents a keyboard event kind.
502
+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
503
+ #[ derive( Debug , PartialOrd , PartialEq , Eq , Clone , Copy , Hash ) ]
504
+ pub enum KeyEventKind {
505
+ Press ,
506
+ Repeat ,
507
+ Release ,
508
+ }
509
+
387
510
/// Represents a key event.
388
511
#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
389
512
#[ derive( Debug , PartialOrd , Clone , Copy ) ]
@@ -392,11 +515,29 @@ pub struct KeyEvent {
392
515
pub code : KeyCode ,
393
516
/// Additional key modifiers.
394
517
pub modifiers : KeyModifiers ,
518
+ /// Kind of event.
519
+ pub kind : KeyEventKind ,
395
520
}
396
521
397
522
impl KeyEvent {
398
523
pub const fn new ( code : KeyCode , modifiers : KeyModifiers ) -> KeyEvent {
399
- KeyEvent { code, modifiers }
524
+ KeyEvent {
525
+ code,
526
+ modifiers,
527
+ kind : KeyEventKind :: Press ,
528
+ }
529
+ }
530
+
531
+ pub const fn new_with_kind (
532
+ code : KeyCode ,
533
+ modifiers : KeyModifiers ,
534
+ kind : KeyEventKind ,
535
+ ) -> KeyEvent {
536
+ KeyEvent {
537
+ code,
538
+ modifiers,
539
+ kind,
540
+ }
400
541
}
401
542
402
543
// modifies the KeyEvent,
@@ -422,6 +563,7 @@ impl From<KeyCode> for KeyEvent {
422
563
KeyEvent {
423
564
code,
424
565
modifiers : KeyModifiers :: empty ( ) ,
566
+ kind : KeyEventKind :: Press ,
425
567
}
426
568
}
427
569
}
@@ -431,22 +573,29 @@ impl PartialEq for KeyEvent {
431
573
let KeyEvent {
432
574
code : lhs_code,
433
575
modifiers : lhs_modifiers,
576
+ kind : lhs_kind,
434
577
} = self . normalize_case ( ) ;
435
578
let KeyEvent {
436
579
code : rhs_code,
437
580
modifiers : rhs_modifiers,
581
+ kind : rhs_kind,
438
582
} = other. normalize_case ( ) ;
439
- ( lhs_code == rhs_code) && ( lhs_modifiers == rhs_modifiers)
583
+ ( lhs_code == rhs_code) && ( lhs_modifiers == rhs_modifiers) && ( lhs_kind == rhs_kind )
440
584
}
441
585
}
442
586
443
587
impl Eq for KeyEvent { }
444
588
445
589
impl Hash for KeyEvent {
446
590
fn hash < H : Hasher > ( & self , state : & mut H ) {
447
- let KeyEvent { code, modifiers } = self . normalize_case ( ) ;
591
+ let KeyEvent {
592
+ code,
593
+ modifiers,
594
+ kind,
595
+ } = self . normalize_case ( ) ;
448
596
code. hash ( state) ;
449
597
modifiers. hash ( state) ;
598
+ kind. hash ( state) ;
450
599
}
451
600
}
452
601
0 commit comments