using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VastPark.Horde3D;
using VastPark.Data.EventArg;
using VastPark.Data;
using VastPark.Data.Collections;
namespace Client
{
///
/// Detects input from a WPF based input source
///
public class WpfInputSource : IInputSource, IDisposable
{
#region Events
public event Event KeyDown;
public event Event KeyUp;
public event Event MouseDown;
public event Event MouseUp;
public event Event MouseMove;
public event Event MouseClick;
public event Event MouseDoubleClick;
public event Event MouseWheel;
#endregion
public bool MouseWrapEnabled { get; set; }
private MouseState _MouseState;
private KeyboardState _KeyboardState;
private System.Windows.DependencyObject _Control;
private System.Timers.Timer _ResetMouseRelativePositionTimer;
private System.Timers.Timer _ResetMouseWheelTimer;
private bool _IsMouseMoveEventExecuting;
public WpfInputSource(System.Windows.DependencyObject control)
{
_Control = control;
_RelativePositionLock = new object();
_MouseWheelLock = new object();
_MouseState.AbsX = -1;
_MouseState.AbsY = -1;
_KeyboardState.Initialise(new ThreadSafeDictionary());
this.MouseWrapEnabled = true;
Array keys = Enum.GetValues(typeof(System.Windows.Input.Key));
foreach (System.Windows.Input.Key key in keys)
{
if (!_KeyboardState.Keys.ContainsKey(key))
_KeyboardState.Keys.Add(key, false);
}
System.Windows.Input.Keyboard.AddKeyDownHandler(_Control, new System.Windows.Input.KeyEventHandler(_KeyDownHandler));
System.Windows.Input.Keyboard.AddKeyUpHandler(_Control, new System.Windows.Input.KeyEventHandler(_KeyUpHandler));
if (_Control is System.Windows.Forms.Integration.WindowsFormsHost)
{
(_Control as System.Windows.Forms.Integration.WindowsFormsHost).Child.MouseMove += new System.Windows.Forms.MouseEventHandler(Child_MouseMove);
(_Control as System.Windows.Forms.Integration.WindowsFormsHost).Child.MouseDown += new System.Windows.Forms.MouseEventHandler(Child_MouseDown);
(_Control as System.Windows.Forms.Integration.WindowsFormsHost).Child.MouseUp += new System.Windows.Forms.MouseEventHandler(Child_MouseUp);
(_Control as System.Windows.Forms.Integration.WindowsFormsHost).Child.MouseClick += new System.Windows.Forms.MouseEventHandler(Child_MouseClick);
(_Control as System.Windows.Forms.Integration.WindowsFormsHost).Child.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(Child_MouseDoubleClick);
(_Control as System.Windows.Forms.Integration.WindowsFormsHost).Child.LostFocus += new EventHandler(Child_LostFocus);
(_Control as System.Windows.Forms.Integration.WindowsFormsHost).Child.DragOver += new System.Windows.Forms.DragEventHandler(Child_DragOver);
(_Control as System.Windows.Forms.Integration.WindowsFormsHost).Child.MouseWheel += new System.Windows.Forms.MouseEventHandler(Child_MouseWheel);
}
_ResetMouseRelativePositionTimer = new System.Timers.Timer(10);
_ResetMouseRelativePositionTimer.Elapsed += new System.Timers.ElapsedEventHandler(_ResetMouseRelativePositionTimer_Elapsed);
_ResetMouseWheelTimer = new System.Timers.Timer(10);
_ResetMouseWheelTimer.Elapsed += new System.Timers.ElapsedEventHandler(_ResetMouseWheelTimer_Elapsed);
}
public KeyboardState GetKeyboardState()
{
return _KeyboardState;
}
public MouseState GetMouseState()
{
return _MouseState;
}
void Child_LostFocus(object sender, EventArgs e)
{
//when losing focus, need to release mouse button states to false
_MouseState[MouseInput.LeftButton] = false;
_MouseState[MouseInput.RightButton] = false;
_MouseState[MouseInput.MiddleButton] = false;
_MouseState[MouseInput.WheelDown] = false;
_MouseState[MouseInput.WheelUp] = false;
}
void Child_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
{
_ResetMouseWheelTimer.Stop();
_IsMouseWheelEventExecuting = true;
lock (_MouseWheelLock)
{
if (e.Delta > 0)
{
_MouseState[MouseInput.WheelUp] = true;
_MouseState[MouseInput.WheelDown] = false;
}
else
{
_MouseState[MouseInput.WheelDown] = true;
_MouseState[MouseInput.WheelUp] = false;
}
}
MouseWheel.Raise(this, _MouseState);
_IsMouseWheelEventExecuting = false;
_ResetMouseWheelTimer.Start();
}
void Child_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
{
_MouseState.Button = _GetMouseInput(e.Button);
MouseClick.Raise(this, _MouseState);
}
void Child_MouseDoubleClick(object sender, System.Windows.Forms.MouseEventArgs e)
{
_MouseState.Button = _GetMouseInput(e.Button);
MouseDoubleClick.Raise(this, _MouseState);
}
private MouseInput _GetMouseInput(System.Windows.Forms.MouseButtons mouseButton)
{
switch (mouseButton)
{
case System.Windows.Forms.MouseButtons.Left:
{
return MouseInput.LeftButton;
}
case System.Windows.Forms.MouseButtons.Right:
{
return MouseInput.RightButton;
}
case System.Windows.Forms.MouseButtons.Middle:
{
return MouseInput.MiddleButton;
}
default:
{
return MouseInput.None;
}
}
}
void Child_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
switch (e.Button)
{
case System.Windows.Forms.MouseButtons.Left:
{
_MouseState[VastPark.Data.MouseInput.LeftButton] = false;
break;
}
case System.Windows.Forms.MouseButtons.Right:
{
_MouseState[VastPark.Data.MouseInput.RightButton] = false;
break;
}
case System.Windows.Forms.MouseButtons.Middle:
{
_MouseState[VastPark.Data.MouseInput.MiddleButton] = false;
break;
}
case System.Windows.Forms.MouseButtons.XButton1:
{
_MouseState[VastPark.Data.MouseInput.FourthButton] = false;
break;
}
}
MouseUp.Raise(this, _MouseState);
}
void Child_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
switch (e.Button)
{
case System.Windows.Forms.MouseButtons.Left:
{
_MouseState[VastPark.Data.MouseInput.LeftButton] = true;
break;
}
case System.Windows.Forms.MouseButtons.Right:
{
_MouseState[VastPark.Data.MouseInput.RightButton] = true;
break;
}
case System.Windows.Forms.MouseButtons.Middle:
{
_MouseState[VastPark.Data.MouseInput.MiddleButton] = true;
break;
}
case System.Windows.Forms.MouseButtons.XButton1:
{
_MouseState[VastPark.Data.MouseInput.FourthButton] = true;
break;
}
}
//manipulate the focus to the control in order to allow mousewheel events to be raised
((System.Windows.Interop.IKeyboardInputSink)_Control).TabInto(new System.Windows.Input.TraversalRequest(System.Windows.Input.FocusNavigationDirection.First));
(sender as System.Windows.Forms.Control).Focus();
MouseDown.Raise(this, _MouseState);
}
void Child_DragOver(object sender, System.Windows.Forms.DragEventArgs e)
{
//MouseMove events are not raised during a drag operation, so we make use of the DragOver event which in essence does the same thing as the move, but only during a drag
var normalisedPoint = (_Control as System.Windows.Forms.Integration.WindowsFormsHost).Child.PointToClient(new System.Drawing.Point(e.X, e.Y));
_HandleMouseMove(normalisedPoint.X, normalisedPoint.Y);
}
void Child_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
_HandleMouseMove(e.X, e.Y);
}
//private int _LastX = -1;
//private int _LastY = -1;
private void _HandleMouseMove(int x, int y)
{
//Note: Exploiting the fact that MouseMove appears to fire continuously, consumers of this InputSource can test for changes to the previous mouse move position and fire either a move or hover based on this
//if (_LastX == x && _LastY == y)
//{
// return;
//}
//System.Diagnostics.Debug.WriteLine(HighResClock.Now.ToString() + string.Format(" MouseMove {0},{1}", x, y));
//_LastX = x;
//_LastY = y;
_ResetMouseRelativePositionTimer.Stop();
_IsMouseMoveEventExecuting = true;
System.Windows.Point absolutePoint = new System.Windows.Point(x, y);
System.Windows.Point relativePoint = new System.Windows.Point();
if (_MouseState.AbsX == -1 && _MouseState.AbsY == -1) //need to initialise
{
_MouseState.AbsX = (int)absolutePoint.X;
_MouseState.AbsY = (int)absolutePoint.Y;
MouseMove.Raise(this, _MouseState);
_IsMouseMoveEventExecuting = false;
return;
}
//relative point is the difference between the new position and the old position
relativePoint.X = absolutePoint.X - _MouseState.AbsX;
relativePoint.Y = absolutePoint.Y - _MouseState.AbsY;
lock (_RelativePositionLock)
{
_MouseState.RelX = (int)relativePoint.X;
_MouseState.RelY = (int)relativePoint.Y;
}
_MouseState.AbsX = (int)absolutePoint.X;
_MouseState.AbsY = (int)absolutePoint.Y;
MouseMove.Raise(this, _MouseState);
_IsMouseMoveEventExecuting = false;
_ResetMouseRelativePositionTimer.Start();
}
private object _MouseWheelLock;
private bool _IsMouseWheelEventExecuting;
void _ResetMouseWheelTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (_IsMouseWheelEventExecuting)
return;
//also update the mouse wheel if needed
lock (_MouseWheelLock)
{
if (_MouseState[MouseInput.WheelDown] || _MouseState[MouseInput.WheelUp])
{
_MouseState[MouseInput.WheelDown] = false;
_MouseState[MouseInput.WheelUp] = false;
MouseWheel.Raise(this, _MouseState);
}
}
}
private object _RelativePositionLock;
void _ResetMouseRelativePositionTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (_IsMouseMoveEventExecuting)
return;
_ResetMouseRelativePositionTimer.Stop();
lock (_RelativePositionLock)
{
_MouseState.RelX = 0;
_MouseState.RelY = 0;
MouseMove.Raise(this, _MouseState);
}
}
private void _KeyDownHandler(object sender, System.Windows.Input.KeyEventArgs e)
{
if (_KeyboardState.IsKeyPressed(e.Key))
return;
_KeyboardState.Keys[e.Key] = e.IsDown;
KeyDown.Raise(this, e.Key, System.Windows.Input.Keyboard.Modifiers);
}
private void _KeyUpHandler(object sender, System.Windows.Input.KeyEventArgs e)
{
if (!_KeyboardState.IsKeyPressed(e.Key))
return;
_KeyboardState.Keys[e.Key] = e.IsDown;
KeyUp.Raise(this, e.Key, System.Windows.Input.Keyboard.Modifiers);
}
#region IDisposable Members
public void Dispose()
{
if (_ResetMouseRelativePositionTimer != null)
_ResetMouseRelativePositionTimer.Stop();
if (_ResetMouseWheelTimer != null)
_ResetMouseWheelTimer.Stop();
System.Windows.Input.Keyboard.RemoveKeyDownHandler(_Control, _KeyDownHandler);
System.Windows.Input.Keyboard.RemoveKeyUpHandler(_Control, _KeyUpHandler);
if (_Control is System.Windows.Forms.Integration.WindowsFormsHost)
{
(_Control as System.Windows.Forms.Integration.WindowsFormsHost).Child.MouseMove -= new System.Windows.Forms.MouseEventHandler(Child_MouseMove);
(_Control as System.Windows.Forms.Integration.WindowsFormsHost).Child.MouseDown -= new System.Windows.Forms.MouseEventHandler(Child_MouseDown);
(_Control as System.Windows.Forms.Integration.WindowsFormsHost).Child.MouseUp -= new System.Windows.Forms.MouseEventHandler(Child_MouseUp);
(_Control as System.Windows.Forms.Integration.WindowsFormsHost).Child.MouseClick -= new System.Windows.Forms.MouseEventHandler(Child_MouseClick);
(_Control as System.Windows.Forms.Integration.WindowsFormsHost).Child.MouseDoubleClick -= new System.Windows.Forms.MouseEventHandler(Child_MouseDoubleClick);
(_Control as System.Windows.Forms.Integration.WindowsFormsHost).Child.LostFocus -= new EventHandler(Child_LostFocus);
(_Control as System.Windows.Forms.Integration.WindowsFormsHost).Child.DragOver -= new System.Windows.Forms.DragEventHandler(Child_DragOver);
(_Control as System.Windows.Forms.Integration.WindowsFormsHost).Child.MouseWheel -= new System.Windows.Forms.MouseEventHandler(Child_MouseWheel);
}
}
#endregion
}
}