Listing 1. The Control source code


using System;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;

namespace KeyProcessor
{
  public class WhiteBoard: UserControl
  {
    private int rowCount = 10;
    private int columnCount = 10;
    private char[,] board;
    private int characterWidth = 10;
    private int characterHeight = 14;
    private int lineSpace = 3;
    public Color foreColor = Color.Black;
    private Thread caretThread;
    private bool caretVisible = true;
    private int caretX, caretY;
    private int penWidth = 2;
    private Pen pen;
    
    public WhiteBoard()
    {
      board = new char[columnCount, rowCount];
      //initialize characters
      for (int i=0; i
		<columnCount; i++)
      {
        for (int j=0; j<rowCount; j++)
        {
          board[i, j] =' '; 
        }
      }
      pen = new Pen(foreColor, penWidth);
      this.BackColor = Color.White;
      this.KeyPress += new KeyPressEventHandler(KeyPressed);

      caretThread = new Thread(new ThreadStart(ShowCaret));
      caretThread.Start();
		}

    void ShowCaret()
    {
      try 
      {
        while (true) 
        {
          this.Invalidate( new 
            Rectangle(caretX * characterWidth, caretY * (characterHeight + lineSpace),
            caretX * characterWidth + 2 * penWidth, (caretY +1) * (characterHeight + 
lineSpace)));
          this.Update();					
          Thread.Sleep(350);
          caretVisible = !caretVisible;
        }
      } 
      catch (Exception) 
      {
      }
    }
		
    protected override void OnPaint(PaintEventArgs e)
    {
      Graphics graphics = e.Graphics;
      Font font = new Font("Courier new", characterWidth);
      Brush brush = new SolidBrush(foreColor);
      for (int i=0; i<rowCount; i++) 
      {
        for (int j=0; j<columnCount; j++)
        {
          graphics.DrawString(board[i, j].ToString(), font, brush, 
            new Point(i*characterWidth, j*(lineSpace+characterHeight)));
        }
      }
      //draw caret here;
      if (caretVisible)
      {
        int x = caretX * characterWidth;
        int y = caretY * (lineSpace + characterHeight);
        graphics.DrawLine(pen, x, y, x, y + lineSpace + characterHeight);
      }
    }

    private void KeyPressed(object sender, KeyPressEventArgs e)
    {
      char c = e.KeyChar;
      int i = (int) c;
      if (i==8)
      {
        if (caretX==0)
        {
          caretX = columnCount - 1;
          caretY--;
          if (caretY <0)
            caretY = rowCount - 1;
        }
        else
        {
          caretX--;
        }
        board[caretX, caretY] = ' ';
      }
      else 
      {
        board[caretX, caretY] = c;
        caretX++;
        if (caretX == columnCount) 
        {
          caretX = 0;
          caretY++;
          if(caretY== rowCount)
            caretY = 0;
        }
      }
      this.Invalidate();
      this.Update();
    }

    protected override void Dispose(bool disposing)
    {
      if (disposing) {
        caretThread.Abort();
      }
      base.Dispose(disposing);
    }
  }
}