From f673ef3b6c6a4f6a2f171a026415605e69e2ce4c Mon Sep 17 00:00:00 2001 From: Tig Date: Sat, 7 Dec 2024 22:12:27 -0800 Subject: [PATCH] Doc updates. Code cleanup --- .../KeyBindingScopeExtensions.cs | 93 ------------------- Terminal.Gui/Input/Keyboard/KeyBinding.cs | 2 +- .../Input/Keyboard/KeyBindingScope.cs | 26 ------ docfx/docs/keyboard.md | 47 +++++++--- 4 files changed, 37 insertions(+), 131 deletions(-) delete mode 100644 Terminal.Gui/EnumExtensions/KeyBindingScopeExtensions.cs delete mode 100644 Terminal.Gui/Input/Keyboard/KeyBindingScope.cs diff --git a/Terminal.Gui/EnumExtensions/KeyBindingScopeExtensions.cs b/Terminal.Gui/EnumExtensions/KeyBindingScopeExtensions.cs deleted file mode 100644 index 6f42f4c826..0000000000 --- a/Terminal.Gui/EnumExtensions/KeyBindingScopeExtensions.cs +++ /dev/null @@ -1,93 +0,0 @@ -#nullable enable - -using System.CodeDom.Compiler; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; - -namespace Terminal.Gui.EnumExtensions; - -/// Extension methods for the type. -[GeneratedCode ("Terminal.Gui.Analyzers.Internal", "1.0")] -[CompilerGenerated] -[DebuggerNonUserCode] -[ExcludeFromCodeCoverage (Justification = "Generated code is already tested.")] -[PublicAPI] -public static class KeyBindingScopeExtensions -{ - /// - /// Directly converts this value to an value with the - /// same binary representation. - /// - /// NO VALIDATION IS PERFORMED! - [MethodImpl (MethodImplOptions.AggressiveInlining)] - public static int AsInt32 (this KeyBindingScope e) => Unsafe.As (ref e); - - /// - /// Directly converts this value to a value with the - /// same binary representation. - /// - /// NO VALIDATION IS PERFORMED! - [MethodImpl (MethodImplOptions.AggressiveInlining)] - public static uint AsUInt32 (this KeyBindingScope e) => Unsafe.As (ref e); - - /// - /// Determines if the specified flags are set in the current value of this - /// . - /// - /// NO VALIDATION IS PERFORMED! - /// - /// True, if all flags present in are also present in the current value of the - /// .
Otherwise false. - ///
- [MethodImpl (MethodImplOptions.AggressiveInlining)] - public static bool FastHasFlags (this KeyBindingScope e, KeyBindingScope checkFlags) - { - ref uint enumCurrentValueRef = ref Unsafe.As (ref e); - ref uint checkFlagsValueRef = ref Unsafe.As (ref checkFlags); - - return (enumCurrentValueRef & checkFlagsValueRef) == checkFlagsValueRef; - } - - /// - /// Determines if the specified mask bits are set in the current value of this - /// . - /// - /// - /// The value to check against the - /// value. - /// - /// A mask to apply to the current value. - /// - /// True, if all bits set to 1 in the mask are also set to 1 in the current value of the - /// .
Otherwise false. - ///
- /// NO VALIDATION IS PERFORMED! - [MethodImpl (MethodImplOptions.AggressiveInlining)] - public static bool FastHasFlags (this KeyBindingScope e, int mask) - { - ref int enumCurrentValueRef = ref Unsafe.As (ref e); - - return (enumCurrentValueRef & mask) == mask; - } - - /// - /// Determines if the specified value is explicitly defined as a named value of the - /// type. - /// - /// - /// Only explicitly named values return true, as with IsDefined. Combined valid flag values of flags enums which are - /// not explicitly named will return false. - /// - public static bool FastIsDefined (this KeyBindingScope _, int value) - { - return value switch - { - 0 => true, - 1 => true, - 2 => true, - 4 => true, - _ => false - }; - } -} diff --git a/Terminal.Gui/Input/Keyboard/KeyBinding.cs b/Terminal.Gui/Input/Keyboard/KeyBinding.cs index 7e05b7b452..8ae7103ea1 100644 --- a/Terminal.Gui/Input/Keyboard/KeyBinding.cs +++ b/Terminal.Gui/Input/Keyboard/KeyBinding.cs @@ -6,7 +6,7 @@ namespace Terminal.Gui; /// -/// Provides a collection of objects that are scoped to . +/// Provides a collection of objects stored in . /// /// /// diff --git a/Terminal.Gui/Input/Keyboard/KeyBindingScope.cs b/Terminal.Gui/Input/Keyboard/KeyBindingScope.cs deleted file mode 100644 index cfd31f6bca..0000000000 --- a/Terminal.Gui/Input/Keyboard/KeyBindingScope.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace Terminal.Gui; - -/// -/// Defines the scope of a that has been bound to a key with -/// . -/// -/// -/// Key bindings are scoped to the most-focused view () by default. -/// -/// -/// -/// -[Flags] -public enum KeyBindingScope -{ - /// The key binding is disabled. - Disabled = 0, - - /// - /// The key binding is scoped to just the view that has focus. - /// - /// - /// - /// - Focused = 1 -} diff --git a/docfx/docs/keyboard.md b/docfx/docs/keyboard.md index ddace3282c..4abd704259 100644 --- a/docfx/docs/keyboard.md +++ b/docfx/docs/keyboard.md @@ -1,4 +1,4 @@ -# Keyboard Events +# Keyboard Deep Dive ## Tenets for Terminal.Gui Keyboard Handling (Unless you know better ones...) @@ -14,19 +14,34 @@ Tenets higher in the list have precedence over tenets lower in the list. * **If It's Hot, It Works** - If a View with a @Terminal.Gui.View.HotKey is visible, and the HotKey is visible, the user should be able to press that HotKey and whatever behavior is defined for it should work. For example, in v1, when a Modal view was active, the HotKeys on MenuBar continued to show "hot". In v2 we strive to ensure this doesn't happen. - ## Keyboard APIs *Terminal.Gui* provides the following APIs for handling keyboard input: -### **[Key](~/api/Terminal.Gui.Key.yml)** - -The `Key` class provides a platform-independent abstraction for common keyboard operations. It is used for processing keyboard input and raising keyboard events. This class provides a high-level abstraction with helper methods and properties for common keyboard operations. Use this class instead of the low-level `KeyCode` enum when possible. +* **Key** - @Terminal.Gui.Key provides a platform-independent abstraction for common keyboard operations. It is used for processing keyboard input and raising keyboard events. This class provides a high-level abstraction with helper methods and properties for common keyboard operations. Use this class instead of the low-level `KeyCode` enum when possible. +* **Key Bindings** - Key Bindings provide a declarative method for handling keyboard input in View implementations. The View calls @Terminal.Gui.AddCommand to declare it supports a particular command and then uses @Terminal.Gui.KeyBindings to indicate which key presses will invoke the command. +* **Key Events** - The Key Bindings API is rich enough to support the vast majority of use-cases. However, in some cases subscribing directly to key events is needed (e.g. when capturing arbitrary typing by a user). Use @Terminal.Gui.View.KeyDown and related events in these cases. -See [Key](~/api/Terminal.Gui.Key.yml) for more details. +Each of these APIs are described more fully below. ### **[Key Bindings](~/api/Terminal.Gui.KeyBindings.yml)** +Key Bindings is the preferred way of handling keyboard input in View implementations. The View calls @Terminal.Gui.AddCommand to declare it supports a particular command and then uses @Terminal.Gui.KeyBindings to indicate which key presses will invoke the command. For example, if a View wants to respond to the user pressing the up arrow key to scroll up it would do this + +```cs +public MyView : View +{ + AddCommand (Command.ScrollUp, () => ScrollVertical (-1)); + KeyBindings.Add (Key.CursorUp, Command.ScrollUp); +} +``` + +The `Character Map` Scenario includes a View called `CharMap` that is a good example of the Key Bindings API. + +The [Command](~/api/Terminal.Gui.Command.yml) enum lists generic operations that are implemented by views. For example `Command.Accept` in a `Button` results in the `Accepting` event +firing while in `TableView` it is bound to `CellActivated`. Not all commands +are implemented by all views (e.g. you cannot scroll in a `Button`). Use the @Terminal.Gui.View.GetSupportedCommands() method to determine which commands are implemented by a `View`. + The default key for activating a button is `Space`. You can change this using `KeyBindings.ReplaceKey()`: @@ -35,11 +50,21 @@ var btn = new Button () { Title = "Press me" }; btn.KeyBindings.ReplaceKey (btn.KeyBindings.GetKeyFromCommands (Command.Accept)); ``` -The [Command](~/api/Terminal.Gui.Command.yml) enum lists generic operations that are implemented by views. For example `Command.Accept` in a `Button` results in the `Clicked` event -firing while in `TableView` it is bound to `CellActivated`. Not all commands -are implemented by all views (e.g. you cannot scroll in a `Button`). Use the @Terminal.Gui.View.GetSupportedCommands() method to determine which commands are implemented by a `View`. +Key Bindings can be added at the `Application` or `View` level. + +For **Application-scoped Key Bindings** there are two categories of Application-scoped Key Bindings: + +1) **Application Command Key Bindings** - Bindings for `Command`s supported by @Terminal.Gui.Application. For example, @Terminal.Gui.Application.QuitKey, which is bound to `Command.Quit` and results in @Terminal.Gui.Application.RequestStop being called. +2) **Application Key Bindings** - Bindings for `Command`s supported on arbitrary `Views` that are meant to be invoked regardless of which part of the application is visible/active. + +Use @Terminal.Gui.Application.KeyBindings to add or modify Application-scoped Key Bindings. + +**View-scoped Key Bindings** also have two categories: + +1) **HotKey Bindings** - These bind to `Command`s that will be invoked regardless of whether the View has focus or not. The most common use-case for `HotKey` bindings is @Terminal.Gui.View.HotKey. For example, a `Button` with a `Title` of `_OK`, the user can press `Alt-O` and the button will be accepted regardless of whether it has focus or not. Add and modify HotKey bindings with @Terminal.Gui.View.HotKeyBindings. +2) **Focused Bindings** - These bind to `Command`s that will be invoked only when the View has focus. Focused Key Bindings are the easiest way to enable a View to support responding to key events. Add and modify Focused bindings with @Terminal.Gui.View.KeyBindings. -Key Bindings can be added at the `Application` or `View` level. For Application-scoped Key Bindings see @Terminal.Gui.Application.Navigation. For View-scoped Key Bindings see @Terminal.Gui.View.KeyBindings. +**Application-Scoped** Key Bindings ### **@"Terminal.Gui.View.HotKey"** @@ -57,7 +82,7 @@ The Command can be invoked even if the `View` that defines them is not focused o [MenuBar](~/api/Terminal.Gui.MenuBar.yml), [ContextMenu](~/api/Terminal.Gui.ContextMenu.yml), and [StatusBar](~/api/Terminal.Gui.StatusBar.yml) support `Shortcut`s. -### **Handling Keyboard Events** +### **Key Events** Keyboard events are retrieved from [Console Drivers](drivers.md) each iteration of the [Application](~/api/Terminal.Gui.Application.yml) [Main Loop](mainloop.md). The console driver raises the @Terminal.Gui.ConsoleDriver.KeyDown and @Terminal.Gui.ConsoleDriver.KeyUp events which invoke @Terminal.Gui.Application.RaiseKeyDown(Terminal.Gui.Key) and @Terminal.Gui.Application.RaiseKeyUp(Terminal.Gui.Key) respectively.