// 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.Input.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;} } #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 InputManager manager; private Rectangle[] keymapPos; private KeyState[] keymapState; private int keymapSize; private KeyboardDefinition keyboard; private Texture2D image; private Vector2 position; private Texture2D overlay; private bool subscribed; #endregion #region Private members /// /// Updates the keyboard. /// public void TouchScreenHandler(object sender, InputManager.TouchLocationEventArgs e) { int x = (int)e.Location.Position.X; int y = (int)e.Location.Position.Y; int f = 0; KeyState key = null; if (e.Location.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 = e.Location.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 (e.Location.State == TouchLocationState.Released) { for(f = 0; f < keymapSize && key == null; f++) { if (keymapState[f].TouchId == e.Location.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}); } } } } // Check if input was used. // if (key != null || keymapState.Where(r => r.TouchId == e.Location.Id).Count() > 0) { e.Handled = true; } } #endregion #region Public members /// /// Stops consuming inputs and releases all keys. /// /// Generates events for cleared keys. public void StopKeyboardUpdates(bool generateEvents) { if (subscribed) { manager.TouchEvent -= TouchScreenHandler; subscribed = false; foreach (KeyState key in keymapState) { if (key.IsPressed) { key.IsPressed = false; if (generateEvents && KeyEvent != null) { KeyEvent(this, new KeyPressEventArgs() {Key = key.Symbol, Pressed = key.IsPressed}); } } } } } /// /// Stops consuming inputs and releases all keys. Generates events for released keys. /// public void StopKeyboardUpdates() { StopKeyboardUpdates(true); } /// /// Starts consuming inputs. /// public void StartKeyboardUpdates() { if (!subscribed) { manager.TouchEvent += TouchScreenHandler; subscribed = true; } } /// /// 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; #endregion #region Constructors /// /// Constructor. /// /// The input manager to attached to. /// 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(InputManager manager, GraphicsDevice graphics, Texture2D image, Vector2 position, KeyboardDefinition keyboard) { this.manager = manager; this.keyboard = keyboard; this.image = image; this.position = position; this.subscribed = false; 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((int)position.X + k.X, (int)position.Y + 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}); StartKeyboardUpdates(); } #endregion } }