875 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			875 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| 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
 | |
| {
 | |
|     /// <summary>
 | |
|     /// Represents virtual keyboard control.
 | |
|     /// </summary>
 | |
|     [ToolboxItem(true)]
 | |
|     public class KeyboardControl : Control
 | |
|     {
 | |
|         private TouchHandler _TouchHandler = null;
 | |
|         /// <summary>
 | |
|         /// Creates a new VirtualKeyboard control.
 | |
|         /// </summary>
 | |
|         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();
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets or sets the Keyboard object that describes the VirtualKeyboard.
 | |
|         /// </summary>
 | |
|         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
 | |
|         public Keyboard Keyboard
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 if(_Keyboard==null)
 | |
|                     _Keyboard = Keyboard.CreateDefaultKeyboard();
 | |
|                 return _Keyboard;
 | |
|             }
 | |
|             set { _Keyboard = value; }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Default width for the keyboard in pixels.
 | |
|         /// </summary>
 | |
|         public static int DefaultWidth
 | |
|         {
 | |
|             get { return 740; }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Default height for the keyboard in pixels.
 | |
|         /// </summary>
 | |
|         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;
 | |
|         /// <summary>
 | |
|         /// Gets or set the ColorTable used to draw the keyboard.
 | |
|         /// </summary>
 | |
|         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();
 | |
|         /// <summary>
 | |
|         /// Gets or sets the Renderer used to render the keyboard.
 | |
|         /// </summary>
 | |
|         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;
 | |
|         /// <summary>
 | |
|         /// Gets or sets a value indicating if the top bar of the keyboard is visible.
 | |
|         /// </summary>
 | |
|         [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;
 | |
|         /// <summary>
 | |
|         /// Indicates the height of the keyboard caption which hosts the close button.
 | |
|         /// </summary>
 | |
|         [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;
 | |
|         /// <summary>
 | |
|         /// Indicates whether touch support is enabled when provided by hardware.
 | |
|         /// </summary>
 | |
|         [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);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Called when TouchEnabled property has changed.
 | |
|         /// </summary>
 | |
|         /// <param name="oldValue">Old property value</param>
 | |
|         /// <param name="newValue">New property value</param>
 | |
|         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<TouchEventArgs>(TouchHandlerTouchDown);
 | |
|                 _TouchHandler.TouchUp += new EventHandler<TouchEventArgs>(TouchHandlerTouchUp);
 | |
|                 // Don't need touch move action for keyboard handling
 | |
|                 //_TouchHandler.TouchMove += new EventHandler<TouchEventArgs>(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;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Returns the Key at given location. Location expected is in control coordinates.
 | |
|         /// </summary>
 | |
|         /// <param name="location">Location is control coordinates.</param>
 | |
|         /// <returns>Key if there is a key at given location or null/nothing if no key exists at given location.</returns>
 | |
|         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);
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Attaches the Keyboard to the specified control. The keyboard will automatically appear when the control receives input focus.
 | |
|         /// </summary>
 | |
|         /// <param name="control">The control to which the Keyboard will be attached.</param>
 | |
|         public void AttachTo(Control control)
 | |
|         {
 | |
|             control.GotFocus += new EventHandler(control_GotFocus);
 | |
|             control.LostFocus += new EventHandler(control_LostFocus);
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Detaches the Keyboard from the specified control.
 | |
|         /// </summary>
 | |
|         /// <param name="control">The control from which the Keyboard will be detached.</param>
 | |
|         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);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Occurs before the keyboard is closed and allows canceling of keyboard closing.
 | |
|         /// </summary>
 | |
|         [Description("Occurs before the keyboard is closed and allows canceling of keyboard closing.")]
 | |
|         public event CancelEventHandler KeyboardClosing;
 | |
|         /// <summary>
 | |
|         /// Raises KeyboardClosing event.
 | |
|         /// </summary>
 | |
|         /// <param name="e">Provides event arguments.</param>
 | |
|         protected virtual void OnKeyboardClosing(CancelEventArgs e)
 | |
|         {
 | |
|             CancelEventHandler handler = KeyboardClosing;
 | |
|             if (handler != null)
 | |
|                 handler(this, e);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Occurs after keyboard is closed.
 | |
|         /// </summary>
 | |
|         [Description("Occurs after keyboard is closed.")]
 | |
|         public event EventHandler KeyboardClosed;
 | |
|         /// <summary>
 | |
|         /// Raises KeyboardClosed event.
 | |
|         /// </summary>
 | |
|         /// <param name="e">Provides event arguments.</param>
 | |
|         protected virtual void OnKeyboardClosed(EventArgs e)
 | |
|         {
 | |
|             EventHandler handler = KeyboardClosed;
 | |
|             if (handler != null)
 | |
|                 handler(this, e);
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Occurs before the key pressed on keyboard is sent to target control and allows cancellation of the message
 | |
|         /// </summary>
 | |
|         [Description("Occurs before the key pressed on keyboard is sent to target control and allows cancellation of the message.")]
 | |
|         public event KeyCancelEventHandler SendingKey;
 | |
|         /// <summary>
 | |
|         /// Raises SendingKey event.
 | |
|         /// </summary>
 | |
|         /// <param name="e">Provides event arguments.</param>
 | |
|         protected virtual void OnSendingKey(KeyboardKeyCancelEventArgs e)
 | |
|         {
 | |
|             KeyCancelEventHandler handler = SendingKey;
 | |
|             if (handler != null)
 | |
|                 handler(this, e);
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// Occurs after the key is sent to target control.
 | |
|         /// </summary>
 | |
|         [Description("Occurs after the key is sent to target control.")]
 | |
|         public event KeyEventHandler KeySent;
 | |
|         /// <summary>
 | |
|         /// Raises KeySent event.
 | |
|         /// </summary>
 | |
|         /// <param name="e">Provides event arguments.</param>
 | |
|         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
 | |
|     }
 | |
| 
 | |
|     /// <summary>
 | |
|     /// Defines delegate for key-related events.
 | |
|     /// </summary>
 | |
|     /// <param name="sender"></param>
 | |
|     /// <param name="e"></param>
 | |
|     public delegate void KeyEventHandler(object sender, KeyboardKeyEventArgs e);
 | |
|     /// <summary>
 | |
|     /// Provides data for key related events.
 | |
|     /// </summary>
 | |
|     public class KeyboardKeyEventArgs : EventArgs
 | |
|     {
 | |
|         /// <summary>
 | |
|         /// 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
 | |
|         /// </summary>
 | |
|         public readonly string Key;
 | |
|         /// <summary>
 | |
|         /// Initializes a new instance of the KeyboardKeyEventArgs class.
 | |
|         /// </summary>
 | |
|         /// <param name="key"></param>
 | |
|         public KeyboardKeyEventArgs(string key)
 | |
|         {
 | |
|             Key = key;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// <summary>
 | |
|     /// Defines delegate for key-related events.
 | |
|     /// </summary>
 | |
|     /// <param name="sender"></param>
 | |
|     /// <param name="e"></param>
 | |
|     public delegate void KeyCancelEventHandler(object sender, KeyboardKeyCancelEventArgs e);
 | |
|     /// <summary>
 | |
|     /// Provides data for key related events.
 | |
|     /// </summary>
 | |
|     public class KeyboardKeyCancelEventArgs : CancelEventArgs
 | |
|     {
 | |
|         /// <summary>
 | |
|         /// 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
 | |
|         /// </summary>
 | |
|         public readonly string Key;
 | |
|         /// <summary>
 | |
|         /// Initializes a new instance of the KeyCancelEventArgs class.
 | |
|         /// </summary>
 | |
|         /// <param name="key"></param>
 | |
|         public KeyboardKeyCancelEventArgs(string key)
 | |
|         {
 | |
|             Key = key;
 | |
|         }
 | |
|     }
 | |
| 
 | |
| 
 | |
|     
 | |
| }
 |