⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 win32term.cpp

📁 DOS下采用中断接收数据的串口通讯的例子,很难找到的好东西!
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
//  WIN32TERM.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 header file contains the implementation of
// class Win32Term. This class creates a window that
// can be used as part of a Win32 terminal emulator. 
//

#include "Win32Term.h"
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cstring>

//
// With Visual Studio 5.0 SP3, min and max
// quit working when used in conjunction with
// class vector<T>! This code ws required to
// fix the strange problem.
//
#undef max
#undef min

inline int max( int a, int b )
{
    if ( a > b )
        return a;
    else
        return b;
}

inline int min( int a, int b )
{
    if ( a < b )
        return a;
    else
        return b;
}

//
// Static variable to make sure I only 
// register this class with Windows once.
//
bool Win32Term::m_bClassRegistered = false;

//
// The constructor for a Win32 object has to
// pull double duty. It has to create all the
// data structures and so on that will be used
// in the class, then it has to create the 
// window as well. Once this is done, the window
// has been created, the message loop is running,
// and the whole thing is ready to use.
//
// Note that the number of rows and columns in
// the virtual screen is decided here in the 
// constructor, and can't be changed after the
// window is constructed. The values are stored
// in a const Pair, so no amount of coding is 
// going to let them be modified.
//
Win32Term::Win32Term( HWND hParent,
                      const char *window_name,
                      int rows, 
                      int cols ) : m_VirtualSize( cols, rows )
{
    //
    // This code sets the two dimensional arrays to the
    // correct size, and copies default data into 
    // every cell. Much less code here than the equivalent
    // that would be needed for standard C 2-D arrays.
    //
    m_ScreenText.resize( rows, vector<char>( cols ) );
    m_ScreenColor.resize( rows, vector<TextColor>( cols ) );
    m_hParent        = 0;
    m_hWnd           = 0;
    m_bShowingCursor = false;
    m_bWrap          = true;
    m_VisibleSize    = Pair( 0, 0 );
    m_ScrollRange    = Pair( 0, 0 );
    m_Position       = Pair( 0, rows - 1 );
    //
    // setup default font information
    // 
    m_lfFont.lfHeight =         12 ;
    m_lfFont.lfWidth =          0 ;
    m_lfFont.lfEscapement =     0 ;
    m_lfFont.lfOrientation =    0 ;
    m_lfFont.lfWeight =         0 ;
    m_lfFont.lfItalic =         0 ;
    m_lfFont.lfUnderline =      0 ;
    m_lfFont.lfStrikeOut =      0 ;
    m_lfFont.lfCharSet =        OEM_CHARSET ;
    m_lfFont.lfOutPrecision =   OUT_DEFAULT_PRECIS ;
    m_lfFont.lfClipPrecision =  CLIP_DEFAULT_PRECIS ;
    m_lfFont.lfQuality =        DEFAULT_QUALITY ;
    m_lfFont.lfPitchAndFamily = FIXED_PITCH | FF_MODERN ;
    strcpy( m_lfFont.lfFaceName, "FixedSys" ) ;
    SetFont( m_lfFont );
    SetForegroundColor( RGB( 0, 0, 0 ) );
    SetBackgroundColor( RGB( 255, 255, 255 ) );
    Clear();
    //
    // Now I create the actual window
    //
    if ( !m_bClassRegistered ) {
        WNDCLASS wc = { 0 };
        wc.lpfnWndProc      = WindowProc;
        wc.hInstance        = GetModuleHandle( NULL );
        wc.hCursor          = LoadCursor( NULL, IDC_IBEAM );
        wc.hbrBackground    = ::CreateSolidBrush( RGB( 255, 255, 255 ) );
        wc.lpszClassName    = "Win32TermClass";
        wc.lpszMenuName     = NULL;
        wc.hIcon            = NULL;
        wc.cbWndExtra       = sizeof( Win32Term * );
        RegisterClass( &wc );
        m_bClassRegistered  = true;
    }
    m_BorderColor = RGB( 255, 255, 255 );
    m_hParent = hParent;
    //
    // I have to pass a pointer to myself to the window
    // so that it can store the pointer in the window long
    // word. Data that is going to be passed to a 
    // WM_CREATE handler has to go in this funny structure.
    //
    CreateData data = { sizeof( Win32Term * ), 
                        this 
                      };
    CreateWindow( "Win32TermClass", 
                  window_name, 
                  WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL,
                  0,0,
                  0,0,
                  m_hParent, 
                  0, 
                  GetModuleHandle( NULL ), 
                  &data );
}

//
// If the user manages to pass me a good
// LOGFONT, this should all go fairly
// smoothly. The old font is deleted, the
// new one is created, we get some info
// about it, then we redo the screen size,
// offsets, scroll ranges, etc. Finally,
// we do an invalidate to force the whole
// thing to be redrawn.
//
void Win32Term::SetFont( LOGFONT LogFont )
{
    TEXTMETRIC tm;
    HDC  hDC;
    if ( m_hFont )
        DeleteObject( m_hFont );

    m_lfFont = LogFont;
    m_hFont = CreateFontIndirect( &m_lfFont );

    hDC = GetDC( m_hParent ) ;
    SelectObject( hDC, m_hFont ) ;
    GetTextMetrics( hDC, &tm ) ;
    ReleaseDC( m_hParent, hDC ) ;

    m_CharSize.x = tm.tmAveCharWidth;
    m_CharSize.y = tm.tmHeight + tm.tmExternalLeading;
    m_iCharDescent = tm.tmDescent;

    m_Offset.x = 0 ;
    m_Offset.y = m_CharSize.y * m_Position.y;
    Size( m_VisibleSize.x, m_VisibleSize.y );
    ::InvalidateRect( m_hWnd, NULL, TRUE );
    if ( m_hWnd ) {
        KillFocus();
        SetFocus();
    }
}

//
// The routine has a lot to do. Please be sure
// to refer to the explanation in the book for
// a comprehensive discussion fo this routine.
// You really need to understand the member
// variables that are used in this routine to
// follow the code.
//
BOOL Win32Term::Paint()
{
    PAINTSTRUCT  ps;

    HDC hDC = BeginPaint( m_hWnd, &ps ) ;
    HFONT hOldFont = SelectObject( hDC, m_hFont ) ;
    //
    // The first thing we do is figure out the 
    // minimum and maximum row in the update 
    // rectangle, along with the minumum and 
    // maximum column. We aren't going to try
    // to display any characters outside of that
    // cell, because there wouldn't be any point.
    // This makes the routine quite a bit more
    // efficient.
    RECT rect = ps.rcPaint;
    int nRow = min( m_VirtualSize.y - 1, 
                    max( 0, 
                         (rect.top + m_Offset.y ) / m_CharSize.y
                       ) 
                  );
    int nEndRow = min( m_VirtualSize.y - 1,
                       ( (rect.bottom + m_Offset.y - 1 ) / m_CharSize.y ) 
                     );
    int nCol = min( m_VirtualSize.x - 1,
                    max( 0, 
                         ( rect.left + m_Offset.x ) / m_CharSize.x 
                       ) 
                  );
    int nEndCol = min( m_VirtualSize.x - 1,
                       ( ( rect.right + m_Offset.x - 1 ) / m_CharSize.x ) 
                     );
    //
    // Given that info, we now enter a big for loop 
    // that is going to update the display of one row
    // at a time. We print each row in blocks of text
    // that are all the same color. Printing out a
    // string of characters is much more efficient
    // than just doing a single character at a time,
    // so its worth it to do the work of figuring out
    // which ones can be done in a single shot.
    //
    for ( ; nRow <= nEndRow; nRow++ )
    {
        int nVertPos = (nRow * m_CharSize.y ) - m_Offset.y;
        //
        // For each row, we perform an ExtTextOut() for each of
        // the contiguous blocks of the same color.
        //
        for ( int start_col = nCol; start_col <= nEndCol ; ) {
            TextColor current_color = m_ScreenColor[ nRow ][ start_col ];
            for ( int end_col = start_col ; end_col <= nEndCol ; end_col++ )
                if ( current_color != m_ScreenColor[ nRow ][ end_col ] )
                    break;
            end_col--;
            //
            // At this point I can print all the columns between 
            // start_col and end_col using the same color
            //
            int count = end_col - start_col + 1;
            int nHorzPos = (start_col * m_CharSize.x ) - m_Offset.x;
            rect.top = nVertPos ;
            rect.bottom = nVertPos + m_CharSize.y;
            rect.left = nHorzPos;
            rect.right = nHorzPos + m_CharSize.x * count;
            SetTextColor( hDC, m_ScreenColor[ nRow ][ start_col ].m_Foreground ) ;
            SetBkColor( hDC, m_ScreenColor[ nRow ][ start_col ].m_Background ) ;
            SetBkMode( hDC, OPAQUE );
            ExtTextOut( hDC, 
                        nHorzPos, 
                        nVertPos, 
                        ETO_OPAQUE | ETO_CLIPPED, 
                        &rect,
                        (LPSTR)( m_ScreenText[ nRow ].begin() + start_col ),
                        count, 
                        NULL );
            start_col = end_col + 1;
        }
    }
    SelectObject( hDC, hOldFont );
    EndPaint( m_hWnd, &ps );
    UpdateCursor();
    return TRUE;
}

//
// If we currently have the focus, I'll update
// the position of the cursor when this is called.
// If it is called when we don't have the focus,
// I won't try to move the caret. That would
// cause a lot of trouble.
//
void Win32Term::UpdateCursor()
{
   if ( m_bShowingCursor )
      SetCaretPos( 
                   ( m_Position.x * m_CharSize.x ) - m_Offset.x,
                   ( m_Position.y * m_CharSize.y ) - m_Offset.y 
                 );
   
}

//
// This is the handler that is called when this
// window gest the focus. If we didn't already
// have the cursor up, we put it up here.
//
void Win32Term::SetFocus()
{
   if ( !m_bShowingCursor )
   {
      CreateCaret( m_hWnd, NULL, m_CharSize.x, m_CharSize.y ) ;
      ShowCaret( m_hWnd ) ;
      m_bShowingCursor = true;
   }
   UpdateCursor();
}

//
// When we lose the focus we have to destroy
// the cursor. There is only one caret per 
// system, hogging it is very bad.
//
void Win32Term::KillFocus()
{
   if ( m_bShowingCursor )
   {
      HideCaret( m_hWnd );
      DestroyCaret() ;
      m_bShowingCursor = false;
   }
}


//
// The two output routines are nearly identical, The
// string output routine simply sits in a loop 
// repeating the code in the character routine over
// and over until the string is gone.
//
void Win32Term::Output( char c )
{
    switch ( c ) {
    //
    // The alert or BEL character gets special
    // handling. In this case, special means
    // that we play a beep sound to annoy the
    // user.
    //
    case '\a' :
        MessageBeep( 0 ) ;
        break ;

    //
    // The backspace key doesn't display anything
    // on the screen, it just backs up the cursor
    // by one cell if possible. 
    //
    case '\b' :                 
        if ( m_Position.x > 0 )
            m_Position.x-- ;
        break ;

    //
    // The Carriage Return doesn't do anything
    // to the contents of the screen either. It
    // just returns the cursor to the first column.
    // This is usually matched up with a line feed
    // immediately following.
    //
    case '\r' :                 
        m_Position.x = 0 ;
		break;

    //
    // The line feed character causes the cursor to
    // go to the next row. Normally this is not a
    // big deal, but if we were already on the last 
    // row of the screen, we have to scroll the whole
    // thing up, which is a big deal.
    //
    case '\n' :                 
        if ( m_Position.y++ == ( m_VirtualSize.y - 1 ) )
        {
            for ( int j = 0 ; j < ( m_VirtualSize.y - 1 ) ; j++ ) {
                m_ScreenText[ j ] = m_ScreenText[ j + 1 ];
                m_ScreenColor[ j ] = m_ScreenColor[ j + 1 ];
            }
            fill( m_ScreenText.back().begin(),
                  m_ScreenText.back().end(),
                  ' ' );
            fill( m_ScreenColor.back().begin(),
                  m_ScreenColor.back().end(),
                  m_CurrentColor );
            InvalidateRect( m_hWnd, NULL, FALSE );
            m_Position.y--;
        }
        break;

    //
    // Normal character processing is straightforward.
    // We stuff the character and its color into the
    // screen at the current insertion point, then update
    // the cursor position. We also invalidate the tiny
    // bit of the screen that we just modified so that it
    // will get repainted.
    //
    default:
        {
            RECT rect;
            m_ScreenText[ m_Position.y ][ m_Position.x ] = c;
            m_ScreenColor[ m_Position.y ][ m_Position.x ] = m_CurrentColor;
            rect.left = ( m_Position.x * m_CharSize.x ) - m_Offset.x;
            rect.right = rect.left + m_CharSize.x;
            rect.top = ( m_Position.y * m_CharSize.y ) - m_Offset.y;
            rect.bottom = rect.top + m_CharSize.y;
            InvalidateRect( m_hWnd, &rect, FALSE ) ;
            // 
            // If we reach the end of the line, we
            // might have to wrap to the next line.
            //
            if ( m_Position.x < ( m_VirtualSize.x - 1)  )
                m_Position.x++;
            else if ( m_bWrap ) 
                Output( "\r\n" ) ;
            break;
        }
    }
    UpdateCursor();
}

//
// See the previous routine for docs, it is nearly
// identical.
//
void Win32Term::Output( const char *pBuf, int length /* = -1 */ )
{
    if ( length == -1 )
        length = strlen( pBuf );
    for ( int i = 0 ; i < length ; i++ ) {
        switch ( pBuf[ i ] ) {
        case '\a' :                
            MessageBeep( 0 ) ;
            break ;

        case '\b' : 
            if ( m_Position.x > 0 )
                m_Position.x-- ;
            break ;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -