using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; namespace MrGameEng.Input; /// Mouse buttons addressable through . public enum MouseButton { /// Left button. Left, /// Right button. Right, /// Middle button (wheel click). Middle, } /// /// Polls keyboard, mouse and gamepad once per frame and keeps the previous frame's state, /// enabling edge queries (Pressed = went down this frame, Released = went up). /// Registered as a service by scene.UseInput(); polled by /// at the start of the update phase. While /// is set (e.g. the developer console is open), game-facing input reads as released. /// public sealed class InputManager { private readonly MrGameEng.Core.InputCapture? _capture; private KeyboardState _keyboard; private KeyboardState _previousKeyboard; private MouseState _mouse; private MouseState _previousMouse; private GamePadState _gamePad; private GamePadState _previousGamePad; /// /// Creates a manager. With a , input is suppressed while a UI /// overlay holds it (keys/buttons read as released, mouse position and wheel freeze). /// public InputManager(MrGameEng.Core.InputCapture? capture = null) => _capture = capture; /// Polls all devices. Called once per frame by . public void Update() { if (_capture?.Captured == true) { // Оверлей (консоль) захватил ввод: клавиши и кнопки считаются отпущенными, // позиция мыши и счётчик колеса замораживаются — все дельты нулевые. Apply( default, new MouseState( _mouse.X, _mouse.Y, _mouse.ScrollWheelValue, ButtonState.Released, ButtonState.Released, ButtonState.Released, ButtonState.Released, ButtonState.Released ), default ); return; } Apply(Keyboard.GetState(), Mouse.GetState(), GamePad.GetState(PlayerIndex.One)); } internal void Apply(KeyboardState keyboard, MouseState mouse, GamePadState gamePad) { _previousKeyboard = _keyboard; _previousMouse = _mouse; _previousGamePad = _gamePad; _keyboard = keyboard; _mouse = mouse; _gamePad = gamePad; } /// True while the key is held down. public bool IsKeyDown(Keys key) => _keyboard.IsKeyDown(key); /// True only on the frame the key went down. public bool IsKeyPressed(Keys key) => _keyboard.IsKeyDown(key) && _previousKeyboard.IsKeyUp(key); /// True only on the frame the key went up. public bool IsKeyReleased(Keys key) => _keyboard.IsKeyUp(key) && _previousKeyboard.IsKeyDown(key); /// Mouse cursor position in window pixels. public Point MousePosition => _mouse.Position; /// Cursor movement since the previous frame. public Point MouseDelta => _mouse.Position - _previousMouse.Position; /// Scroll wheel change since the previous frame (positive = up). public int WheelDelta => _mouse.ScrollWheelValue - _previousMouse.ScrollWheelValue; /// True while the mouse button is held down. public bool IsMouseDown(MouseButton button) => GetButton(_mouse, button) == ButtonState.Pressed; /// True only on the frame the mouse button went down. public bool IsMousePressed(MouseButton button) => GetButton(_mouse, button) == ButtonState.Pressed && GetButton(_previousMouse, button) == ButtonState.Released; /// True only on the frame the mouse button went up. public bool IsMouseReleased(MouseButton button) => GetButton(_mouse, button) == ButtonState.Released && GetButton(_previousMouse, button) == ButtonState.Pressed; /// True while the gamepad button is held down. public bool IsButtonDown(Buttons button) => _gamePad.IsButtonDown(button); /// True only on the frame the gamepad button went down. public bool IsButtonPressed(Buttons button) => _gamePad.IsButtonDown(button) && _previousGamePad.IsButtonUp(button); /// True only on the frame the gamepad button went up. public bool IsButtonReleased(Buttons button) => _gamePad.IsButtonUp(button) && _previousGamePad.IsButtonDown(button); /// Left thumbstick, x/y in [-1, 1]. Y is inverted to match the engine's y-down world. public Vector2 LeftStick => new(_gamePad.ThumbSticks.Left.X, -_gamePad.ThumbSticks.Left.Y); private static ButtonState GetButton(in MouseState state, MouseButton button) => button switch { MouseButton.Left => state.LeftButton, MouseButton.Right => state.RightButton, MouseButton.Middle => state.MiddleButton, _ => ButtonState.Released, }; }