mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
* Fixes #2865. Unknown character sequence while resizing terminal. * Added USE_IOCTL definition for toggle. * Explaining that is a CSI (Esc[) = 27;91. --------- Co-authored-by: Tig <tig@users.noreply.github.com>
This commit is contained in:
@@ -341,6 +341,7 @@ namespace Terminal.Gui {
|
||||
Key k = Key.Null;
|
||||
|
||||
if (code == Curses.KEY_CODE_YES) {
|
||||
var lastWch = wch;
|
||||
while (code == Curses.KEY_CODE_YES && wch == Curses.KeyResize) {
|
||||
ProcessWinChange ();
|
||||
code = Curses.get_wch (out wch);
|
||||
@@ -379,6 +380,25 @@ namespace Terminal.Gui {
|
||||
} else if (wch >= 325 && wch <= 327) { // Shift+Alt+(F1 - F3)
|
||||
wch -= 60;
|
||||
k = Key.ShiftMask | Key.AltMask | MapCursesKey (wch);
|
||||
} else {
|
||||
code = Curses.get_wch (out wch);
|
||||
if (code == 0) {
|
||||
switch (wch) {
|
||||
// Shift code.
|
||||
case 16:
|
||||
keyModifiers.Shift = true;
|
||||
break;
|
||||
default:
|
||||
if (lastWch == Curses.KeyResize && wch == 91) {
|
||||
// Returns this keys to the std input which is a CSI (\x1b[).
|
||||
Curses.ungetch (91); // [
|
||||
Curses.ungetch (27); // Esc
|
||||
return;
|
||||
} else {
|
||||
throw new Exception ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
keyDownHandler (new KeyEvent (k, MapKeyModifiers (k)));
|
||||
keyHandler (new KeyEvent (k, MapKeyModifiers (k)));
|
||||
@@ -388,8 +408,6 @@ namespace Terminal.Gui {
|
||||
|
||||
// Special handling for ESC, we want to try to catch ESC+letter to simulate alt-letter as well as Alt-Fkey
|
||||
if (wch == 27) {
|
||||
Curses.timeout (10);
|
||||
|
||||
code = Curses.get_wch (out int wch2);
|
||||
|
||||
if (code == Curses.KEY_CODE_YES) {
|
||||
@@ -425,6 +443,56 @@ namespace Terminal.Gui {
|
||||
} else if (wch >= (uint)Key.A && wch <= (uint)Key.Z) {
|
||||
keyModifiers.Shift = true;
|
||||
keyModifiers.Alt = true;
|
||||
} else if (wch2 == Curses.KeySS3) {
|
||||
while (code > -1) {
|
||||
code = Curses.get_wch (out wch2);
|
||||
if (code == 0) {
|
||||
switch (wch2) {
|
||||
case 16:
|
||||
keyModifiers.Shift = true;
|
||||
break;
|
||||
case 108:
|
||||
k = (Key)'+';
|
||||
break;
|
||||
case 109:
|
||||
k = (Key)'-';
|
||||
break;
|
||||
case 112:
|
||||
k = Key.InsertChar;
|
||||
break;
|
||||
case 113:
|
||||
k = Key.End;
|
||||
break;
|
||||
case 114:
|
||||
k = Key.CursorDown;
|
||||
break;
|
||||
case 115:
|
||||
k = Key.PageDown;
|
||||
break;
|
||||
case 116:
|
||||
k = Key.CursorLeft;
|
||||
break;
|
||||
case 117:
|
||||
k = Key.Clear;
|
||||
break;
|
||||
case 118:
|
||||
k = Key.CursorRight;
|
||||
break;
|
||||
case 119:
|
||||
k = Key.Home;
|
||||
break;
|
||||
case 120:
|
||||
k = Key.CursorUp;
|
||||
break;
|
||||
case 121:
|
||||
k = Key.PageUp;
|
||||
break;
|
||||
default:
|
||||
k = (Key)wch2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (wch2 < 256) {
|
||||
k = (Key)wch2;
|
||||
keyModifiers.Alt = true;
|
||||
@@ -559,7 +627,6 @@ namespace Terminal.Gui {
|
||||
public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<KeyEvent> keyDownHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> mouseHandler)
|
||||
{
|
||||
// Note: Curses doesn't support keydown/up events and thus any passed keyDown/UpHandlers will never be called
|
||||
Curses.timeout (0);
|
||||
this.keyHandler = keyHandler;
|
||||
this.keyDownHandler = keyDownHandler;
|
||||
this.keyUpHandler = keyUpHandler;
|
||||
@@ -572,9 +639,7 @@ namespace Terminal.Gui {
|
||||
return true;
|
||||
});
|
||||
|
||||
mLoop.WinChanged += () => {
|
||||
ProcessInput ();
|
||||
};
|
||||
mLoop.WinChanged += () => ProcessWinChange ();
|
||||
}
|
||||
|
||||
public override void Init (Action terminalResized)
|
||||
@@ -585,6 +650,7 @@ namespace Terminal.Gui {
|
||||
try {
|
||||
window = Curses.initscr ();
|
||||
Curses.set_escdelay (10);
|
||||
Curses.nodelay (window.Handle, true);
|
||||
} catch (Exception e) {
|
||||
throw new Exception ($"Curses failed to initialize, the exception is: {e.Message}");
|
||||
}
|
||||
@@ -673,13 +739,11 @@ namespace Terminal.Gui {
|
||||
|
||||
ResizeScreen ();
|
||||
UpdateOffScreen ();
|
||||
|
||||
}
|
||||
|
||||
public override void ResizeScreen ()
|
||||
{
|
||||
Clip = new Rect (0, 0, Cols, Rows);
|
||||
Curses.refresh ();
|
||||
}
|
||||
|
||||
public override void UpdateOffScreen ()
|
||||
|
||||
@@ -41,22 +41,26 @@
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
//#define USE_IOCTL
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Terminal.Gui;
|
||||
|
||||
namespace Unix.Terminal {
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
public partial class Curses {
|
||||
//[StructLayout (LayoutKind.Sequential)]
|
||||
//public struct winsize {
|
||||
// public ushort ws_row;
|
||||
// public ushort ws_col;
|
||||
// public ushort ws_xpixel; /* unused */
|
||||
// public ushort ws_ypixel; /* unused */
|
||||
//};
|
||||
#if USE_IOCTL
|
||||
|
||||
[StructLayout (LayoutKind.Sequential)]
|
||||
public struct winsize {
|
||||
public ushort ws_row;
|
||||
public ushort ws_col;
|
||||
public ushort ws_xpixel; /* unused */
|
||||
public ushort ws_ypixel; /* unused */
|
||||
};
|
||||
#endif
|
||||
[StructLayout (LayoutKind.Sequential)]
|
||||
public struct MouseEvent {
|
||||
public short ID;
|
||||
@@ -77,10 +81,11 @@ namespace Unix.Terminal {
|
||||
|
||||
[DllImport ("libc")]
|
||||
public extern static int setlocale (int cate, [MarshalAs (UnmanagedType.LPStr)] string locale);
|
||||
#if USE_IOCTL
|
||||
|
||||
//[DllImport ("libc")]
|
||||
//public extern static int ioctl (int fd, int cmd, out winsize argp);
|
||||
|
||||
[DllImport ("libc")]
|
||||
public extern static int ioctl (int fd, int cmd, out winsize argp);
|
||||
#endif
|
||||
static void LoadMethods ()
|
||||
{
|
||||
var libs = UnmanagedLibrary.IsMacOSPlatform ? new string [] { "libncurses.dylib" } : new string [] { "libncursesw.so.6", "libncursesw.so.5" };
|
||||
@@ -227,9 +232,32 @@ namespace Unix.Terminal {
|
||||
|
||||
internal static void console_sharp_get_dims (out int lines, out int cols)
|
||||
{
|
||||
#if USE_IOCTL
|
||||
|
||||
if (UnmanagedLibrary.IsMacOSPlatform) {
|
||||
int cmd = TIOCGWINSZ_MAC;
|
||||
|
||||
if (ioctl (1, cmd, out winsize ws) == 0) {
|
||||
lines = ws.ws_row;
|
||||
cols = ws.ws_col;
|
||||
|
||||
if (lines == Lines && cols == Cols) {
|
||||
return;
|
||||
}
|
||||
|
||||
resizeterm (lines, cols);
|
||||
} else {
|
||||
lines = Lines;
|
||||
cols = Cols;
|
||||
}
|
||||
} else {
|
||||
lines = Marshal.ReadInt32 (lines_ptr);
|
||||
cols = Marshal.ReadInt32 (cols_ptr);
|
||||
}
|
||||
#else
|
||||
lines = Marshal.ReadInt32 (lines_ptr);
|
||||
cols = Marshal.ReadInt32 (cols_ptr);
|
||||
|
||||
#endif
|
||||
//int cmd;
|
||||
//if (UnmanagedLibrary.IsMacOSPlatform) {
|
||||
// cmd = TIOCGWINSZ_MAC;
|
||||
@@ -347,6 +375,7 @@ namespace Unix.Terminal {
|
||||
static public int savetty () => methods.savetty ();
|
||||
static public int resetty () => methods.resetty ();
|
||||
static public int set_escdelay (int size) => methods.set_escdelay (size);
|
||||
static public int nodelay (IntPtr win, bool bf) => methods.nodelay (win, bf);
|
||||
}
|
||||
|
||||
#pragma warning disable RCS1102 // Make class static.
|
||||
@@ -424,6 +453,7 @@ namespace Unix.Terminal {
|
||||
public delegate int savetty ();
|
||||
public delegate int resetty ();
|
||||
public delegate int set_escdelay (int size);
|
||||
public delegate int nodelay (IntPtr win, bool bf);
|
||||
}
|
||||
|
||||
internal class NativeMethods {
|
||||
@@ -498,6 +528,7 @@ namespace Unix.Terminal {
|
||||
public readonly Delegates.savetty savetty;
|
||||
public readonly Delegates.resetty resetty;
|
||||
public readonly Delegates.set_escdelay set_escdelay;
|
||||
public readonly Delegates.nodelay nodelay;
|
||||
public UnmanagedLibrary UnmanagedLibrary;
|
||||
|
||||
public NativeMethods (UnmanagedLibrary lib)
|
||||
@@ -574,6 +605,7 @@ namespace Unix.Terminal {
|
||||
savetty = lib.GetNativeMethodDelegate<Delegates.savetty> ("savetty");
|
||||
resetty = lib.GetNativeMethodDelegate<Delegates.resetty> ("resetty");
|
||||
set_escdelay = lib.GetNativeMethodDelegate<Delegates.set_escdelay> ("set_escdelay");
|
||||
nodelay = lib.GetNativeMethodDelegate<Delegates.nodelay> ("nodelay");
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
@@ -106,6 +106,7 @@ namespace Unix.Terminal {
|
||||
public const int KeyHome = unchecked((int)0x106);
|
||||
public const int KeyMouse = unchecked((int)0x199);
|
||||
public const int KeyCSI = unchecked((int)0x5b);
|
||||
public const int KeySS3 = unchecked((int)0x4f);
|
||||
public const int KeyEnd = unchecked((int)0x168);
|
||||
public const int KeyDeleteChar = unchecked((int)0x14a);
|
||||
public const int KeyInsertChar = unchecked((int)0x14b);
|
||||
|
||||
101
UICatalog/Scenarios/MainLoopTimeouts.cs
Normal file
101
UICatalog/Scenarios/MainLoopTimeouts.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
#pragma warning disable format
|
||||
|
||||
#pragma warning restore format
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Terminal.Gui;
|
||||
|
||||
namespace UICatalog.Scenarios {
|
||||
[ScenarioMetadata (Name: "MainLoopTimeouts", Description: "MainLoop Timeouts")]
|
||||
[ScenarioCategory ("Tests")]
|
||||
public class MainLoopTimeouts : Scenario {
|
||||
static readonly List<string> GlobalList = new () { "1" };
|
||||
static readonly ListView GlobalListView = new () { Width = Dim.Fill (), Height = Dim.Fill () };
|
||||
|
||||
static Label CounterLabel;
|
||||
static Label BlinkingLabel;
|
||||
|
||||
static int Counter = 0;
|
||||
|
||||
static object _listToken = null;
|
||||
static object _blinkToken = null;
|
||||
static object _countToken = null;
|
||||
|
||||
public override void Init (ColorScheme colorScheme)
|
||||
{
|
||||
Application.Init ();
|
||||
|
||||
var startButton = new Button ("Start");
|
||||
var stopButton = new Button ("Stop") { Y = 1 };
|
||||
var container = new View () { X = Pos.Center (), Y = Pos.Center (), Width = 8, Height = 8, ColorScheme = Colors.Error };
|
||||
|
||||
CounterLabel = new Label ("0") { X = Pos.X (container), Y = Pos.Y (container) - 2 };
|
||||
BlinkingLabel = new Label ("Blink") { X = Pos.X (container), Y = Pos.Bottom (container) + 1 };
|
||||
|
||||
startButton.Clicked += Start;
|
||||
stopButton.Clicked += Stop;
|
||||
|
||||
GlobalListView.SetSource (GlobalList);
|
||||
container.Add (GlobalListView);
|
||||
|
||||
Application.Top.Add (container, CounterLabel, BlinkingLabel);
|
||||
Application.Top.Add (startButton, stopButton);
|
||||
Application.Run ();
|
||||
Application.Shutdown ();
|
||||
}
|
||||
|
||||
public override void Run ()
|
||||
{
|
||||
}
|
||||
|
||||
private static void Start ()
|
||||
{
|
||||
_listToken = Application.MainLoop.AddTimeout (TimeSpan.FromMilliseconds (100), Add);
|
||||
_blinkToken = Application.MainLoop.AddTimeout (TimeSpan.FromMilliseconds (1000), Blink);
|
||||
_countToken = Application.MainLoop.AddTimeout (TimeSpan.FromMilliseconds (1000), Count);
|
||||
}
|
||||
|
||||
private static void Stop ()
|
||||
{
|
||||
Application.MainLoop.RemoveTimeout (_listToken);
|
||||
Application.MainLoop.RemoveTimeout (_blinkToken);
|
||||
Application.MainLoop.RemoveTimeout (_countToken);
|
||||
}
|
||||
|
||||
private static bool Add (MainLoop mainLoop)
|
||||
{
|
||||
Application.MainLoop.Invoke (() => {
|
||||
GlobalList.Add (new Random ().Next (100).ToString ());
|
||||
GlobalListView.MoveDown ();
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool Blink (MainLoop mainLoop)
|
||||
{
|
||||
Application.MainLoop.Invoke (() => {
|
||||
if (BlinkingLabel.Visible) {
|
||||
BlinkingLabel.Visible = false;
|
||||
System.Diagnostics.Debug.WriteLine (BlinkingLabel.Visible);
|
||||
} else {
|
||||
BlinkingLabel.Visible = true;
|
||||
System.Diagnostics.Debug.WriteLine (BlinkingLabel.Visible);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool Count (MainLoop mainLoop)
|
||||
{
|
||||
Application.MainLoop.Invoke (() => {
|
||||
Counter++;
|
||||
CounterLabel.Text = Counter.ToString ();
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user