mirror of
https://github.com/AlexMacocian/MonoGame.Extended.git
synced 2026-07-15 15:09:29 +00:00
refactored on input events
This commit is contained in:
@@ -194,3 +194,4 @@ FakesAssemblies/
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
*.DotSettings
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace MonoGame.Extended.InputEvents
|
||||
{
|
||||
public abstract class Input
|
||||
{
|
||||
protected Game Game { get; set; }
|
||||
|
||||
protected Input(Game game)
|
||||
{
|
||||
Game = game;
|
||||
}
|
||||
|
||||
/*####################################################################*/
|
||||
/* Input Events */
|
||||
/*####################################################################*/
|
||||
|
||||
public abstract void Update(GameTime gameTime);
|
||||
|
||||
/*####################################################################*/
|
||||
/* Keyboard Events */
|
||||
/*####################################################################*/
|
||||
|
||||
public abstract event EventHandler<KeyboardCharacterEventArgs> CharacterTyped;
|
||||
|
||||
public abstract event EventHandler<KeyboardKeyEventArgs> KeyDown;
|
||||
public abstract event EventHandler<KeyboardKeyEventArgs> KeyUp;
|
||||
|
||||
/*####################################################################*/
|
||||
/* Mouse Events */
|
||||
/*####################################################################*/
|
||||
|
||||
public abstract event EventHandler<MouseEventArgs> MouseMoved;
|
||||
public abstract event EventHandler<MouseEventArgs> MouseDoubleClick;
|
||||
|
||||
public abstract event EventHandler<MouseEventArgs> MouseDown;
|
||||
public abstract event EventHandler<MouseEventArgs> MouseUp;
|
||||
|
||||
public abstract event EventHandler<MouseEventArgs> MouseWheel;
|
||||
|
||||
/*####################################################################*/
|
||||
/* Touch Events */
|
||||
/*####################################################################*/
|
||||
|
||||
public abstract event EventHandler<TouchEventArgs> TouchBegan;
|
||||
public abstract event EventHandler<TouchEventArgs> TouchMoved;
|
||||
public abstract event EventHandler<TouchEventArgs> TouchEnded;
|
||||
public abstract event EventHandler<TouchEventArgs> TouchCancelled;
|
||||
}
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Input
|
||||
{
|
||||
internal class MonoGameMouseEventArgs : MouseEventArgs
|
||||
{
|
||||
internal TimeSpan Time { get; set; }
|
||||
|
||||
internal MouseState Previous { get; private set; }
|
||||
internal MouseState Current { get; private set; }
|
||||
|
||||
internal MonoGameMouseEventArgs(int x, int y, TimeSpan time, MouseState previous, MouseState current,
|
||||
MouseButton button = MouseButton.None, int? value = null, int? delta = null)
|
||||
: base(x, y, button, value, delta)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Time = time;
|
||||
Previous = previous;
|
||||
Current = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Input
|
||||
{
|
||||
internal class MonoGameKeyboardEvents
|
||||
{
|
||||
internal event EventHandler<KeyboardCharacterEventArgs> CharacterTyped;
|
||||
internal event EventHandler<KeyboardKeyEventArgs> KeyPressed;
|
||||
internal event EventHandler<KeyboardKeyEventArgs> KeyReleased;
|
||||
|
||||
|
||||
private static int InitialDelay { get; set; }
|
||||
private static int RepeatDelay { get; set; }
|
||||
|
||||
private Keys _lastKey;
|
||||
private TimeSpan _lastPress;
|
||||
private bool _isInitial;
|
||||
|
||||
private KeyboardState _previous;
|
||||
|
||||
public MonoGameKeyboardEvents()
|
||||
{
|
||||
InitialDelay = 800;
|
||||
RepeatDelay = 50;
|
||||
}
|
||||
|
||||
public void Update(GameTime gameTime)
|
||||
{
|
||||
var current = Keyboard.GetState();
|
||||
|
||||
if (!current.IsKeyDown(Keys.LeftAlt)
|
||||
&& !current.IsKeyDown(Keys.RightAlt))
|
||||
{
|
||||
foreach (var key in Enum.GetValues(typeof (Keys))
|
||||
.Cast<Keys>()
|
||||
.Where(key => current.IsKeyDown(key) && _previous.IsKeyUp(key)))
|
||||
{
|
||||
var args = new KeyboardKeyEventArgs(key);
|
||||
|
||||
OnKeyPressed(this, args);
|
||||
|
||||
_lastKey = key;
|
||||
_lastPress = gameTime.TotalGameTime;
|
||||
_isInitial = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var key in
|
||||
Enum.GetValues(typeof(Keys))
|
||||
.Cast<Keys>()
|
||||
.Where(key => current.IsKeyUp(key) && _previous.IsKeyDown(key)))
|
||||
{
|
||||
OnKeyReleased(this, new KeyboardKeyEventArgs(key));
|
||||
}
|
||||
|
||||
var elapsedTime = (gameTime.TotalGameTime - _lastPress).TotalMilliseconds;
|
||||
|
||||
if (current.IsKeyDown(_lastKey) &&
|
||||
((_isInitial && elapsedTime > InitialDelay) ||
|
||||
(!_isInitial && elapsedTime > RepeatDelay)))
|
||||
{
|
||||
OnCharacterPressed(this, new KeyboardKeyEventArgs(_lastKey));
|
||||
|
||||
_lastPress = gameTime.TotalGameTime;
|
||||
_isInitial = false;
|
||||
}
|
||||
|
||||
_previous = current;
|
||||
}
|
||||
|
||||
private void OnKeyPressed(object sender, KeyboardKeyEventArgs args)
|
||||
{
|
||||
if (KeyPressed != null)
|
||||
{
|
||||
KeyPressed(sender, args);
|
||||
}
|
||||
|
||||
OnCharacterPressed(sender, args);
|
||||
}
|
||||
|
||||
private void OnCharacterPressed(object sender, KeyboardKeyEventArgs args)
|
||||
{
|
||||
if (CharacterTyped == null) { return; }
|
||||
|
||||
var character = KeyboardUtil.ToChar(args.Key, args.Modifiers);
|
||||
if (character.HasValue)
|
||||
{
|
||||
CharacterTyped(this, new KeyboardCharacterEventArgs(character.Value));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnKeyReleased(object sender, KeyboardKeyEventArgs args)
|
||||
{
|
||||
if (KeyReleased != null)
|
||||
{
|
||||
KeyReleased(sender, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,238 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Input
|
||||
{
|
||||
internal class MonoGameMouseEvents
|
||||
{
|
||||
internal event EventHandler<MouseEventArgs> ButtonReleased;
|
||||
internal event EventHandler<MouseEventArgs> ButtonPressed;
|
||||
internal event EventHandler<MouseEventArgs> ButtonDoubleClicked;
|
||||
internal event EventHandler<MouseEventArgs> MouseMoved;
|
||||
internal event EventHandler<MouseEventArgs> MouseWheelMoved;
|
||||
|
||||
private MouseState _previous;
|
||||
private MonoGameMouseEventArgs _lastClick;
|
||||
|
||||
private readonly int _doubleClickMaxTimeDelta;
|
||||
private readonly int _doubleClickMaxMovementDelta;
|
||||
|
||||
internal MonoGameMouseEvents(int doubleClickMaxTimeDelta, int doubleClickMaxMovementDelta)
|
||||
{
|
||||
_doubleClickMaxTimeDelta = doubleClickMaxTimeDelta;
|
||||
_doubleClickMaxMovementDelta = doubleClickMaxMovementDelta;
|
||||
|
||||
_lastClick = new MonoGameMouseEventArgs(
|
||||
-1,
|
||||
-1,
|
||||
new TimeSpan(),
|
||||
Mouse.GetState(),
|
||||
Mouse.GetState());
|
||||
}
|
||||
|
||||
internal void Update(GameTime gameTime)
|
||||
{
|
||||
var current = Mouse.GetState();
|
||||
|
||||
// Check button press events.
|
||||
if (current.LeftButton == ButtonState.Pressed
|
||||
&& _previous.LeftButton == ButtonState.Released)
|
||||
{
|
||||
OnButtonPressed(this, new MonoGameMouseEventArgs(
|
||||
current.X,
|
||||
current.Y,
|
||||
gameTime.TotalGameTime,
|
||||
_previous,
|
||||
current,
|
||||
MouseButton.Left));
|
||||
}
|
||||
|
||||
if (current.MiddleButton == ButtonState.Pressed
|
||||
&& _previous.MiddleButton == ButtonState.Released)
|
||||
{
|
||||
OnButtonPressed(this, new MonoGameMouseEventArgs(
|
||||
current.X,
|
||||
current.Y,
|
||||
gameTime.TotalGameTime,
|
||||
_previous,
|
||||
current,
|
||||
MouseButton.Middle));
|
||||
}
|
||||
|
||||
if (current.RightButton == ButtonState.Pressed
|
||||
&& _previous.RightButton == ButtonState.Released)
|
||||
{
|
||||
OnButtonPressed(this, new MonoGameMouseEventArgs(
|
||||
current.X,
|
||||
current.Y,
|
||||
gameTime.TotalGameTime,
|
||||
_previous,
|
||||
current,
|
||||
MouseButton.Right));
|
||||
}
|
||||
|
||||
if (current.XButton1 == ButtonState.Pressed
|
||||
&& _previous.XButton1 == ButtonState.Released)
|
||||
{
|
||||
OnButtonPressed(this, new MonoGameMouseEventArgs(
|
||||
current.X,
|
||||
current.Y,
|
||||
gameTime.TotalGameTime,
|
||||
_previous,
|
||||
current,
|
||||
MouseButton.XButton1));
|
||||
}
|
||||
|
||||
if (current.XButton2 == ButtonState.Pressed
|
||||
&& _previous.XButton2 == ButtonState.Released)
|
||||
{
|
||||
OnButtonPressed(this, new MonoGameMouseEventArgs(
|
||||
current.X,
|
||||
current.Y,
|
||||
gameTime.TotalGameTime,
|
||||
_previous,
|
||||
current,
|
||||
MouseButton.XButton2));
|
||||
}
|
||||
|
||||
// Check button releases.
|
||||
if (current.LeftButton == ButtonState.Released
|
||||
&& _previous.LeftButton == ButtonState.Pressed)
|
||||
{
|
||||
OnButtonReleased(this, new MonoGameMouseEventArgs(
|
||||
current.X,
|
||||
current.Y,
|
||||
gameTime.TotalGameTime,
|
||||
_previous,
|
||||
current,
|
||||
MouseButton.Left));
|
||||
}
|
||||
|
||||
if (current.MiddleButton == ButtonState.Released
|
||||
&& _previous.MiddleButton == ButtonState.Pressed)
|
||||
{
|
||||
OnButtonReleased(this, new MonoGameMouseEventArgs(
|
||||
current.X,
|
||||
current.Y,
|
||||
gameTime.TotalGameTime,
|
||||
_previous,
|
||||
current,
|
||||
MouseButton.Middle));
|
||||
}
|
||||
|
||||
if (current.RightButton == ButtonState.Released
|
||||
&& _previous.RightButton == ButtonState.Pressed)
|
||||
{
|
||||
OnButtonReleased(this, new MonoGameMouseEventArgs(
|
||||
current.X,
|
||||
current.Y,
|
||||
gameTime.TotalGameTime,
|
||||
_previous,
|
||||
current,
|
||||
MouseButton.Right));
|
||||
}
|
||||
|
||||
if (current.XButton1 == ButtonState.Released
|
||||
&& _previous.XButton1 == ButtonState.Pressed)
|
||||
{
|
||||
OnButtonReleased(this, new MonoGameMouseEventArgs(
|
||||
current.X,
|
||||
current.Y,
|
||||
gameTime.TotalGameTime,
|
||||
_previous,
|
||||
current,
|
||||
MouseButton.XButton1));
|
||||
}
|
||||
|
||||
if (current.XButton2 == ButtonState.Released
|
||||
&& _previous.XButton2 == ButtonState.Pressed)
|
||||
{
|
||||
OnButtonReleased(this, new MonoGameMouseEventArgs(
|
||||
current.X,
|
||||
current.Y,
|
||||
gameTime.TotalGameTime,
|
||||
_previous,
|
||||
current,
|
||||
MouseButton.XButton2));
|
||||
}
|
||||
|
||||
// Check for any sort of mouse movement. If a button is down, it's a drag,
|
||||
// otherwise it's a move.
|
||||
if (_previous.X != current.X || _previous.Y != current.Y)
|
||||
{
|
||||
OnMouseMoved(this, new MonoGameMouseEventArgs(
|
||||
current.X,
|
||||
current.Y,
|
||||
gameTime.TotalGameTime,
|
||||
_previous,
|
||||
current));
|
||||
}
|
||||
|
||||
// Handle mouse wheel events.
|
||||
if (_previous.ScrollWheelValue != current.ScrollWheelValue)
|
||||
{
|
||||
var value = current.ScrollWheelValue / 120;
|
||||
var delta = (current.ScrollWheelValue - _previous.ScrollWheelValue) / 120;
|
||||
OnMouseWheelMoved(this, new MonoGameMouseEventArgs(
|
||||
current.X,
|
||||
current.Y,
|
||||
gameTime.TotalGameTime,
|
||||
_previous,
|
||||
current,
|
||||
MouseButton.None,
|
||||
value,
|
||||
delta));
|
||||
}
|
||||
|
||||
_previous = current;
|
||||
}
|
||||
|
||||
private void OnButtonReleased(object sender, MonoGameMouseEventArgs args)
|
||||
{
|
||||
if (ButtonReleased != null)
|
||||
{
|
||||
ButtonReleased(sender, args);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnButtonPressed(object sender, MonoGameMouseEventArgs args)
|
||||
{
|
||||
// If this click is within the right time and position of the last click,
|
||||
// raise a double-click event as well.
|
||||
if (ButtonDoubleClicked != null &&
|
||||
_lastClick.Button == args.Button &&
|
||||
(args.Time - _lastClick.Time).TotalMilliseconds < _doubleClickMaxTimeDelta &&
|
||||
DistanceBetween(args.Current, _lastClick.Current) < _doubleClickMaxMovementDelta)
|
||||
{
|
||||
ButtonDoubleClicked(sender, args);
|
||||
//args.Time = new TimeSpan(0);
|
||||
}
|
||||
else if (ButtonPressed != null)
|
||||
{
|
||||
ButtonPressed(sender, args);
|
||||
}
|
||||
|
||||
_lastClick = args;
|
||||
}
|
||||
|
||||
private static int DistanceBetween(MouseState a, MouseState b)
|
||||
{
|
||||
return Math.Abs(a.X - b.X) + Math.Abs(a.Y - b.Y);
|
||||
}
|
||||
|
||||
private void OnMouseMoved(object sender, MouseEventArgs args)
|
||||
{
|
||||
if (MouseMoved != null)
|
||||
{
|
||||
MouseMoved(sender, args);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMouseWheelMoved(object sender, MouseEventArgs args)
|
||||
{
|
||||
if (MouseWheelMoved != null)
|
||||
{
|
||||
MouseWheelMoved(sender, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework.Input.Touch;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Input
|
||||
{
|
||||
public class MonoGameTouchEvents
|
||||
{
|
||||
internal event EventHandler<TouchEventArgs> TouchBegan;
|
||||
internal event EventHandler<TouchEventArgs> TouchMoved;
|
||||
internal event EventHandler<TouchEventArgs> TouchEnded;
|
||||
internal event EventHandler<TouchEventArgs> TouchCancelled;
|
||||
|
||||
|
||||
public void Update(GameTime gameTime)
|
||||
{
|
||||
TouchCollection touchCollection = TouchPanel.GetState();
|
||||
foreach (TouchLocation tl in touchCollection)
|
||||
{
|
||||
switch (tl.State)
|
||||
{
|
||||
case TouchLocationState.Pressed:
|
||||
OnTouchBegan(this, new TouchEventArgs(tl));
|
||||
break;
|
||||
case TouchLocationState.Moved:
|
||||
OnTouchMoved(this, new TouchEventArgs(tl));
|
||||
break;
|
||||
case TouchLocationState.Released:
|
||||
OnTouchEnded(this, new TouchEventArgs(tl));
|
||||
break;
|
||||
case TouchLocationState.Invalid:
|
||||
OnTouchCancelled(this, new TouchEventArgs(tl));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTouchBegan(object sender, TouchEventArgs args)
|
||||
{
|
||||
if (TouchBegan != null)
|
||||
{
|
||||
TouchBegan(sender, args);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTouchMoved(object sender, TouchEventArgs args)
|
||||
{
|
||||
if (TouchMoved != null)
|
||||
{
|
||||
TouchMoved(sender, args);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTouchEnded(object sender, TouchEventArgs args)
|
||||
{
|
||||
if (TouchEnded != null)
|
||||
{
|
||||
TouchEnded(sender, args);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTouchCancelled(object sender, TouchEventArgs args)
|
||||
{
|
||||
if (TouchCancelled != null)
|
||||
{
|
||||
TouchCancelled(sender, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace MonoGame.Extended.InputEvents
|
||||
{
|
||||
public sealed class MonoGameInput : Input
|
||||
{
|
||||
private readonly MonoGameMouseEvents _mouseEvents;
|
||||
private readonly MonoGameKeyboardEvents _monoGameKeyboardEvents;
|
||||
private readonly MonoGameTouchEvents _monoGameTouchEvents;
|
||||
|
||||
public MonoGameInput(Game game, int? doubleClickMaxTimeDelta = null,
|
||||
int? doubleClickMaxMovementDelta = null) : base(game)
|
||||
{
|
||||
if (doubleClickMaxTimeDelta == null)
|
||||
{
|
||||
doubleClickMaxTimeDelta = 500; //Windows default
|
||||
}
|
||||
|
||||
if (doubleClickMaxMovementDelta == null)
|
||||
{
|
||||
doubleClickMaxMovementDelta = 2; //Windows default
|
||||
}
|
||||
|
||||
_mouseEvents = new MonoGameMouseEvents(
|
||||
doubleClickMaxTimeDelta.Value,
|
||||
doubleClickMaxTimeDelta.Value);
|
||||
|
||||
_monoGameKeyboardEvents = new MonoGameKeyboardEvents();
|
||||
|
||||
_monoGameTouchEvents = new MonoGameTouchEvents();
|
||||
}
|
||||
|
||||
override public void Update(GameTime gameTime)
|
||||
{
|
||||
_mouseEvents.Update(gameTime);
|
||||
_monoGameKeyboardEvents.Update(gameTime);
|
||||
_monoGameTouchEvents.Update(gameTime);
|
||||
}
|
||||
|
||||
|
||||
/*####################################################################*/
|
||||
/* Keyboard Events */
|
||||
/*####################################################################*/
|
||||
|
||||
public override event EventHandler<KeyboardCharacterEventArgs> CharacterTyped
|
||||
{
|
||||
add { _monoGameKeyboardEvents.CharacterTyped += value; }
|
||||
remove { _monoGameKeyboardEvents.CharacterTyped -= value; }
|
||||
}
|
||||
|
||||
public override event EventHandler<KeyboardKeyEventArgs> KeyDown
|
||||
{
|
||||
add { _monoGameKeyboardEvents.KeyPressed += value; }
|
||||
remove { _monoGameKeyboardEvents.KeyPressed -= value; }
|
||||
}
|
||||
|
||||
public override event EventHandler<KeyboardKeyEventArgs> KeyUp
|
||||
{
|
||||
add { _monoGameKeyboardEvents.KeyReleased += value; }
|
||||
remove { _monoGameKeyboardEvents.KeyReleased -= value; }
|
||||
}
|
||||
|
||||
|
||||
/*####################################################################*/
|
||||
/* Mouse Events */
|
||||
/*####################################################################*/
|
||||
|
||||
//Movement
|
||||
public override event EventHandler<MouseEventArgs> MouseMoved
|
||||
{
|
||||
add { _mouseEvents.MouseMoved += value; }
|
||||
remove { _mouseEvents.MouseMoved -= value; }
|
||||
}
|
||||
|
||||
//Buttons
|
||||
public override event EventHandler<MouseEventArgs> MouseDoubleClick
|
||||
{
|
||||
add { _mouseEvents.ButtonDoubleClicked += value; }
|
||||
remove { _mouseEvents.ButtonDoubleClicked -= value; }
|
||||
}
|
||||
|
||||
public override event EventHandler<MouseEventArgs> MouseDown
|
||||
{
|
||||
add { _mouseEvents.ButtonPressed += value; }
|
||||
remove { _mouseEvents.ButtonPressed -= value; }
|
||||
}
|
||||
|
||||
public override event EventHandler<MouseEventArgs> MouseUp
|
||||
{
|
||||
add { _mouseEvents.ButtonReleased += value; }
|
||||
remove { _mouseEvents.ButtonReleased -= value; }
|
||||
}
|
||||
|
||||
//Wheel
|
||||
public override event EventHandler<MouseEventArgs> MouseWheel
|
||||
{
|
||||
add { _mouseEvents.MouseWheelMoved += value; }
|
||||
remove { _mouseEvents.MouseWheelMoved -= value; }
|
||||
}
|
||||
|
||||
/*####################################################################*/
|
||||
/* Touch Events */
|
||||
/*####################################################################*/
|
||||
|
||||
public override event EventHandler<TouchEventArgs> TouchBegan
|
||||
{
|
||||
add { _monoGameTouchEvents.TouchBegan += value; }
|
||||
remove { _monoGameTouchEvents.TouchBegan -= value; }
|
||||
}
|
||||
|
||||
public override event EventHandler<TouchEventArgs> TouchMoved
|
||||
{
|
||||
add { _monoGameTouchEvents.TouchMoved += value; }
|
||||
remove { _monoGameTouchEvents.TouchMoved -= value; }
|
||||
}
|
||||
|
||||
public override event EventHandler<TouchEventArgs> TouchEnded
|
||||
{
|
||||
add { _monoGameTouchEvents.TouchEnded += value; }
|
||||
remove { _monoGameTouchEvents.TouchEnded -= value; }
|
||||
}
|
||||
|
||||
public override event EventHandler<TouchEventArgs> TouchCancelled
|
||||
{
|
||||
add { _monoGameTouchEvents.TouchCancelled += value; }
|
||||
remove { _monoGameTouchEvents.TouchCancelled -= value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
# MonoGame-EventDriven-Input
|
||||
|
||||
This project provides event driven input for desktop MonoGame projects. The input has been designed to mimic the behavior of the Windows Message Queue as closely as possible creating as familiar as possible behavior.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Using the library is very simple. Simple create an instance of the MonoGameInput object, call Update in the Game.Update function, and then subscribe to the events. You can even create multiple MonoGameInput instances as an easy way or organize different input schemes (for example one for your menu and one for gameplay input). To disable a MonoGameInput instance simply stop updating it.
|
||||
|
||||
```C#
|
||||
Input _eventDrivenInput;
|
||||
_eventDrivenInput = new MonoGameInput(this);
|
||||
|
||||
_eventDrivenInput.Update(gameTime);
|
||||
|
||||
_eventDrivenInput.KeyDown += (sender, keyDown) =>
|
||||
{
|
||||
//Subscribe to the events
|
||||
};
|
||||
```
|
||||
|
||||
Below are the currently available events.
|
||||
|
||||
```C#
|
||||
public abstract event EventHandler<KeyboardCharacterEventArgs> CharacterTyped;
|
||||
public abstract event EventHandler<KeyboardKeyEventArgs> KeyDown;
|
||||
public abstract event EventHandler<KeyboardKeyEventArgs> KeyUp;
|
||||
|
||||
public abstract event EventHandler<MouseEventArgs> MouseMoved;
|
||||
public abstract event EventHandler<MouseEventArgs> MouseDoubleClick;
|
||||
public abstract event EventHandler<MouseEventArgs> MouseDown;
|
||||
public abstract event EventHandler<MouseEventArgs> MouseUp;
|
||||
public abstract event EventHandler<MouseEventArgs> MouseWheel;
|
||||
|
||||
public abstract event EventHandler<TouchEventArgs> TouchBegan;
|
||||
public abstract event EventHandler<TouchEventArgs> TouchMoved;
|
||||
public abstract event EventHandler<TouchEventArgs> TouchEnded;
|
||||
public abstract event EventHandler<TouchEventArgs> TouchCancelled;
|
||||
```
|
||||
|
||||
## Roadmap
|
||||
|
||||
- Move the project into [MonoGame.Extended](https://github.com/craftworkgames/MonoGame.Extended).
|
||||
- Add support for subscribing event classes to provide an abstraction over the event subscription.
|
||||
- Test against FNA and XNA
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Input
|
||||
{
|
||||
public class KeyboardCharacterEventArgs : EventArgs
|
||||
{
|
||||
public char Character { get; private set; }
|
||||
|
||||
internal KeyboardCharacterEventArgs(char character)
|
||||
{
|
||||
Character = character;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Input
|
||||
{
|
||||
public class KeyboardKeyEventArgs : EventArgs
|
||||
{
|
||||
public Keys Key { get; private set; }
|
||||
public Modifiers Modifiers { get; private set; }
|
||||
|
||||
protected internal KeyboardKeyEventArgs(Keys key)
|
||||
{
|
||||
Key = key;
|
||||
|
||||
var current = Keyboard.GetState();
|
||||
Modifiers = Modifiers.None;
|
||||
if (current.IsKeyDown(Keys.LeftControl) || current.IsKeyDown(Keys.RightControl))
|
||||
{
|
||||
Modifiers |= Modifiers.Control;
|
||||
}
|
||||
if (current.IsKeyDown(Keys.LeftShift) || current.IsKeyDown(Keys.RightShift))
|
||||
{
|
||||
Modifiers |= Modifiers.Shift;
|
||||
}
|
||||
if (current.IsKeyDown(Keys.LeftAlt) || current.IsKeyDown(Keys.RightAlt))
|
||||
{
|
||||
Modifiers |= Modifiers.Alt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Input
|
||||
{
|
||||
public abstract class MouseEventArgs : EventArgs
|
||||
{
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
|
||||
public MouseButton Button { get; protected set; }
|
||||
|
||||
public int? Value { get; protected set; }
|
||||
public int? Delta { get; protected set; }
|
||||
|
||||
protected internal MouseEventArgs(int x, int y, MouseButton button, int? value, int? delta)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Button = button;
|
||||
Value = value;
|
||||
Delta = delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework.Input.Touch;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Input
|
||||
{
|
||||
public class TouchEventArgs : EventArgs
|
||||
{
|
||||
public TouchLocation TouchLocation { get; private set; }
|
||||
|
||||
internal TouchEventArgs (TouchLocation touchLocation)
|
||||
{
|
||||
TouchLocation = touchLocation;
|
||||
}
|
||||
|
||||
public override bool Equals(System.Object obj)
|
||||
{
|
||||
if (obj == null) { return false; }
|
||||
|
||||
// If parameter cannot be cast to Point return false.
|
||||
TouchEventArgs t = obj as TouchEventArgs;
|
||||
if ((System.Object)t == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return TouchLocation.GetHashCode () == t.GetHashCode();
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return TouchLocation.Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
namespace Microsoft.Xna.Framework.Input
|
||||
{
|
||||
internal static class KeyboardUtil
|
||||
{
|
||||
internal static char? ToChar(Keys key, Modifiers modifiers = Modifiers.None)
|
||||
{
|
||||
if (key == Keys.A) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'A' : 'a'; }
|
||||
if (key == Keys.B) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'B' : 'b'; }
|
||||
if (key == Keys.C) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'C' : 'c'; }
|
||||
if (key == Keys.D) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'D' : 'd'; }
|
||||
if (key == Keys.E) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'E' : 'e'; }
|
||||
if (key == Keys.F) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'F' : 'f'; }
|
||||
if (key == Keys.G) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'G' : 'g'; }
|
||||
if (key == Keys.H) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'H' : 'h'; }
|
||||
if (key == Keys.I) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'I' : 'i'; }
|
||||
if (key == Keys.J) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'J' : 'j'; }
|
||||
if (key == Keys.K) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'K' : 'k'; }
|
||||
if (key == Keys.L) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'L' : 'l'; }
|
||||
if (key == Keys.M) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'M' : 'm'; }
|
||||
if (key == Keys.N) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'N' : 'n'; }
|
||||
if (key == Keys.O) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'O' : 'o'; }
|
||||
if (key == Keys.P) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'P' : 'p'; }
|
||||
if (key == Keys.Q) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'Q' : 'q'; }
|
||||
if (key == Keys.R) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'R' : 'r'; }
|
||||
if (key == Keys.S) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'S' : 's'; }
|
||||
if (key == Keys.T) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'T' : 't'; }
|
||||
if (key == Keys.U) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'U' : 'u'; }
|
||||
if (key == Keys.V) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'V' : 'v'; }
|
||||
if (key == Keys.W) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'W' : 'w'; }
|
||||
if (key == Keys.X) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'X' : 'x'; }
|
||||
if (key == Keys.Y) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'Y' : 'y'; }
|
||||
if (key == Keys.Z) { return ((modifiers & Modifiers.Shift) == Modifiers.Shift) ? 'Z' : 'z'; }
|
||||
|
||||
if ((key == Keys.D0 && !ShiftDown(modifiers)) || key == Keys.NumPad0) { return '0'; }
|
||||
if ((key == Keys.D1 && !ShiftDown(modifiers)) || key == Keys.NumPad1) { return '1'; }
|
||||
if ((key == Keys.D2 && !ShiftDown(modifiers)) || key == Keys.NumPad2) { return '2'; }
|
||||
if ((key == Keys.D3 && !ShiftDown(modifiers)) || key == Keys.NumPad3) { return '3'; }
|
||||
if ((key == Keys.D4 && !ShiftDown(modifiers)) || key == Keys.NumPad4) { return '4'; }
|
||||
if ((key == Keys.D5 && !ShiftDown(modifiers)) || key == Keys.NumPad5) { return '5'; }
|
||||
if ((key == Keys.D6 && !ShiftDown(modifiers)) || key == Keys.NumPad6) { return '6'; }
|
||||
if ((key == Keys.D7 && !ShiftDown(modifiers)) || key == Keys.NumPad7) { return '7'; }
|
||||
if ((key == Keys.D8 && !ShiftDown(modifiers)) || key == Keys.NumPad8) { return '8'; }
|
||||
if ((key == Keys.D9 && !ShiftDown(modifiers)) || key == Keys.NumPad9) { return '9'; }
|
||||
|
||||
if (key == Keys.D0 && ShiftDown(modifiers)) { return ')'; }
|
||||
if (key == Keys.D1 && ShiftDown(modifiers)) { return '!'; }
|
||||
if (key == Keys.D2 && ShiftDown(modifiers)) { return '@'; }
|
||||
if (key == Keys.D3 && ShiftDown(modifiers)) { return '#'; }
|
||||
if (key == Keys.D4 && ShiftDown(modifiers)) { return '$'; }
|
||||
if (key == Keys.D5 && ShiftDown(modifiers)) { return '%'; }
|
||||
if (key == Keys.D6 && ShiftDown(modifiers)) { return '^'; }
|
||||
if (key == Keys.D7 && ShiftDown(modifiers)) { return '&'; }
|
||||
if (key == Keys.D8 && ShiftDown(modifiers)) { return '*'; }
|
||||
if (key == Keys.D9 && ShiftDown(modifiers)) { return '('; }
|
||||
|
||||
if (key == Keys.Space) { return ' '; }
|
||||
if (key == Keys.Tab) { return '\t'; }
|
||||
if (key == Keys.Enter) { return (char)13; }
|
||||
if (key == Keys.Back) { return (char)8; }
|
||||
|
||||
if (key == Keys.Add) { return '+'; }
|
||||
if (key == Keys.Decimal) { return '.'; }
|
||||
if (key == Keys.Divide) { return '/'; }
|
||||
if (key == Keys.Multiply) { return '*'; }
|
||||
if (key == Keys.OemBackslash) { return '\\'; }
|
||||
if (key == Keys.OemComma && !ShiftDown(modifiers)) { return ','; }
|
||||
if (key == Keys.OemComma && ShiftDown(modifiers)) { return '<'; }
|
||||
if (key == Keys.OemOpenBrackets && !ShiftDown(modifiers)) { return '['; }
|
||||
if (key == Keys.OemOpenBrackets && ShiftDown(modifiers)) { return '{'; }
|
||||
if (key == Keys.OemCloseBrackets && !ShiftDown(modifiers)) { return ']'; }
|
||||
if (key == Keys.OemCloseBrackets && ShiftDown(modifiers)) { return '}'; }
|
||||
if (key == Keys.OemPeriod && !ShiftDown(modifiers)) { return '.'; }
|
||||
if (key == Keys.OemPeriod && ShiftDown(modifiers)) { return '>'; }
|
||||
if (key == Keys.OemPipe && !ShiftDown(modifiers)) { return '\\'; }
|
||||
if (key == Keys.OemPipe && ShiftDown(modifiers)) { return '|'; }
|
||||
if (key == Keys.OemPlus && !ShiftDown(modifiers)) { return '='; }
|
||||
if (key == Keys.OemPlus && ShiftDown(modifiers)) { return '+'; }
|
||||
if (key == Keys.OemMinus && !ShiftDown(modifiers)) { return '-'; }
|
||||
if (key == Keys.OemMinus && ShiftDown(modifiers)) { return '_'; }
|
||||
if (key == Keys.OemQuestion && !ShiftDown(modifiers)) { return '/'; }
|
||||
if (key == Keys.OemQuestion && ShiftDown(modifiers)) { return '?'; }
|
||||
if (key == Keys.OemQuotes && !ShiftDown(modifiers)) { return '\''; }
|
||||
if (key == Keys.OemQuotes && ShiftDown(modifiers)) { return '"'; }
|
||||
if (key == Keys.OemSemicolon && !ShiftDown(modifiers)) { return ';'; }
|
||||
if (key == Keys.OemSemicolon && ShiftDown(modifiers)) { return ':'; }
|
||||
if (key == Keys.OemTilde && !ShiftDown(modifiers)) { return '`'; }
|
||||
if (key == Keys.OemTilde && ShiftDown(modifiers)) { return '~'; }
|
||||
if (key == Keys.Subtract) { return '-'; }
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool ShiftDown(Modifiers modifiers)
|
||||
{
|
||||
return ((modifiers & Modifiers.Shift) == Modifiers.Shift);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Input
|
||||
{
|
||||
[Flags]
|
||||
public enum Modifiers
|
||||
{
|
||||
Control = 1,
|
||||
Shift = 2,
|
||||
Alt = 4,
|
||||
None = 0
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace MonoGame.Extended.InputListeners
|
||||
{
|
||||
public abstract class EventListener
|
||||
{
|
||||
protected void RaiseEvent<T>(EventHandler<T> eventHandler, T args)
|
||||
where T : EventArgs
|
||||
{
|
||||
var handler = eventHandler;
|
||||
|
||||
if (handler != null)
|
||||
handler(this, args);
|
||||
}
|
||||
|
||||
public abstract void Update(GameTime gameTime);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace MonoGame.Extended.InputListeners
|
||||
{
|
||||
public sealed class EventListenerManager
|
||||
{
|
||||
private readonly List<EventListener> _listeners;
|
||||
|
||||
public List<EventListener> Listeners
|
||||
{
|
||||
get { return _listeners; }
|
||||
}
|
||||
|
||||
public EventListenerManager()
|
||||
{
|
||||
_listeners = new List<EventListener>();
|
||||
}
|
||||
|
||||
public void Update(GameTime gameTime)
|
||||
{
|
||||
foreach (var eventListener in _listeners)
|
||||
eventListener.Update(gameTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace MonoGame.Extended.InputListeners
|
||||
{
|
||||
public class KeyboardEventArgs : EventArgs
|
||||
{
|
||||
public KeyboardEventArgs(Keys key, KeyboardState keyboardState)
|
||||
{
|
||||
Key = key;
|
||||
|
||||
Modifiers = KeyboardModifiers.None;
|
||||
|
||||
if (keyboardState.IsKeyDown(Keys.LeftControl) || keyboardState.IsKeyDown(Keys.RightControl))
|
||||
Modifiers |= KeyboardModifiers.Control;
|
||||
|
||||
if (keyboardState.IsKeyDown(Keys.LeftShift) || keyboardState.IsKeyDown(Keys.RightShift))
|
||||
Modifiers |= KeyboardModifiers.Shift;
|
||||
|
||||
if (keyboardState.IsKeyDown(Keys.LeftAlt) || keyboardState.IsKeyDown(Keys.RightAlt))
|
||||
Modifiers |= KeyboardModifiers.Alt;
|
||||
}
|
||||
|
||||
public Keys Key { get; private set; }
|
||||
public KeyboardModifiers Modifiers { get; private set; }
|
||||
|
||||
public char? Character
|
||||
{
|
||||
get { return ToChar(Key, Modifiers); }
|
||||
}
|
||||
|
||||
internal static char? ToChar(Keys key, KeyboardModifiers modifiers = KeyboardModifiers.None)
|
||||
{
|
||||
var isShiftDown = ((modifiers & KeyboardModifiers.Shift) == KeyboardModifiers.Shift);
|
||||
|
||||
if (key == Keys.A) { return isShiftDown ? 'A' : 'a'; }
|
||||
if (key == Keys.B) { return isShiftDown ? 'B' : 'b'; }
|
||||
if (key == Keys.C) { return isShiftDown ? 'C' : 'c'; }
|
||||
if (key == Keys.D) { return isShiftDown ? 'D' : 'd'; }
|
||||
if (key == Keys.E) { return isShiftDown ? 'E' : 'e'; }
|
||||
if (key == Keys.F) { return isShiftDown ? 'F' : 'f'; }
|
||||
if (key == Keys.G) { return isShiftDown ? 'G' : 'g'; }
|
||||
if (key == Keys.H) { return isShiftDown ? 'H' : 'h'; }
|
||||
if (key == Keys.I) { return isShiftDown ? 'I' : 'i'; }
|
||||
if (key == Keys.J) { return isShiftDown ? 'J' : 'j'; }
|
||||
if (key == Keys.K) { return isShiftDown ? 'K' : 'k'; }
|
||||
if (key == Keys.L) { return isShiftDown ? 'L' : 'l'; }
|
||||
if (key == Keys.M) { return isShiftDown ? 'M' : 'm'; }
|
||||
if (key == Keys.N) { return isShiftDown ? 'N' : 'n'; }
|
||||
if (key == Keys.O) { return isShiftDown ? 'O' : 'o'; }
|
||||
if (key == Keys.P) { return isShiftDown ? 'P' : 'p'; }
|
||||
if (key == Keys.Q) { return isShiftDown ? 'Q' : 'q'; }
|
||||
if (key == Keys.R) { return isShiftDown ? 'R' : 'r'; }
|
||||
if (key == Keys.S) { return isShiftDown ? 'S' : 's'; }
|
||||
if (key == Keys.T) { return isShiftDown ? 'T' : 't'; }
|
||||
if (key == Keys.U) { return isShiftDown ? 'U' : 'u'; }
|
||||
if (key == Keys.V) { return isShiftDown ? 'V' : 'v'; }
|
||||
if (key == Keys.W) { return isShiftDown ? 'W' : 'w'; }
|
||||
if (key == Keys.X) { return isShiftDown ? 'X' : 'x'; }
|
||||
if (key == Keys.Y) { return isShiftDown ? 'Y' : 'y'; }
|
||||
if (key == Keys.Z) { return isShiftDown ? 'Z' : 'z'; }
|
||||
|
||||
if ((key == Keys.D0 && !isShiftDown) || key == Keys.NumPad0) { return '0'; }
|
||||
if ((key == Keys.D1 && !isShiftDown) || key == Keys.NumPad1) { return '1'; }
|
||||
if ((key == Keys.D2 && !isShiftDown) || key == Keys.NumPad2) { return '2'; }
|
||||
if ((key == Keys.D3 && !isShiftDown) || key == Keys.NumPad3) { return '3'; }
|
||||
if ((key == Keys.D4 && !isShiftDown) || key == Keys.NumPad4) { return '4'; }
|
||||
if ((key == Keys.D5 && !isShiftDown) || key == Keys.NumPad5) { return '5'; }
|
||||
if ((key == Keys.D6 && !isShiftDown) || key == Keys.NumPad6) { return '6'; }
|
||||
if ((key == Keys.D7 && !isShiftDown) || key == Keys.NumPad7) { return '7'; }
|
||||
if ((key == Keys.D8 && !isShiftDown) || key == Keys.NumPad8) { return '8'; }
|
||||
if ((key == Keys.D9 && !isShiftDown) || key == Keys.NumPad9) { return '9'; }
|
||||
|
||||
if (key == Keys.D0 && isShiftDown) { return ')'; }
|
||||
if (key == Keys.D1 && isShiftDown) { return '!'; }
|
||||
if (key == Keys.D2 && isShiftDown) { return '@'; }
|
||||
if (key == Keys.D3 && isShiftDown) { return '#'; }
|
||||
if (key == Keys.D4 && isShiftDown) { return '$'; }
|
||||
if (key == Keys.D5 && isShiftDown) { return '%'; }
|
||||
if (key == Keys.D6 && isShiftDown) { return '^'; }
|
||||
if (key == Keys.D7 && isShiftDown) { return '&'; }
|
||||
if (key == Keys.D8 && isShiftDown) { return '*'; }
|
||||
if (key == Keys.D9 && isShiftDown) { return '('; }
|
||||
|
||||
if (key == Keys.Space) { return ' '; }
|
||||
if (key == Keys.Tab) { return '\t'; }
|
||||
if (key == Keys.Enter) { return (char)13; }
|
||||
if (key == Keys.Back) { return (char)8; }
|
||||
|
||||
if (key == Keys.Add) { return '+'; }
|
||||
if (key == Keys.Decimal) { return '.'; }
|
||||
if (key == Keys.Divide) { return '/'; }
|
||||
if (key == Keys.Multiply) { return '*'; }
|
||||
if (key == Keys.OemBackslash) { return '\\'; }
|
||||
if (key == Keys.OemComma && !isShiftDown) { return ','; }
|
||||
if (key == Keys.OemComma && isShiftDown) { return '<'; }
|
||||
if (key == Keys.OemOpenBrackets && !isShiftDown) { return '['; }
|
||||
if (key == Keys.OemOpenBrackets && isShiftDown) { return '{'; }
|
||||
if (key == Keys.OemCloseBrackets && !isShiftDown) { return ']'; }
|
||||
if (key == Keys.OemCloseBrackets && isShiftDown) { return '}'; }
|
||||
if (key == Keys.OemPeriod && !isShiftDown) { return '.'; }
|
||||
if (key == Keys.OemPeriod && isShiftDown) { return '>'; }
|
||||
if (key == Keys.OemPipe && !isShiftDown) { return '\\'; }
|
||||
if (key == Keys.OemPipe && isShiftDown) { return '|'; }
|
||||
if (key == Keys.OemPlus && !isShiftDown) { return '='; }
|
||||
if (key == Keys.OemPlus && isShiftDown) { return '+'; }
|
||||
if (key == Keys.OemMinus && !isShiftDown) { return '-'; }
|
||||
if (key == Keys.OemMinus && isShiftDown) { return '_'; }
|
||||
if (key == Keys.OemQuestion && !isShiftDown) { return '/'; }
|
||||
if (key == Keys.OemQuestion && isShiftDown) { return '?'; }
|
||||
if (key == Keys.OemQuotes && !isShiftDown) { return '\''; }
|
||||
if (key == Keys.OemQuotes && isShiftDown) { return '"'; }
|
||||
if (key == Keys.OemSemicolon && !isShiftDown) { return ';'; }
|
||||
if (key == Keys.OemSemicolon && isShiftDown) { return ':'; }
|
||||
if (key == Keys.OemTilde && !isShiftDown) { return '`'; }
|
||||
if (key == Keys.OemTilde && isShiftDown) { return '~'; }
|
||||
if (key == Keys.Subtract) { return '-'; }
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace MonoGame.Extended.InputListeners
|
||||
{
|
||||
public class KeyboardEventListener : EventListener
|
||||
{
|
||||
public KeyboardEventListener(int initialDelay = 800, int repeatDelay = 50)
|
||||
{
|
||||
InitialDelay = initialDelay;
|
||||
RepeatDelay = repeatDelay;
|
||||
}
|
||||
|
||||
private Keys _previousKey;
|
||||
private TimeSpan _lastPressTime;
|
||||
private bool _isInitial;
|
||||
private KeyboardState _previousState;
|
||||
|
||||
public event EventHandler<KeyboardEventArgs> KeyTyped;
|
||||
public event EventHandler<KeyboardEventArgs> KeyPressed;
|
||||
public event EventHandler<KeyboardEventArgs> KeyReleased;
|
||||
|
||||
public int InitialDelay { get; private set; }
|
||||
public int RepeatDelay { get; private set; }
|
||||
|
||||
public override void Update(GameTime gameTime)
|
||||
{
|
||||
var currentState = Keyboard.GetState();
|
||||
|
||||
RaisePressedEvents(gameTime, currentState);
|
||||
RaiseReleasedEvents(currentState);
|
||||
RaiseRepeatEvents(gameTime, currentState);
|
||||
|
||||
_previousState = currentState;
|
||||
}
|
||||
|
||||
private void RaisePressedEvents(GameTime gameTime, KeyboardState currentState)
|
||||
{
|
||||
if (!currentState.IsKeyDown(Keys.LeftAlt) && !currentState.IsKeyDown(Keys.RightAlt))
|
||||
{
|
||||
var pressedKeys = Enum.GetValues(typeof (Keys))
|
||||
.Cast<Keys>()
|
||||
.Where(key => currentState.IsKeyDown(key) && _previousState.IsKeyUp(key));
|
||||
|
||||
foreach (var key in pressedKeys)
|
||||
{
|
||||
var args = new KeyboardEventArgs(key, currentState);
|
||||
|
||||
RaiseEvent(KeyPressed, args);
|
||||
|
||||
if (args.Character.HasValue)
|
||||
RaiseEvent(KeyTyped, args);
|
||||
|
||||
_previousKey = key;
|
||||
_lastPressTime = gameTime.TotalGameTime;
|
||||
_isInitial = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RaiseReleasedEvents(KeyboardState currentState)
|
||||
{
|
||||
var releasedKeys = Enum.GetValues(typeof (Keys))
|
||||
.Cast<Keys>()
|
||||
.Where(key => currentState.IsKeyUp(key) && _previousState.IsKeyDown(key));
|
||||
|
||||
foreach (var key in releasedKeys)
|
||||
RaiseEvent(KeyReleased, new KeyboardEventArgs(key, currentState));
|
||||
}
|
||||
|
||||
private void RaiseRepeatEvents(GameTime gameTime, KeyboardState currentState)
|
||||
{
|
||||
var elapsedTime = (gameTime.TotalGameTime - _lastPressTime).TotalMilliseconds;
|
||||
|
||||
if (currentState.IsKeyDown(_previousKey) && ((_isInitial && elapsedTime > InitialDelay) || (!_isInitial && elapsedTime > RepeatDelay)))
|
||||
{
|
||||
var args = new KeyboardEventArgs(_previousKey, currentState);
|
||||
|
||||
if (args.Character.HasValue)
|
||||
RaiseEvent(KeyTyped, args);
|
||||
|
||||
_lastPressTime = gameTime.TotalGameTime;
|
||||
_isInitial = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace MonoGame.Extended.InputListeners
|
||||
{
|
||||
[Flags]
|
||||
public enum KeyboardModifiers
|
||||
{
|
||||
Control = 1,
|
||||
Shift = 2,
|
||||
Alt = 4,
|
||||
None = 0
|
||||
};
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
namespace Microsoft.Xna.Framework.Input
|
||||
namespace MonoGame.Extended.InputListeners
|
||||
{
|
||||
public enum MouseButton
|
||||
{
|
||||
@@ -9,4 +9,4 @@
|
||||
XButton1,
|
||||
XButton2
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace MonoGame.Extended.InputListeners
|
||||
{
|
||||
public class MouseEventArgs : EventArgs
|
||||
{
|
||||
public MouseEventArgs(int x, int y, TimeSpan time, MouseState previous, MouseState current,
|
||||
MouseButton button = MouseButton.None, int? value = null, int? delta = null)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Button = button;
|
||||
Value = value;
|
||||
Delta = delta;
|
||||
Time = time;
|
||||
Previous = previous;
|
||||
Current = current;
|
||||
}
|
||||
|
||||
public TimeSpan Time { get; set; }
|
||||
public MouseState Previous { get; private set; }
|
||||
public MouseState Current { get; private set; }
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
public MouseButton Button { get; protected set; }
|
||||
public int? Value { get; protected set; }
|
||||
public int? Delta { get; protected set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace MonoGame.Extended.InputListeners
|
||||
{
|
||||
public class MouseEventListener : EventListener
|
||||
{
|
||||
public event EventHandler<MouseEventArgs> ButtonReleased;
|
||||
public event EventHandler<MouseEventArgs> ButtonPressed;
|
||||
public event EventHandler<MouseEventArgs> ButtonDoubleClicked;
|
||||
public event EventHandler<MouseEventArgs> MouseMoved;
|
||||
public event EventHandler<MouseEventArgs> MouseWheelMoved;
|
||||
|
||||
private MouseState _previousState;
|
||||
private MouseEventArgs _lastClick;
|
||||
|
||||
private readonly int _doubleClickMaxTimeDelta;
|
||||
private readonly int _doubleClickMaxMovementDelta;
|
||||
|
||||
public MouseEventListener(int doubleClickMaxTimeDelta = 500, int doubleClickMaxMovementDelta = 2) // initial values are windows defaults
|
||||
{
|
||||
_doubleClickMaxTimeDelta = doubleClickMaxTimeDelta;
|
||||
_doubleClickMaxMovementDelta = doubleClickMaxMovementDelta;
|
||||
_lastClick = new MouseEventArgs(-1, -1, TimeSpan.Zero, Mouse.GetState(), Mouse.GetState());
|
||||
}
|
||||
|
||||
public override void Update(GameTime gameTime)
|
||||
{
|
||||
var currentState = Mouse.GetState();
|
||||
|
||||
// Check button press events.
|
||||
if (currentState.LeftButton == ButtonState.Pressed
|
||||
&& _previousState.LeftButton == ButtonState.Released)
|
||||
{
|
||||
OnButtonPressed(this, new MouseEventArgs(currentState.X,currentState.Y, gameTime.TotalGameTime, _previousState,
|
||||
currentState, MouseButton.Left));
|
||||
}
|
||||
|
||||
if (currentState.MiddleButton == ButtonState.Pressed
|
||||
&& _previousState.MiddleButton == ButtonState.Released)
|
||||
{
|
||||
OnButtonPressed(this, new MouseEventArgs(currentState.X, currentState.Y, gameTime.TotalGameTime, _previousState,
|
||||
currentState, MouseButton.Middle));
|
||||
}
|
||||
|
||||
if (currentState.RightButton == ButtonState.Pressed
|
||||
&& _previousState.RightButton == ButtonState.Released)
|
||||
{
|
||||
OnButtonPressed(this, new MouseEventArgs(currentState.X, currentState.Y, gameTime.TotalGameTime, _previousState,
|
||||
currentState, MouseButton.Right));
|
||||
}
|
||||
|
||||
if (currentState.XButton1 == ButtonState.Pressed
|
||||
&& _previousState.XButton1 == ButtonState.Released)
|
||||
{
|
||||
OnButtonPressed(this, new MouseEventArgs(currentState.X, currentState.Y, gameTime.TotalGameTime, _previousState,
|
||||
currentState, MouseButton.XButton1));
|
||||
}
|
||||
|
||||
if (currentState.XButton2 == ButtonState.Pressed
|
||||
&& _previousState.XButton2 == ButtonState.Released)
|
||||
{
|
||||
OnButtonPressed(this, new MouseEventArgs(currentState.X, currentState.Y, gameTime.TotalGameTime, _previousState,
|
||||
currentState, MouseButton.XButton2));
|
||||
}
|
||||
|
||||
// Check button releases.
|
||||
if (currentState.LeftButton == ButtonState.Released && _previousState.LeftButton == ButtonState.Pressed)
|
||||
{
|
||||
RaiseEvent(ButtonReleased, new MouseEventArgs(currentState.X, currentState.Y, gameTime.TotalGameTime, _previousState,
|
||||
currentState, MouseButton.Left));
|
||||
}
|
||||
|
||||
if (currentState.MiddleButton == ButtonState.Released && _previousState.MiddleButton == ButtonState.Pressed)
|
||||
{
|
||||
RaiseEvent(ButtonReleased, new MouseEventArgs(currentState.X, currentState.Y, gameTime.TotalGameTime, _previousState,
|
||||
currentState, MouseButton.Middle));
|
||||
}
|
||||
|
||||
if (currentState.RightButton == ButtonState.Released && _previousState.RightButton == ButtonState.Pressed)
|
||||
{
|
||||
RaiseEvent(ButtonReleased, new MouseEventArgs(currentState.X, currentState.Y, gameTime.TotalGameTime, _previousState,
|
||||
currentState, MouseButton.Right));
|
||||
}
|
||||
|
||||
if (currentState.XButton1 == ButtonState.Released && _previousState.XButton1 == ButtonState.Pressed)
|
||||
{
|
||||
RaiseEvent(ButtonReleased, new MouseEventArgs(currentState.X, currentState.Y, gameTime.TotalGameTime, _previousState,
|
||||
currentState, MouseButton.XButton1));
|
||||
}
|
||||
|
||||
if (currentState.XButton2 == ButtonState.Released && _previousState.XButton2 == ButtonState.Pressed)
|
||||
{
|
||||
RaiseEvent(ButtonReleased, new MouseEventArgs(currentState.X, currentState.Y, gameTime.TotalGameTime, _previousState,
|
||||
currentState, MouseButton.XButton2));
|
||||
}
|
||||
|
||||
// Check for any sort of mouse movement. If a button is down, it's a drag,
|
||||
// otherwise it's a move.
|
||||
if (_previousState.X != currentState.X || _previousState.Y != currentState.Y)
|
||||
{
|
||||
RaiseEvent(MouseMoved, new MouseEventArgs(currentState.X, currentState.Y, gameTime.TotalGameTime, _previousState,
|
||||
currentState));
|
||||
}
|
||||
|
||||
// Handle mouse wheel events.
|
||||
if (_previousState.ScrollWheelValue != currentState.ScrollWheelValue)
|
||||
{
|
||||
var value = currentState.ScrollWheelValue / 120;
|
||||
var delta = (currentState.ScrollWheelValue - _previousState.ScrollWheelValue) / 120;
|
||||
|
||||
RaiseEvent(MouseWheelMoved, new MouseEventArgs(currentState.X, currentState.Y, gameTime.TotalGameTime, _previousState,
|
||||
currentState, MouseButton.None, value, delta));
|
||||
}
|
||||
|
||||
_previousState = currentState;
|
||||
}
|
||||
|
||||
private void OnButtonPressed(object sender, MouseEventArgs args)
|
||||
{
|
||||
// If this click is within the right time and position of the last click,
|
||||
// raise a double-click event as well.
|
||||
if (ButtonDoubleClicked != null && _lastClick.Button == args.Button &&
|
||||
(args.Time - _lastClick.Time).TotalMilliseconds < _doubleClickMaxTimeDelta &&
|
||||
DistanceBetween(args.Current, _lastClick.Current) < _doubleClickMaxMovementDelta)
|
||||
{
|
||||
ButtonDoubleClicked(sender, args);
|
||||
//args.Time = new TimeSpan(0);
|
||||
}
|
||||
else if (ButtonPressed != null)
|
||||
{
|
||||
ButtonPressed(sender, args);
|
||||
}
|
||||
|
||||
_lastClick = args;
|
||||
}
|
||||
|
||||
private static int DistanceBetween(MouseState a, MouseState b)
|
||||
{
|
||||
return Math.Abs(a.X - b.X) + Math.Abs(a.Y - b.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using Microsoft.Xna.Framework.Input.Touch;
|
||||
|
||||
namespace MonoGame.Extended.InputListeners
|
||||
{
|
||||
public class TouchEventArgs : System.EventArgs
|
||||
{
|
||||
public TouchLocation TouchLocation { get; private set; }
|
||||
|
||||
internal TouchEventArgs(TouchLocation touchLocation)
|
||||
{
|
||||
TouchLocation = touchLocation;
|
||||
}
|
||||
|
||||
public override bool Equals(System.Object obj)
|
||||
{
|
||||
if (obj == null) { return false; }
|
||||
|
||||
// If parameter cannot be cast to Point return false.
|
||||
TouchEventArgs t = obj as TouchEventArgs;
|
||||
if ((System.Object)t == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return TouchLocation.GetHashCode() == t.GetHashCode();
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return TouchLocation.Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Input.Touch;
|
||||
|
||||
namespace MonoGame.Extended.InputListeners
|
||||
{
|
||||
public class TouchEventListener : EventListener
|
||||
{
|
||||
internal event EventHandler<TouchEventArgs> TouchStarted;
|
||||
internal event EventHandler<TouchEventArgs> TouchEnded;
|
||||
internal event EventHandler<TouchEventArgs> TouchMoved;
|
||||
internal event EventHandler<TouchEventArgs> TouchCancelled;
|
||||
|
||||
public override void Update(GameTime gameTime)
|
||||
{
|
||||
var touchCollection = TouchPanel.GetState();
|
||||
|
||||
foreach (var touchLocation in touchCollection)
|
||||
{
|
||||
switch (touchLocation.State)
|
||||
{
|
||||
case TouchLocationState.Pressed:
|
||||
RaiseEvent(TouchStarted, new TouchEventArgs(touchLocation));
|
||||
break;
|
||||
case TouchLocationState.Moved:
|
||||
RaiseEvent(TouchMoved, new TouchEventArgs(touchLocation));
|
||||
break;
|
||||
case TouchLocationState.Released:
|
||||
RaiseEvent(TouchEnded, new TouchEventArgs(touchLocation));
|
||||
break;
|
||||
case TouchLocationState.Invalid:
|
||||
RaiseEvent(TouchCancelled, new TouchEventArgs(touchLocation));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,19 +47,16 @@
|
||||
<Compile Include="Content\ContentLoader.cs" />
|
||||
<Compile Include="Content\ContentManagerExtensions.cs" />
|
||||
<Compile Include="Camera2D.cs" />
|
||||
<Compile Include="InputEvents\Input.cs" />
|
||||
<Compile Include="InputEvents\MonoGame.Input\EventArgs\MonoGameMouseEventArgs.cs" />
|
||||
<Compile Include="InputEvents\MonoGame.Input\Keyboard\MonoGameMouseEvents.cs" />
|
||||
<Compile Include="InputEvents\MonoGame.Input\Mouse\MonoGameMouseEvents.cs" />
|
||||
<Compile Include="InputEvents\MonoGame.Input\Touch\MonoGameTouchEvents.cs" />
|
||||
<Compile Include="InputEvents\MonoGameInput.cs" />
|
||||
<Compile Include="InputEvents\Shared\EventArgs\KeyboardCharacterEventArgs.cs" />
|
||||
<Compile Include="InputEvents\Shared\EventArgs\KeyboardKeyEventArgs.cs" />
|
||||
<Compile Include="InputEvents\Shared\EventArgs\MouseEventArgs.cs" />
|
||||
<Compile Include="InputEvents\Shared\EventArgs\TouchEventArgs.cs" />
|
||||
<Compile Include="InputEvents\Shared\Keyboard\KeyboardUtil.cs" />
|
||||
<Compile Include="InputEvents\Shared\Keyboard\Modifiers.cs" />
|
||||
<Compile Include="InputEvents\Shared\Mouse\MouseButton.cs" />
|
||||
<Compile Include="InputListeners\KeyboardEventArgs.cs" />
|
||||
<Compile Include="InputListeners\KeyboardModifiers.cs" />
|
||||
<Compile Include="InputListeners\MouseButton.cs" />
|
||||
<Compile Include="InputListeners\MouseEventArgs.cs" />
|
||||
<Compile Include="InputListeners\KeyboardEventListener.cs" />
|
||||
<Compile Include="InputListeners\MouseEventListener.cs" />
|
||||
<Compile Include="InputListeners\EventListener.cs" />
|
||||
<Compile Include="InputListeners\TouchEventArgs.cs" />
|
||||
<Compile Include="InputListeners\TouchEventListener.cs" />
|
||||
<Compile Include="InputListeners\EventListenerManager.cs" />
|
||||
<Compile Include="Sprites\SpriteExtensions.cs" />
|
||||
<Compile Include="TextureAtlases\TextureAtlas.cs" />
|
||||
<Compile Include="TextureAtlases\TextureAtlasReader.cs" />
|
||||
@@ -90,7 +87,6 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="InputEvents\README.md" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||
|
||||
@@ -5,11 +5,11 @@ using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using MonoGame.Extended;
|
||||
using MonoGame.Extended.BitmapFonts;
|
||||
using MonoGame.Extended.InputListeners;
|
||||
using MonoGame.Extended.Maps.Tiled;
|
||||
using MonoGame.Extended.Sprites;
|
||||
using MonoGame.Extended.TextureAtlases;
|
||||
using MonoGame.Extended.ViewportAdapters;
|
||||
using MonoGame.Extended.InputEvents;
|
||||
|
||||
namespace Sandbox
|
||||
{
|
||||
@@ -30,7 +30,7 @@ namespace Sandbox
|
||||
private BitmapFont _bitmapFont;
|
||||
private TiledMap _tiledMap;
|
||||
|
||||
private Input _eventDrivenInput;
|
||||
private EventListenerManager _inputManager;
|
||||
|
||||
private Vector2 _cameraDirection = Vector2.Zero;
|
||||
private float _cameraRotation = 0f;
|
||||
@@ -88,16 +88,15 @@ namespace Sandbox
|
||||
{
|
||||
}
|
||||
|
||||
private int _previousScrollWheelValue;
|
||||
private TextureRegion2D _textureRegion;
|
||||
|
||||
protected override void Update(GameTime gameTime)
|
||||
{
|
||||
_eventDrivenInput.Update(gameTime);
|
||||
_inputManager.Update(gameTime);
|
||||
|
||||
var deltaTime = (float) gameTime.ElapsedGameTime.TotalMilliseconds * .001f;
|
||||
var keyboardState = Keyboard.GetState();
|
||||
var mouseState = Mouse.GetState();
|
||||
//var mouseState = Mouse.GetState();
|
||||
//var gamePadState = GamePad.GetState(PlayerIndex.One);
|
||||
|
||||
if (keyboardState.IsKeyDown(Keys.Escape))
|
||||
@@ -106,6 +105,8 @@ namespace Sandbox
|
||||
_camera.Move(_cameraDirection * deltaTime);
|
||||
_camera.Rotation += _cameraRotation * deltaTime;
|
||||
|
||||
_sprite.Rotation += deltaTime;
|
||||
|
||||
base.Update(gameTime);
|
||||
}
|
||||
|
||||
@@ -141,15 +142,19 @@ namespace Sandbox
|
||||
|
||||
private void SetUpInput()
|
||||
{
|
||||
_eventDrivenInput = new MonoGameInput(this);
|
||||
_inputManager = new EventListenerManager();
|
||||
|
||||
var up = new Vector2(0, -250);
|
||||
var right = new Vector2(250, 0);
|
||||
|
||||
//camera movment
|
||||
_eventDrivenInput.KeyDown += (sender, keyDown) =>
|
||||
//camera movement
|
||||
var keyboardListener = new KeyboardEventListener();
|
||||
var mouseListener = new MouseEventListener();
|
||||
_inputManager.Listeners.Add(keyboardListener);
|
||||
|
||||
keyboardListener.KeyPressed += (sender, args) =>
|
||||
{
|
||||
switch (keyDown.Key)
|
||||
switch (args.Key)
|
||||
{
|
||||
case Keys.Escape:
|
||||
Exit();
|
||||
@@ -176,10 +181,10 @@ namespace Sandbox
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
_eventDrivenInput.KeyUp += (sender, keyUp) =>
|
||||
|
||||
keyboardListener.KeyReleased += (sender, args) =>
|
||||
{
|
||||
switch (keyUp.Key)
|
||||
switch (args.Key)
|
||||
{
|
||||
case Keys.Q:
|
||||
_cameraRotation -= 1;
|
||||
@@ -204,18 +209,18 @@ namespace Sandbox
|
||||
};
|
||||
|
||||
// zoom
|
||||
_eventDrivenInput.MouseWheel += (sender, mouseEvent) =>
|
||||
mouseListener.MouseWheelMoved += (sender, args) =>
|
||||
{
|
||||
_camera.Zoom += mouseEvent.Delta.Value * 0.0001f;
|
||||
_camera.Zoom += args.Delta.Value * 0.0001f;
|
||||
};
|
||||
|
||||
// look at
|
||||
_eventDrivenInput.MouseUp += (sender, mouseUp) =>
|
||||
mouseListener.ButtonReleased += (sender, args) =>
|
||||
{
|
||||
if (mouseUp.Button == MouseButton.Left)
|
||||
if (args.Button == MouseButton.Left)
|
||||
{
|
||||
var p = _viewportAdapter.PointToScreen(mouseUp.X, mouseUp.Y);
|
||||
Trace.WriteLine(string.Format("{0},{1} => {2},{3}", mouseUp.X, mouseUp.Y, p.X, p.Y));
|
||||
var p = _viewportAdapter.PointToScreen(args.X, args.Y);
|
||||
Trace.WriteLine(string.Format("{0},{1} => {2},{3}", args.X, args.Y, p.X, p.Y));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user