The Consoul API
This documentation refers to version 01.02.05 of the library.
Consoul is a (win32, 32 & 64 bits) code control contained in a Windows DLL. To display the text that is output to a Consoul control, Consoul creates a child window, the console window, inside an already existing window.
API functions are documented here by presenting their VBA (Microsoft Visual Basic for Application) declarations. VBA is the (single threaded) programming language found in Microsoft Office applications like Access, Excel and Word.
Consoul being a standard Windows DLL (one for x86 and one for x64), it can be used by compiled or interpreted languages that have the ability to interface with a dynamic library like C, C++, AutoIT, TwinBasic, RAD Basic, Xojo, WinDEV, C# etc... The VBA declarations should be hopefully comprehensive enough to infer their usage in those other languages.
Consoul is able to output text using the full Unicode character set of the font (that is specified at creation time).
Consoul relies on the
DrawText Win32 API function to render text blocks.
The available color range for the background and the text of each character is the full RGB spectrum as color values are 32 bits integers.
Consoul supports an nice subset of the VT100 escape codes that allows to change font attributes like bold, underline, italic and strikethru (or crossedout), on the fly. This makes it possible to display, and even animate, beautiful ASCII art pictures.
Text & blocks
Consoul splits the text that is output into the console into two types of blocks:
Control blocks are characters that form a valid vt100 escape sequence.
Text blocks are characters that are not part of an escape sequence.
This is something that should be cared about when using non proportional fonts with console windowx, as Consoul will assume in all cases that each character takes up exactly the same amount of horizontal space for features like cursor positioning and functions like CSGetMaxVisibleCols.
However, once Consoul has split the text that has to be output in text blocks and control blocks, it will render them sequentially. That's why outputting a control block with an escape sequence that enables a forecolor influences the next blocks that are output.
Text blocks are rendered as one piece, using the Win32
DrawText API function.
To output a text block, Consoul needs a rectangle. At the beginning of the line, the rectangle takes the full line width and the height is given by the CSGetLineHeight function.
Once Consoul has output a text block, it advances the left position of the drawing rectangle at the end of the text that was output, ready for the next text output on the same line, and so on.
The left position of the drawing rectangle can be moved forwards or backwards with
VT100_ADVANCEABS control blocks escape sequences.
VT100X_SAVEGPOS escape sequence temporarly saves the current left position of the drawing rectangle; the position can be reached again later with the
VT100X_RESTOREGPOS escape sequence.
The width of the drawing rectangle always extends to the end of the visible portion of the line, but can be constrained by outputting a control block with a
VT100X_SETWIDTH before the text block.
By default, Consoul assumes that the height of a line is the height given by the CSGetCharHeight function. This height can be modified using the CSSetLineSpacing function, which can add additional height on the top or the bottom of the CSGetCharHeight height.
When drawing a line Consoul clips the graphical output to the drawing rectangle and draws the textblock in it. The text is normally output at the vertical position that is the top of the drawing rectangle, plus the top line spacing. To move the text up or down this position, use the CSSetLinePadding function. The unit is pixels.
This schema summarizes the situation:
- When padding is added to the top, text is pushed down.
- When padding is added to the bottom, the text rectangle shrinks.
- When spacing is added to the top, the text is pushed down.
- When spacing is added to the bottom, space is added after the text and padding, the next line will begin farther.
Negative spacing and padding can also be used. Try it or download AsciiPaint to test these variables live and visually.
Internal output buffer queue
Each console window created by Consoul has its own set of properties and its output buffer queue. The handle of the console window that Consoul creates (returned by CSCreateLogWindow) is used as a key to identify on which properties and buffer queue each of the API function (except CSCreateLogWindow) operates.
The output buffer is a queue of text lines that are added to a console window with the CSPushLine API function. The size of the queue (or the number of lines that a queue can hold) is specified at creation time and cannot be changed after.
When a text line is pushed in the console and the buffer is full, Consoul rotates the queue, popping out the oldest one (first in, first out).
Each line pushed in a console window buffer queue can be referenced by its position in the queue (the line number), which is valid between 1 and CSLineCount. CSPushLine returns this position after each call, so when the queue buffer rotates because its full, CSPushLine will return 1 again, then 2, and so on.
The vertical scrollbar in a console window is automatically shown when the number of lines in the queue exceeds the maximum number of visible rows.
CSGetMaxVisibleRows and CSGetMaxVisibleCols give the number of rows, respectively the number of columns, that the console window can display, based on its actual size. The values are computed by both functions at each call with the assumption that a fixed width font name has been used to create the console window (the font name and font size cannot be changed after creation). Note that the number of visible lines that a console queue actually holds can be smaller than the number of currently visible rows.
With an original concept of zones, Consoul helps to easily setup some interesting interaction, like clickable links, within the output text.
To help the host to implement its own keyboard handling logic, and display back some interaction visual cues, Consoul can show a caret (or cursor). Consoul carets are not Windows API carets, only the Consoul API can manipulate them. There is one caret per console window and It is the responsibility of the host to position the caret. By default, the caret is hidden. It can be shown with the CSShowCaret API function. The default caret is a blinking square that is drawn at the current caret position as an inverted rectangle. When the caret is visible, a timer of 500 milliseconds interval is used to make it blink. The timer interval can be changed with the CSSetCaretBlinkMs API function; setting it to zero stops the blinking effect but leaves the caret visible. The width of the caret rectangle can also be changed with the CSSetCaretWidth API function.
So, with some tweaking done in the host's code (keyboard handling, caret size and blinking), the caret can be used for various purposes. One example of tweaking the caret properties would be to simulate a selection rectangle and make the target console window resemble and act like a listbox.
Consoul has a callback mechanism for the mouse events listed in the CSSetOnMouseButtonCallback API function documentation.
The messages and callback page holds a more detailed section about mouse input.
A traditional mouse event information carries information like the position of the mouse (x, y) and flags about the mouse button that generated the event (left, middle, right, etc.). Consoul adds valuable information like the row and the column, and the ID of the zone at the mouse position. When multiple zone overlap at the event position, Consoul does not by default call back as many times as there are touched zones (and at least one time if there are no zones at the event position). This default behavior can be changed with CSSetMultiZoneClick; when set to False (the default), Consoul will call back only one time to signal the event only for the nearest zone intersecting with the mouse cursor position.
Consoul does not implement a full blown console window like the command prompt we have in Windows. For instance, there is no Keyboard input handling done in the library, although the host can still handle the keyboard itself. This can be done in VB/A by setting the host Form's
KeyPreview property to
True and handling keyboard input as wished in the
Form_Keydown event handler, or by trapping the
KeyDown event of a textbox (and setting
KeyCode to zero) that the Consoul window covers.
Host tab order
VB/A environments (as maybe others) are not aware of the windows created by Consoul, as they are windows created at runtime which existence the host doesn't know of. The tab order defined at design time is not influenced by Consoul windows. This should not be a problem, unless you want to somehow control the flow or tab order of the controls on a Form, including Consoul's windows (they're not "tab reachable").
Parameters and return types
The following type identifiers, and their corresponding bit size and VB/A variable type name, are used in this API documentation.
|Type name||32 bits||64 bits||VB/A|
|Integer||32 bits integer||64 bits integer||Long (32bits) or
LongPtr/LongLong (32 and 64 bits VB7)
|Long||32 bits integer||32 bits integer||Long|
|Word||16 bits integer||16 bits integer||Integer|
|String||32 bits pointer||64 bits pointer||StrPtr(string variable)
Long (32bits) or LongPtr (32 and 64 bits VB7)
Consoul is not multi-threading safe at this time.
Integrating Consoul in VB/A is a dangerous game mainly because the edit and continue feature of VBA environments do scramble compiled stuff in the background.
Please save often, particularly before running your application or when you modify code while running that will force the host to recompile your VBA code, like changing the value of a global constant. Or when you modify the signature of a function in the VBE editor; the host (Access or any) recompiles the module on the fly, thus potentially changing the address of a function that was passed to Consoul, leading to a host crash if Consoul calls back on the old function address.
Also, stopping execution on a breakpoint in the VBE editor, then returning to the application UI and interacting with the Consoul window can lead to a crash as Consoul will still be running and try to callback a stopped host that is unable to serve the callback request.