Browse Source

Merge pull request #1102 from G-Freart/caret_sizing

Cursor shape and visibility
Charlie Kindel 4 years ago
parent
commit
72361de53e

+ 67 - 0
Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs

@@ -22,6 +22,9 @@ namespace Terminal.Gui {
 		public override int Top => 0;
 		public override bool HeightAsBuffer { get; set; }
 
+		CursorVisibility? initialCursorVisibility = null;
+		CursorVisibility? currentCursorVisibility = null;
+
 		// Current row, and current col, tracked by Move/AddRune only
 		int ccol, crow;
 		bool needMove;
@@ -82,6 +85,9 @@ namespace Terminal.Gui {
 			if (reportableMouseEvents.HasFlag (Curses.Event.ReportMousePosition)) {
 				StopReportingMouseMoves ();
 			}
+
+			SetCursorVisibility (CursorVisibility.Default);
+			
 			Curses.endwin ();
 			// Clear and reset entire screen.
 			Console.Out.Write ("\x1b[2J");
@@ -689,6 +695,30 @@ namespace Terminal.Gui {
 			} catch (Exception e) {
 				Console.WriteLine ("Curses failed to initialize, the exception is: " + e);
 			}
+
+			// 
+			// We are setting Invisible as default so we could ignore XTerm DECSUSR setting
+			//
+			switch (Curses.curs_set (0)) {
+				case 0:		
+					currentCursorVisibility = initialCursorVisibility = CursorVisibility.Invisible;	
+					break;
+
+				case 1:		
+					currentCursorVisibility = initialCursorVisibility = CursorVisibility.Underline;	
+					Curses.curs_set (1); 
+					break;
+
+				case 2:		
+					currentCursorVisibility = initialCursorVisibility = CursorVisibility.Box;		
+					Curses.curs_set (2); 
+					break;
+
+				default:	
+					currentCursorVisibility = initialCursorVisibility = null;						
+					break;
+			}
+
 			Curses.raw ();
 			Curses.noecho ();
 
@@ -868,6 +898,43 @@ namespace Terminal.Gui {
 		{
 			return currentAttribute;
 		}
+
+		/// <inheritdoc/>
+		public override bool GetCursorVisibility (out CursorVisibility visibility)
+		{
+			visibility = CursorVisibility.Invisible;
+
+			if (!currentCursorVisibility.HasValue)
+				return false;
+
+			visibility = currentCursorVisibility.Value;
+
+			return true;
+		}
+
+		/// <inheritdoc/>
+		public override bool SetCursorVisibility (CursorVisibility visibility)
+		{
+			if (initialCursorVisibility.HasValue == false) 
+				return false;
+
+			Curses.curs_set (((int) visibility >> 16) & 0x000000FF);
+
+			if (visibility != CursorVisibility.Invisible) {
+				Console.Out.Write ("\x1b[{0} q", ((int) visibility >> 24) & 0xFF);
+				Console.Out.Flush ();
+			}
+
+			currentCursorVisibility = visibility;
+
+			return true;
+		}
+
+		/// <inheritdoc/>
+		public override bool EnsureCursorVisibility ()
+		{
+			return false;
+		}
 	}
 
 	internal static class Platform {

+ 4 - 0
Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs

@@ -250,6 +250,7 @@ namespace Unix.Terminal {
 		//static public int wredrawwin (IntPtr win, int beg_line, int num_lines) => methods.wredrawwin (win, beg_line, num_lines);
 		static public int wnoutrefresh (IntPtr win) => methods.wnoutrefresh (win);
 		static public int move (int line, int col) => methods.move (line, col);
+		static public int curs_set (int visibility) => methods.curs_set (visibility);
 		//static public int addch (int ch) => methods.addch (ch);
 		static public int addwstr (string s) => methods.addwstr (s);
 		static public int wmove (IntPtr win, int line, int col) => methods.wmove (win, line, col);
@@ -310,6 +311,7 @@ namespace Unix.Terminal {
 		//public delegate int wredrawwin (IntPtr win, int beg_line, int num_lines);
 		public delegate int wnoutrefresh (IntPtr win);
 		public delegate int move (int line, int col);
+		public delegate int curs_set (int visibility);
 		public delegate int addch (int ch);
 		public delegate int addwstr([MarshalAs(UnmanagedType.LPWStr)]string s);
 		public delegate int wmove (IntPtr win, int line, int col);
@@ -369,6 +371,7 @@ namespace Unix.Terminal {
 		//public readonly Delegates.wredrawwin wredrawwin;
 		public readonly Delegates.wnoutrefresh wnoutrefresh;
 		public readonly Delegates.move move;
+		public readonly Delegates.curs_set curs_set;
 		public readonly Delegates.addch addch;
 		public readonly Delegates.addwstr addwstr;
 		public readonly Delegates.wmove wmove;
@@ -430,6 +433,7 @@ namespace Unix.Terminal {
 			//wredrawwin = lib.GetNativeMethodDelegate<Delegates.wredrawwin> ("wredrawwin");
 			wnoutrefresh = lib.GetNativeMethodDelegate<Delegates.wnoutrefresh> ("wnoutrefresh");
 			move = lib.GetNativeMethodDelegate<Delegates.move> ("move");
+			curs_set = lib.GetNativeMethodDelegate<Delegates.curs_set> ("curs_set");
 			addch = lib.GetNativeMethodDelegate<Delegates.addch>("addch");
 			addwstr = lib.GetNativeMethodDelegate<Delegates.addwstr> ("addwstr");
 			wmove = lib.GetNativeMethodDelegate<Delegates.wmove> ("wmove");

+ 21 - 0
Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs

@@ -417,6 +417,27 @@ namespace Terminal.Gui {
 		public override void UncookMouse ()
 		{
 		}
+
+		/// <inheritdoc/>
+		public override bool GetCursorVisibility (out CursorVisibility visibility)
+		{
+			visibility = CursorVisibility.Default;
+
+			return false;
+		}
+
+		/// <inheritdoc/>
+		public override bool SetCursorVisibility (CursorVisibility visibility)
+		{
+			return false;
+		}
+
+		/// <inheritdoc/>
+		public override bool EnsureCursorVisibility ()
+		{
+			return false;
+		}
+
 		#endregion
 #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
 	}

+ 20 - 0
Terminal.Gui/ConsoleDrivers/NetDriver.cs

@@ -1712,6 +1712,26 @@ namespace Terminal.Gui {
 		public override void UncookMouse ()
 		{
 		}
+
+		/// <inheritdoc/>
+		public override bool GetCursorVisibility (out CursorVisibility visibility)
+		{
+			visibility = CursorVisibility.Default;
+
+			return false;
+		}
+
+		/// <inheritdoc/>
+		public override bool SetCursorVisibility (CursorVisibility visibility)
+		{
+			return false;
+		}
+
+		/// <inheritdoc/>
+		public override bool EnsureCursorVisibility ()
+		{
+			return false;
+		}
 		#endregion
 
 		//

+ 115 - 0
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -41,6 +41,9 @@ namespace Terminal.Gui {
 		internal IntPtr InputHandle, OutputHandle;
 		IntPtr ScreenBuffer;
 		uint originalConsoleMode;
+		CursorVisibility? initialCursorVisibility = null;
+		CursorVisibility? currentCursorVisibility = null;
+		CursorVisibility? pendingCursorVisibility = null;
 
 		public WindowsConsole ()
 		{
@@ -82,6 +85,10 @@ namespace Terminal.Gui {
 				}
 			}
 
+			if (!initialCursorVisibility.HasValue && GetCursorVisibility (out CursorVisibility visibility)) {
+				initialCursorVisibility = visibility;
+			}
+
 			if (!SetConsoleActiveScreenBuffer (ScreenBuffer)) {
 				var err = Marshal.GetLastWin32Error ();
 				if (HeightAsBuffer) {
@@ -100,8 +107,83 @@ namespace Terminal.Gui {
 			return SetConsoleCursorPosition (ScreenBuffer, position);
 		}
 
+		public void SetInitialCursorVisibility ()
+		{
+			if (initialCursorVisibility.HasValue == false && GetCursorVisibility (out CursorVisibility visibility)) {
+				initialCursorVisibility = visibility;
+			}
+		}
+
+		public bool GetCursorVisibility (out CursorVisibility visibility)
+		{
+			if (!GetConsoleCursorInfo (ScreenBuffer, out ConsoleCursorInfo info)) {
+				var err = Marshal.GetLastWin32Error ();
+				if (err != 0) {
+					throw new System.ComponentModel.Win32Exception (err);
+				}				
+				visibility = Gui.CursorVisibility.Default;
+
+				return false;
+			}
+
+			if (!info.bVisible)        
+				visibility = CursorVisibility.Invisible;
+			else if (info.dwSize > 50) 
+				visibility = CursorVisibility.Box;
+			else                       
+				visibility = CursorVisibility.Underline;
+
+			return true;
+		}
+
+		public bool EnsureCursorVisibility () 
+		{
+			if (initialCursorVisibility.HasValue && pendingCursorVisibility.HasValue && SetCursorVisibility (pendingCursorVisibility.Value)) {
+				pendingCursorVisibility = null;
+
+				return true;
+			}
+
+			return false;
+		}
+
+		public void ForceRefreshCursorVisibility ()
+		{
+			if (currentCursorVisibility.HasValue) {
+				pendingCursorVisibility = currentCursorVisibility;
+				currentCursorVisibility = null;
+			}
+		}
+
+		public bool SetCursorVisibility (CursorVisibility visibility)
+		{
+			if (initialCursorVisibility.HasValue == false) {
+				pendingCursorVisibility = visibility;
+
+				return false;
+			}
+
+			if (currentCursorVisibility.HasValue == false || currentCursorVisibility.Value != visibility) {
+				ConsoleCursorInfo info = new ConsoleCursorInfo {
+					dwSize   =  (uint) visibility & 0x00FF,
+					bVisible = ((uint) visibility & 0xFF00) != 0
+				};
+
+				if (!SetConsoleCursorInfo (ScreenBuffer, ref info)) 
+					return false;
+
+				currentCursorVisibility = visibility;
+			}
+
+			return true;
+		}
+
 		public void Cleanup ()
 		{
+			if (initialCursorVisibility.HasValue) {
+				SetCursorVisibility (initialCursorVisibility.Value);
+			}
+
 			ConsoleMode = originalConsoleMode;
 			//ContinueListeningForConsoleEvents = false;
 			if (!SetConsoleActiveScreenBuffer (OutputHandle)) {
@@ -414,6 +496,18 @@ namespace Terminal.Gui {
 		[DllImport ("kernel32.dll")]
 		static extern bool SetConsoleCursorPosition (IntPtr hConsoleOutput, Coord dwCursorPosition);
 
+		[StructLayout (LayoutKind.Sequential)]
+		public struct ConsoleCursorInfo {
+			public uint dwSize;
+			public bool bVisible;
+		}
+
+		[DllImport ("kernel32.dll", SetLastError = true)]
+		static extern bool SetConsoleCursorInfo (IntPtr hConsoleOutput, [In] ref ConsoleCursorInfo lpConsoleCursorInfo);
+
+		[DllImport ("kernel32.dll", SetLastError = true)]
+		static extern bool GetConsoleCursorInfo (IntPtr hConsoleOutput, out ConsoleCursorInfo lpConsoleCursorInfo);
+
 		[DllImport ("kernel32.dll")]
 		static extern bool GetConsoleMode (IntPtr hConsoleHandle, out uint lpMode);
 
@@ -1219,6 +1313,7 @@ namespace Terminal.Gui {
 				Bottom = (short)Rows,
 				Right = (short)Cols
 			};
+			winConsole.ForceRefreshCursorVisibility ();
 		}
 
 		void UpdateOffScreen ()
@@ -1299,6 +1394,8 @@ namespace Terminal.Gui {
 		public override void Refresh ()
 		{
 			UpdateScreen ();
+
+			winConsole.SetInitialCursorVisibility ();
 #if false
 			var bufferCoords = new WindowsConsole.Coord (){
 				X = (short)Clip.Width,
@@ -1359,6 +1456,24 @@ namespace Terminal.Gui {
 			return currentAttribute;
 		}
 
+		/// <inheritdoc/>
+		public override bool GetCursorVisibility (out CursorVisibility visibility)
+		{
+			return winConsole.GetCursorVisibility (out visibility);
+		}
+
+		/// <inheritdoc/>
+		public override bool SetCursorVisibility (CursorVisibility visibility)
+		{
+			return winConsole.SetCursorVisibility (visibility);
+		}
+
+		/// <inheritdoc/>
+		public override bool EnsureCursorVisibility ()
+		{
+			return winConsole.EnsureCursorVisibility ();
+		}
+
 		#region Unused
 		public override void SetColors (ConsoleColor foreground, ConsoleColor background)
 		{

+ 4 - 0
Terminal.Gui/Core/Application.cs

@@ -617,6 +617,10 @@ namespace Terminal.Gui {
 
 					MainLoop.MainIteration ();
 					Iteration?.Invoke ();
+					
+					if (Driver.EnsureCursorVisibility ()) {
+						state.Toplevel.SetNeedsDisplay ();
+					}
 				} else if (!wait) {
 					return;
 				}

+ 78 - 0
Terminal.Gui/Core/ConsoleDriver.cs

@@ -476,6 +476,64 @@ namespace Terminal.Gui {
 		public static Dictionary<string, ColorScheme> ColorSchemes { get; }
 	}
 
+	/// <summary>
+	/// Cursors Visibility that are displayed
+	/// </summary>
+	// 
+	// Hexa value are set as 0xAABBCCDD where :
+	//
+	//     AA stand for the TERMINFO DECSUSR parameter value to be used under Linux & MacOS
+	//     BB stand for the NCurses curs_set parameter value to be used under Linux & MacOS
+	//     CC stand for the CONSOLE_CURSOR_INFO.bVisible parameter value to be used under Windows
+	//     DD stand for the CONSOLE_CURSOR_INFO.dwSize parameter value to be used under Windows
+	//
+	public enum CursorVisibility {
+		/// <summary>
+		///	Cursor caret has default
+		/// </summary>
+		/// <remarks>Works under Xterm-like terminal otherwise this is equivalent to <see ref="Underscore"/>. This default directly depends of the XTerm user configuration settings so it could be Block, I-Beam, Underline with possible blinking.</remarks>
+		Default = 0x00010119,
+
+		/// <summary>
+		///	Cursor caret is hidden
+		/// </summary>
+		Invisible = 0x03000019,
+
+		/// <summary>
+		///	Cursor caret is normally shown as a blinking underline bar _
+		/// </summary>
+		Underline = 0x03010119,
+
+		/// <summary>
+		///	Cursor caret is normally shown as a underline bar _
+		/// </summary>
+		/// <remarks>Under Windows, this is equivalent to <see ref="UnderscoreBlinking"/></remarks>
+		UnderlineFix = 0x04010119,
+
+		/// <summary>
+		///	Cursor caret is displayed a blinking vertical bar |
+		/// </summary>
+		/// <remarks>Works under Xterm-like terminal otherwise this is equivalent to <see ref="Underscore"/></remarks>
+		Vertical = 0x05010119,
+
+		/// <summary>
+		///	Cursor caret is displayed a blinking vertical bar |
+		/// </summary>
+		/// <remarks>Works under Xterm-like terminal otherwise this is equivalent to <see ref="Underscore"/></remarks>
+		VerticalFix = 0x06010119,
+
+		/// <summary>
+		///	Cursor caret is displayed as a blinking block ▉
+		/// </summary>
+		Box = 0x01020164,
+
+		/// <summary>
+		///	Cursor caret is displayed a block ▉
+		/// </summary>
+		/// <remarks>Works under Xterm-like terminal otherwise this is equivalent to <see ref="Block"/></remarks>
+		BoxFix = 0x02020164,
+	}
+
 	///// <summary>
 	///// Special characters that can be drawn with 
 	///// </summary>
@@ -628,6 +686,26 @@ namespace Terminal.Gui {
 		/// </summary>
 		public abstract void UpdateCursor ();
 
+		/// <summary>
+		/// Retreive the cursor caret visibility
+		/// </summary>
+		/// <param name="visibility">The current <see cref="CursorVisibility"/></param>
+		/// <returns>true upon success</returns>
+		public abstract bool GetCursorVisibility (out CursorVisibility visibility);
+
+		/// <summary>
+		/// Change the cursor caret visibility
+		/// </summary>
+		/// <param name="visibility">The wished <see cref="CursorVisibility"/></param>
+		/// <returns>true upon success</returns>
+		public abstract bool SetCursorVisibility (CursorVisibility visibility);
+
+		/// <summary>
+		/// Ensure the cursor visibility
+		/// </summary>
+		/// <returns>true upon success</returns>
+		public abstract bool EnsureCursorVisibility ();
+
 		/// <summary>
 		/// Ends the execution of the console driver.
 		/// </summary>

+ 8 - 0
Terminal.Gui/Views/Button.cs

@@ -248,5 +248,13 @@ namespace Terminal.Gui {
 			}
 			base.PositionCursor ();
 		}
+
+		///<inheritdoc/>
+		public override bool OnEnter (View view)
+		{
+			Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
+
+			return base.OnEnter (view);
+		}
 	}
 }

+ 8 - 0
Terminal.Gui/Views/Checkbox.cs

@@ -159,5 +159,13 @@ namespace Terminal.Gui {
 
 			return true;
 		}
+
+		///<inheritdoc/>
+		public override bool OnEnter (View view)
+		{
+			Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
+
+			return base.OnEnter (view);
+		}
 	}
 }

+ 11 - 0
Terminal.Gui/Views/FrameView.cs

@@ -9,6 +9,7 @@
 //  - Does not support IEnumerable
 // Any udpates done here should probably be done in Window as well; TODO: Merge these classes
 
+using System.Linq;
 using NStack;
 
 namespace Terminal.Gui {
@@ -191,5 +192,15 @@ namespace Terminal.Gui {
 				base.TextAlignment = contentView.TextAlignment = value;
 			}
 		}
+
+		///<inheritdoc/>
+		public override bool OnEnter (View view)
+		{
+			if (Subviews.Count == 0 || !Subviews.Any (subview => subview.CanFocus)) {
+				Application.Driver?.SetCursorVisibility (CursorVisibility.Invisible);
+			}
+
+			return base.OnEnter (view);
+		}
 	}
 }

+ 17 - 0
Terminal.Gui/Views/HexView.cs

@@ -395,5 +395,22 @@ namespace Terminal.Gui {
 			}
 			edits = new SortedDictionary<long, byte> ();
 		}
+
+		private CursorVisibility desiredCursorVisibility = CursorVisibility.Default;
+
+		/// <summary>
+		/// Get / Set the wished cursor when the field is focused
+		/// </summary>
+		public CursorVisibility DesiredCursorVisibility 
+		{ 
+			get => desiredCursorVisibility; 
+			set {
+				if (desiredCursorVisibility != value && HasFocus) {
+					Application.Driver.SetCursorVisibility (value);		
+				}
+
+				desiredCursorVisibility = value;
+			}
+		}
 	}
 }

+ 8 - 0
Terminal.Gui/Views/Label.cs

@@ -96,5 +96,13 @@ namespace Terminal.Gui {
 			}
 			return false;
 		}
+
+		///<inheritdoc/>
+		public override bool OnEnter (View view)
+		{
+			Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
+
+			return base.OnEnter (view);
+		}
 	}
 }

+ 2 - 0
Terminal.Gui/Views/ListView.cs

@@ -657,6 +657,8 @@ namespace Terminal.Gui {
 		///<inheritdoc/>
 		public override bool OnEnter (View view)
 		{
+			Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
+
 			if (lastSelectedItem == -1) {
 				EnsuresVisibilitySelectedItem ();
 				OnSelectedChanged ();

+ 16 - 1
Terminal.Gui/Views/Menu.cs

@@ -749,6 +749,14 @@ namespace Terminal.Gui {
 
 			return pos;
 		}
+
+		///<inheritdoc/>
+		public override bool OnEnter (View view)
+		{
+			Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
+
+			return base.OnEnter (view);
+		}
 	}
 
 
@@ -1621,6 +1629,13 @@ namespace Terminal.Gui {
 
 			return true;
 		}
-	}
 
+		///<inheritdoc/>
+		public override bool OnEnter (View view)
+		{
+			Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
+
+			return base.OnEnter (view);
+		}
+	}
 }

+ 8 - 0
Terminal.Gui/Views/ProgressBar.cs

@@ -102,5 +102,13 @@ namespace Terminal.Gui {
 					Driver.AddRune (' ');
 			}
 		}
+
+		///<inheritdoc/>
+		public override bool OnEnter (View view)
+		{
+			Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
+
+			return base.OnEnter (view);
+		}
 	}
 }

+ 8 - 0
Terminal.Gui/Views/RadioGroup.cs

@@ -355,6 +355,14 @@ namespace Terminal.Gui {
 			}
 			return true;
 		}
