Input events

Hello! I’m having some trouble with input in MonoGame.

When running a DX build it’s easy enough to do:

var form = Win.Control.FromHandle(winHandle);
form.MouseDown += Input_MouseDown;
form.MouseUp += Input_MouseUp;
form.MouseClick += Input_MouseClick;
form.MouseDoubleClick += Input_MouseDoubleClick;
form.MouseMove += Input_MouseMove;
form.MouseWheel += Input_MouseWheel;
form.KeyDown += Input_KeyDown;
form.KeyUp += Input_KeyUp;

To access the input of the actual window. However when running GL (3.5 OpenTK or 3.6 SDL2) I guess those libraries does not use a regular WinForm internally so it does not work. How do you recommend getting input from MonoGame? I cannot use Keyboard.GetState() for my use case since it does not keep up when a user types fast. I need to buffer the input.

I realize

game.Window.TextInput += window_TextInput;

exists but that’s only CharEntered. I would need KeyDown, KeyUp, MouseDown etc. as well.

Best regards,
cmmart

The mouse stuff should be easily handled.

So your problem is people typing faster than 60x per second? (or edge cases I assume where they type with two fingers just right after each other).

Thank you for the reply, I’m glad someone took the time to read this.

How is the mouse stuff easily handled? Is there a way to sign up for the MouseMove/MouseDown/MouseUp events even in GL?

It’s not really typing faster than 60/100/120/144x per second that is an issue but if you press and release quickly the “KeyboardState” won’t have the key as “IsKeyDown” as it is no longer down when you query the state.

I think that MonoGame would benefit greatly from exposing the mouse/keyboard events directly on the window in the same way for every supported platform. Not only from KeyboardState/MouseState but also as the actual events from WndProc or whatever platform it’s running on.

Without buffering I don’t think there’s a way to process input correctly.

Sorry not 100% sure if you really want platform events or just general input handling.

Would caching the previous frame solve your problems?

Check current frame vs last frame and you can determine if mouseUp, or if it is still mouseDown etc.

I used to do this to detect clicks/keypress but I found it unreliable based on what I just mentioned. I did this until I found out that I could get the GameWindow and grab the actual WinForm using the handle and sign up to the “real” input events. Sadly, this only works for DX based projects and currently I’m looking at going with GL since I’d want to develop for Linux as well.

Not too sure on Unix machines about getting input.

You could look into getting the real events from the GL window that is made for opengl projects, which may be the best bet.

Or check out SDL in the repo if you can use that directly somehow.

Sorry this has gone a bit beyond me now, hope it helps.

Yes, I’ve been looking at these options as well and while I think it would work eventually it’s a very fragile solution. It may break whenever MonoGame is updated. For example now they’re replacing OpenTK with SDL going from 3.5 -> 3.6.

In my opinion it would be great it MonoGame itself supported a cross platform way of generating input events and not only exposing the keyboard/mouse through the MouseState and KeyboardState classes. I mean someone must have realized that this is in fact an issue since there’s a TextInput event exposed on the GameWindow. Sadly this does not seem to be true for other input.

Thank you for taking your time to try to assist me, very appreciated.

Is this actually causing issues? I mean, did you test it out and run into this? A frame is usually really really short. I can’t manage to press a button just in between two frames without having it registered. TextInput is specifically for handling… text input. For handling button presses in your game the recommended way is using the Keyboard.GetState() stuff and I’ve never read about issues with that before on the forum.

Thank you for taking an interest in my issue.

If you read what I wrote I think you’ll see that I understand that TextInput is for TextInput. I was just saying that someone noticed this very issue but only implemented a solution for TextInput when all the input needs to be processed like this. (MouseMove is an even better example…).

Yes it is indeed a problem and I did test it. The higher the framerate the lower the risk of it occurring, of course, since we are measuring per frame using the Keyboard.GetState() or Mouse.GetState() methods.

For example, I ran the following code locked at 25fps, totally possible framerate depending on the scene being rendered and hardware used:

int eventCount = 0;
public override void MouseUp(object sender, MistMouseEventArgs e)
{
    base.MouseUp(sender, e);
    eventCount++;
}

