172 lines
5.7 KiB
C#
172 lines
5.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using System.Drawing;
|
|
using System.ComponentModel;
|
|
|
|
namespace DevComponents.DotNetBar.Keyboard
|
|
{
|
|
internal class PopupVirtualKeyboard : Form
|
|
{
|
|
/// <summary>
|
|
/// Creates a new floating virtual keyboard.
|
|
/// </summary>
|
|
public PopupVirtualKeyboard()
|
|
{
|
|
StartPosition = FormStartPosition.Manual;
|
|
|
|
// Make sure the popup window does not appear in the taskbar.
|
|
ShowInTaskbar = false;
|
|
|
|
MinimizeBox = false;
|
|
MaximizeBox = false;
|
|
//ControlBox = false;
|
|
}
|
|
|
|
|
|
#region Window activation handling
|
|
|
|
// We need to prevent the keyboard window from activating, otherwise will still focus from our target control.
|
|
// Also to achieve this effect, there must be no focusable control in the popup window.
|
|
|
|
private const int WM_MOUSEACTIVATE = 0x0021;
|
|
private const int MA_NOACTIVATE = 0x0003;
|
|
private const int WS_EX_NOACTIVATE = 0x08000000;
|
|
|
|
// Override CreateParams to specify that this Form should not be activated.
|
|
protected override CreateParams CreateParams
|
|
{
|
|
get
|
|
{
|
|
CreateParams createParams = base.CreateParams;
|
|
createParams.ExStyle = createParams.ExStyle & WS_EX_NOACTIVATE;
|
|
return createParams;
|
|
}
|
|
}
|
|
|
|
|
|
protected override void WndProc(ref Message m)
|
|
{
|
|
// This prevents the window from being activated with the mouse,
|
|
// but allows the window to be resized (with the mouse).
|
|
if (m.Msg == WM_MOUSEACTIVATE)
|
|
{
|
|
m.Result = (IntPtr)MA_NOACTIVATE;
|
|
}
|
|
else
|
|
{
|
|
base.WndProc(ref m);
|
|
}
|
|
}
|
|
|
|
|
|
protected override void OnActivated(EventArgs e)
|
|
{
|
|
Owner.Activate();
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
protected override void OnClosing(CancelEventArgs e)
|
|
{
|
|
// Cancel the Closing event as this will Dispose the form.
|
|
e.Cancel = true;
|
|
Hide();
|
|
}
|
|
|
|
|
|
protected override void OnVisibleChanged(EventArgs e)
|
|
{
|
|
base.OnVisibleChanged(e);
|
|
|
|
if (Visible && CurrentControl != _LastControl && CurrentControl != null)
|
|
{
|
|
_LastControl = CurrentControl;
|
|
}
|
|
}
|
|
|
|
|
|
internal Control CurrentControl { get; set; }
|
|
private Control _LastControl;
|
|
/*
|
|
public void MoveNearControl(Control control)
|
|
{
|
|
// We want to show the keyboard near the target control, horizontally centered,
|
|
// under the control or above it and without overlapping it, if possible.
|
|
|
|
// First try to position the Keyboard under the target control.
|
|
Point location = control.PointToScreen(Point.Empty);
|
|
location.Offset(control.Width / 2 - Width / 2, control.Height);
|
|
Location = location;
|
|
|
|
// And make sure it is in the screen containing the control.
|
|
EnsureInScreen(control);
|
|
|
|
// Now check if this position does not overlap the control.
|
|
if (!OverlapsControl(control))
|
|
return;
|
|
|
|
// Now we try to position the Keyboard above the control.
|
|
location = control.PointToScreen(Point.Empty);
|
|
location.Offset(control.Width / 2 - Width / 2, -Height);
|
|
Location = location;
|
|
|
|
// And again make sure this location is in the screen with the control.
|
|
EnsureInScreen(control);
|
|
|
|
// And check if it does not overlap the control.
|
|
if (!OverlapsControl(control))
|
|
return;
|
|
|
|
// If both below and above the control was not a good position, then this means the
|
|
// target control is quite large, so show the Keyboard inside it.
|
|
location = control.PointToScreen(Point.Empty);
|
|
location.Offset(control.Width / 2 - Width / 2, control.Height / 2 - Height / 2);
|
|
|
|
// And again, make sure the Keybboard is not clipped by the screen.
|
|
EnsureInScreen(control);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true if the Keyboard overlaps the specified control.
|
|
/// </summary>
|
|
/// <param name="control">The control for which to check if it is overlapped by the Keyboard.</param>
|
|
/// <returns></returns>
|
|
private bool OverlapsControl(Control control)
|
|
{
|
|
Rectangle rect = new Rectangle(control.PointToScreen(Point.Empty), control.Size);
|
|
return rect.IntersectsWith(Bounds);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if the Keyboard is in the screen containing the specified control, and if
|
|
/// the Keyboard is not fully visible, adjusts it's location accordingly.
|
|
/// </summary>
|
|
/// <param name="control">The control from which the screen is checked. If null, the primary screen is used.</param>
|
|
private void EnsureInScreen(Control control)
|
|
{
|
|
Screen screen = Screen.PrimaryScreen;
|
|
|
|
if(control != null)
|
|
screen = Screen.FromControl(control);
|
|
|
|
Rectangle rect = screen.WorkingArea;
|
|
|
|
if (Location.X < rect.Left)
|
|
Location = new Point(rect.Left, Location.Y);
|
|
|
|
if (Location.Y < rect.Top)
|
|
Location = new Point(Location.X, rect.Top);
|
|
|
|
if (Bounds.Right > rect.Right)
|
|
Location = new Point(rect.Right - Width, Location.Y);
|
|
|
|
if (Bounds.Bottom > rect.Bottom)
|
|
Location = new Point(Location.X, rect.Bottom - Height);
|
|
}
|
|
*/
|
|
}
|
|
}
|