// This file is part of the Noddybox.Emulation C# suite.
//
// Noddybox.Emulation is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Noddybox.Emulation is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Noddybox.Emulation. If not, see .
//
// Copyright (c) 2012 Ian Cowburn
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Noddybox.Emulation.Keyboard.Schema;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input.Touch;
namespace Noddybox.Emulation.Xna.Keyboard
{
///
/// Displays and drives the keyboard.
///
/// The enumerated type matching the symbols in the used keyboard definition.
public class KeyboardDriver where T: struct,IConvertible
{
#region Event arguments
///
/// Event data when a key is pressed or released.
///
public class KeyPressEventArgs : EventArgs
{
///
/// The key that was pressed.
///
public T Key {get;set;}
///
/// True if the key was pressed. False if released.
///
public bool Pressed {get; set;}
}
///
/// Event data when the screen is touched away from a key.
///
public class TouchLocationEventArgs : EventArgs
{
///
/// The touch.
///
public TouchLocation Location {get; set;}
}
#endregion
#region Private data
private class KeyState
{
public T Symbol {get;set;}
public bool IsPressed {get; set;}
public bool IsSticky {get; set;}
public int TouchId {get; set;}
}
private Rectangle[] keymapPos;
private KeyState[] keymapState;
private int keymapSize;
private KeyboardDefinition keyboard;
private Texture2D image;
private Vector2 position;
private Texture2D overlay;
#endregion
#region Private members
#endregion
#region Public members
///
/// Updates the keyboard. Note that this will consume all the key press events.
///
public void Update()
{
foreach (TouchLocation t in TouchPanel.GetState())
{
int x = (int)t.Position.X;
int y = (int)t.Position.Y;
int f = 0;
KeyState key = null;
if (t.State == TouchLocationState.Pressed)
{
for(f = 0; f < keymapSize && key == null; f++)
{
if (keymapPos[f].Contains(x, y))
{
key = keymapState[f];
}
}
if (key != null)
{
key.TouchId = t.Id;
if (key.IsSticky)
{
key.IsPressed = !key.IsPressed;
}
else
{
key.IsPressed = true;
}
if (KeyEvent != null)
{
KeyEvent(this, new KeyPressEventArgs() {Key = key.Symbol, Pressed = key.IsPressed});
}
}
}
else if (t.State == TouchLocationState.Released)
{
for(f = 0; f < keymapSize && key == null; f++)
{
if (keymapState[f].TouchId == t.Id)
{
key = keymapState[f];
}
}
if (key != null)
{
if (!key.IsSticky)
{
key.IsPressed = false;
if (KeyEvent != null)
{
KeyEvent(this, new KeyPressEventArgs() {Key = key.Symbol, Pressed = key.IsPressed});
}
}
}
}
// If no key handled, pass on the event
//
if (key == null && keymapState.Where(r => r.TouchId == t.Id).Count() == 0)
{
if (TouchEvent != null)
{
TouchEvent(this, new TouchLocationEventArgs() {Location = t});
}
}
}
}
///
/// Draw the keyboard
///
///
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(image, position, Color.White);
for(int f = 0; f < keymapSize; f++)
{
if (keymapState[f].IsPressed)
{
spriteBatch.Draw(overlay, keymapPos[f], new Color(200, 200, 0, 25));
}
}
}
#endregion
#region Events
public EventHandler KeyEvent;
public EventHandler TouchEvent;
#endregion
#region Constructors
///
/// Constructor.
///
/// The graphics device to associate textures with.
/// The image for the keyboard.
/// Where to draw and offset the keyboard to.
/// The keyboard to drive this from.
public KeyboardDriver(GraphicsDevice graphics, Texture2D image, Vector2 position, KeyboardDefinition keyboard)
{
this.keyboard = keyboard;
this.image = image;
this.position = position;
keymapSize = keyboard.Definitions.Count;
keymapPos = new Rectangle[keymapSize];
keymapState = new KeyState[keymapSize];
for(int f = 0; f < keymapSize; f++)
{
KeyboardKey k = keyboard.Definitions[f];
keymapPos[f] = new Rectangle(k.X, k.Y, k.Width, k.Height);
keymapState[f] = new KeyState()
{
Symbol = (T)Enum.Parse(typeof(T), k.KeySymbol, false),
IsPressed = false,
IsSticky = k.Sticky
};
}
Color c = Color.White;
overlay = new Texture2D(graphics, 2, 2, false, SurfaceFormat.Color);
overlay.SetData(new Color[] {c, c, c, c});
}
#endregion
}
}