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 } }