title: Simulate animation with bitmap changes
body: <p>I have a bitmap of a keyboard layout that I have 'image mapped' into sections, so I can determine what 'key' has been clicked by mapping it to the overall bitmap.</p>
  
  <p>Once the 'key' has been determined, I would like to shrink the area (by a few pixels) occupied by the key and paint a reduced sized image onto the bitmap to simulate a <code>keydown</code> action. When the key is released the original image area should be restored.</p>
  
  <p>I need to do this in C# for NET 4.0, can anyone give me some pointers?</p>
  
  <p>Here is the code I have so far:</p>
  
  <pre><code>//--- Private helper class.
  private class ImageMap
  {
    public ImageMap(System.Drawing.Rectangle areaTeclaNormal, System.Windows.Forms.Keys key, string textString, System.Drawing.Rectangle areaTeclaPulsada)
    {
      AreaTeclaNormal = areaTeclaNormal;
      Key = key;
      TextString = textString;
      BitmapTeclaNormal = getBitmapFrom(MapaTecladoNormal, areaTeclaNormal);
      BitmapTeclaPulsada = getBitmapFrom(MapaTecladoPulsado, areaTeclaPulsada);
    }
  
    public System.Drawing.Rectangle AreaTeclaNormal { get; private set; }
    public System.Windows.Forms.Keys Key { get; private set; }
    public string TextString { get; private set; }
    public System.Drawing.Bitmap BitmapTeclaNormal { get; private set; }
    public System.Drawing.Bitmap BitmapTeclaPulsada { get; private set; }
    public bool? IsTeclaPulsada { get; set; }
    public static System.Drawing.Bitmap MapaTecladoNormal { get; set; }
    public static System.Drawing.Bitmap MapaTecladoPulsado { get; set; }
  
    private static System.Drawing.Bitmap getBitmapFrom(System.Drawing.Bitmap bmTecladoPulsado, System.Drawing.Rectangle rectangle)
    {
      return bmTecladoPulsado.Clone(rectangle, bmTecladoPulsado.PixelFormat);
    }
  }
  
  
  //--- This is a class member to store the list of maps.
  private readonly List&lt;ImageMap&gt; listaImageMaps = new List&lt;ImageMap&gt;();
  
  //--- Inside my c'tor.
  listaImageMaps.Add(new ImageMap(new System.Drawing.Rectangle(3, 187, 60, 60), System.Windows.Forms.Keys.NumPad1, "1", new System.Drawing.Rectangle(3, 174, 56, 56)));
  listaImageMaps.Add(new ImageMap(new System.Drawing.Rectangle(64, 187, 60, 60), System.Windows.Forms.Keys.NumPad2, "2", new System.Drawing.Rectangle(60, 174, 56, 56)));
  listaImageMaps.Add(new ImageMap(new System.Drawing.Rectangle(124, 187, 60, 60), System.Windows.Forms.Keys.NumPad3, "3", new System.Drawing.Rectangle(116, 174, 56, 56)));
  
  //--- Eventa handlers
  private void editImage_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
  {
    ImageMap imageMap = listaImageMaps.Find(item =&gt; item.AreaTeclaNormal.IntersectsWith(new System.Drawing.Rectangle(e.X, e.Y, 1, 1)));
    if(imageMap != null)
    {
      imageMap.IsTeclaPulsada = true;
      editImage.Update();
    }
  }
  
  private void editImage_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
  {
    ImageMap imageMap = listaImageMaps.Find(item =&gt; item.IsTeclaPulsada.HasValue &amp;&amp; item.IsTeclaPulsada == true);
    if(imageMap != null)
    {
      imageMap.IsTeclaPulsada = false;
      editImage.Update();
    }
  }
  
  private void editImage_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
  {
    ImageMap imageMap = listaImageMaps.Find(item =&gt; item.IsTeclaPulsada.HasValue);
    if(imageMap != null)
    {
      if(imageMap.IsTeclaPulsada == true)
      {
        e.Graphics.DrawImage(imageMap.BitmapTeclaPulsada, imageMap.AreaTeclaNormal.Left + 2, imageMap.AreaTeclaNormal.Top + 2, imageMap.BitmapTeclaPulsada.Width, imageMap.BitmapTeclaPulsada.Height);
      }
      else
      {
        e.Graphics.DrawImage(imageMap.BitmapTeclaNormal, imageMap.AreaTeclaNormal.Left, imageMap.AreaTeclaNormal.Top, imageMap.BitmapTeclaNormal.Width, imageMap.BitmapTeclaNormal.Height);
        imageMap.IsTeclaPulsada = null;
      }
    }
  }
  </code></pre>
  
  <p>The ImageMap helper class is used to define the different regions within the main bitmap, it defines the area occupied and the non-pressed key image and the pressed key image.</p>
  
  <p>I use the nullable IsTeclaPulsada property to indicate if any painting is needed: True = paint the pressed key image, False = paint the normal key image and Null = requieres no processing.</p>
  
  <p>I use the MouseDown and MouseUp events to trigger the process and the Paint event to paint the required key state regions.</p>
  
  <p>The first event (MouseDown) paints the pressed image, but when the MouseUp has triggered the painting event does not paint the unpressed image straight away (it take several seconds!)</p>