Journal Articles
Browse in : |
All
> Journals
> CVu
> 114
(20)
|
Note: when you create a new publication type, the articles module will automatically use the templates user-display-[publicationtype].xt and user-summary-[publicationtype].xt. If those templates do not exist when you try to preview or display a new article, you'll get this warning :-) Please place your own templates in themes/yourtheme/modules/articles . The templates will get the extension .xt there.
Title: Handling the Windows Console
Author: Administrator
Date: 03 June 1999 13:15:31 +01:00 or Thu, 03 June 1999 13:15:31 +01:00
Summary:
Body:
When I first loaded Microsoft Visual C++ 5.0 onto my PC, I was rather shocked to discover that none of my old text mode programs would compile. The reason being that the int86() library call had disappeared completely and none of the simple screen handling these programs had inherited from their DOS roots would work. After several days of muttering under my breath about backward compatibility, I dug through the sample code and the header files and discovered that there is still a way to manipulate the DOS box, or console as we are encouraged to call it these days. The API is neither well-documented nor easy to use but at least it works.
The key to the console API is the header file wincon.h which contains the usual structure definitions and prototypes. Before you can do anything, you need to get handles for the console using GetStdHandle():
conOut = GetStdHandle(STD_OUTPUT_HANDLE); conIn = GetStdHandle(STD_INPUT_HANDLE);
Once you have the handles, it is a good idea to turn off various input options to prevent the console from echoing characters or waiting until the user hits the Enter key:
DWORD modeIn; GetConsoleMode( conIn, &modeIn ); modeIn = modeIn & ~(ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT); SetConsoleMode( conIn, modeIn );
After the console has been configured, you can write characters and attributes to the console using the functions WriteConsoleOutputCharacter() and WriteConsoleOutputAttribute() as the following code illustrates:
void ScrWriteString( int row, int col, char* text, WORD attr ) { COORD pos; pos.X = (SHORT)col; pos.Y = (SHORT)row; DWORD nChars; WriteConsoleOutputCharacter( conOut, text, strlen(text), pos, &nChars ); WORD* attrs = (WORD*)malloc( sizeof(WORD) * strlen(text) ); if ( attrs ) { for( size_t i=0; i<strlen(text); i++ ) attrs[i] = attr; WriteConsoleOutputAttribute( conOut, attrs, strlen(text), pos, &nChars ); free( attrs ); } return; }
As you can see, both functions take a start position encoded as a COORD structure and a length parameter to indicate how many characters or attributes to write. They also return the number of characters or attributes actually written. The most counterintuitive part of the process is that characters and attributes are treated separately which seems very strange to someone who is used to packing a character and an attribute into a 16-bit word. The attributes themselves consist of foreground and background colours ORed together so, for instance, FOREGROUND_RED|BACKGROUND_BLUE specifies red text on a blue background.
If you are used to programming in an event driven environment, console programming will feel strange because there is no message queue. You have to go and grab the events you want. The code to read keystrokes from the console looks something like this:
WORD ScrGetKey( WORD& key ) { INPUT_RECORD inputBuffer; DWORD nEvents; // Wait for the key to be released do { // Read input events until we get a key ReadConsoleInput( conIn, &inputBuffer, 1, &nEvents ); if ( inputBuffer.EventType == KEY_EVENT ) key = inputBuffer.Event.KeyEvent.wVirtualKeyCode; } while( !((inputBuffer.EventType == KEY_EVENT ) && (inputBuffer.Event.KeyEvent.bKeyDown == FALSE)) ); return( key ); }
The KeyEvent structure also returns information about the actual character read but this handled differently in Windows 95, which returns an 8-bit ASCII character, and Windows NT, which returns a Unicode character.
Because ReadConsoleInput() returns raw keyboard events, I find it best to catch keystrokes when the key is released (bKeyDown == FALSE) otherwise you can get a lot of spurious keystrokes if the user holds down a key. The keystrokes returned are the standard, Windows virtual key codes such as VK_ESCAPE and VK_LEFT.
ReadConsoleInput() can also be used to read mouse events and a number of window-related events but, if you need to use these, you would probably end up having to hand-code a complete message queue. At this point, you'd be better off writing a full-blown Windows application.
The cursor size and visibility can be set using a CONSOLE_CURSOR_INFO structure and the SetConsoleCursorInfo() function. The cursor position can be set using SetConsoleCursorPosition():
void ScrMove( int row, int col ) { COORD position; position.X = (SHORT)col; position.Y = (SHORT)row; SetConsoleCursorPosition( conOut, position ); return; }
There are also functions to set the console's title, to set a control-C handler, and even to set a code-page for the console.
As you can see, it is possible to manipulate the Windows console in much the same way as the old DOS screen; it's just that the interface has changed rather radically. At first this annoyed me but then I realised that it was probably a result of insulating the programmer from the hardware interrupts which is a sensible precaution given the complexity of the Windows environment.
Notes:
More fields may be available via dynamicdata ..