int stateCount = 0;
public override void Update(GameTime gameTime)
{
    MouseState = Mouse.GetState();

    if (MouseState.LeftButton == ButtonState.Released && OldMouseState.LeftButton == ButtonState.Pressed)
        stateCount++;

    base.Update(gameTime);

    OldMouseState = MouseState;
}

public override void Render(SpriteBatch spriteBatch, GameTime gameTime)
{
    base.Render(spriteBatch, gameTime);

    string countString = string.Format("Event count: {0} State count: {1}", eventCount, stateCount);
    spriteBatch.DrawString(Font, countString, new Vector2(10, 10), Color.White);
}

After 100 clicks the eventCount was 100 and the stateCount was 96. That means that I would have missed proper clicks and the user would be frustrated most likely. Imagine trying to click a button and it does not trigger. I mean sure, it works most of the time but would it not be better to have a solution that always works?

96/100 @ 25fps doesn’t sound too bad. I have played clicker games where I go as fast as I can at clicking but I don’t measure if actually every one of them hits.

Keep in mind most games will still update at 60fps but render at 25fps if we take your scenario and generalise it.

This means even if a heavy scene is rendering and an older computer lags, the 60fps update loop isn’t likely to be affected.

(This is all of course dependent on implementation.)

I think your assumptions here are wrong. Those 4/100 that are missed are just because you managed to click twice in one frame. So the button clicked would indeed trigger, the second click in that same frame is essentially ignored.

Hello again! Yes it does not sound too bad but it is not as good as it can be. I have seen many people play for example World of Warcraft and raids they drop to 10-15 fps. Imagine if some of the keyboard input would be lost during those fights. It would be unplayable.

This would be nice if it was the case but I managed to “miss” a click when doing one at a time as well. Not only spamming. While two per frame is definitely an issue as well, so is one that is too fast.

I am not trying to rant about MonoGame not handling my use case well, quite the opposite in fact. I am looking for a solution to my issue so that I can keep using this great framework and if no such solution currently exists then I would love to see one implemented.

It seems @cmmart is doomed to be misunderstood here. It’s a damn shame, because he’s clearly put a lot of effort into explaining his issue, and is more than grateful for what must be frustrating responses.

I’m having the same issues using Monogame. I’ll try to spell it out explicitly, as well as why this is a serious issue without a work-around.

Imagine you’ve written a game with a moderate amount of computation to do each frame. Now imagine a user would like to play your game on his low-end computer, where the FPS dips to say 10 fps, but he’s okay with that, because you’re a goddamn rockstar gamedev and he’s a big fan of the fundamental mechanics of the game.

But: if you’ve used monogame to handle keyboard input, then your Update function will be unaware of a significant portion of his keyboard or click events, as if they never happened. There is no workaround for this in Monogame. A button that fails silently (but only sometimes!) is one of the most annoying user experiences there is, and you the game dev can’t even address the problem.

Other game frameworks I’ve used expose some sort of “OnKeyPress” paradigm for precisely this reason.

After sinking hours into slowly gaining momentum with F# and Monogame (and no complaints until now), I am honestly pretty devastated and discouraged to discover such an unsolvable issue. Now I must make the following unpleasant choice:

A. Accept the fact that input will be fundamentally broken if my framerate dips too low (not even that low!)
B. Try using TextInput for something it wasn’t meant for, which may fail and certainly isn’t elegant.
C. Try routing around Monogame to get the events from some deeper process (OpenGL? Idk, I guess research would be the first step. Is this even possible?)
D. Abandon Monogame in favor of another framework that exposes event queues or key event listeners.

We’ve added key down and up events:
https://docs.monogame.net/api/Microsoft.Xna.Framework.GameWindow.html#Microsoft_Xna_Framework_GameWindow_KeyDown

using System;

class Game1 : Game
{
    protected override Initialize()
    {
        Window.KeyDown += (s, e) => Console.WriteLine($"{e.Key} down");
        Window.KeyUp += (s, e) => Console.WriteLine($"{e.Key} up");
        base.Initialize();
    }
}
1 Like