This repository has been archived on 2023-07-11. You can view files and clone it, but cannot push or open issues or pull requests.
gwen-dotnet/Gwen/Input/InputHandler.cs

411 lines
13 KiB
C#

using System;
//using System.Drawing;
using System.Linq;
using System.Text;
using Gwen.Control;
using Gwen.DragDrop;
namespace Gwen.Input
{
/// <summary>
/// Input handling.
/// </summary>
public static class InputHandler
{
private static readonly KeyData m_KeyData = new KeyData();
private static readonly float[] m_LastClickTime = new float[MaxMouseButtons];
private static Point m_LastClickPos;
/// <summary>
/// Control currently hovered by mouse.
/// </summary>
public static Base HoveredControl;
/// <summary>
/// Control that corrently has keyboard focus.
/// </summary>
public static Base KeyboardFocus;
/// <summary>
/// Control that currently has mouse focus.
/// </summary>
public static Base MouseFocus;
/// <summary>
/// Maximum number of mouse buttons supported.
/// </summary>
public static int MaxMouseButtons { get { return 5; } }
/// <summary>
/// Maximum time in seconds between mouse clicks to be recognized as double click.
/// </summary>
public static float DoubleClickSpeed { get { return 0.5f; } }
/// <summary>
/// Time in seconds between autorepeating of keys.
/// </summary>
public static float KeyRepeatRate { get { return 0.03f; } }
/// <summary>
/// Time in seconds before key starts to autorepeat.
/// </summary>
public static float KeyRepeatDelay { get { return 0.5f; } }
/// <summary>
/// Indicates whether the left mouse button is down.
/// </summary>
public static bool IsLeftMouseDown { get { return m_KeyData.LeftMouseDown; } }
/// <summary>
/// Indicates whether the right mouse button is down.
/// </summary>
public static bool IsRightMouseDown { get { return m_KeyData.RightMouseDown; } }
/// <summary>
/// Current mouse position.
/// </summary>
public static Point MousePosition; // not property to allow modification of Point fields
/// <summary>
/// Indicates whether the shift key is down.
/// </summary>
public static bool IsShiftDown { get { return IsKeyDown(Key.Shift); } }
/// <summary>
/// Indicates whether the control key is down.
/// </summary>
public static bool IsControlDown { get { return IsKeyDown(Key.Control); } }
/// <summary>
/// Checks if the given key is pressed.
/// </summary>
/// <param name="key">Key to check.</param>
/// <returns>True if the key is down.</returns>
public static bool IsKeyDown(Key key)
{
return m_KeyData.KeyState[(int)key];
}
/// <summary>
/// Handles copy, paste etc.
/// </summary>
/// <param name="canvas">Canvas.</param>
/// <param name="chr">Input character.</param>
/// <returns>True if the key was handled.</returns>
public static bool DoSpecialKeys(Base canvas, char chr)
{
if (null == KeyboardFocus) return false;
if (KeyboardFocus.GetCanvas() != canvas) return false;
if (!KeyboardFocus.IsVisible) return false;
if (!IsControlDown) return false;
if (chr == 'C' || chr == 'c')
{
KeyboardFocus.InputCopy(null);
return true;
}
if (chr == 'V' || chr == 'v')
{
KeyboardFocus.InputPaste(null);
return true;
}
if (chr == 'X' || chr == 'x')
{
KeyboardFocus.InputCut(null);
return true;
}
if (chr == 'A' || chr == 'a')
{
KeyboardFocus.InputSelectAll(null);
return true;
}
return false;
}
/// <summary>
/// Handles accelerator input.
/// </summary>
/// <param name="canvas">Canvas.</param>
/// <param name="chr">Input character.</param>
/// <returns>True if the key was handled.</returns>
public static bool HandleAccelerator(Base canvas, char chr)
{
//Build the accelerator search string
StringBuilder accelString = new StringBuilder();
if (IsControlDown)
accelString.Append("CTRL+");
if (IsShiftDown)
accelString.Append("SHIFT+");
// [omeg] todo: alt?
accelString.Append(chr);
String acc = accelString.ToString();
//Debug::Msg("Accelerator string :%S\n", accelString.c_str());)
if (KeyboardFocus != null && KeyboardFocus.HandleAccelerator(acc))
return true;
if (MouseFocus != null && MouseFocus.HandleAccelerator(acc))
return true;
if (canvas.HandleAccelerator(acc))
return true;
return false;
}
/// <summary>
/// Mouse moved handler.
/// </summary>
/// <param name="canvas">Canvas.</param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="dx"></param>
/// <param name="dy"></param>
public static void OnMouseMoved(Base canvas, int x, int y, int dx, int dy)
{
// Send input to canvas for study
MousePosition.X = x;
MousePosition.Y = y;
UpdateHoveredControl(canvas);
}
/// <summary>
/// Handles focus updating and key autorepeats.
/// </summary>
/// <param name="control">Unused.</param>
public static void OnCanvasThink(Base control)
{
if (MouseFocus != null && !MouseFocus.IsVisible)
MouseFocus = null;
if (KeyboardFocus != null && (!KeyboardFocus.IsVisible || !KeyboardFocus.KeyboardInputEnabled))
KeyboardFocus = null;
if (null == KeyboardFocus) return;
if (KeyboardFocus.GetCanvas() != control) return;
float time = Platform.Neutral.GetTimeInSeconds();
//
// Simulate Key-Repeats
//
for (int i = 0; i < (int)Key.Count; i++)
{
if (m_KeyData.KeyState[i] && m_KeyData.Target != KeyboardFocus)
{
m_KeyData.KeyState[i] = false;
continue;
}
if (m_KeyData.KeyState[i] && time > m_KeyData.NextRepeat[i])
{
m_KeyData.NextRepeat[i] = Platform.Neutral.GetTimeInSeconds() + KeyRepeatRate;
if (KeyboardFocus != null)
{
KeyboardFocus.InputKeyPressed((Key)i);
}
}
}
}
/// <summary>
/// Mouse click handler.
/// </summary>
/// <param name="canvas">Canvas.</param>
/// <param name="mouseButton">Mouse button number.</param>
/// <param name="down">Specifies if the button is down.</param>
/// <returns>True if handled.</returns>
public static bool OnMouseClicked(Base canvas, int mouseButton, bool down)
{
// If we click on a control that isn't a menu we want to close
// all the open menus. Menus are children of the canvas.
if (down && (null == HoveredControl || !HoveredControl.IsMenuComponent))
{
canvas.CloseMenus();
}
if (null == HoveredControl) return false;
if (HoveredControl.GetCanvas() != canvas) return false;
if (!HoveredControl.IsVisible) return false;
if (HoveredControl == canvas) return false;
if (mouseButton > MaxMouseButtons)
return false;
if (mouseButton == 0)
m_KeyData.LeftMouseDown = down;
else if (mouseButton == 1)
m_KeyData.RightMouseDown = down;
// Double click.
// Todo: Shouldn't double click if mouse has moved significantly
bool isDoubleClick = false;
if (down &&
m_LastClickPos.X == MousePosition.X &&
m_LastClickPos.Y == MousePosition.Y &&
(Platform.Neutral.GetTimeInSeconds() - m_LastClickTime[mouseButton]) < DoubleClickSpeed)
{
isDoubleClick = true;
}
if (down && !isDoubleClick)
{
m_LastClickTime[mouseButton] = Platform.Neutral.GetTimeInSeconds();
m_LastClickPos = MousePosition;
}
if (down)
{
FindKeyboardFocus(HoveredControl);
}
HoveredControl.UpdateCursor();
// This tells the child it has been touched, which
// in turn tells its parents, who tell their parents.
// This is basically so that Windows can pop themselves
// to the top when one of their children have been clicked.
if (down)
HoveredControl.Touch();
#if GWEN_HOOKSYSTEM
if (bDown)
{
if (Hook::CallHook(&Hook::BaseHook::OnControlClicked, HoveredControl, MousePosition.x,
MousePosition.y))
return true;
}
#endif
switch (mouseButton)
{
case 0:
{
if (DragAndDrop.OnMouseButton(HoveredControl, MousePosition.X, MousePosition.Y, down))
return true;
if (isDoubleClick)
HoveredControl.InputMouseDoubleClickedLeft(MousePosition.X, MousePosition.Y);
else
HoveredControl.InputMouseClickedLeft(MousePosition.X, MousePosition.Y, down);
return true;
}
case 1:
{
if (isDoubleClick)
HoveredControl.InputMouseDoubleClickedRight(MousePosition.X, MousePosition.Y);
else
HoveredControl.InputMouseClickedRight(MousePosition.X, MousePosition.Y, down);
return true;
}
}
return false;
}
/// <summary>
/// Key handler.
/// </summary>
/// <param name="canvas">Canvas.</param>
/// <param name="key">Key.</param>
/// <param name="down">True if the key is down.</param>
/// <returns>True if handled.</returns>
public static bool OnKeyEvent(Base canvas, Key key, bool down)
{
if (null == KeyboardFocus) return false;
if (KeyboardFocus.GetCanvas() != canvas) return false;
if (!KeyboardFocus.IsVisible) return false;
int iKey = (int)key;
if (down)
{
if (!m_KeyData.KeyState[iKey])
{
m_KeyData.KeyState[iKey] = true;
m_KeyData.NextRepeat[iKey] = Platform.Neutral.GetTimeInSeconds() + KeyRepeatDelay;
m_KeyData.Target = KeyboardFocus;
return KeyboardFocus.InputKeyPressed(key);
}
}
else
{
if (m_KeyData.KeyState[iKey])
{
m_KeyData.KeyState[iKey] = false;
// BUG BUG. This causes shift left arrow in textboxes
// to not work. What is disabling it here breaking?
//m_KeyData.Target = NULL;
return KeyboardFocus.InputKeyPressed(key, false);
}
}
return false;
}
private static void UpdateHoveredControl(Base inCanvas)
{
Base hovered = inCanvas.GetControlAt(MousePosition.X, MousePosition.Y);
if (hovered != HoveredControl)
{
if (HoveredControl != null)
{
var oldHover = HoveredControl;
HoveredControl = null;
oldHover.InputMouseLeft();
}
HoveredControl = hovered;
if (HoveredControl != null)
{
HoveredControl.InputMouseEntered();
}
}
if (MouseFocus != null && MouseFocus.GetCanvas() == inCanvas)
{
if (HoveredControl != null)
{
var oldHover = HoveredControl;
HoveredControl = null;
oldHover.Redraw();
}
HoveredControl = MouseFocus;
}
}
private static void FindKeyboardFocus(Base control)
{
if (null == control) return;
if (control.KeyboardInputEnabled)
{
//Make sure none of our children have keyboard focus first - todo recursive
if (control.Children.Any(child => child == KeyboardFocus))
{
return;
}
control.Focus();
return;
}
FindKeyboardFocus(control.Parent);
return;
}
}
}