using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Collections;
using System.Runtime.InteropServices;
using DevComponents.DotNetBar.Touch;
namespace DevComponents.DotNetBar.Keyboard
{
    /// 
    /// Represents virtual keyboard control.
    /// 
    [ToolboxItem(true)]
    public class KeyboardControl : Control
    {
        private TouchHandler _TouchHandler = null;
        /// 
        /// Creates a new VirtualKeyboard control.
        /// 
        public KeyboardControl()
        {
            _ColorTable = _DefaultColorTable;
            // Do not allow the control to receive focus.
            SetStyle(ControlStyles.Selectable, false);
            // Do not call OnPaintBackground().
            SetStyle(ControlStyles.Opaque, true);
            // Enable double buffering. OptimizedDoubleBuffer and AllPaintingInWmPaint are set by the DoubleBuffered property below.
            //SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            //SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            DoubleBuffered = true;
            ResizeRedraw = true;
            _RepeatTimer = new Timer();
            _RepeatTimer.Tick += new EventHandler(RepeatTimer_Tick);
        }
        // The model for the Keyboard. This object contains all the information about the keys
        // and the possible layouts of the keyboard.
        private Keyboard _Keyboard = null; //Keyboard.CreateDefaultKeyboard();
        /// 
        /// Gets or sets the Keyboard object that describes the VirtualKeyboard.
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Keyboard Keyboard
        {
            get
            {
                if(_Keyboard==null)
                    _Keyboard = Keyboard.CreateDefaultKeyboard();
                return _Keyboard;
            }
            set { _Keyboard = value; }
        }
        /// 
        /// Default width for the keyboard in pixels.
        /// 
        public static int DefaultWidth
        {
            get { return 740; }
        }
        /// 
        /// Default height for the keyboard in pixels.
        /// 
        public static int DefaultHeight {
            get { return 250; }
        }
        protected override Size DefaultSize
        {
            get
            {
                return Dpi.Size(new Size(DefaultWidth, DefaultHeight));
            }
        }
        private VirtualKeyboardColorTable _DefaultColorTable = new VirtualKeyboardColorTable();
        private VirtualKeyboardColorTable _ColorTable;
        /// 
        /// Gets or set the ColorTable used to draw the keyboard.
        /// 
        public VirtualKeyboardColorTable ColorTable
        {
            get { return _ColorTable; }
            set
            {
                _ColorTable = value;
                Invalidate(); // Ok to invalidate entire control, to render everything with the new colors.
            }
        }
        private Renderer _Renderer = new FlatStyleRenderer();
        /// 
        /// Gets or sets the Renderer used to render the keyboard.
        /// 
        public Renderer Renderer
        {
            get { return _Renderer; }
            set
            {
                if (value == null)
                    value = new FlatStyleRenderer();
                _Renderer = value;
                Invalidate(); // Ok to invalidate entire control, to redraw everything with the new renderer.
            }
        }
        // Through this method, the keys generated by the Virtual Keyboard are sent to the target control.
        // In this version, the current target control is always the control with input focus and the keyboard
        // is only visible when the control (to which the keyboard was previously attached) has input focus.
        // Therefore, SendKeys.Send offers all the logic needed for this version of the keyboard.
        //
        // For future versions, we might consider using the Win32 API SendInput function for greater flexibility.
        private void SendKeysToTarget(string info)
        {
            KeyboardKeyCancelEventArgs cancelArgs = new KeyboardKeyCancelEventArgs(info);
            OnSendingKey(cancelArgs);
            if (cancelArgs.Cancel) return;
            SendKeys.Send(info);
            OnKeySent(new KeyboardKeyEventArgs(info));
        }
        #region Send repeating key if mouse is hold down
        private Timer _RepeatTimer; // Used to send repeated keys to the target control.
        private Key _PressedKey; // Used to keep the keys that is repeatedly sent to the target control.
        private void RepeatTimer_Tick(object sender, EventArgs e)
        {
            if (_PressedKey != null)
            {
                if (_RepeatTimer.Interval == KeyboardDelay)
                    _RepeatTimer.Interval = KeyboardSpeed;
                SendKeysToTarget(_PressedKey.Info);
            }
        }
        private void CancelRepeatKey()
        {
            _PressedKey = null;
            _RepeatTimer.Stop();
        }
        private void StartRepeatKey(Key key)
        {
            _PressedKey = key;
            _RepeatTimer.Start();
            _RepeatTimer.Interval = KeyboardDelay;
        }
        private static int KeyboardDelay
        {
            get
            {
                // SystemInformation.KeyboardDelay is between 0 (2.5 repetitions per second) and 31 (about 30 per second)
                // but these values arre hardware dependendant, so the fomula below is a fast and accurate enough not to feel
                // any difference between this and a real keyboard at the same values.
                return 1000 / (SystemInformation.KeyboardDelay + 1);
            }
        }
        private static int KeyboardSpeed
        {
            get
            {
                // See KeyboardDelay for details.
                return 1000 / (SystemInformation.KeyboardSpeed + 1);
            }
        }
        #endregion
        private bool _IsTopBarVisible = true;
        /// 
        /// Gets or sets a value indicating if the top bar of the keyboard is visible.
        /// 
        [DefaultValue(true)]
        [Description("Indicates if the top bar of  the keyboard is visible.")]
        [Category("Appearance")]
        public bool IsTopBarVisible
        {
            get { return _IsTopBarVisible; }
            set
            {
                _IsTopBarVisible = value;
                this.Invalidate();
            }
        }
        private int _CaptionHeight = 20;
        /// 
        /// Indicates the height of the keyboard caption which hosts the close button.
        /// 
        [DefaultValue(20), Category("Appearance"), Description("Indicates the height of the keyboard caption which hosts the close button.")]
        public int CaptionHeight
        {
            get { return _CaptionHeight; }
            set
            {
                if (value != _CaptionHeight)
                {
                    int oldValue = _CaptionHeight;
                    _CaptionHeight = value;
                    this.Invalidate();
                }
            }
        }
        
