From 4fcb164f4b00f39b1edb3fb79a43508421c1fc43 Mon Sep 17 00:00:00 2001 From: BDisp Date: Sun, 31 May 2020 01:43:47 +0100 Subject: [PATCH] Added class KeyModifiers which improvements better control over the combinations keys. --- Example/demo.cs | 3 +- .../CursesDriver/CursesDriver.cs | 93 +++++++++++++------ Terminal.Gui/ConsoleDrivers/NetDriver.cs | 6 +- Terminal.Gui/ConsoleDrivers/WindowsDriver.cs | 44 ++++++--- Terminal.Gui/Core/Event.cs | 89 +++++++++++++++--- Terminal.Gui/Views/HexView.cs | 10 +- 6 files changed, 186 insertions(+), 59 deletions(-) diff --git a/Example/demo.cs b/Example/demo.cs index edae3a77b..3fbad8a38 100644 --- a/Example/demo.cs +++ b/Example/demo.cs @@ -469,7 +469,8 @@ static class Demo { if ((keyEvent.Key & Key.AltMask) != 0) msg += "Alt "; msg += $"{(((uint)keyEvent.KeyValue & (uint)Key.CharMask) > 26 ? $"{(char)keyEvent.KeyValue}" : $"{keyEvent.Key}")}"; - list.Add (msg); + //list.Add (msg); + list.Add (keyEvent.ToString ()); break; diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index 38a26b9fd..33f8848ec 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -379,12 +379,39 @@ namespace Terminal.Gui { }; } + KeyModifiers keyModifiers; + + KeyModifiers MapKeyModifiers (Key key) + { + if (keyModifiers == null) + keyModifiers = new KeyModifiers (); + + if (!keyModifiers.Shift && key.HasFlag (Key.ShiftMask)) + keyModifiers.Shift = true; + if (!keyModifiers.Alt && key.HasFlag (Key.AltMask)) + keyModifiers.Alt = true; + if (!keyModifiers.Ctrl && key.HasFlag (Key.CtrlMask)) + keyModifiers.Ctrl = true; + //if (!keyModifiers.Capslock) + // keyModifiers.Capslock = true; + //if (!keyModifiers.Numlock) + // keyModifiers.Numlock = true; + //if (!keyModifiers.Scrolllock) + // keyModifiers.Scrolllock = true; + + return keyModifiers; + } + void ProcessInput (Action keyHandler, Action keyDownHandler, Action keyUpHandler, Action mouseHandler) { int wch; var code = Curses.get_wch (out wch); if (code == Curses.ERR) return; + + keyModifiers = new KeyModifiers (); + Key k; + if (code == Curses.KEY_CODE_YES) { if (wch == Curses.KeyResize) { if (Curses.CheckWinChange ()) { @@ -398,8 +425,8 @@ namespace Terminal.Gui { mouseHandler (ToDriverMouse (ev)); return; } - keyHandler (new KeyEvent (MapCursesKey (wch))); - keyUpHandler (new KeyEvent (MapCursesKey (wch))); + keyHandler (new KeyEvent (MapCursesKey (wch), keyModifiers)); + keyUpHandler (new KeyEvent (MapCursesKey (wch), keyModifiers)); return; } @@ -408,43 +435,57 @@ namespace Terminal.Gui { Curses.timeout (200); code = Curses.get_wch (out int wch2); - if (code == Curses.KEY_CODE_YES) - keyHandler (new KeyEvent (Key.AltMask | MapCursesKey (wch))); + + if (code == Curses.KEY_CODE_YES) { + k = Key.AltMask | MapCursesKey (wch); + keyHandler (new KeyEvent (k, MapKeyModifiers (k))); + } if (code == 0) { KeyEvent key; // The ESC-number handling, debatable. // Simulates the AltMask itself by pressing Alt + Space. - if (wch2 == (int)Key.Space) - key = new KeyEvent (Key.AltMask); - else if (wch2 - (int)Key.Space >= 'A' && wch2 - (int)Key.Space <= 'Z') - key = new KeyEvent ((Key)((uint)Key.AltMask + (wch2 - (int)Key.Space))); - else if (wch2 >= '1' && wch <= '9') - key = new KeyEvent ((Key)((int)Key.F1 + (wch2 - '0' - 1))); - else if (wch2 == '0') - key = new KeyEvent (Key.F10); - else if (wch2 == 27) - key = new KeyEvent ((Key)wch2); - else - key = new KeyEvent (Key.AltMask | (Key)wch2); + if (wch2 == (int)Key.Space) { + k = Key.AltMask; + key = new KeyEvent (k, MapKeyModifiers (k)); + } else if (wch2 - (int)Key.Space >= 'A' && wch2 - (int)Key.Space <= 'Z') { + k = (Key)((uint)Key.AltMask + (wch2 - (int)Key.Space)); + key = new KeyEvent (k, MapKeyModifiers (k)); + } else if (wch2 >= '1' && wch <= '9') { + k = (Key)((int)Key.F1 + (wch2 - '0' - 1)); + key = new KeyEvent (k, MapKeyModifiers (k)); + } else if (wch2 == '0') { + k = Key.F10; + key = new KeyEvent (k, MapKeyModifiers (k)); + } else if (wch2 == 27) { + k = (Key)wch2; + key = new KeyEvent (k, MapKeyModifiers (k)); + } else { + k = Key.AltMask | (Key)wch2; + key = new KeyEvent (k, MapKeyModifiers (k)); + } keyHandler (key); } else { - keyHandler (new KeyEvent (Key.Esc)); + k = Key.Esc; + keyHandler (new KeyEvent (k, MapKeyModifiers (k))); } } else if (wch == Curses.KeyTab) { - keyDownHandler (new KeyEvent (MapCursesKey (wch))); - keyHandler (new KeyEvent (MapCursesKey (wch))); + k = MapCursesKey (wch); + keyDownHandler (new KeyEvent (k, MapKeyModifiers (k))); + keyHandler (new KeyEvent (k, MapKeyModifiers (k))); } else { - keyDownHandler (new KeyEvent ((Key)wch)); - keyHandler (new KeyEvent ((Key)wch)); + k = (Key)wch; + keyDownHandler (new KeyEvent (k, MapKeyModifiers (k))); + keyHandler (new KeyEvent (k, MapKeyModifiers (k))); } // Cause OnKeyUp and OnKeyPressed. Note that the special handling for ESC above // will not impact KeyUp. - if (wch == Curses.KeyTab) { - keyUpHandler (new KeyEvent (MapCursesKey (wch))); - } else { - keyUpHandler (new KeyEvent ((Key)wch)); - } + // This is causing ESC firing even if another keystroke was handled. + //if (wch == Curses.KeyTab) { + // keyUpHandler (new KeyEvent (MapCursesKey (wch), keyModifiers)); + //} else { + // keyUpHandler (new KeyEvent ((Key)wch, keyModifiers)); + //} } Action mouseHandler; diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 0fe103693..3d0cd8645 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -335,6 +335,8 @@ namespace Terminal.Gui { return (Key)(0xffffffff); } + KeyModifiers keyModifiers = new KeyModifiers (); + public override void PrepareToRun (MainLoop mainLoop, Action keyHandler, Action keyDownHandler, Action keyUpHandler, Action mouseHandler) { // Note: Net doesn't support keydown/up events and thus any passed keyDown/UpHandlers will never be called @@ -342,8 +344,8 @@ namespace Terminal.Gui { var map = MapKey (consoleKey); if (map == (Key)0xffffffff) return; - keyHandler (new KeyEvent (map)); - keyUpHandler (new KeyEvent (map)); + keyHandler (new KeyEvent (map, keyModifiers)); + keyUpHandler (new KeyEvent (map, keyModifiers)); }; } diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index e0df1eef7..53ecbf236 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -646,17 +646,17 @@ namespace Terminal.Gui { WindowsConsole.ControlKeyState.LeftControlPressed | WindowsConsole.ControlKeyState.EnhancedKey: case WindowsConsole.ControlKeyState.EnhancedKey: - key = new KeyEvent (Key.CtrlMask | Key.AltMask); + key = new KeyEvent (Key.CtrlMask | Key.AltMask, keyModifiers); break; case WindowsConsole.ControlKeyState.LeftAltPressed: - key = new KeyEvent (Key.AltMask); + key = new KeyEvent (Key.AltMask, keyModifiers); break; case WindowsConsole.ControlKeyState.RightControlPressed: case WindowsConsole.ControlKeyState.LeftControlPressed: - key = new KeyEvent (Key.CtrlMask); + key = new KeyEvent (Key.CtrlMask, keyModifiers); break; case WindowsConsole.ControlKeyState.ShiftPressed: - key = new KeyEvent (Key.ShiftMask); + key = new KeyEvent (Key.ShiftMask, keyModifiers); break; case WindowsConsole.ControlKeyState.NumlockOn: break; @@ -667,16 +667,16 @@ namespace Terminal.Gui { default: switch (inputEvent.KeyEvent.wVirtualKeyCode) { case 0x10: - key = new KeyEvent (Key.ShiftMask); + key = new KeyEvent (Key.ShiftMask, keyModifiers); break; case 0x11: - key = new KeyEvent (Key.CtrlMask); + key = new KeyEvent (Key.CtrlMask, keyModifiers); break; case 0x12: - key = new KeyEvent (Key.AltMask); + key = new KeyEvent (Key.AltMask, keyModifiers); break; default: - key = new KeyEvent (Key.Unknown); + key = new KeyEvent (Key.Unknown, keyModifiers); break; } break; @@ -689,12 +689,13 @@ namespace Terminal.Gui { } else { if (inputEvent.KeyEvent.bKeyDown) { // Key Down - Fire KeyDown Event and KeyStroke (ProcessKey) Event - keyDownHandler (new KeyEvent (map)); - keyHandler (new KeyEvent (map)); + keyDownHandler (new KeyEvent (map, keyModifiers)); + keyHandler (new KeyEvent (map, keyModifiers)); } else { - keyUpHandler (new KeyEvent (map)); + keyUpHandler (new KeyEvent (map, keyModifiers)); } } + keyModifiers = null; break; case WindowsConsole.EventType.Mouse: @@ -906,6 +907,8 @@ namespace Terminal.Gui { return mouseFlag; } + KeyModifiers keyModifiers; + public ConsoleKeyInfoEx ToConsoleKeyInfoEx (WindowsConsole.KeyEventRecord keyEvent) { var state = keyEvent.dwControlKeyState; @@ -915,6 +918,22 @@ namespace Terminal.Gui { bool control = (state & (WindowsConsole.ControlKeyState.LeftControlPressed | WindowsConsole.ControlKeyState.RightControlPressed)) != 0; bool capslock = (state & (WindowsConsole.ControlKeyState.CapslockOn)) != 0; bool numlock = (state & (WindowsConsole.ControlKeyState.NumlockOn)) != 0; + bool scrolllock = (state & (WindowsConsole.ControlKeyState.ScrolllockOn)) != 0; + + if (keyModifiers == null) + keyModifiers = new KeyModifiers (); + if (shift) + keyModifiers.Shift = shift; + if (alt) + keyModifiers.Alt = alt; + if (control) + keyModifiers.Ctrl = control; + if (capslock) + keyModifiers.Capslock = capslock; + if (numlock) + keyModifiers.Numlock = numlock; + if (scrolllock) + keyModifiers.Scrolllock = scrolllock; var ConsoleKeyInfo = new ConsoleKeyInfo (keyEvent.UnicodeChar, (ConsoleKey)keyEvent.wVirtualKeyCode, shift, alt, control); return new ConsoleKeyInfoEx (ConsoleKeyInfo, capslock, numlock); @@ -1029,7 +1048,7 @@ namespace Terminal.Gui { return (Key)(0xffffffff); } - private static Key MapKeyModifiers (ConsoleKeyInfo keyInfo, Key key) + private Key MapKeyModifiers (ConsoleKeyInfo keyInfo, Key key) { Key keyMod = new Key (); if (keyInfo.Modifiers.HasFlag (ConsoleModifiers.Shift)) @@ -1048,7 +1067,6 @@ namespace Terminal.Gui { SetupColorsAndBorders (); } - void ResizeScreen () { OutputBuffer = new WindowsConsole.CharInfo [Rows * Cols]; diff --git a/Terminal.Gui/Core/Event.cs b/Terminal.Gui/Core/Event.cs index 8c6fd3b2b..895b6d3d1 100644 --- a/Terminal.Gui/Core/Event.cs +++ b/Terminal.Gui/Core/Event.cs @@ -8,6 +8,36 @@ using System; namespace Terminal.Gui { + /// + /// Manage the keys modifiers within a key event. + /// + public class KeyModifiers { + /// + /// Check if the Shift key was pressed or not. + /// + public bool Shift; + /// + /// Check if the Alt key was pressed or not. + /// + public bool Alt; + /// + /// Check if the Ctrl key was pressed or not. + /// + public bool Ctrl; + /// + /// Check if the Caps lock key was pressed or not. + /// + public bool Capslock; + /// + /// Check if the Num lock key was pressed or not. + /// + public bool Numlock; + /// + /// Check if the Scroll lock key was pressed or not. + /// + public bool Scrolllock; + } + /// /// The enumeration contains special encoding for some keys, but can also /// encode all the unicode values that can be passed. @@ -302,6 +332,11 @@ namespace Terminal.Gui { /// public Key Key; + /// + /// Check if the Shift key was pressed or not. + /// + public KeyModifiers KeyModifiers; + /// /// The key value cast to an integer, you will typical use this for /// extracting the Unicode rune value out of a key, when none of the @@ -313,20 +348,38 @@ namespace Terminal.Gui { /// Gets a value indicating whether the Shift key was pressed. /// /// true if is shift; otherwise, false. - public bool IsShift => (Key & Key.ShiftMask) != 0; + public bool IsShift => KeyModifiers.Shift; /// /// Gets a value indicating whether the Alt key was pressed (real or synthesized) /// /// true if is alternate; otherwise, false. - public bool IsAlt => (Key & Key.AltMask) != 0; + public bool IsAlt => KeyModifiers.Alt; /// /// Determines whether the value is a control key (and NOT just the ctrl key) /// /// true if is ctrl; otherwise, false. //public bool IsCtrl => ((uint)Key >= 1) && ((uint)Key <= 26); - public bool IsCtrl => (Key & Key.CtrlMask) != 0; + public bool IsCtrl => KeyModifiers.Ctrl; + + /// + /// Gets a value indicating whether the Caps lock key was pressed (real or synthesized) + /// + /// true if is alternate; otherwise, false. + public bool IsCapslock => KeyModifiers.Capslock; + + /// + /// Gets a value indicating whether the Num lock key was pressed (real or synthesized) + /// + /// true if is alternate; otherwise, false. + public bool IsNumlock => KeyModifiers.Numlock; + + /// + /// Gets a value indicating whether the Scroll lock key was pressed (real or synthesized) + /// + /// true if is alternate; otherwise, false. + public bool IsScrolllock => KeyModifiers.Scrolllock; /// /// Constructs a new @@ -334,14 +387,16 @@ namespace Terminal.Gui { public KeyEvent () { Key = Key.Unknown; + KeyModifiers = new KeyModifiers (); } /// /// Constructs a new from the provided Key value - can be a rune cast into a Key value /// - public KeyEvent (Key k) + public KeyEvent (Key k, KeyModifiers km) { Key = k; + KeyModifiers = km; } /// @@ -349,21 +404,27 @@ namespace Terminal.Gui { { string msg = ""; var key = this.Key; - if ((this.Key & Key.ShiftMask) != 0) { + if (KeyModifiers.Shift) { msg += "Shift-"; } - if ((this.Key & Key.CtrlMask) != 0) { - msg += "Ctrl-"; - } - if ((this.Key & Key.AltMask) != 0) { + if (KeyModifiers.Alt) { msg += "Alt-"; } - - if (string.IsNullOrEmpty (msg)) { - msg += $"{(((uint)this.KeyValue & (uint)Key.CharMask) > 27 ? $"{(char)this.KeyValue}" : $"{key}")}"; - } else { - msg += $"{(((uint)this.KeyValue & (uint)Key.CharMask) > 27 ? $"{(char)this.KeyValue}" : $"")}"; + if (KeyModifiers.Ctrl) { + msg += "Ctrl-"; } + if (KeyModifiers.Capslock) { + msg += "Capslock-"; + } + if (KeyModifiers.Numlock) { + msg += "Numlock-"; + } + if (KeyModifiers.Scrolllock) { + msg += "Scrolllock-"; + } + + msg += $"{(((uint)this.KeyValue & (uint)Key.CharMask) > 27 ? $"{(char)this.KeyValue}" : $"{key}")}"; + return msg; } } diff --git a/Terminal.Gui/Views/HexView.cs b/Terminal.Gui/Views/HexView.cs index ada9544b1..08609731b 100644 --- a/Terminal.Gui/Views/HexView.cs +++ b/Terminal.Gui/Views/HexView.cs @@ -312,9 +312,13 @@ namespace Terminal.Gui { MoveUp (bytesPerLine); break; case Key.Tab: - leftSide = !leftSide; - RedisplayLine (position); - firstNibble = true; + if (keyEvent.IsCtrl) { + SuperView.FocusNext (); + } else { + leftSide = !leftSide; + RedisplayLine (position); + firstNibble = true; + } break; case ((int)'v' + Key.AltMask): case Key.PageUp: