home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / Epoc / Palmtime / files / FrotzCE2_src.ZIP / FrotzCE / FrotzCEView.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-15  |  38.8 KB  |  1,765 lines

  1. // FrotzCEView.cpp : implementation of the CFrotzCEView class
  2. //
  3.  
  4. #include "stdafx.h"
  5. #include "FrotzCE.h"
  6.  
  7. #include "FrotzCEDoc.h"
  8. #include "FrotzCEView.h"
  9. #include "MainFrm.h"
  10.  
  11. extern "C"
  12. {
  13. #include "Frotz/Frotz.h"
  14.  
  15. extern char euro_substitute[];
  16. }
  17.  
  18. #ifdef _DEBUG
  19. #define new DEBUG_NEW
  20. #undef THIS_FILE
  21. static char THIS_FILE[] = __FILE__;
  22. #endif
  23.  
  24. /////////////////////////////////////////////////////////////////////////////
  25. // CFrotzCEView
  26.  
  27. IMPLEMENT_DYNCREATE(CFrotzCEView, CView)
  28.  
  29. BEGIN_MESSAGE_MAP(CFrotzCEView, CView)
  30.     //{{AFX_MSG_MAP(CFrotzCEView)
  31.     ON_WM_CHAR()
  32.     ON_WM_SYSCHAR()
  33.     ON_WM_KEYDOWN()
  34.     ON_MESSAGE(WM_CREATE_CURSOR, OnCreateCursor)
  35.     ON_MESSAGE(WM_UPDATE_CURSOR, OnUpdateCursor)
  36.     ON_MESSAGE(WM_SHOW_CURSOR, OnShowCursor)
  37.     ON_MESSAGE(WM_TAKE_FOCUS, OnTakeFocus)
  38.     ON_COMMAND(ID_DOWN, OnDown)
  39.     ON_COMMAND(ID_EAST, OnEast)
  40.     ON_COMMAND(ID_INVENTORY, OnInventory)
  41.     ON_COMMAND(ID_LOOK, OnLook)
  42.     ON_COMMAND(ID_NORTH, OnNorth)
  43.     ON_COMMAND(ID_SOUTH, OnSouth)
  44.     ON_COMMAND(ID_TAKE, OnTake)
  45.     ON_COMMAND(ID_UP, OnUp)
  46.     ON_COMMAND(ID_WEST, OnWest)
  47.     ON_WM_LBUTTONDOWN()
  48.     ON_COMMAND(ID_RESTORE, OnRestore)
  49.     ON_COMMAND(ID_SAVE, OnSave)
  50.     ON_COMMAND(ID_UNDO, OnUndo)
  51.     ON_COMMAND(ID_OPEN, OnOpen)
  52.     ON_COMMAND(ID_GO, OnGo)
  53.     ON_COMMAND(ID_DROP, OnDrop)
  54.     ON_COMMAND(ID_QUIT, OnQuit)
  55.     ON_WM_TIMER()
  56.     //}}AFX_MSG_MAP
  57. END_MESSAGE_MAP()
  58.  
  59. /////////////////////////////////////////////////////////////////////////////
  60. // CFrotzCEView construction/destruction
  61.  
  62. CFrotzCEView::CFrotzCEView()
  63. {
  64.     m_pScreen = NULL;
  65.     m_pAttributes = NULL;
  66.  
  67.     m_pcReadKeyBuffer = m_acKeyBuffer;
  68.     m_pcWriteKeyBuffer = m_acKeyBuffer;
  69.  
  70.     m_bExpectingInput = FALSE;
  71.  
  72.     m_bRedraw = TRUE;
  73.  
  74.     m_bInstantRefresh = FALSE;
  75.  
  76.     m_nState = STATE_NONE;
  77.  
  78.     m_hCurrentFont = NULL;
  79.  
  80.     // Set up pallette
  81.     m_acPallette[PALLETTE_BLACK] = RGB(0,0,0);
  82.     m_acPallette[PALLETTE_DARKGREY] = RGB(0x7f,0x7f,0x7f);
  83.     m_acPallette[PALLETTE_LIGHTGREY] = RGB(0xaf,0xaf,0xaf);
  84.     m_acPallette[PALLETTE_WHITE] = RGB(0xff,0xff,0xff);
  85. }
  86.  
  87. CFrotzCEView::~CFrotzCEView()
  88. {
  89.     // Free font object
  90.     if (m_hCurrentFont) ::DeleteObject( m_hCurrentFont );
  91.  
  92.     // Free screen buffers
  93.     if (m_pScreen) ::LocalFree( m_pScreen );
  94.     if (m_pAttributes) ::LocalFree( m_pAttributes );
  95. }
  96.  
  97. BOOL CFrotzCEView::PreCreateWindow(CREATESTRUCT& cs)
  98. {
  99.     return CView::PreCreateWindow(cs);
  100. }
  101.  
  102. /////////////////////////////////////////////////////////////////////////////
  103. // CFrotzCEView drawing
  104.  
  105. void CFrotzCEView::OnDraw( CDC* pDC )
  106. {
  107.     // Is there a screen to draw?
  108.     if (m_pScreen)
  109.     {
  110.         ::EnterCriticalSection( &m_cScrnCriticalSection );
  111.  
  112.         BYTE nOldColour = m_nCurrentColour;
  113.         int nOldStyle = m_nCurrentStyle;
  114.  
  115.         // Set default colour
  116.         m_nCurrentColour = DEF_TEXT_COLOUR;
  117.  
  118.         // Set default style
  119.         m_nCurrentStyle = NORMAL_STYLE;
  120.  
  121.         // Update the entire screen
  122.         UpdateScreenArea( pDC, 0, 0, m_nHeight-1, m_nWidth-1 );
  123.  
  124.         // Restore previous style and colours
  125.         if (nOldColour != m_nCurrentColour) SetColour( pDC, nOldColour );
  126.         if (nOldStyle != m_nCurrentStyle) 
  127.         {
  128.         HFONT hOldFont;
  129.  
  130.             hOldFont = SetStyle( pDC, nOldStyle );
  131.             pDC->SelectObject( hOldFont );
  132.         }
  133.  
  134.         ::LeaveCriticalSection( &m_cScrnCriticalSection );
  135.     }
  136.     else CView::OnDraw( pDC );
  137. }
  138.  
  139. void CFrotzCEView::UpdateScreenArea( CDC* pDC, int nTop, int nLeft, int nBottom, int nRight )
  140. {
  141. HFONT hOldFont;
  142.  
  143.     // Hide cursor
  144.     SendMessage( WM_SHOW_CURSOR, FALSE );
  145.  
  146.     // Set colour
  147.     SetColour( pDC, m_nCurrentColour );
  148.  
  149.     // Select font into device context
  150.     hOldFont = SetStyle( pDC, m_nCurrentStyle );
  151.  
  152.     // Go through each row in the screen buffer
  153.     for (int nRow = nTop, nYPos = nTop*m_nCharHeight; 
  154.         nRow <= nBottom; 
  155.         nRow++, nYPos += m_nCharHeight) 
  156.     {
  157.         for (int nCol = nLeft, nXPos = nLeft*m_nCharWidth, nChars = 0;;)
  158.         {
  159.             // Count no. of chars with current colour and style
  160.             for (nChars = 0; (nCol + nChars) <= nRight
  161.                 && COLOUR(m_pAttributes[(nRow*m_nWidth) + (nCol + nChars)]) == m_nCurrentColour
  162.                 && STYLE(m_pAttributes[(nRow*m_nWidth) + (nCol + nChars)]) == m_nCurrentStyle;
  163.                 nChars++);
  164.  
  165.             // Any chars to output with this style?
  166.             if (nChars)
  167.             {
  168.                 // Output the char to the device context
  169.                 pDC->ExtTextOut( nCol*m_nCharWidth, nRow*m_nCharHeight, ETO_OPAQUE, 
  170.                     CRect( nCol*m_nCharWidth, nRow*m_nCharHeight,  
  171.                     (nCol+1)*m_nCharWidth, (nRow+1)*m_nCharHeight), 
  172.                     (LPCTSTR) &m_pScreen[(nRow*m_nWidth) + nCol], 
  173.                     nChars, NULL );
  174.  
  175.                 nCol += nChars;
  176.                 nXPos += (nChars * m_nCharWidth);
  177.             }
  178.  
  179.             // Not reached end of line?
  180.             if (nCol <= nRight)
  181.             {
  182.                 // Colour changed?
  183.                 if (COLOUR(m_pAttributes[(nRow*m_nWidth) + nCol]) != m_nCurrentColour)
  184.                 {
  185.                     // Set current colour
  186.                     SetColour( pDC, COLOUR(m_pAttributes[(nRow*m_nWidth) + nCol]) );
  187.                 }
  188.                 // Style changed?
  189.                 if (STYLE(m_pAttributes[(nRow*m_nWidth) + nCol]) != m_nCurrentStyle)
  190.                 {
  191.                     // Select previous font into device context
  192.                     pDC->SelectObject( hOldFont );
  193.                     // Set current style
  194.                     hOldFont = SetStyle( pDC, STYLE(m_pAttributes[(nRow*m_nWidth) + nCol]) );
  195.                 }
  196.             }
  197.             else break;
  198.         }
  199.     }
  200.  
  201.     // Select original font back into device context
  202.     pDC->SelectObject( hOldFont );
  203.  
  204.     // Show cursor
  205.     SendMessage( WM_SHOW_CURSOR, TRUE );
  206. }
  207.  
  208. /////////////////////////////////////////////////////////////////////////////
  209. // CFrotzCEView diagnostics
  210.  
  211. #ifdef _DEBUG
  212. void CFrotzCEView::AssertValid() const
  213. {
  214.     CView::AssertValid();
  215. }
  216.  
  217. void CFrotzCEView::Dump(CDumpContext& dc) const
  218. {
  219.     CView::Dump(dc);
  220. }
  221.  
  222. CFrotzCEDoc* CFrotzCEView::GetDocument() // non-debug version is inline
  223. {
  224.     ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFrotzCEDoc)));
  225.     return (CFrotzCEDoc*)m_pDocument;
  226. }
  227. #endif //_DEBUG
  228.  
  229. // Initialises the display
  230. void CFrotzCEView::InitialiseScreen()
  231. {
  232. CRect cRect;
  233. TEXTMETRIC sTextMetrics;
  234. CDC *pDC;
  235. HFONT hOldFont;
  236.  
  237.     // Copy screen info
  238.     m_bUseStyles = FROTZCEAPP->m_bUseStyles;
  239.     m_nDefaultStyle = FROTZCEAPP->m_nDefaultStyle;
  240.     m_nDefaultFontHeight = FROTZCEAPP->m_nFontHeight;
  241.     m_nDefaultFontWidth = FROTZCEAPP->m_nFontWidth;
  242.     m_bUseEuroChars = FROTZCEAPP->m_bUseEuroChars;
  243.     m_bUseColours = FROTZCEAPP->m_bUseColours;
  244.  
  245.     // Create keypress event object
  246.     m_hKeyEvent = ::CreateEvent( NULL, FALSE, FALSE, NULL );
  247.  
  248.     // Initialise critical sections
  249.     memset( &m_cKbdCriticalSection, 0, sizeof( m_cKbdCriticalSection ) );
  250.     ::InitializeCriticalSection( &m_cKbdCriticalSection );
  251.     memset( &m_cScrnCriticalSection, 0, sizeof( m_cScrnCriticalSection ) );
  252.     ::InitializeCriticalSection( &m_cScrnCriticalSection );
  253.  
  254.     // Set cursor state
  255.     m_bCursorOn = FALSE;
  256.     m_bCursorSet = TRUE;
  257.  
  258.     // Reset widths etc.
  259.     m_nWidth = 0;
  260.     m_nCharWidth = 0;
  261.     m_nHeight = 0;
  262.     m_nCharHeight = 0;
  263.  
  264.     // Get frame window rectangle
  265.     MAINFRAME->GetClientRect( cRect );
  266.  
  267.     // Subtract size of command bar if it's showing
  268.     if (MAINFRAME->m_bShowCommandBar) 
  269.         cRect.top += MAINFRAME->m_nCmdBarHeight;
  270.  
  271.     // Resize the view to cover the entire frame window client area
  272.     MoveWindow( cRect, FALSE );
  273.  
  274.     // Get window rectangle
  275.     GetClientRect( cRect );
  276.  
  277.     // Get device context
  278.     pDC = GetDC();
  279.  
  280.     // Set colour
  281.     SetColour( pDC, DEF_TEXT_COLOUR );
  282.  
  283.     // Using text styles?
  284.     if (m_bUseStyles)
  285.     {
  286.         // Select font into device context
  287.         hOldFont = SetStyle( pDC, NORMAL_STYLE | BOLDFACE_STYLE | EMPHASIS_STYLE, TRUE );
  288.     }
  289.     else
  290.     {
  291.         // Select font into device context
  292.         hOldFont = SetStyle( pDC, NORMAL_STYLE, TRUE );
  293.     }
  294.  
  295.     // Get the font metrics
  296.     pDC->GetTextMetrics( &sTextMetrics );
  297.  
  298.     // Save character dimensions
  299.     m_nCharWidth = (USHORT) sTextMetrics.tmMaxCharWidth + sTextMetrics.tmOverhang;
  300.     m_nCharHeight = (USHORT) sTextMetrics.tmHeight;
  301.  
  302.     // Set colour
  303.     SetColour( pDC, DEF_TEXT_COLOUR );
  304.  
  305.     // Using text styles?
  306.     if (m_bUseStyles)
  307.     {
  308.         // Select previous font into device context
  309.         pDC->SelectObject( hOldFont );
  310.         // Select font into device context
  311.         hOldFont = SetStyle( pDC, m_nDefaultStyle );
  312.     }
  313.  
  314.     // Select previous font into device context
  315.     pDC->SelectObject( hOldFont );
  316.  
  317.     // Release device context
  318.     ReleaseDC( pDC );
  319.  
  320.     // Save screen dimensions
  321.     m_nWidth = cRect.Width() / m_nCharWidth;
  322.     m_nHeight = cRect.Height() / m_nCharHeight;
  323.  
  324.     // Allocate screen buffers
  325.     m_pScreen = 
  326.         (TCHAR *) ::LocalAlloc( LPTR, m_nWidth * m_nHeight * sizeof( TCHAR ) );
  327.     m_pAttributes = 
  328.         (BYTE *) ::LocalAlloc( LPTR, m_nWidth * m_nHeight );
  329.  
  330.     // Clear the screen
  331.     ClearScreen( FALSE );
  332.  
  333.     // Send a message to the view to create the caret
  334.     SendMessage( WM_CREATE_CURSOR );
  335.  
  336.     // Create timer to do update
  337.     m_hUpdateTimer = SetTimer( ID_UPDATE_TIMER, FROTZCE_UPDATE_MS, NULL );
  338. }
  339.  
  340. void CFrotzCEView::ResetScreen()
  341. {
  342. CRect cRect;
  343.  
  344.     // Free event object
  345.     ::CloseHandle( m_hKeyEvent );
  346.  
  347.     // Release critical sections
  348.     ::DeleteCriticalSection( &m_cKbdCriticalSection );
  349.     ::DeleteCriticalSection( &m_cScrnCriticalSection );
  350.  
  351.     // Free font object
  352.     if (m_hCurrentFont) 
  353.     {
  354.         ::DeleteObject( m_hCurrentFont );
  355.         m_hCurrentFont = NULL;
  356.     }
  357.  
  358.     // Free screen buffers
  359.     if (m_pScreen) 
  360.     {
  361.         ::LocalFree( m_pScreen );
  362.         m_pScreen = NULL;
  363.     }
  364.     if (m_pAttributes)
  365.     {
  366.         ::LocalFree( m_pAttributes );
  367.         m_pAttributes = NULL;
  368.     }
  369.  
  370.     // Get frame window rectangle
  371.     MAINFRAME->GetClientRect( cRect );
  372.     cRect.top += MAINFRAME->m_nCmdBarHeight;
  373.  
  374.     // Resize the view to cover the entire frame window client area
  375.     MoveWindow( cRect, FALSE );
  376.  
  377.     // Free timer
  378.     if (m_hUpdateTimer) KillTimer( m_hUpdateTimer );
  379.  
  380.     // Clear screen
  381.     Invalidate( TRUE );
  382. }
  383.  
  384. void CFrotzCEView::ClearScreen( BOOL bUpdate )
  385. {
  386.     // Erase the entire screen
  387.     EraseScreenArea( 0, 0, m_nHeight-1, m_nWidth-1 );
  388.  
  389.     // Set the cursor position to upper left-hand corner
  390.     SetCursorPos( 0, 0 );
  391. }
  392.  
  393. void CFrotzCEView::EraseScreenArea( int nTop, int nLeft, int nBottom, int nRight )
  394. {
  395.     // Make sure extents are in range
  396.     if (nBottom > m_nHeight-1) nBottom = m_nHeight-1;
  397.     if (nRight > m_nWidth-1) nRight = m_nWidth - 1;
  398.  
  399.     ::EnterCriticalSection( &m_cScrnCriticalSection );
  400.  
  401.     // Fill screen buffer with spaces
  402.     for (int nRow = nTop; nRow <= nBottom; nRow++)
  403.     {
  404.         for (int nCol = nLeft; nCol <= nRight; nCol++)
  405.         {
  406.             m_pScreen[(nRow * m_nWidth) + nCol] = _T(' ');
  407.             m_pAttributes[(nRow * m_nWidth) + nCol] = 
  408.                 (m_nCurrentColour << NUM_STYLE_BITS) | m_nCurrentStyle;
  409.         }
  410.     }
  411.  
  412.     ::LeaveCriticalSection( &m_cScrnCriticalSection );
  413.  
  414.     // Refresh instantly?
  415.     if (m_bInstantRefresh)
  416.     {
  417.         // Get device context
  418.         CDC *pDC = GetDC();
  419.  
  420.         ::EnterCriticalSection( &m_cScrnCriticalSection );
  421.  
  422.         // Update scrolled area
  423.         UpdateScreenArea( pDC, nTop, nLeft, nBottom, nRight );
  424.  
  425.         ::LeaveCriticalSection( &m_cScrnCriticalSection );
  426.  
  427.         // Release device context
  428.         ReleaseDC( pDC );
  429.     }
  430.     else
  431.     {
  432.         // Flag that screen must be redrawn
  433.         m_bRedraw = TRUE;
  434.     }
  435. }
  436.  
  437. void CFrotzCEView::GetCursorPos( int *pnRow, int *pnCol )
  438. {
  439.     // Save cursor position
  440.     *pnRow = m_nCursorRow;
  441.     *pnCol = m_nCursorCol;
  442. }
  443.  
  444. void CFrotzCEView::SetCursorPos( int nRow, int nCol, BOOL bUpdate )
  445. {
  446.     // Make sure row and column are in range
  447.     if (nRow < 0) nRow = 0;
  448.     else if (nRow > m_nHeight-1) nRow = m_nHeight - 1;
  449.     if (nCol < 0) nCol = 0;
  450.     else if (nCol > m_nWidth-1) nCol = m_nWidth - 1;
  451.  
  452.     // Save cursor position
  453.     m_nCursorRow = nRow;
  454.     m_nCursorCol = nCol;
  455.  
  456.     // Update caret position
  457.     if (bUpdate) UpdateCaretPos();
  458. }
  459.  
  460.  
  461. void CFrotzCEView::UpdateCaretPos()
  462. {
  463.     // Send a message to the view to update the caret
  464.     SendMessage( WM_UPDATE_CURSOR );
  465. }
  466.  
  467. void CFrotzCEView::OnCreateCursor()
  468. {
  469.     // Create a cursor
  470.     CreateSolidCaret( m_nCharWidth, m_nCharHeight );
  471. }
  472.  
  473. void CFrotzCEView::OnUpdateCursor()
  474. {
  475. POINT sCaretPos;
  476.  
  477.     // Calculate new caret position
  478.     sCaretPos.x = m_nCursorCol * m_nCharWidth;
  479.     sCaretPos.y = m_nCursorRow * m_nCharHeight;
  480.  
  481.     SetCaretPos( sCaretPos );
  482.  
  483.     // Cursor state needs setting
  484.     if (!m_bCursorSet)
  485.     {
  486.         m_bCursorSet = TRUE;
  487.         
  488.         // Show or hide cursor
  489.         OnShowCursor( m_bCursorOn );
  490.     }
  491. }
  492.  
  493. void CFrotzCEView::OnShowCursor( UINT bShow )
  494. {
  495.     // Show or hide cursor
  496.     if (bShow) ShowCaret();
  497.     else HideCaret();
  498. }
  499.  
  500. void CFrotzCEView::OnTakeFocus()
  501. {
  502.     SetFocus();
  503. }
  504.  
  505. void CFrotzCEView::SetCursorState( BOOL bCursorOn )
  506. {
  507.     // Changing state?
  508.     if (m_bCursorOn != bCursorOn)
  509.     {
  510.         // Set cursor state
  511.         m_bCursorOn  = bCursorOn;
  512.         // Flag that state has changed
  513.         m_bCursorSet = FALSE;
  514.  
  515.         // Update caret
  516.         UpdateCaretPos();
  517.     }
  518. }
  519.  
  520. void CFrotzCEView::SetColour( CDC* pDC, BYTE nColour )
  521. {
  522.     // Set current text colour
  523.     m_nCurrentColour = nColour;
  524.  
  525.     // Reverse mode?
  526.     if (m_nCurrentStyle & REVERSE_STYLE)
  527.     {
  528.         // Set text and background colours to reverse
  529.         pDC->SetTextColor( 
  530.             pDC->GetNearestColor( m_acPallette[m_nCurrentColour>>2] ) );
  531.         pDC->SetBkColor( 
  532.             pDC->GetNearestColor( m_acPallette[m_nCurrentColour&3] ) );
  533.     }
  534.     else
  535.     {
  536.         // Set text and background colours
  537.         pDC->SetTextColor( 
  538.             pDC->GetNearestColor( m_acPallette[m_nCurrentColour&3] ) );
  539.         pDC->SetBkColor( 
  540.             pDC->GetNearestColor( m_acPallette[m_nCurrentColour>>2] ) );
  541.     }
  542. }
  543.  
  544. HFONT CFrotzCEView::SetStyle( CDC* pDC, BYTE nStyle, BOOL bForce )
  545. {
  546.     // Not using text styles?
  547.     if (!m_bUseStyles)
  548.     {
  549.         // Remove style flags
  550.         nStyle &= ~BOLDFACE_STYLE;
  551.         nStyle &= ~EMPHASIS_STYLE;
  552.     }
  553.  
  554.     // Use default style
  555.     nStyle |= m_nDefaultStyle;
  556.  
  557.     // Style changed?
  558.     if (nStyle != m_nCurrentStyle || bForce)
  559.     {
  560.     LOGFONT sLogFont;
  561.     HFONT hNewFont;
  562.  
  563.         // Reverse style changing?
  564.         if ((m_nCurrentStyle & REVERSE_STYLE) != (nStyle & REVERSE_STYLE))
  565.         {
  566.             // Set current text style
  567.             m_nCurrentStyle = nStyle;
  568.  
  569.             // Set current text colour
  570.             SetColour( pDC, m_nCurrentColour );
  571.         }
  572.         // Set current text style
  573.         else m_nCurrentStyle = nStyle;
  574.  
  575.         // Set up logical font structure
  576.         memset ((char *) &sLogFont, 0, sizeof( sLogFont ));
  577.         sLogFont.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
  578.         sLogFont.lfCharSet = ANSI_CHARSET;
  579.  
  580.         // Set font quality
  581.         sLogFont.lfQuality = DRAFT_QUALITY;
  582.  
  583.         // Small font?
  584.         if (m_nDefaultFontWidth == SMALL_FONT_WIDTH)
  585.         {
  586.             // Set up font name
  587.             #define TERMINAL_FONT TEXT("Courier New")
  588.             memcpy( sLogFont.lfFaceName, TERMINAL_FONT, sizeof( TERMINAL_FONT ) );
  589.             #undef TERMINAL_FONT
  590.  
  591.             // Set font width
  592.             sLogFont.lfWidth = m_nDefaultFontWidth;
  593.             // Set font height
  594.             sLogFont.lfHeight = m_nDefaultFontHeight;
  595.         }
  596.         else
  597.         {
  598.             // Set font height
  599.             if (m_nCharHeight) sLogFont.lfHeight = m_nCharHeight;
  600.             else sLogFont.lfHeight = m_nDefaultFontHeight;
  601.  
  602.             // Set font width
  603.             if (m_nCharWidth) sLogFont.lfWidth = m_nCharWidth;
  604.             else sLogFont.lfWidth = m_nDefaultFontWidth;
  605.         }
  606.  
  607.         // Bold?
  608.         if (m_nCurrentStyle & BOLDFACE_STYLE) 
  609.             sLogFont.lfWeight = FW_BOLD;
  610.  
  611.         // Italic?
  612.         if (m_nCurrentStyle & EMPHASIS_STYLE)
  613.         {
  614.             sLogFont.lfWeight = FW_BOLD;
  615.             sLogFont.lfItalic = TRUE;
  616.         }
  617.  
  618.         // Create font
  619.         if ((hNewFont = ::CreateFontIndirect( &sLogFont )) != NULL)
  620.         {
  621.             // Replace current font
  622.             if (m_hCurrentFont) ::DeleteObject( (HGDIOBJ) m_hCurrentFont );
  623.             m_hCurrentFont = hNewFont;
  624.  
  625.             // Select font into device context
  626.             return (HFONT) pDC->SelectObject( hNewFont );
  627.         }
  628.         else return NULL;
  629.     }
  630.     else
  631.     {
  632.         // Select current font into device context
  633.         return (HFONT) pDC->SelectObject( m_hCurrentFont );
  634.     }
  635. }
  636.  
  637. void CFrotzCEView::DisplayChar( char ch, BOOL bUpdateCaret )
  638. {
  639.     // Check for special characters
  640.     switch( ch )
  641.     {
  642.     // Paragraph indent?
  643.     case 11:
  644.         DisplayChar( ' ' );
  645.     // Tab?
  646.     case 9:
  647.         DisplayChar( ' ' );
  648.         ch = ' ';
  649.     // Everything else
  650.     default:
  651.         int nCurrPos;
  652.         
  653.         // Save cursor pos.
  654.         nCurrPos = m_nCursorCol;
  655.  
  656.         // Update cursor position
  657.         m_nCursorCol++;
  658.         if (bUpdateCaret) UpdateCaretPos();
  659.  
  660.         // On screen?
  661.         if (nCurrPos < m_nWidth && m_nCursorRow < m_nHeight)
  662.         {
  663.             ::EnterCriticalSection( &m_cScrnCriticalSection );
  664.     
  665.             // Put the char into the screen buffer
  666.             m_pScreen[(m_nCursorRow * m_nWidth) + nCurrPos] = (TCHAR) ch;
  667.  
  668.             m_pAttributes[(m_nCursorRow * m_nWidth) + nCurrPos] = 
  669.                 (BYTE) ((m_nCurrentColour << NUM_STYLE_BITS) | m_nCurrentStyle);
  670.  
  671.             // Refresh instantly?
  672.             if (m_bInstantRefresh || m_bExpectingInput)
  673.             {
  674.             HFONT hOldFont;
  675.  
  676.                 // Get device context
  677.                 CDC *pDC = GetDC();
  678.  
  679.                 // Set colour
  680.                 SetColour( pDC, m_nCurrentColour );
  681.  
  682.                 // Select font into device context
  683.                 hOldFont = SetStyle( pDC, m_nCurrentStyle );
  684.  
  685.                 // Output the char to the device context
  686.                 pDC->ExtTextOut( nCurrPos*m_nCharWidth, m_nCursorRow*m_nCharHeight, ETO_OPAQUE, 
  687.                     CRect( nCurrPos*m_nCharWidth, m_nCursorRow*m_nCharHeight, (nCurrPos+1)*m_nCharWidth, (m_nCursorRow+1)*m_nCharHeight), 
  688.                     (LPCTSTR) &m_pScreen[(m_nCursorRow * m_nWidth) + nCurrPos], 
  689.                     1, NULL );
  690.  
  691.                 // Select previous font into device context
  692.                 pDC->SelectObject( hOldFont );
  693.  
  694.                 // Release device context
  695.                 ReleaseDC( pDC );
  696.             }
  697.             else
  698.             {
  699.                 // Flag that screen must be redrawn
  700.                 m_bRedraw = TRUE;
  701.             }
  702.  
  703.             ::LeaveCriticalSection( &m_cScrnCriticalSection );
  704.         }
  705.     }
  706. }
  707.  
  708. void CFrotzCEView::DisplayString( const char* acString )
  709. {
  710. const unsigned char *pcCurr = (unsigned char *) acString;
  711. int nStartCol = m_nCursorCol;
  712. int nCurrentStyle;
  713. int nCurrentColour;
  714.  
  715.  
  716.     ::EnterCriticalSection( &m_cScrnCriticalSection );
  717.  
  718.     // Save current style and colours
  719.     nCurrentStyle = m_nCurrentStyle;
  720.     nCurrentColour = m_nCurrentColour;
  721.  
  722.     ::LeaveCriticalSection( &m_cScrnCriticalSection );
  723.  
  724.     // Process string
  725.     for (; *pcCurr; pcCurr++)
  726.     {
  727.         // New style?
  728.         if (*pcCurr == NEW_FONT || *pcCurr == NEW_STYLE) 
  729.         {
  730.             // Style change?
  731.             if (*pcCurr == NEW_STYLE)
  732.             {
  733.                 pcCurr++;
  734.  
  735.                 // Set current style
  736.                 nCurrentStyle = *pcCurr;
  737.  
  738.                 // Not using text styles?
  739.                 if (!m_bUseStyles)
  740.                 {
  741.                     // Remove style flags
  742.                     nCurrentStyle &= ~BOLDFACE_STYLE;
  743.                     nCurrentStyle &= ~EMPHASIS_STYLE;
  744.                 }
  745.  
  746.                 // Use default style
  747.                 nCurrentStyle |= m_nDefaultStyle;
  748.             }
  749.             else
  750.             {
  751.                 pcCurr++;
  752.             }
  753.         }
  754.         else 
  755.         {
  756.             // European char?
  757.             if (m_bUseEuroChars && *pcCurr >= EURO_MIN && *pcCurr <= EURO_MAX)
  758.             {
  759.             int c1 = euro_substitute[2 * (*pcCurr - EURO_MIN)];
  760.             int c2 = euro_substitute[2 * (*pcCurr - EURO_MIN) + 1];
  761.  
  762.                 // On screen?
  763.                 if (m_nCursorCol < m_nWidth && m_nCursorRow < m_nHeight)
  764.                 {
  765.                     // Put the char into the screen buffer
  766.                     m_pScreen[(m_nCursorRow * m_nWidth) + m_nCursorCol] = (TCHAR) c1;
  767.                     m_pAttributes[(m_nCursorRow * m_nWidth) + m_nCursorCol] = 
  768.                         (BYTE) ((nCurrentColour << NUM_STYLE_BITS) | nCurrentStyle); 
  769.                     m_nCursorCol++;
  770.                 }
  771.  
  772.                 // Second char to display?
  773.                 if (c2 != ' ') 
  774.                 {
  775.                     // On screen?
  776.                     if (m_nCursorCol < m_nWidth && m_nCursorRow < m_nHeight)
  777.                     {
  778.                         // Put the char into the screen buffer
  779.                         m_pScreen[(m_nCursorRow * m_nWidth) + m_nCursorCol] = (TCHAR) c2;
  780.                         m_pAttributes[(m_nCursorRow * m_nWidth) + m_nCursorCol] = 
  781.                             (BYTE) ((nCurrentColour << NUM_STYLE_BITS) | nCurrentStyle); 
  782.                         m_nCursorCol++;
  783.                     }
  784.                 }
  785.             }
  786.             // Display char
  787.             else
  788.             {
  789.             char ch = (char) *pcCurr;
  790.  
  791.                 // Check for special characters
  792.                 switch( *pcCurr )
  793.                 {
  794.                 // Paragraph indent?
  795.                 case 11:
  796.                     // On screen?
  797.                     if (m_nCursorCol < m_nWidth && m_nCursorRow < m_nHeight)
  798.                     {
  799.                         // Put the char into the screen buffer
  800.                         m_pScreen[(m_nCursorRow * m_nWidth) + m_nCursorCol] = _T(' ');
  801.                         m_pAttributes[(m_nCursorRow * m_nWidth) + m_nCursorCol] = 
  802.                             (BYTE) ((nCurrentColour << NUM_STYLE_BITS) | nCurrentStyle); 
  803.                         m_nCursorCol++;
  804.                     }
  805.                 // Tab?
  806.                 case 9:
  807.                     // On screen?
  808.                     if (m_nCursorCol < m_nWidth && m_nCursorRow < m_nHeight)
  809.                     {
  810.                         // Put the char into the screen buffer
  811.                         m_pScreen[(m_nCursorRow * m_nWidth) + m_nCursorCol] = _T(' ');
  812.                         m_pAttributes[(m_nCursorRow * m_nWidth) + m_nCursorCol] = 
  813.                             (BYTE) ((nCurrentColour << NUM_STYLE_BITS) | nCurrentStyle); 
  814.                         m_nCursorCol++;
  815.                     }
  816.                     ch = ' ';
  817.                 // Everything else
  818.                 default:
  819.                     // On screen?
  820.                     if (m_nCursorCol < m_nWidth && m_nCursorRow < m_nHeight)
  821.                     {
  822.                         // Put the char into the screen buffer
  823.                         m_pScreen[(m_nCursorRow * m_nWidth) + m_nCursorCol] = (TCHAR) ch;
  824.                         m_pAttributes[(m_nCursorRow * m_nWidth) + m_nCursorCol] = 
  825.                             (BYTE) ((nCurrentColour << NUM_STYLE_BITS) | nCurrentStyle); 
  826.                         m_nCursorCol++;
  827.                     }
  828.                     break;
  829.                 }
  830.             }
  831.         }
  832.     }
  833.  
  834.     // Refresh instantly?
  835.     if (m_bInstantRefresh)
  836.     {
  837.         // Get device context
  838.         CDC *pDC = GetDC();
  839.  
  840.         ::EnterCriticalSection( &m_cScrnCriticalSection );
  841.  
  842.         // Anything to display?
  843.         if (m_nCursorCol > nStartCol)
  844.         {
  845.             // Update display
  846.             UpdateScreenArea( pDC, m_nCursorRow, nStartCol, m_nCursorRow, m_nCursorCol-1 );
  847.         }
  848.  
  849.         // Set style?
  850.         if (nCurrentStyle != m_nCurrentStyle) 
  851.         {
  852.         HFONT hOldFont;
  853.  
  854.             hOldFont = SetStyle( pDC, nCurrentStyle );
  855.  
  856.             // Select previous font into device context
  857.             pDC->SelectObject( hOldFont );
  858.         }
  859.  
  860.  
  861.         ::LeaveCriticalSection( &m_cScrnCriticalSection );
  862.  
  863.         // Release device context
  864.         ReleaseDC( pDC );
  865.     }
  866.     else
  867.     {
  868.         ::EnterCriticalSection( &m_cScrnCriticalSection );
  869.  
  870.         // Set style
  871.         if (nCurrentStyle != m_nCurrentStyle) 
  872.             m_nCurrentStyle = nCurrentStyle;
  873.  
  874.         ::LeaveCriticalSection( &m_cScrnCriticalSection );
  875.  
  876.         // Flag that screen must be redrawn
  877.         m_bRedraw = TRUE;
  878.     }
  879. }
  880.  
  881. // Gets a key
  882. int CFrotzCEView::GetKey( int nTimeOut )
  883. {
  884. DWORD dwTimeOut = INFINITE;
  885. unsigned char ch = 0;
  886.  
  887.     // Update cursor position
  888.     UpdateCaretPos();
  889.  
  890.     // Timeout specified?
  891.     if (nTimeOut > 0) dwTimeOut = nTimeOut * 100;
  892.  
  893.     // Set flag to indicate we're expecting input
  894.     m_bExpectingInput = TRUE;
  895.  
  896.     // Got a key?
  897.     if (m_pcReadKeyBuffer != m_pcWriteKeyBuffer 
  898.         || ::WaitForSingleObject( m_hKeyEvent, dwTimeOut ) != WAIT_TIMEOUT)
  899.     {
  900.         // Was a key pressed?
  901.         if (m_pcReadKeyBuffer != m_pcWriteKeyBuffer)
  902.         {
  903.             // Get key from buffer
  904.             ch = *m_pcReadKeyBuffer;
  905.             m_pcReadKeyBuffer++;
  906.  
  907.             // Gone past end of buffer?
  908.             if (m_pcReadKeyBuffer > &m_acKeyBuffer[KEYBUFFER_SIZE-1])
  909.             {
  910.                 // Go back to beginning of buffer
  911.                 m_pcReadKeyBuffer = &m_acKeyBuffer[0];
  912.             }
  913.         }
  914.     }
  915.  
  916.     m_bExpectingInput = FALSE;
  917.  
  918.     return (int) ch;
  919. }
  920.  
  921. #define MAX_LINE 80
  922. #define MAX_HISTORY 5
  923.  
  924. // Gets a line
  925. int CFrotzCEView::GetLine( char *acBuffer, int nMax, int nTimeOut )
  926. {
  927. DWORD dwTimeOut = INFINITE;
  928. int ch = 0;
  929. int nCurrChar = strlen( acBuffer );
  930. static nNextHistoryPos = 0, nCurrHistoryPos = 0;
  931. static char acHistory[MAX_HISTORY][MAX_LINE];
  932.  
  933.     // Timeout specified?
  934.     if (nTimeOut > 0) dwTimeOut = nTimeOut * 100;
  935.  
  936.     // Update cursor position
  937.     UpdateCaretPos();
  938.  
  939.     // Set flag to indicate we're expecting input
  940.     m_bExpectingInput = TRUE;
  941.  
  942.     do
  943.     {
  944.         // Was a key pressed?
  945.         if (m_pcReadKeyBuffer != m_pcWriteKeyBuffer)
  946.         {
  947.             // Get key from buffer
  948.             ch = *m_pcReadKeyBuffer;
  949.             m_pcReadKeyBuffer++;
  950.  
  951.             // Gone past end of buffer?
  952.             if (m_pcReadKeyBuffer > &m_acKeyBuffer[KEYBUFFER_SIZE-1])
  953.             {
  954.                 // Go back to beginning of buffer
  955.                 m_pcReadKeyBuffer = &m_acKeyBuffer[0];
  956.             }
  957.         }
  958.         else
  959.         {
  960.             // Received a keypress notification?
  961.             if (::WaitForSingleObject( m_hKeyEvent, dwTimeOut ) != WAIT_TIMEOUT)
  962.             {
  963.                 continue;
  964.             }
  965.             else ch = 0;
  966.         }
  967.  
  968.         // Add character to buffer
  969.         if (ch && !is_terminator( (int) ch )) 
  970.         {
  971.             // Check key pressed
  972.             switch (ch)
  973.             {
  974.             case BACKSPACE_KEY:
  975.                 // At beginning of line?
  976.                 if (nCurrChar > 0)
  977.                 {
  978.                     nCurrChar--;
  979.                     m_nCursorCol--;
  980.                     DisplayChar( ' ', TRUE );
  981.                     m_nCursorCol--;
  982.                     UpdateCaretPos();
  983.                 }
  984.                 break;
  985.  
  986.             case TAB_KEY:
  987.                 char acExt[16];
  988.                 int nExtSize;
  989.  
  990.                 // Terminate buffer
  991.                 acBuffer[nCurrChar] = '\0';
  992.  
  993.                 // Completion successful?
  994.                 completion( acBuffer, acExt );
  995.                 if ((nExtSize = strlen( acExt )) > 0)
  996.                 {
  997.                     // Copy chars into buffer and display them
  998.                     for (int i=0; i < nExtSize && nCurrChar <= nMax; i++)
  999.                     {
  1000.                         acBuffer[nCurrChar++] = acExt[i];
  1001.                         DisplayChar( acExt[i], TRUE );
  1002.                     }
  1003.                 }
  1004.                 break;
  1005.  
  1006.             case ESC_KEY:
  1007.                 // Go until beginning of line
  1008.                 while (nCurrChar > 0)
  1009.                 {
  1010.                     nCurrChar--;
  1011.                     m_nCursorCol--;
  1012.                     DisplayChar( ' ', TRUE );
  1013.                     m_nCursorCol--;
  1014.                 }
  1015.                 UpdateCaretPos();
  1016.                 break;
  1017.  
  1018.             case UP_ARROW_KEY:
  1019.             case DOWN_ARROW_KEY:
  1020.                 int nHistorySize;
  1021.  
  1022.                 // Go until beginning of line
  1023.                 while (nCurrChar > 0)
  1024.                 {
  1025.                     nCurrChar--;
  1026.                     m_nCursorCol--;
  1027.                     DisplayChar( ' ', TRUE );
  1028.                     m_nCursorCol--;
  1029.                 }
  1030.                 UpdateCaretPos();
  1031.  
  1032.                 // Up arrow?
  1033.                 if (ch == UP_ARROW_KEY) 
  1034.                 {
  1035.                     nCurrHistoryPos--;
  1036.                     if (nCurrHistoryPos < 0) 
  1037.                         nCurrHistoryPos = MAX_HISTORY - 1;
  1038.                 }
  1039.                 else 
  1040.                 {
  1041.                     nCurrHistoryPos++;
  1042.                     if (nCurrHistoryPos >= MAX_HISTORY) 
  1043.                         nCurrHistoryPos = 0;
  1044.                 }
  1045.  
  1046.                 // Got anything?
  1047.                 if ((nHistorySize = strlen( acHistory[nCurrHistoryPos] )) > 0)
  1048.                 {
  1049.                     // Copy chars into buffer and display them
  1050.                     for (int i=0; i < nHistorySize && nCurrChar <= nMax; i++)
  1051.                     {
  1052.                         acBuffer[nCurrChar++] = acHistory[nCurrHistoryPos][i];
  1053.                         DisplayChar( acHistory[nCurrHistoryPos][i], TRUE );
  1054.                     }
  1055.  
  1056.                     nNextHistoryPos = nCurrHistoryPos;
  1057.                     UpdateCaretPos();
  1058.                 }
  1059.                 break;
  1060.  
  1061.             case SPECIAL_KEY_HOME:
  1062.             case SPECIAL_KEY_END:
  1063.             case SPECIAL_KEY_DELETE:
  1064.             case SPECIAL_KEY_INSERT:
  1065.             case SPECIAL_KEY_PAGE_UP:
  1066.             case SPECIAL_KEY_PAGE_DOWN:
  1067.             case LEFT_ARROW_KEY:
  1068.             case RIGHT_ARROW_KEY:
  1069.                 break;
  1070.  
  1071.             // Any other key...
  1072.             default:
  1073.                 acBuffer[nCurrChar++] = (unsigned char) ch;
  1074.                 DisplayChar( ch, TRUE );
  1075.                 UpdateCaretPos();
  1076.                 break;
  1077.             }
  1078.         }
  1079.         else break;
  1080.     }
  1081.     while (nCurrChar <= nMax);
  1082.  
  1083.     // Null-terminate buffer
  1084.     acBuffer[nCurrChar] = '\0';
  1085.  
  1086.     // Anything entered?
  1087.     if (strlen( acBuffer ) > 0 && acBuffer[0] != '\n')
  1088.     {
  1089.         // Copy string to history buffer
  1090.         strcpy( acHistory[nNextHistoryPos], acBuffer );
  1091.         nNextHistoryPos++;
  1092.         nCurrHistoryPos = nNextHistoryPos;
  1093.         if (nNextHistoryPos >= MAX_HISTORY) nNextHistoryPos = 0;
  1094.     }
  1095.  
  1096.     m_bExpectingInput = FALSE;
  1097.     m_nState = STATE_NONE;
  1098.  
  1099.     return ch;
  1100. }
  1101.  
  1102. // Scrolls an area of the screen
  1103. void CFrotzCEView::ScrollScreenArea( int nTop, int nLeft, int nBottom, int nRight, int nUnits )
  1104. {
  1105. int nRow;
  1106.  
  1107.     // Scroll each line upwards
  1108.     for (nRow = nTop + nUnits; nRow <= nBottom; nRow++)
  1109.     {
  1110.         memcpy( &m_pScreen[((nRow - nUnits) * m_nWidth) + nLeft],
  1111.             &m_pScreen[(nRow * m_nWidth) + nLeft], 
  1112.             ((nRight - nLeft) + 1) * sizeof( TCHAR ) );
  1113.         memcpy( &m_pAttributes[((nRow - nUnits) * m_nWidth) + nLeft],
  1114.             &m_pAttributes[(nRow * m_nWidth) + nLeft], 
  1115.             ((nRight - nLeft) + 1) );
  1116.     }
  1117.  
  1118.     ::EnterCriticalSection( &m_cScrnCriticalSection );
  1119.  
  1120.     // Fill rows below scrolled area with spaces
  1121.     for (nRow = nBottom; nRow > nBottom - nUnits; nRow--)
  1122.     {
  1123.         for (int nCol = nLeft; nCol <= nRight; nCol++)
  1124.         {
  1125.             m_pScreen[(nRow * m_nWidth) + nCol] = _T(' ');
  1126.             m_pAttributes[(nRow * m_nWidth) + nCol] = 
  1127.                 (BYTE) ((m_nCurrentColour << NUM_STYLE_BITS) | m_nCurrentStyle);
  1128.         }
  1129.     }
  1130.  
  1131.     ::LeaveCriticalSection( &m_cScrnCriticalSection );
  1132.  
  1133.     // Refresh instantly?
  1134.     if (m_bInstantRefresh)
  1135.     {
  1136.         // Get device context
  1137.         CDC *pDC = GetDC();
  1138.  
  1139.         ::EnterCriticalSection( &m_cScrnCriticalSection );
  1140.  
  1141.         // Update scrolled area
  1142.         UpdateScreenArea( pDC, nTop, nLeft, nBottom, nRight );
  1143.  
  1144.         ::LeaveCriticalSection( &m_cScrnCriticalSection );
  1145.  
  1146.         // Release device context
  1147.         ReleaseDC( pDC );
  1148.     }    
  1149.     else
  1150.     {
  1151.         // Flag that screen must be redrawn
  1152.         m_bRedraw = TRUE;
  1153.     }
  1154. }
  1155.  
  1156. // Sets the current text style
  1157. void CFrotzCEView::SetTextStyle( int nStyle )
  1158. {
  1159.     // Style change?
  1160.     if (nStyle != m_nCurrentStyle)
  1161.     {
  1162.     HFONT hOldFont;
  1163.  
  1164.         ::EnterCriticalSection( &m_cScrnCriticalSection );
  1165.  
  1166.         CDC *pDC = GetDC();
  1167.  
  1168.         // Set current style
  1169.         hOldFont = SetStyle( pDC, nStyle );
  1170.  
  1171.         // Select previous font into device context
  1172.         pDC->SelectObject( hOldFont );
  1173.  
  1174.         // Release device context
  1175.         ReleaseDC( pDC );
  1176.  
  1177.         ::LeaveCriticalSection( &m_cScrnCriticalSection );
  1178.     }
  1179. }
  1180.  
  1181. // Sets the current text colour
  1182. void CFrotzCEView::SetTextColour( int nFgCol, int nBkCol )
  1183. {
  1184. BYTE nColour = 0;
  1185.  
  1186.     // Use colours?
  1187.     if (m_bUseColours)
  1188.     {
  1189.         // Map foreground colour
  1190.         switch (nFgCol)
  1191.         {
  1192.             case WHITE_COLOUR:
  1193.                 nColour = PALLETTE_WHITE;
  1194.                 break;
  1195.             case GREY_COLOUR:
  1196.             case RED_COLOUR:
  1197.             case GREEN_COLOUR:
  1198.             case BLUE_COLOUR:
  1199.                 nColour = PALLETTE_DARKGREY;
  1200.                 break;
  1201.             case MEDIUMGREY_COLOUR:
  1202.             case YELLOW_COLOUR:
  1203.             case MAGENTA_COLOUR:
  1204.             case CYAN_COLOUR:
  1205.                 nColour = PALLETTE_LIGHTGREY;
  1206.                 break;
  1207.             case DARKGREY_COLOUR:
  1208.             case BLACK_COLOUR:
  1209.             case 0:
  1210.             default:
  1211.                 nColour = PALLETTE_BLACK;
  1212.                 break;
  1213.         }
  1214.  
  1215.         // Map background colour
  1216.         switch (nBkCol)
  1217.         {
  1218.             case WHITE_COLOUR:
  1219.             case 0:
  1220.                 nColour |= (PALLETTE_WHITE<<2);
  1221.                 break;
  1222.             case GREY_COLOUR:
  1223.             case RED_COLOUR:
  1224.             case GREEN_COLOUR:
  1225.             case BLUE_COLOUR:
  1226.                 nColour |= (PALLETTE_DARKGREY<<2);
  1227.                 break;
  1228.             case MEDIUMGREY_COLOUR:
  1229.             case YELLOW_COLOUR:
  1230.             case MAGENTA_COLOUR:
  1231.             case CYAN_COLOUR:
  1232.                 nColour |= (PALLETTE_LIGHTGREY<<2);
  1233.                 break;
  1234.             case DARKGREY_COLOUR:
  1235.             case BLACK_COLOUR:
  1236.             default:
  1237.                 nColour |= (PALLETTE_BLACK<<2);
  1238.                 break;
  1239.         }
  1240.     }
  1241.     else nColour = DEF_TEXT_COLOUR;
  1242.  
  1243.     ::EnterCriticalSection( &m_cScrnCriticalSection );
  1244.  
  1245.     // Colour change?
  1246.     if (nColour != m_nCurrentColour)
  1247.     {
  1248.     CDC *pDC = GetDC();
  1249.  
  1250.         // Set current colour
  1251.         SetColour( pDC, nColour );
  1252.  
  1253.         // Release device context
  1254.         ReleaseDC( pDC );
  1255.     }
  1256.  
  1257.     ::LeaveCriticalSection( &m_cScrnCriticalSection );
  1258. }
  1259.  
  1260. void CFrotzCEView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
  1261. {
  1262.     // Expecting input?
  1263.     if (m_bExpectingInput)
  1264.     {
  1265.         ::EnterCriticalSection( &m_cKbdCriticalSection );
  1266.  
  1267.         // Add key to buffer
  1268.         *m_pcWriteKeyBuffer = nChar;
  1269.         m_pcWriteKeyBuffer++;
  1270.  
  1271.         // Gone past end of buffer?
  1272.         if (m_pcWriteKeyBuffer > &m_acKeyBuffer[KEYBUFFER_SIZE-1])
  1273.         {
  1274.             // Go back to beginning of buffer
  1275.             m_pcWriteKeyBuffer = &m_acKeyBuffer[0];
  1276.         }
  1277.  
  1278.         ::LeaveCriticalSection( &m_cKbdCriticalSection );
  1279.  
  1280.         // Signal that a keypress event has occurred
  1281.         ::SetEvent( m_hKeyEvent );
  1282.     }
  1283.     else CView::OnChar( nChar, nRepCnt, nFlags);
  1284. }
  1285.  
  1286. void CFrotzCEView::OnSysChar(UINT nChar, UINT nRepCnt, UINT nFlags)
  1287. {
  1288.     // Expecting input?
  1289.     if (m_bExpectingInput)
  1290.     {
  1291.         // Alt key pressed?
  1292.         if ((nFlags & (1 << 13)) != 0)
  1293.         {
  1294.         int ch;
  1295.  
  1296.             // Check for special keys
  1297.             switch (nChar)
  1298.             {
  1299.             case 'H':
  1300.             case 'h':
  1301.                 ch = HOT_KEY_HELP;
  1302.                 break;
  1303.  
  1304.             case 'D':            
  1305.             case 'd':
  1306.                 ch = HOT_KEY_DEBUGGING;
  1307.                 break;
  1308.  
  1309.             case 'N':            
  1310.             case 'n':
  1311.                 ch = HOT_KEY_RESTART;
  1312.                 break;
  1313.  
  1314.             case 'P':            
  1315.             case 'p':
  1316.                 ch = HOT_KEY_PLAYBACK;
  1317.                 break;
  1318.  
  1319.             case 'R':            
  1320.             case 'r':
  1321.                 ch = HOT_KEY_RECORDING;
  1322.                 break;
  1323.  
  1324.             case 'S':            
  1325.             case 's':
  1326.                 ch = HOT_KEY_SEED;
  1327.                 break;
  1328.             
  1329.             case 'U':            
  1330.             case 'u':
  1331.                 ch = HOT_KEY_UNDO;
  1332.                 break;
  1333.  
  1334.             case 'X':
  1335.             case 'x':
  1336.                 ch = HOT_KEY_QUIT;
  1337.                 break;
  1338.  
  1339.             default:
  1340.                 ch = 0;
  1341.                 break;
  1342.             }
  1343.  
  1344.             // Got anything?
  1345.             if (ch)
  1346.             {
  1347.                 ::EnterCriticalSection( &m_cKbdCriticalSection );
  1348.  
  1349.                 // Add hotkey to buffer
  1350.                 *m_pcWriteKeyBuffer = ch;
  1351.                 m_pcWriteKeyBuffer++;
  1352.  
  1353.                 // Gone past end of buffer?
  1354.                 if (m_pcWriteKeyBuffer > &m_acKeyBuffer[KEYBUFFER_SIZE-1])
  1355.                 {
  1356.                     // Go back to beginning of buffer
  1357.                     m_pcWriteKeyBuffer = &m_acKeyBuffer[0];
  1358.                 }
  1359.  
  1360.                 ::LeaveCriticalSection( &m_cKbdCriticalSection );
  1361.  
  1362.                 // Signal that a keypress event has occurred
  1363.                 ::SetEvent( m_hKeyEvent );
  1364.             }
  1365.             else CView::OnSysChar( nChar, nRepCnt, nFlags );
  1366.         }
  1367.     }
  1368.     else CView::OnSysChar( nChar, nRepCnt, nFlags );
  1369. }
  1370.  
  1371. void CFrotzCEView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
  1372. {
  1373.     // Expecting input?
  1374.     if (m_bExpectingInput)
  1375.     {
  1376.     int ch;
  1377.  
  1378.         // Check for recognised keys
  1379.         switch (nChar)
  1380.         {
  1381.         // Left arrow
  1382.         case 37:
  1383.             ch = LEFT_ARROW_KEY;
  1384.             break;
  1385.         // Right arrow
  1386.         case 39:
  1387.             ch = RIGHT_ARROW_KEY;
  1388.             break;
  1389.         // Up arrow
  1390.         case 38:
  1391.             ch = UP_ARROW_KEY;
  1392.             break;
  1393.         // Down arrow
  1394.         case 40:
  1395.             ch = DOWN_ARROW_KEY;
  1396.             break;
  1397.         // Page up
  1398.         case 33:
  1399.             ch = SPECIAL_KEY_PAGE_UP;
  1400.             break;
  1401.         // Page down
  1402.         case 34:
  1403.             ch = SPECIAL_KEY_PAGE_DOWN;
  1404.             break;
  1405.         // Home
  1406.         case 36:
  1407.             ch = SPECIAL_KEY_HOME;
  1408.             break;
  1409.         // End
  1410.         case 35:
  1411.             ch = SPECIAL_KEY_END;
  1412.             break;
  1413.         // Del
  1414.         case 46:
  1415.             ch = SPECIAL_KEY_DELETE;
  1416.             break;
  1417.         // Insert
  1418.         case 45:
  1419.             ch = SPECIAL_KEY_INSERT;
  1420.             break;
  1421.         default:
  1422.             ch = 0;
  1423.             break;
  1424.         }
  1425.  
  1426.         // Got anything?
  1427.         if (ch)
  1428.         {
  1429.             ::EnterCriticalSection( &m_cKbdCriticalSection );
  1430.  
  1431.             // Add hotkey to buffer
  1432.             *m_pcWriteKeyBuffer = ch;
  1433.             m_pcWriteKeyBuffer++;
  1434.  
  1435.             // Gone past end of buffer?
  1436.             if (m_pcWriteKeyBuffer > &m_acKeyBuffer[KEYBUFFER_SIZE-1])
  1437.             {
  1438.                 // Go back to beginning of buffer
  1439.                 m_pcWriteKeyBuffer = &m_acKeyBuffer[0];
  1440.             }
  1441.  
  1442.             ::LeaveCriticalSection( &m_cKbdCriticalSection );
  1443.  
  1444.             // Signal that a keypress event has occurred
  1445.             ::SetEvent( m_hKeyEvent );
  1446.         }
  1447.         else CView::OnKeyDown(nChar, nRepCnt, nFlags);
  1448.     }
  1449.     else CView::OnKeyDown(nChar, nRepCnt, nFlags);
  1450. }
  1451.  
  1452. void CFrotzCEView::StuffKeyboard( const char *pchChars, BOOL bReturn, BOOL bEsc )
  1453. {
  1454.     ::EnterCriticalSection( &m_cKbdCriticalSection );
  1455.  
  1456.     // Clear input first?
  1457.     if (bEsc)
  1458.     {
  1459.         // Add ESC key to buffer
  1460.         *m_pcWriteKeyBuffer = ESC_KEY;
  1461.         m_pcWriteKeyBuffer++;
  1462.  
  1463.         // Gone past end of buffer?
  1464.         if (m_pcWriteKeyBuffer > &m_acKeyBuffer[KEYBUFFER_SIZE-1])
  1465.         {
  1466.             // Go back to beginning of buffer
  1467.             m_pcWriteKeyBuffer = &m_acKeyBuffer[0];
  1468.         }
  1469.     }
  1470.  
  1471.     // Stuff chars into buffer
  1472.     while (*pchChars)
  1473.     {
  1474.         // Add char to buffer
  1475.         *m_pcWriteKeyBuffer = (int) *pchChars;
  1476.         pchChars++;
  1477.         m_pcWriteKeyBuffer++;
  1478.  
  1479.         // Gone past end of buffer?
  1480.         if (m_pcWriteKeyBuffer > &m_acKeyBuffer[KEYBUFFER_SIZE-1])
  1481.         {
  1482.             // Go back to beginning of buffer
  1483.             m_pcWriteKeyBuffer = &m_acKeyBuffer[0];
  1484.         }
  1485.     }
  1486.  
  1487.     // Want a return?
  1488.     if (bReturn)
  1489.     {
  1490.         // Add return key to buffer
  1491.         *m_pcWriteKeyBuffer = ENTER_KEY;
  1492.         m_pcWriteKeyBuffer++;
  1493.  
  1494.         // Gone past end of buffer?
  1495.         if (m_pcWriteKeyBuffer > &m_acKeyBuffer[KEYBUFFER_SIZE-1])
  1496.         {
  1497.             // Go back to beginning of buffer
  1498.             m_pcWriteKeyBuffer = &m_acKeyBuffer[0];
  1499.         }
  1500.     }
  1501.  
  1502.     ::LeaveCriticalSection( &m_cKbdCriticalSection );
  1503.  
  1504.     // Signal that a keypress event has occurred
  1505.     ::SetEvent( m_hKeyEvent );
  1506. }
  1507.  
  1508. void CFrotzCEView::OnRestore() 
  1509. {
  1510.     if (m_bExpectingInput) StuffKeyboard( "Restore", TRUE, TRUE );
  1511. }
  1512.  
  1513. void CFrotzCEView::OnSave() 
  1514. {
  1515.     if (m_bExpectingInput) StuffKeyboard( "Save", TRUE, TRUE );
  1516. }
  1517.  
  1518. void CFrotzCEView::OnUndo() 
  1519. {
  1520.     // Expecting input?
  1521.     if (m_bExpectingInput)
  1522.     {
  1523.         ::EnterCriticalSection( &m_cKbdCriticalSection );
  1524.  
  1525.         // Add char to buffer
  1526.         *m_pcWriteKeyBuffer = HOT_KEY_UNDO;
  1527.         m_pcWriteKeyBuffer++;
  1528.  
  1529.         // Gone past end of buffer?
  1530.         if (m_pcWriteKeyBuffer > &m_acKeyBuffer[KEYBUFFER_SIZE-1])
  1531.         {
  1532.             // Go back to beginning of buffer
  1533.             m_pcWriteKeyBuffer = &m_acKeyBuffer[0];
  1534.         }
  1535.  
  1536.         ::LeaveCriticalSection( &m_cKbdCriticalSection );
  1537.  
  1538.         // Signal that a keypress event has occurred
  1539.         ::SetEvent( m_hKeyEvent );
  1540.     }
  1541. }
  1542.  
  1543. void CFrotzCEView::OnDown() 
  1544. {
  1545.     if (m_bExpectingInput) StuffKeyboard( "Down", TRUE, TRUE );
  1546. }
  1547.  
  1548. void CFrotzCEView::OnEast() 
  1549. {
  1550.     if (m_bExpectingInput) 
  1551.     {
  1552.     BOOL bReturn = (m_nState == STATE_MOVING);
  1553.  
  1554.         m_nState = STATE_MOVING;
  1555.  
  1556.         StuffKeyboard( "East", bReturn );
  1557.     }
  1558. }
  1559.  
  1560. void CFrotzCEView::OnInventory() 
  1561. {
  1562.     if (m_bExpectingInput) StuffKeyboard( "Inventory", TRUE, TRUE );
  1563. }
  1564.  
  1565. void CFrotzCEView::OnLook() 
  1566. {
  1567.     if (m_bExpectingInput) 
  1568.     {
  1569.         m_nState = STATE_LOOKING;
  1570.  
  1571.         StuffKeyboard( "Look", FALSE, TRUE );
  1572.     }
  1573. }
  1574.  
  1575. void CFrotzCEView::OnOpen() 
  1576. {
  1577.     if (m_bExpectingInput) 
  1578.     {
  1579.         m_nState = STATE_OPENING;
  1580.  
  1581.         StuffKeyboard( "Open ", FALSE, TRUE );
  1582.     }
  1583. }
  1584.  
  1585. void CFrotzCEView::OnNorth() 
  1586. {
  1587.     if (m_bExpectingInput) 
  1588.     {
  1589.         m_nState = STATE_MOVING;
  1590.  
  1591.         StuffKeyboard( "North", FALSE, TRUE );
  1592.     }
  1593. }
  1594.  
  1595. void CFrotzCEView::OnSouth() 
  1596. {
  1597.     if (m_bExpectingInput) 
  1598.     {
  1599.         m_nState = STATE_MOVING;
  1600.  
  1601.         StuffKeyboard( "South", FALSE, TRUE );
  1602.     }
  1603. }
  1604.  
  1605. void CFrotzCEView::OnTake() 
  1606. {
  1607.     if (m_bExpectingInput) 
  1608.     {
  1609.         m_nState = STATE_TAKING;
  1610.  
  1611.         StuffKeyboard( "Take ", FALSE, TRUE );
  1612.     }
  1613. }
  1614.  
  1615. void CFrotzCEView::OnDrop() 
  1616. {
  1617.     if (m_bExpectingInput) 
  1618.     {
  1619.         m_nState = STATE_TAKING;
  1620.  
  1621.         StuffKeyboard( "Drop ", FALSE, TRUE );
  1622.     }
  1623. }
  1624.  
  1625. void CFrotzCEView::OnGo() 
  1626. {
  1627.     if (m_bExpectingInput) 
  1628.     {
  1629.         m_nState = STATE_GOING;
  1630.  
  1631.         StuffKeyboard( "Go to ", FALSE, TRUE );
  1632.     }
  1633. }
  1634.  
  1635. void CFrotzCEView::OnUp() 
  1636. {
  1637.     if (m_bExpectingInput) StuffKeyboard( "Up", TRUE, TRUE );
  1638. }
  1639.  
  1640. void CFrotzCEView::OnWest() 
  1641. {
  1642.     if (m_bExpectingInput) 
  1643.     {
  1644.     BOOL bReturn = (m_nState == STATE_MOVING);
  1645.  
  1646.         m_nState = STATE_MOVING;
  1647.  
  1648.         StuffKeyboard( "West", bReturn );
  1649.     }
  1650. }
  1651.  
  1652. void CFrotzCEView::OnLButtonDown(UINT nFlags, CPoint point) 
  1653. {
  1654.     // Expecting input?
  1655.     if (m_bExpectingInput) 
  1656.     {
  1657.     int nCharRow, nCharCol;
  1658.     char *pszBuffer = new char[m_nWidth+1];
  1659.     int i = 0;
  1660.     BOOL bReturn = TRUE;
  1661.  
  1662.         // Calculate char position
  1663.         nCharRow = point.y / m_nCharHeight;
  1664.         nCharCol = point.x / m_nCharWidth;
  1665.  
  1666.         // Go backwards until beginning of word
  1667.         while (nCharCol)
  1668.         {
  1669.             if (m_pScreen[(nCharRow * m_nWidth) + nCharCol-1] != _T(' ')) nCharCol--;
  1670.             else break;
  1671.         }
  1672.  
  1673.         // Valid row?
  1674.         if (nCharRow < m_nHeight)
  1675.         {
  1676.             // Copy word to buffer
  1677.             for (; nCharCol < m_nWidth; i++)
  1678.             {
  1679.                 pszBuffer[i] = (char) m_pScreen[(nCharRow * m_nWidth) + nCharCol + i];
  1680.  
  1681.                 if (pszBuffer[i] == ' ') break;
  1682.             }
  1683.         }
  1684.  
  1685.         pszBuffer[i] = '\0';
  1686.  
  1687.         // Check current state
  1688.         switch (m_nState)
  1689.         {
  1690.         case STATE_NONE:
  1691.             if (strlen( pszBuffer )) bReturn = FALSE;
  1692.             break;
  1693.         case STATE_LOOKING:
  1694.             if (strlen( pszBuffer )) StuffKeyboard( " at ", FALSE );
  1695.             break;
  1696.         case STATE_TAKING:
  1697.             if (!strlen( pszBuffer )) StuffKeyboard( "all", FALSE );
  1698.             break;
  1699.         case STATE_OPENING:
  1700.             if (!strlen( pszBuffer )) StuffKeyboard( "Door", FALSE );
  1701.             break;
  1702.         case STATE_MOVING:
  1703.             pszBuffer[0] = '\0';
  1704.             break;
  1705.         }
  1706.  
  1707.         // Copy buffer into keyboard buffer
  1708.         StuffKeyboard( pszBuffer, bReturn );
  1709.  
  1710.         // Add a space if we're not adding a return
  1711.         if (!bReturn) StuffKeyboard( " ", FALSE );
  1712.  
  1713.         delete [] pszBuffer;
  1714.     }
  1715.  
  1716.     CView::OnLButtonDown(nFlags, point);
  1717. }
  1718.  
  1719. void CFrotzCEView::OnQuit() 
  1720. {
  1721.     // Expecting input?
  1722.     if (m_bExpectingInput) 
  1723.     {
  1724.         ::EnterCriticalSection( &m_cKbdCriticalSection );
  1725.  
  1726.         // Add hotkey to buffer
  1727.         *m_pcWriteKeyBuffer = HOT_KEY_QUIT;
  1728.         m_pcWriteKeyBuffer++;
  1729.  
  1730.         // Gone past end of buffer?
  1731.         if (m_pcWriteKeyBuffer > &m_acKeyBuffer[KEYBUFFER_SIZE-1])
  1732.         {
  1733.             // Go back to beginning of buffer
  1734.             m_pcWriteKeyBuffer = &m_acKeyBuffer[0];
  1735.         }
  1736.  
  1737.         ::LeaveCriticalSection( &m_cKbdCriticalSection );
  1738.  
  1739.         // Signal that a keypress event has occurred
  1740.         ::SetEvent( m_hKeyEvent );
  1741.     }
  1742. }
  1743.  
  1744. void CFrotzCEView::OnTimer(UINT nIDEvent) 
  1745. {
  1746.     // Need to do a refresh?
  1747.     if (m_bRedraw)
  1748.     {
  1749.         // Using text styles?
  1750.         if (m_bUseStyles)
  1751.         {
  1752.             // Invalidate and clear client area
  1753.              Invalidate( TRUE );
  1754.         }
  1755.         else
  1756.         {
  1757.             // Invalidate client area
  1758.              Invalidate( FALSE );
  1759.         }
  1760.  
  1761.         // Flag that refresh has been done
  1762.         m_bRedraw = FALSE;
  1763.     }
  1764. }
  1765.