        //private const int TopBarHeight = 20;
        private int TopBarVisibleHeight
        {
            get { return IsTopBarVisible ? ActualCaptionHeight + Border : 0; }
        }
        public int Border {
            get { return Dpi.Width10; }
        }
        private readonly Key HideKeyboardKey = new Key("Hide", info: null);
        private int ActualCaptionHeight
        {
            get { return Dpi.Height(_CaptionHeight); }
        }
        private Rectangle TopBarRectangle
        {
            get { return new Rectangle(Border, Border, Width - 2 * Border, ActualCaptionHeight); }
        }
        private Rectangle CloseButtonRectangle
        {
            get { return new Rectangle(Width - ActualCaptionHeight - Border, Border, ActualCaptionHeight, ActualCaptionHeight); }
        }
        private Rectangle KeysRectangle
        {
            get
            {
                Rectangle rect = new Rectangle(Border, Border, Width - 2 * Border, Height - 2 * Border);
                if (IsTopBarVisible)
                {
                    rect.Y += ActualCaptionHeight + Border;
                    rect.Height -= ActualCaptionHeight + Border;
                }
                return rect;
            }
        }
        protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
        {
            Dpi.SetScaling(factor);
            base.ScaleControl(factor, specified);
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            KeyboardLayout currentLayout = Keyboard.CurrentLayout;
            if (currentLayout.LogicalWidth <= 0 || currentLayout.LogicalHeight <= 0)
                return;
            Rectangle rectKeys = KeysRectangle;
            float sfx = (float)rectKeys.Width / currentLayout.LogicalWidth;
            float sfy = (float)rectKeys.Height / currentLayout.LogicalHeight;
            Renderer.ColorTable = ColorTable;
            Renderer.BeginFrame(new BeginFrameRendererEventArgs(e.Graphics, e.ClipRectangle, rectKeys, Font, currentLayout));
            Renderer.DrawBackground(new BackgroundRendererEventArgs(e.Graphics, e.ClipRectangle, new Rectangle(0, 0, Width, Height)));
            if (IsTopBarVisible)
            {
                Renderer.DrawTopBar(new TopBarRendererEventArgs(e.Graphics, e.ClipRectangle, TopBarRectangle, Text, Font));
                Renderer.DrawCloseButton(new CloseButtonRendererEventArgs(e.Graphics, _PressedKey == HideKeyboardKey, e.ClipRectangle, CloseButtonRectangle));
            }
            foreach (Key key in currentLayout.Keys)
            {
                Rectangle rectKey = new Rectangle((int)(key.Bounds.X * sfx), (int)(key.Bounds.Y * sfy),
                    (int)(key.Bounds.Width * sfx), (int)(key.Bounds.Height * sfy));
                rectKey.Offset(rectKeys.Left, rectKeys.Top);
                Renderer.DrawKey(new KeyRendererEventArgs(e.Graphics, key, key == _PressedKey, e.ClipRectangle, rectKey));
            }
            Renderer.EndFrame();
#if TRIAL
            using (Font font = new System.Drawing.Font(this.Font.FontFamily, 7, FontStyle.Regular))
            {
                using (SolidBrush brush = new SolidBrush(Color.FromArgb(24, Color.White)))
                    e.Graphics.DrawString("DotNetBar Trial Version", font, brush, (this.ClientRectangle.Width - 80) / 2, this.ClientRectangle.Height - 32);
            }
#endif
        }
        private void PerformMoveAction(Point location)
        {
            if (IsTopBarVisible && CloseButtonRectangle.Contains(location))
            {
                Cursor = Cursors.Hand;
            }
            else
            {
                KeyboardLayout currentLayout = Keyboard.CurrentLayout;
                Rectangle rectKeys = KeysRectangle;
                float fx = (float)rectKeys.Width / currentLayout.LogicalWidth;
                float fy = (float)rectKeys.Height / currentLayout.LogicalHeight;
                if (_PressedKey == HideKeyboardKey)
                {
                    if (_PressedKey != null)
                    {
                        Invalidate(GetKeyPhysicalBounds(_PressedKey, fx, fy));
                    }
                    _PressedKey = null;
                    Invalidate(CloseButtonRectangle);
                    this.Update();
                }
                Key key = null;
                if (KeysRectangle.Contains(location))
                    key = currentLayout.KeyHitTest((int)((location.X - rectKeys.Left) / fx), (int)((location.Y - rectKeys.Top) / fy));
                // If the mouse is over a key, change the cursor to the Hand cursor, to provide
                // a visual feedback for the user to know that it can interact with this key.
                Key pressedKey = _PressedKey;
                if (key == null)
                {
                    Cursor = Cursors.Arrow;
                    CancelRepeatKey();
                    if (pressedKey != null)
                    {
                        Invalidate(GetKeyPhysicalBounds(pressedKey, fx, fy)); // Only invalidate area under the currently pressed key.
                        this.Update();
                    }
                }
                else if (key != pressedKey)
                {
                    Cursor = Cursors.Hand;
                    CancelRepeatKey();
                    if (pressedKey != null)
                    {
                        Invalidate(GetKeyPhysicalBounds(pressedKey, fx, fy)); // Only invalidate area under the currently pressed key.
                        this.Update();
                    }
                }
                else
                {
                    Cursor = Cursors.Hand;
                }
            }
        }
        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (ProcessMouseAction)
            {
                PerformMoveAction(e.Location);
                _LastTouchAction = null;
            }
            base.OnMouseMove(e);
        }
        protected override void OnMouseLeave(EventArgs e)
        {
            KeyboardLayout currentLayout = Keyboard.CurrentLayout;
            Rectangle rectKeys = KeysRectangle;
            float fx = (float)rectKeys.Width / currentLayout.LogicalWidth;
            float fy = (float)rectKeys.Height / currentLayout.LogicalHeight;
            if (_PressedKey != HideKeyboardKey)
                Invalidate(CloseButtonRectangle);
            else if (_PressedKey != null)
            {
                Invalidate(GetKeyPhysicalBounds(_PressedKey, fx, fy)); // Only invalidate area under the currently pressed key.
                this.Update();
            }
            CancelRepeatKey();
        }
        private bool _TouchEnabled = true;
        /// 
        /// Indicates whether touch support is enabled when provided by hardware.
        /// 
        [DefaultValue(true), Category("Behavior"), Description("Indicates whether touch support is enabled when provided by hardware.")]
        public bool TouchEnabled
        {
            get { return _TouchEnabled; }
            set
            {
                if (value != _TouchEnabled)
                {
                    bool oldValue = _TouchEnabled;
                    _TouchEnabled = value;
                    OnTouchEnabledChanged(oldValue, value);
                }
            }
        }
        /// 
        /// Called when TouchEnabled property has changed.
        /// 
        /// Old property value
        /// New property value
        protected virtual void OnTouchEnabledChanged(bool oldValue, bool newValue)
        {
            //OnPropertyChanged(new PropertyChangedEventArgs("TouchEnabled"));
        }
        protected override void OnHandleCreated(EventArgs e)
        {
            if (TouchHandler.IsTouchEnabled)
            {
                _TouchHandler = new TouchHandler(this, eTouchHandlerType.Touch);
                _TouchHandler.TouchDown += new EventHandler(TouchHandlerTouchDown);
                _TouchHandler.TouchUp += new EventHandler(TouchHandlerTouchUp);
                // Don't need touch move action for keyboard handling
                //_TouchHandler.TouchMove += new EventHandler(TouchHandlerTouchMove);
            }
            base.OnHandleCreated(e);
        }
        private DateTime? _LastTouchAction = null;
        //void TouchHandlerTouchMove(object sender, TouchEventArgs e)
        //{
        //    PerformMoveAction(e.Location);
        //    _LastTouchAction = DateTime.Now;
        //}
        void TouchHandlerTouchUp(object sender, TouchEventArgs e)
        {
            if (_TouchEnabled)
            {
                // Process keybaord hiding through the MouseUp event instead of touch event since if closed using touch the mouse up will occur on control
                // which is under keyboard after keyboard is hidden which is not desired
                if (IsTopBarVisible && CloseButtonRectangle.Contains(e.Location))
                {
                    _LastTouchAction = null;
                    return;
                }
                PerformUpAction(e.Location);
                _LastTouchAction = DateTime.Now;
            }
        }
        void TouchHandlerTouchDown(object sender, TouchEventArgs e)
        {
            if (_TouchEnabled)
            {
                PerformDownAction(e.Location);
                _LastTouchAction = DateTime.Now;
            }
        }
        /// 
        /// Returns the Key at given location. Location expected is in control coordinates.
        /// 
        /// Location is control coordinates.
        /// Key if there is a key at given location or null/nothing if no key exists at given location.
        public Key HitTest(Point location)
        {
            KeyboardLayout currentLayout = Keyboard.CurrentLayout;
            Rectangle rectKeys = KeysRectangle;
            float fx = (float)rectKeys.Width / currentLayout.LogicalWidth;
            float fy = (float)rectKeys.Height / currentLayout.LogicalHeight;
            Key key = null;
            if (KeysRectangle.Contains(location))
                key = currentLayout.KeyHitTest((int)((location.X - rectKeys.Left) / fx), (int)((location.Y - rectKeys.Top) / fy));
            return key;
        }
        private void PerformDownAction(Point location)
        {
            if (_PressedKey != null) // This can happen because multi-touch can send multiple down messages
            {
                PerformUpAction(location);
            }
            if (IsTopBarVisible && CloseButtonRectangle.Contains(location))
            {
                _PressedKey = HideKeyboardKey;
                Invalidate(CloseButtonRectangle);
            }
            else
            {
                KeyboardLayout currentLayout = Keyboard.CurrentLayout;
                Rectangle rectKeys = KeysRectangle;
                float fx = (float)rectKeys.Width / currentLayout.LogicalWidth;
                float fy = (float)rectKeys.Height / currentLayout.LogicalHeight;
                Key key = HitTest(location);
                if (key != null)
                {
                    TimeSpan ts = DateTime.Now.Subtract(_LastMouseUpEvent);
                    if (_LastKeyUp != null && key.Caption == _LastKeyUp.Caption && ts < TimeSpan.FromMilliseconds(SystemInformation.DoubleClickTime) && key.ChangeToLayoutEx >= 0)
                    {
                        Keyboard.CurrentLayoutIndex = key.ChangeToLayoutEx;
                        _LastMouseUpEvent = DateTime.MinValue;
                        Invalidate();
                    }
                    else
                    {
                        _PressedKey = key;
                        if (_PressedKey.Info != null && _PressedKey.Info != "")
                        {
                            StartRepeatKey(key);
                            SendKeysToTarget(key.Info);
                        }
                    }
                    Invalidate(GetKeyPhysicalBounds(key, fx, fy)); // Only invalidate area under the currently pressed key.
                }
            }
            this.Update();
        }
        private int TouchMouseInputFilterDelay = 2000;
        private bool ProcessMouseAction
        {
            get
            {
                return _LastTouchAction == null ||
                    (_LastTouchAction != null && DateTime.Now.Subtract(_LastTouchAction.Value).TotalMilliseconds > TouchMouseInputFilterDelay);
            }
        }
        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (ProcessMouseAction)
            {
                PerformDownAction(e.Location);
                _LastTouchAction = null;
            }
            base.OnMouseDown(e);
        }
        private DateTime _LastMouseUpEvent = DateTime.MinValue;
        private Key _LastKeyUp = null;
        private void PerformUpAction(Point location)
        {
            if (IsTopBarVisible && CloseButtonRectangle.Contains(location))
            {
                if (_PressedKey == HideKeyboardKey)
                {
                    HideKeyboard();
                    _PressedKey = null;
                }
                CancelRepeatKey();
            }
            else
            {
                Key pressedKey = _PressedKey;
                CancelRepeatKey();
                if (pressedKey != null)
                {
                    KeyboardLayout currentLayout = Keyboard.CurrentLayout;
                    Rectangle rectKeys = KeysRectangle;
                    float fx = (float)rectKeys.Width / currentLayout.LogicalWidth;
                    float fy = (float)rectKeys.Height / currentLayout.LogicalHeight;
                    _LastMouseUpEvent = DateTime.Now;
                    _LastKeyUp = pressedKey;
                    if (pressedKey.ChangeToLayout >= 0)
                    {
                        Keyboard.CurrentLayoutIndex = pressedKey.ChangeToLayout;
                        Invalidate(); // Ok to invalidate entire control because we need to draw a whole new layout.
                    }
                    else if (pressedKey.ChangeToLayout == KeyboardLayout.PreviousLayout)
                    {
                        Keyboard.ChangeToPreviousLayout();
                        Invalidate(); // Ok to invalidate entire control because we need to draw a whole new layout.
                    }
                    else
                    {
                        Invalidate(GetKeyPhysicalBounds(pressedKey, fx, fy)); // Only invalidate area under the currently pressed key.
                    }
                }
            }
            this.Update();
        }
        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (ProcessMouseAction)
            {
                PerformUpAction(e.Location);
                base.OnMouseUp(e);
            }
            _LastTouchAction = null;
        }
        private Rectangle GetKeyPhysicalBounds(Key key, float scaleFactorX, float scaleFactorY)
        {
            Rectangle r = key.Bounds;
            r.X = (int)(r.X * scaleFactorX) + Border;
            r.Y = (int)(r.Y * scaleFactorY) + Border + TopBarVisibleHeight;
            r.Width = (int)(r.Width * scaleFactorX);
            r.Height = (int)(r.Height * scaleFactorY);
            return r;
        }
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_DefaultColorTable != null)
                    _DefaultColorTable.Dispose();
                if (_RepeatTimer != null)
                    _RepeatTimer.Dispose();
            }
            base.Dispose(disposing);
        }
        /// 
        /// Attaches the Keyboard to the specified control. The keyboard will automatically appear when the control receives input focus.
        /// 
        /// The control to which the Keyboard will be attached.
        public void AttachTo(Control control)
        {
            control.GotFocus += new EventHandler(control_GotFocus);
            control.LostFocus += new EventHandler(control_LostFocus);
        }
        /// 
        /// Detaches the Keyboard from the specified control.
        /// 
        /// The control from which the Keyboard will be detached.
        public void DetachFrom(Control control)
        {
            control.GotFocus -= new EventHandler(control_GotFocus);
            control.LostFocus -= new EventHandler(control_LostFocus);
        }
        public void UnlockCapsLock()
        {
            if (Control.IsKeyLocked(Keys.CapsLock))
            {
                OSVERSIONINFO info=new OSVERSIONINFO();
                info.dwOSVersionInfoSize= System.Runtime.InteropServices.Marshal.SizeOf(typeof(OSVERSIONINFO));
                GetVersionEx(ref info);
                byte[] keys= new byte[255];
                if(info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) // Win95/98
                {
                    keys[VK_CAPITAL] = 1;
                    SetKeyboardState(keys);
                }
                else if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
                {
                    // Simulate Key Press
                    keybd_event(VK_CAPITAL, 0X45, KEYEVENTF_EXTENDEDKEY | 0, 0);
                    // Simulate Key Release
                    keybd_event(VK_CAPITAL, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
                }
            }
        }
        void control_GotFocus(object sender, EventArgs e)
        {
            Show();
        }
        void control_LostFocus(object sender, EventArgs e)
        {
            HideKeyboard();
        }
        private void HideKeyboard()
        {
            CancelEventArgs ce = new CancelEventArgs();
            OnKeyboardClosing(ce);
            if (ce.Cancel) return;
            this.Hide();
            OnKeyboardClosed(EventArgs.Empty);
        }
        /// 
        /// Occurs before the keyboard is closed and allows canceling of keyboard closing.
        /// 
        [Description("Occurs before the keyboard is closed and allows canceling of keyboard closing.")]
        public event CancelEventHandler KeyboardClosing;
        /// 
        /// Raises KeyboardClosing event.
        /// 
        /// Provides event arguments.
        protected virtual void OnKeyboardClosing(CancelEventArgs e)
        {
            CancelEventHandler handler = KeyboardClosing;
            if (handler != null)
                handler(this, e);
        }
        /// 
        /// Occurs after keyboard is closed.
        /// 
        [Description("Occurs after keyboard is closed.")]
        public event EventHandler KeyboardClosed;
        /// 
        /// Raises KeyboardClosed event.
        /// 
        /// Provides event arguments.
        protected virtual void OnKeyboardClosed(EventArgs e)
        {
            EventHandler handler = KeyboardClosed;
            if (handler != null)
                handler(this, e);
        }
        /// 
        /// Occurs before the key pressed on keyboard is sent to target control and allows cancellation of the message
        /// 
        [Description("Occurs before the key pressed on keyboard is sent to target control and allows cancellation of the message.")]
        public event KeyCancelEventHandler SendingKey;
        /// 
        /// Raises SendingKey event.
        /// 
        /// Provides event arguments.
        protected virtual void OnSendingKey(KeyboardKeyCancelEventArgs e)
        {
            KeyCancelEventHandler handler = SendingKey;
            if (handler != null)
                handler(this, e);
        }
        /// 
        /// Occurs after the key is sent to target control.
        /// 
        [Description("Occurs after the key is sent to target control.")]
        public event KeyEventHandler KeySent;
        /// 
        /// Raises KeySent event.
        /// 
        /// Provides event arguments.
        protected virtual void OnKeySent(KeyboardKeyEventArgs e)
        {
            KeyEventHandler handler = KeySent;
            if (handler != null)
                handler(this, e);
        }
        protected override void OnTextChanged(EventArgs e)
        {
            this.Invalidate();
            base.OnTextChanged(e);
        }
        #region Windows API
        //  Declare Type for API call:
        [StructLayout(LayoutKind.Sequential)]
        internal struct OSVERSIONINFO
        {
            public int dwOSVersionInfoSize;
            public int dwMajorVersion;
            public int dwMinorVersion;
            public int dwBuildNumber;
            public int dwPlatformId;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            public string szCSDVersion;
        }
        //  Constant declarations:
        const int VK_CAPITAL = 0x14;
        const int KEYEVENTF_EXTENDEDKEY = 1;
        const int KEYEVENTF_KEYUP = 2;
        const int VER_PLATFORM_WIN32_NT = 2;
        const int VER_PLATFORM_WIN32_WINDOWS = 1;
        //  API declarations:
        [DllImport("kernel32.Dll")]
        private static extern short GetVersionEx(ref OSVERSIONINFO o);
        [DllImport("user32.dll")]
        static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
        [DllImport("user32.dll")]
        static extern bool SetKeyboardState(byte[] lpKeyState);
        #endregion
    }
    /// 
    /// Defines delegate for key-related events.
    /// 
    /// 
    /// 
    public delegate void KeyEventHandler(object sender, KeyboardKeyEventArgs e);
    /// 
    /// Provides data for key related events.
    /// 
    public class KeyboardKeyEventArgs : EventArgs
    {
        /// 
        /// Gets the key being pressed. The format of this information
        /// must confirm to the description for the SendKeys.Send function. For more details, see:
        /// http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.aspx
        /// 
        public readonly string Key;
        /// 
        /// Initializes a new instance of the KeyboardKeyEventArgs class.
        /// 
        /// 
        public KeyboardKeyEventArgs(string key)
        {
            Key = key;
        }
    }
    /// 
    /// Defines delegate for key-related events.
    /// 
    /// 
    /// 
    public delegate void KeyCancelEventHandler(object sender, KeyboardKeyCancelEventArgs e);
    /// 
    /// Provides data for key related events.
    /// 
    public class KeyboardKeyCancelEventArgs : CancelEventArgs
    {
        /// 
        /// Gets the key being pressed. The format of this information
        /// must confirm to the description for the SendKeys.Send function. For more details, see:
        /// http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.aspx
        /// 
        public readonly string Key;
        /// 
        /// Initializes a new instance of the KeyCancelEventArgs class.
        /// 
        /// 
        public KeyboardKeyCancelEventArgs(string key)
        {
            Key = key;
        }
    }
    
}