public override bool Initialize(GameHost host) { base.Initialize(host); Enabled.BindValueChanged(enabled => { if (enabled) { host.Window.MouseMove += handleMouseEvent; host.Window.MouseDown += handleMouseEvent; host.Window.MouseUp += handleMouseEvent; host.Window.MouseWheel += handleMouseEvent; // polling is used to keep a valid mouse position when we aren't receiving events. OpenTK.Input.MouseState?lastCursorState = null; host.InputThread.Scheduler.Add(scheduled = new ScheduledDelegate(delegate { // we should be getting events if the mouse is inside the window. if (MouseInWindow || !host.Window.Visible || host.Window.WindowState == WindowState.Minimized) { return; } var cursorState = OpenTK.Input.Mouse.GetCursorState(); if (cursorState.Equals(lastCursorState)) { return; } lastCursorState = cursorState; var mapped = host.Window.PointToClient(new Point(cursorState.X, cursorState.Y)); var newState = new OpenTKPollMouseState(cursorState, host.IsActive, new Vector2(mapped.X, mapped.Y)); HandleState(newState, lastPollState, true); lastPollState = newState; }, 0, 1000.0 / 60)); } else { scheduled?.Cancel(); host.Window.MouseMove -= handleMouseEvent; host.Window.MouseDown -= handleMouseEvent; host.Window.MouseUp -= handleMouseEvent; host.Window.MouseWheel -= handleMouseEvent; lastPollState = null; lastEventState = null; } }, true); return(true); }
private Vector2 getUpdatedPosition(OpenTK.Input.MouseState state, OpenTKMouseState lastState) { Vector2 currentPosition; if ((state.Flags & MouseStateFlags.MoveAbsolute) > 0) { const int raw_input_resolution = 65536; if (mapAbsoluteInputToWindow) { // map directly to local window currentPosition.X = ((float)((state.X - raw_input_resolution / 2f) * sensitivity.Value) + raw_input_resolution / 2f) / raw_input_resolution * Host.Window.Width; currentPosition.Y = ((float)((state.Y - raw_input_resolution / 2f) * sensitivity.Value) + raw_input_resolution / 2f) / raw_input_resolution * Host.Window.Height; } else { Rectangle screenRect = (state.Flags & MouseStateFlags.VirtualDesktop) > 0 ? Platform.Windows.Native.Input.GetVirtualScreenRect() : new Rectangle(0, 0, DisplayDevice.Default.Width, DisplayDevice.Default.Height); // map to full screen space currentPosition.X = (float)state.X / raw_input_resolution * screenRect.Width + screenRect.X; currentPosition.Y = (float)state.Y / raw_input_resolution * screenRect.Height + screenRect.Y; // find local window coordinates var clientPos = Host.Window.PointToClient(new Point((int)Math.Round(currentPosition.X), (int)Math.Round(currentPosition.Y))); // apply sensitivity from window's centre currentPosition.X = (float)((clientPos.X - Host.Window.Width / 2f) * sensitivity.Value + Host.Window.Width / 2f); currentPosition.Y = (float)((clientPos.Y - Host.Window.Height / 2f) * sensitivity.Value + Host.Window.Height / 2f); } } else { if (lastState == null) { // when we return from being outside of the window, we want to set the new position of our game cursor // to where the OS cursor is, just once. var cursorState = OpenTK.Input.Mouse.GetCursorState(); var screenPoint = Host.Window.PointToClient(new Point(cursorState.X, cursorState.Y)); currentPosition = new Vector2(screenPoint.X, screenPoint.Y); } else { currentPosition = lastState.Position + new Vector2(state.X - lastState.RawState.X, state.Y - lastState.RawState.Y) * (float)sensitivity.Value; } } return(currentPosition); }
private void handleMouseEvent(object sender, OpenTK.Input.MouseEventArgs e) { if (!MouseInWindow) { return; } if (e.Mouse.X < 0 || e.Mouse.Y < 0) { // todo: investigate further why we are getting negative values from OpenTK events // on windows when crossing centre screen boundaries (width/2 or height/2). return; } var newState = new OpenTKEventMouseState(e.Mouse, Host.IsActive, null); HandleState(newState, lastEventState, true); lastEventState = newState; }
protected void HandleState(OpenTKMouseState state, OpenTKMouseState lastState, bool isAbsolutePosition) { if (lastState == null || isAbsolutePosition) { PendingInputs.Enqueue(new MousePositionAbsoluteInput { Position = state.Position }); currentPosition = state.Position; } else { var delta = state.Position - lastState.Position; if (delta != Vector2.Zero) { PendingInputs.Enqueue(new MousePositionRelativeInput { Delta = delta }); currentPosition += delta; } } if (lastState != null) { var scrollDelta = state.Scroll - lastState.Scroll; if (scrollDelta != Vector2.Zero) { PendingInputs.Enqueue(new MouseScrollRelativeInput { Delta = scrollDelta, IsPrecise = state.HasPreciseScroll }); } } PendingInputs.Enqueue(new MouseButtonInput(state.Buttons, lastState?.Buttons)); FrameStatistics.Increment(StatisticsCounterType.MouseEvents); }
public override bool Initialize(GameHost host) { base.Initialize(host); // Get the bindables we need to determine whether to confine the mouse to window or not if (host.Window is DesktopGameWindow desktopWindow) { confineMode.BindTo(desktopWindow.ConfineMouseMode); windowMode.BindTo(desktopWindow.WindowMode); mapAbsoluteInputToWindow.BindTo(desktopWindow.MapAbsoluteInputToWindow); } Enabled.ValueChanged += enabled => { if (enabled) { host.InputThread.Scheduler.Add(scheduled = new ScheduledDelegate(delegate { if (!host.Window.Visible || host.Window.WindowState == WindowState.Minimized) { return; } if ((MouseInWindow || lastEachDeviceStates.Any(s => s != null && s.HasAnyButtonPressed)) && host.Window.Focused) { var newRawStates = new List <OpenTK.Input.MouseState>(mostSeenStates + 1); for (int i = 0; i <= mostSeenStates + 1; i++) { var s = OpenTK.Input.Mouse.GetState(i); if (s.IsConnected || i < mostSeenStates) { newRawStates.Add(s); mostSeenStates = i; } } while (lastEachDeviceStates.Count < newRawStates.Count) { lastEachDeviceStates.Add(null); } for (int i = 0; i < newRawStates.Count; i++) { if (newRawStates[i].IsConnected != true) { lastEachDeviceStates[i] = null; continue; } var rawState = newRawStates[i]; var lastState = lastEachDeviceStates[i]; if (lastState != null && rawState.Equals(lastState.RawState)) { continue; } var newState = new OpenTKPollMouseState(rawState, host.IsActive, getUpdatedPosition(rawState, lastState)); HandleState(newState, lastState, (rawState.Flags & MouseStateFlags.MoveAbsolute) > 0); lastEachDeviceStates[i] = newState; lastUnfocusedState = null; } } else { var state = OpenTK.Input.Mouse.GetCursorState(); var screenPoint = host.Window.PointToClient(new Point(state.X, state.Y)); var newState = new UnfocusedMouseState(new OpenTK.Input.MouseState(), host.IsActive, new Vector2(screenPoint.X, screenPoint.Y)); HandleState(newState, lastUnfocusedState, true); lastUnfocusedState = newState; lastEachDeviceStates.Clear(); } }, 0, 0)); } else { scheduled?.Cancel(); lastEachDeviceStates.Clear(); lastUnfocusedState = null; } }; Enabled.TriggerChange(); return(true); }
private Vector2 getUpdatedPosition(OpenTK.Input.MouseState state, OpenTKMouseState lastState) { Vector2 currentPosition; if ((state.RawFlags & RawMouseFlags.MOUSE_MOVE_ABSOLUTE) > 0) { const int raw_input_resolution = 65536; if (mapAbsoluteInputToWindow) { // map directly to local window currentPosition.X = ((float)((state.X - raw_input_resolution / 2f) * sensitivity.Value) + raw_input_resolution / 2f) / raw_input_resolution * host.Window.Width; currentPosition.Y = ((float)((state.Y - raw_input_resolution / 2f) * sensitivity.Value) + raw_input_resolution / 2f) / raw_input_resolution * host.Window.Height; } else { Rectangle screenRect = (state.RawFlags & RawMouseFlags.MOUSE_VIRTUAL_DESKTOP) > 0 ? Platform.Windows.Native.Input.GetVirtualScreenRect() : new Rectangle(0, 0, DisplayDevice.Default.Width, DisplayDevice.Default.Height); // map to full screen space currentPosition.X = (float)state.X / raw_input_resolution * screenRect.Width + screenRect.X; currentPosition.Y = (float)state.Y / raw_input_resolution * screenRect.Height + screenRect.Y; // find local window coordinates var clientPos = host.Window.PointToClient(new Point((int)Math.Round(currentPosition.X), (int)Math.Round(currentPosition.Y))); // apply sensitivity from window's centre currentPosition.X = (float)((clientPos.X - host.Window.Width / 2f) * sensitivity.Value + host.Window.Width / 2f); currentPosition.Y = (float)((clientPos.Y - host.Window.Height / 2f) * sensitivity.Value + host.Window.Height / 2f); } } else { if (lastState == null) { // when we return from being outside of the window, we want to set the new position of our game cursor // to where the OS cursor is, just once. var cursorState = OpenTK.Input.Mouse.GetCursorState(); var screenPoint = host.Window.PointToClient(new Point(cursorState.X, cursorState.Y)); currentPosition = new Vector2(screenPoint.X, screenPoint.Y); } else { currentPosition = lastState.Position + new Vector2(state.X - lastState.RawState.X, state.Y - lastState.RawState.Y) * (float)sensitivity.Value; // When confining, clamp to the window size. if (confineMode.Value == ConfineMouseMode.Always || confineMode.Value == ConfineMouseMode.Fullscreen && windowMode.Value == WindowMode.Fullscreen) { currentPosition = Vector2.Clamp(currentPosition, Vector2.Zero, new Vector2(host.Window.Width, host.Window.Height)); } // update the windows cursor to match our raw cursor position. // this is important when sensitivity is decreased below 1.0, where we need to ensure the cursor stays within the window. var screenPoint = host.Window.PointToScreen(new Point((int)currentPosition.X, (int)currentPosition.Y)); OpenTK.Input.Mouse.SetPosition(screenPoint.X, screenPoint.Y); } } return(currentPosition); }