+
+		///<inheritdoc/>
+		public override bool OnEnter (View view)
+		{
+			Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
+
+			return base.OnEnter (view);
+		}
 	}
 
 	/// <summary>

+ 8 - 0
Terminal.Gui/Views/ScrollBarView.cs

@@ -658,5 +658,13 @@ namespace Terminal.Gui {
 				(KeepContentAlwaysInViewport ? Host.Bounds.Height + (showBothScrollIndicator ? -2 : -1) : 0) :
 				(KeepContentAlwaysInViewport ? Host.Bounds.Width + (showBothScrollIndicator ? -2 : -1) : 0);
 		}
+
+		///<inheritdoc/>
+		public override bool OnEnter (View view)
+		{
+			Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
+
+			return base.OnEnter (view);
+		}
 	}
 }

+ 11 - 0
Terminal.Gui/Views/ScrollView.cs

@@ -12,6 +12,7 @@
 // - Perhaps allow an option to not display the scrollbar arrow indicators?
 
 using System;
+using System.Linq;
 using System.Reflection;
 
 namespace Terminal.Gui {
@@ -522,5 +523,15 @@ namespace Terminal.Gui {
 			}
 			base.Dispose (disposing);
 		}
+
+		///<inheritdoc/>
+		public override bool OnEnter (View view)
+		{
+			if (Subviews.Count == 0 || !Subviews.Any (subview => subview.CanFocus)) {
+				Application.Driver?.SetCursorVisibility (CursorVisibility.Invisible);
+			}
+
+			return base.OnEnter (view);
+		}
 	}
 }

