📄 ansiwinterm.cpp
字号:
//
// 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -