// // AnsiWinTerm.cpp // // Source code from: // // Serial Communications: A C++ Developer's Guide, 2nd Edition // by Mark Nelson, M&T Books, 1999 // // Please see the book for information on usage. // // This file contains the implementation for much of class // AnsiWinTerm, the glue class that holds together all the // pieces needed to create a Win32 terminal emulator. This // class is used in the example program for Chapter 13. // #include "AnsiWinTerm.h" // // Class AnsiWinTerm is derived from Win32Term, which provides // basic support for fixed width colored characters on a screen. // Most of what we need in terms of window message processing // is done by that class, but there are a few messages that we // need to intercept and handle ourselves. We do that by // overriding the Dispatch() member of that class, giving us // first crack at all the messages. Note that at the bottom of // this routine, if we haven't handled the message, we gladly // pass it on to Win32Term::Dispatch(). If it has anything to // do with painting, scrolling, or sizing, that is undoubtedly // where it needs to be handled. // LRESULT AnsiWinTerm::Dispatch( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch( uMsg ) { // // There are two types of keyboard messages // in Windows. Normal ASCII keys are sent in // via WM_CHAR, but extended/function keys // arrive via WM_KEYDOWN. We have to do some // interpretation here to convert windows // scan codes into key codes that the terminal // emulation classes know how to deal with. // // This handling of incoming keys is a bit // incomplete, I don't do anything in response // to control or shift keys in combination with // function keys. Implementing complete support // for all possible states isn't particularly // hard, but the listing would be quite long. // // When we do finally figure out what key has // been pressed, and converted it to a value // that the emulation classes understand, we // have to call the WriteKey() member of the // AnsiTerminal class. It takes care of all the // processing and translation needed. // case WM_KEYDOWN : { int key; switch (wParam ) { case VK_UP : key = UP; break; case VK_DOWN : key = DOWN; break; case VK_LEFT : key = LEFT; break; case VK_RIGHT : key = RIGHT; break; case VK_PRIOR : key = PGUP; break; case VK_NEXT : key = PGDN; break; case VK_END : key = END; break; case VK_HOME : key = HOME; break; default : return -1; } bool control = ( GetKeyState( VK_CONTROL ) & ~1 ) != 0; bool shift = ( GetKeyState( VK_SHIFT )& ~1 ) != 0; int count = lParam & 0xffff; if ( m_pTerminal ) for ( int i = 0 ; i < count ; i++ ) m_pTerminal->WriteKey( key ); } break; // // WM_CHAR has the same responsibilties as WM_KEYDOWN, // but no translation is necessary, the ASCII value // passed in here is just what we expect it to be. // case WM_CHAR: if ( m_pTerminal ) m_pTerminal->WriteKey( (char) wParam ); break; // // When we get notification that RX characters have // arrived, we simply read in as many as we can and // send them off to the emulator object via the // member function Display() // case WM_SERIAL_RX_NOTIFY : { for ( ; ; ) { int c = m_pTerminal->ReadPort(); if ( c >= 0 ) m_pTerminal->Display( c ); else break; } } break; // // Any message that we didn't handle gets routed up // to our base class, Win32Term. It is responsible for // painting the window, handling scroll bars, etc. // default: return Win32Term::Dispatch( hWnd, uMsg, wParam, lParam ); } return 0L; } // // The owner of this object is usually going to // be the main window of an emulation program. Instead of // letting the main window own the RS232 port, we pull it // into this class. We don't let the outside world manipulate // the port directly, so if anyone wants to open it or close // it they have to go through member functions of this class. // // This open function is a little anemic, I don't have any // options for baud rate, parity, etc. They could easialy be // added one by one to the list of arguments, then passed // directly to the call to create the Win32Port object. // // If we are successful when it comes to opening the port, // we also create the emulation object, which will handle // all of the incoming characters from the port. // bool AnsiWinTerm::OpenPort( const string &name ) { m_pPort = new MyWin32Port( name, m_hWnd ); if ( m_pPort->ErrorStatus() < 0 ) { ::MessageBox( m_hWnd, m_pPort->ErrorName( m_pPort->ErrorStatus() ), "Error opening COM Port", MB_OK ); delete m_pPort; m_pPort = 0; return false; } m_pTerminal = new AnsiTerminal( *m_pPort, *this ); return true; } // // Closing the port translates into destroying two // objects: the terminal emulator and the port itself. // void AnsiWinTerm::ClosePort() { delete m_pTerminal; m_pTerminal = 0; delete m_pPort; m_pPort = 0; } // // These two static arrays provide the translation // from the display attribute values to RGB values needed // by Win32Term. Note that this emulator skips out on // some of the more difficult attributes, such as blinking. // These are the simple colors used in the original EGA // display and supported by the ANSI.SYS driver from // MS-DOS. // const COLORREF AnsiWinTerm::ForegroundPalette[ 16 ] = { RGB( 0, 0, 0 ), // Black RGB( 128, 0, 0 ), // Red RGB( 0, 128, 0 ), // Green RGB( 128, 128, 0 ), // Yellow RGB( 0, 0, 128 ), // Blue RGB( 128, 0, 128 ), // Magenta RGB( 0, 128, 128 ), // Cyan RGB( 210, 210, 210 ), // White RGB( 0, 0, 0 ), // Black RGB( 255, 0, 0 ), // Bold Red RGB( 0, 255, 0 ), // Bold Green RGB( 255, 255, 0 ), // Bold Yellow RGB( 0, 0, 255 ), // Bold Blue RGB( 255, 0, 255 ), // Bold Magenta RGB( 0, 255, 255 ), // Bold Cyan RGB( 255, 255, 255 ) // Bold White }; const COLORREF AnsiWinTerm::BackgroundPalette[ 8 ] = { RGB( 0, 0, 0 ), // Black RGB( 128, 0, 0 ), // Red RGB( 0, 128, 0 ), // Green RGB( 128, 128, 0 ), // Yellow RGB( 0, 0, 128 ), // Blue RGB( 128, 0, 128 ), // Magenta RGB( 0, 128, 128 ), // Cyan RGB( 255, 255, 255 ) // White }; //EOF AnsiWinTerm.cpp