+ 8 - 0
Terminal.Gui/Views/StatusBar.cs

@@ -215,5 +215,13 @@ namespace Terminal.Gui {
 				disposedValue = true;
 			}
 		}
+
+		///<inheritdoc/>
+		public override bool OnEnter (View view)
+		{
+			Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
+
+			return base.OnEnter (view);
+		}
 	}
 }

+ 25 - 0
Terminal.Gui/Views/TextField.cs

@@ -866,6 +866,31 @@ namespace Terminal.Gui {
 			TextChanging?.Invoke (ev);
 			return ev;
 		}
+
+		private CursorVisibility desiredCursorVisibility = CursorVisibility.Default;
+
+		/// <summary>
+		/// Get / Set the wished cursor when the field is focused
+		/// </summary>
+		public CursorVisibility DesiredCursorVisibility 
+		{ 
+			get => desiredCursorVisibility; 
+			set {
+				if (desiredCursorVisibility != value && HasFocus) {
+					Application.Driver.SetCursorVisibility (value);		
+				}
+
+				desiredCursorVisibility = value;
+			}
+		}
+
+		///<inheritdoc/>
+		public override bool OnEnter (View view)
+		{
+			Application.Driver.SetCursorVisibility (DesiredCursorVisibility);
+
+			return base.OnEnter (view);
+		}
 	}
 
 	/// <summary>

