Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should I create a custom graphical console/terminal on Windows?

The Windows console interface (think cmd window) is to the user a pretty simple GUI. The level of efficiency with which it handles rendering, user input, and scrolling is however very high. The methods used to create this interface are undoubtedly quite different to those of a traditional desktop GUI.

I am interested in creating my own custom console/terminal for Windows, preferably using C# and .NET-based technologies (e.g. managed GDI+ or WPF). As a starting point, I'd be quite keen simply to recreate the standard simple Windows shell. I could then expand things and add features from there.

I'm looking for general guidance on how to go about creating such a console UI, but some specific points include:

  • What sort of rendering model should I use? A render loop? Partial updates (like WPF)? The WinForms model (not sure how this works)?

  • What sort of caching is used in the rendering model?

  • How are fonts loaded and how are they rendered? Are they standard TrueType fonts, bitmap fonts, or something else?

  • How is scrolled performed so efficiently?

  • Anything else you think might be relevant!

Any explanation of how the inbuilt Windows console UI (or even the superior Linux terminal UI) do these things - and how I could emulate them - would be ideal, in fact.

Edit: To be clear, I really want to do this completely from scratch. Based on a graphical framework like GDI+ or WPF, but no more.

like image 396
Noldorin Avatar asked Feb 22 '12 15:02

Noldorin


People also ask

Is Windows Terminal the same as Command Prompt?

Windows Terminal is a modern host application for the command-line shells you already love, like Command Prompt, PowerShell, and bash (via Windows Subsystem for Linux (WSL)).


2 Answers

I once implemented a text output window from scratch - I wanted one that works like the Output window in Visual Studio. It turned out to be more complicated than I expected, and that was without any input capabilities.

Unfortunately the code is in C++ and belongs to a former employer, so I can't share it with you. But I can give you an idea of what to expect.

You need a way to store the lines of output that you can index quickly. If you're going to place a limit on the number of lines displayed it will also need to be easy to erase lines from the top. In C++ a deque<string> was perfect, I don't know what the equivalent is (if any) in C#.

You'll need handlers for the following Windows messages, in no particular order.

  • WM_LBUTTONDOWN - to start a selection. Use SetCapture to track the mouse while the button is down.
  • WM_LBUTTONUP - to end a selection.
  • WM_RBUTTONUP - translate into WM_CONTEXTMENU.
  • WM_CONTEXTMENU - to display a menu with Copy/Cut/Paste and whatever else you want.
  • WM_KEYDOWN - to respond to the 4 cursor keys, Home/End, PageUp/PageDown. Ctrl-A/Ctrl-C/Ctrl-X/Ctrl-V/Ctrl-D.
  • WM_PAINT - to paint the contents of the window.
  • WM_SIZE - to update the scrollbars when the window size changes.
  • WM_VSCROLL - to update the visible portion of the window during vertical scrolling.
  • WM_HSCROLL - to update the visible portion of the window during horizontal scrolling.
  • WM_CREATE - for initialization when the window is created.
  • WM_SETFOCUS - to create a system caret to show the current position in the window.
  • WM_KILLFOCUS - to kill the caret since only the currently focused window should show a caret.
  • WM_MOUSEMOVE - to track changes to the selection while the left mouse button is down.
  • WM_CAPTURECHANGED - to end a selection.
  • WM_TIMER - to auto-scroll when the cursor leaves the window during a selection.
  • WM_GETDLGCODE - to add DLGC_WANTARROWS so that the arrow keys will get through.
  • WM_MOUSEWHEEL - to respond to the mouse wheel for scrolling.

As lines are added to the text buffer, adjust the range of the scrollbars. The vertical scrollbar range will be the total number of lines, and the horizontal scrollbar range will be the width of the widest line.

It is best to have a single font which is monospaced - it makes the calculations a lot easier. The specific font technology doesn't matter so much. You just need to be able to track the positions of the characters.

How is scrolled performed so efficiently? You track the top and bottom lines of the window as it scrolls, and when a paint message comes you only paint the lines that are currently visible. The others are still in the buffer but they don't get touched. It's possible to blit the contents of the window as it scrolls and only paint the parts that come in from the top or bottom, but with today's processors it's a wasted effort - the window will do a full repaint so quickly that you won't notice.

Edit: Coincidentally I came across this Microsoft guide to scroll bars which should be essential reading for this task. http://msdn.microsoft.com/en-us/library/windows/desktop/bb787527.aspx

like image 171
Mark Ransom Avatar answered Sep 29 '22 01:09

Mark Ransom


If you want to create a beautiful .NET based command prompt replacement, then I suggest looking at http://poshconsole.codeplex.com/ It uses WPF for graphical elements and it implements a PowerShell script host. PowerShell is Microsoft's replacement for the venerable command prompt. PowerShell is installed by default with Windows 7, but you can download it for XP and Vista. PowerShell is highly extensible though scripting of using .NET objects directly. It can also be embedded in other programs.

WPF + PowerShell would be a great starting place for what you want to do. If you wanted you could then swap out PowerShell for your own command/scripting engine. If you were really ambitious you could take a whack at implementing your own scripting language on the DLR to act as your command interpreter.

Best of luck.

like image 39
Brad Campbell Avatar answered Sep 29 '22 01:09

Brad Campbell