protected virtual void OnMouseDown(object sender, MouseEventArgs e) { Mouse.Capture(EventSource, CaptureMode.Element); _previousPosition2D = e.GetPosition(EventSource); _previousPosition3D = ProjectToTrackball( EventSource.ActualWidth, EventSource.ActualHeight, _previousPosition2D); }
protected virtual void OnMouseMove(object sender, MouseEventArgs e) { Point currentPosition = e.GetPosition(EventSource); bool ctrlOrShift = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl) || Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.LeftShift); // Prefer tracking to zooming if both buttons are pressed. if (e.LeftButton == MouseButtonState.Pressed && !ctrlOrShift) { if (_mouseLeftDown) { Track(currentPosition); } else { _mouseLeftDown = true; Mouse.Capture(EventSource, CaptureMode.Element); _previousPosition2D = e.GetPosition(EventSource); _previousPosition3D = ProjectToTrackball( EventSource.ActualWidth, EventSource.ActualHeight, _previousPosition2D); } } else if (e.RightButton == MouseButtonState.Pressed || (e.LeftButton == MouseButtonState.Pressed && ctrlOrShift)) { if (_mouseRightDown) { //if (Zoom(currentPosition)) e.Handled = true; Translate(currentPosition); } else { _mouseRightDown = true; Mouse.Capture(EventSource, CaptureMode.Element); _previousPosition2D = e.GetPosition(EventSource); _previousPosition3D = ProjectToTrackball( EventSource.ActualWidth, EventSource.ActualHeight, _previousPosition2D); } } else { _mouseLeftDown = false; _mouseRightDown = false; } _previousPosition2D = currentPosition; }
private void HandleMouse(object sender, MouseEventArgs e) { if (e.Handled) { return; } var pos = Mouse.GetPosition(_focusElement); if (!CaptureMouseWithin) { // clamp as fast moving mouse will somtimes still report values outside the control without explicit capture (e.g. negative values) pos = new Point(Clamp(pos.X, 0, _focusElement.RenderSize.Width), Clamp(pos.Y, 0, _focusElement.RenderSize.Height)); } if (_focusElement.IsMouseDirectlyOver && System.Windows.Input.Keyboard.FocusedElement != _focusElement) { // otherwise focus only when the user clicks into the game // on windows this behaviour doesn't require an explicit left click // instead, left, middle, right and even xbuttons work (the only thing that doesn't trigger focus is scrolling) // so mimic that exactly if (e.LeftButton == MouseButtonState.Pressed || e.RightButton == MouseButtonState.Pressed || e.MiddleButton == MouseButtonState.Pressed || e.XButton1 == MouseButtonState.Pressed || e.XButton2 == MouseButtonState.Pressed) { _focusElement.Focus(); } } if ((!_focusElement.IsMouseDirectlyOver || _focusElement.IsMouseCaptured) && CaptureMouseWithin) { // IsMouseDirectlyOver always returns true if the mouse is captured, so we need to do our own hit testing if the Mouse is captured to find out whether it is actually over the control or not if (_focusElement.IsMouseCaptured) { // apparently all WPF IInputElements are always Visuals, so we can cast directly var v = (Visual)_focusElement; bool hit = false; VisualTreeHelper.HitTest(v, filterTarget => HitTestFilterBehavior.Continue, target => { if (target.VisualHit == _focusElement) { // our actual element was hit hit = true; } return(HitTestResultBehavior.Continue); }, new PointHitTestParameters(pos)); if (!hit) { // outside the hitbox // when the mouse is leaving the control we need to register button releases // when the user clicks in the control, holds the button and moves it outside the control and releases there it normally does not registered // the control would thus think that the button is still pressed // using capture allows us to receive this event, propagate it and then free the mouse _mouseState = new MouseState(_mouseState.X, _mouseState.Y, _mouseState.ScrollWheelValue, (ButtonState)e.LeftButton, (ButtonState)e.MiddleButton, (ButtonState)e.RightButton, (ButtonState)e.XButton1, (ButtonState)e.XButton2); // only release if LeftMouse is up if (e.LeftButton == MouseButtonState.Released) { _focusElement.ReleaseMouseCapture(); } e.Handled = true; return; } // inside the control and captured -> still requires full update, so run code below and don't return right away } else { // mouse is outside the control and not captured, so don't update the mouse state return; } } if (CaptureMouseWithin) { // capture the mouse, this allows receiving of mouse event while the mouse is leaving the control: https://msdn.microsoft.com/en-us/library/ms591452(v=vs.110).aspx if (!_focusElement.IsMouseCaptured) { // however, only focus if we are the active window, otherwise the window will become active and pop into foreground just by hovering the mouse over the game panel if (IsControlOnActiveWindow(_focusElement)) { // however, only focus if we are the active window, otherwise the window will become active while remaining in the background // _focusElement.CaptureMouse(); } else { // don't update mouse events if we are just hovering over different window return; } } } else { if (_focusElement.IsFocused && !IsControlOnActiveWindow(_focusElement)) { // don't update mouse events if we are just hovering over different window return; } } e.Handled = true; var m = _mouseState; var w = e as MouseWheelEventArgs; _mouseState = new MouseState((int)pos.X, (int)pos.Y, m.ScrollWheelValue + (w?.Delta ?? 0), (ButtonState)e.LeftButton, (ButtonState)e.MiddleButton, (ButtonState)e.RightButton, (ButtonState)e.XButton1, (ButtonState)e.XButton2); }
protected virtual void OnMouseUp(object sender, MouseEventArgs e) { Mouse.Capture(EventSource, CaptureMode.None); }