+ 26 - 0
Terminal.Gui/Views/TextView.cs

@@ -598,6 +598,32 @@ namespace Terminal.Gui {
 			}
 		}
 
+		private CursorVisibility desiredCursorVisibility = CursorVisibility.Default;
+
+		/// <summary>
+		/// Get / Set the wished cursor when the field is focused
+		/// </summary>
+		public CursorVisibility DesiredCursorVisibility 
+		{ 
+			get => desiredCursorVisibility; 
+			set {
+				if (desiredCursorVisibility != value && HasFocus) {
+					Application.Driver.SetCursorVisibility (value);		
+				}
+
+				desiredCursorVisibility = value;
+			}
+		}
+
+		///<inheritdoc/>
+		public override bool OnEnter (View view)
+		{
+			//TODO: Improve it by handling read only mode of the text field
+			Application.Driver.SetCursorVisibility (DesiredCursorVisibility);
+
+			return base.OnEnter (view);
+		}
+
 		// Returns an encoded region start..end (top 32 bits are the row, low32 the column)
 		void GetEncodedRegionBounds (out long start, out long end)
 		{

+ 8 - 0
Terminal.Gui/Windows/FileDialog.cs

@@ -465,6 +465,14 @@ namespace Terminal.Gui {
 				}
 			}
 		}
+
+		///<inheritdoc/>
+		public override bool OnEnter (View view)
+		{
+			Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
+
+			return base.OnEnter (view);
+		}
 	}
 
 	/// <summary>

+ 19 - 1
UICatalog/Scenarios/Editor.cs

@@ -36,7 +36,20 @@ namespace UICatalog {
 					new MenuItem ("C_ut", "", () => Cut()),
 					new MenuItem ("_Paste", "", () => Paste())
 				}),
-				new MenuBarItem ("_ScrollBarView", CreateKeepChecked ())
+				new MenuBarItem ("_ScrollBarView", CreateKeepChecked ()),
+				new MenuBarItem ("_Cursor", new MenuItem [] {
+					new MenuItem ("_Invisible", "", () => SetCursor(CursorVisibility.Invisible)),
+					new MenuItem ("_Box", "", () => SetCursor(CursorVisibility.Box)),
+					new MenuItem ("_Underline", "", () => SetCursor(CursorVisibility.Underline)),
+					new MenuItem ("", "", () => {}, () => { return false; }),
+					new MenuItem ("xTerm :", "", () => {}, () => { return false; }),
+					new MenuItem ("", "", () => {}, () => { return false; }),
+					new MenuItem ("  _Default", "", () => SetCursor(CursorVisibility.Default)),
+					new MenuItem ("  _Vertical", "", () => SetCursor(CursorVisibility.Vertical)),
+					new MenuItem ("  V_ertical Fix", "", () => SetCursor(CursorVisibility.VerticalFix)),
+					new MenuItem ("  B_ox Fix", "", () => SetCursor(CursorVisibility.BoxFix)),
+					new MenuItem ("  U_nderline Fix","", () => SetCursor(CursorVisibility.UnderlineFix))
+				})
 			});
 			Top.Add (menu);
 
@@ -141,6 +154,11 @@ namespace UICatalog {
 			//}
 		}
 
+		private void SetCursor (CursorVisibility visibility)
+		{
+			_textView.DesiredCursorVisibility = visibility;
+		}
+
 		private void Open ()
 		{
 			var d = new OpenDialog ("Open", "Open a file") { AllowsMultipleSelection = false };