weixin_39940154
2020-12-28 17:38 阅读 4

KeyboardListener KeyDown?

First off, KeyboardListener is really nice. If it wasn't then whoever did the pull request for it, thank you!

I have been using it to try to control a camera. KeyPressed works just as it is intended when RepeatPress = false, however, when I try to make KeyPressed act as a "KeyDown" event with RepeatPress = true, that takes the capability of having a one press key, like Escape. I tried KeyTyped and input isn't even detected. But as you can see from the snippet below, I tried to emulate "KeyPressed" with KeyTyped so that I can use KeboardListener.KeyPressed with RepeatPress = true as a "KeyDown".

csharp
// RepeatPress = true, RepeatDelayMilliseconds = 0, InitialDelayMilliseconds = 0
// KeyboardListener
listener.KeyTyped += (sender, args) =>
{
if (KeyPressed != null)
foreach (var t in KeyPressed.GetInvocationList())
{
var result = (bool?)t.DynamicInvoke(args);
if (result == null || result == false)
{
// if a event handler returns false, event was handled so break
break;
}
}
};


The KeyboardListener.KeyPressed event as a KeyDown event.

csharp
// RepeatPress = true, RepeatDelayMilliseconds = 0, InitialDelayMilliseconds = 0
// KeyboardListener
listener.KeyPressed += (sender, args) =>
{
if (KeyDown != null)
foreach (var t in KeyDown.GetInvocationList())
{
var result = (bool?)t.DynamicInvoke(args);
if (result == null || result == false)
{
break;
}
}
};


Maybe I am using it wrong and KeyPressed is not meant to be used as a KeyDown event? If that is the case, how is KeyTyped and KeyPressed any different?

• 点赞
• 写回答
• 关注问题
• 收藏
• 复制链接分享

8条回答默认 最新

• weixin_39940154 2020-12-28 17:38

OMG. It was my stupid mistake.

csharp
Input.GetInputDevice<keyboarddevice>().KeyDown += args =>
{
if (args.Key == Microsoft.Xna.Framework.Input.Keys.OemPlus)
{
Game.Camera.MoveUp();
return true; // should be false from the above code to declare the event as handled (true is correct now that I fixed it... fml)
}
</keyboarddevice>
点赞 评论 复制链接分享
• weixin_39940154 2020-12-28 17:38

No, the issue is still occurring. There is no dedicated KeyDown event to distinguish between KeyPressed (with RepeatPress = true) and KeyPressed (with RepeatPress = false). KeyTyped acts as a KeyPressed event with RepeatPress = false so that route didn't work either.

点赞 评论 复制链接分享
• weixin_39940154 2020-12-28 17:38

Alright, I figured out a work around using KeyReleased and checking the listener's RepeatPress event. RepeatPress = true, RepeatDelayMilliseconds = 0, InitialDelayMilliseconds = 0

csharp
listener.KeyPressed += (sender, args) =>
{
if (listener.RepeatPress && KeyDown != null)
foreach (var t in KeyDown.GetInvocationList())
{
var result = (bool)t.DynamicInvoke(args);
if (result == true)
{
// if a event handler returns true, event was handled so break
break;
}
}

if (!listener.RepeatPress && KeyPressed != null)
foreach (var t in KeyPressed.GetInvocationList())
{
var result = (bool)t.DynamicInvoke(args);
if (result == true)
{
// if a event handler returns true, event was handled so break
break;
}
}
};

listener.KeyReleased += (sender, args) =>
{
if (listener.RepeatPress && KeyPressed != null)
foreach (var t in KeyPressed.GetInvocationList())
{
var result = (bool)t.DynamicInvoke(args);
if (result == true)
{
// if a event handler returns true, event was handled so break
break;
}
}

if (KeyReleased != null)
foreach (var t in KeyReleased.GetInvocationList())
{
var result = (bool)t.DynamicInvoke(args);
if (result == true)
{
// if a event handler returns true, event was handled so break
break;
}
}
};

listener.KeyTyped += (sender, args) =>
{
if (!listener.RepeatPress && KeyDown != null)
foreach (var t in KeyDown.GetInvocationList())
{
var result = (bool)t.DynamicInvoke(args);
if (result == true)
{
// if a event handler returns true, event was handled so break
break;
}
}
};

点赞 评论 复制链接分享
• weixin_39940154 2020-12-28 17:38

Well I did find a bug with KeyTyped though. It doesn't support repeating keys. Which explains the reason why my KeyDown event was working like a KeyPressed event when RepeatPress = false.

But with RepeatPress = true, my work around worked. do you think this still needs attention?

点赞 评论 复制链接分享
• weixin_39682560 2020-12-28 17:38

Hey man,

Sorry I only just got around to replying to you here. It looks like you've been talking to yourself for quite some time now lol.

Truth is, it's been a while since I took a close look at this code. I'm not sure if it's behaving correctly or not.

I'm glad you got it working for your case. I'll leave this issue open and take a closer look when I get around to it.

点赞 评论 复制链接分享
• weixin_39590472 2020-12-28 17:38

I believe I'm having the same problem. If I'm using the KeyboardListener for 'KeyDown' events, then I can only accept input for one key. So when I'm moving a camera about using WASD, I can't hold both W, and D (up, and right), as the camera will only go up, or right, and not both.

Looking at the code, it seems that the listener checks for a new key being pressed, and a key being held separately in the RaisePressedEvents, and RaiseRepeatEvents methods.

The first method invokes events (is that the correct terminology?) for all keys that are currently down, but weren't down last update. So let's say it does this for W, and then D. RaiseRepeatEvents then looks at the last key, does it's checks, and then invokes events. The last key may not be the all the repeated keys, which is the problem. So D was the last key in my example, but W will be ignored because this method only looks at the last key even though W is a repeated key.

What we could do is check for all keys that are down that were down last update instead of looking for the last key , or we could have a list of all keys that were pressed last update.

I have to be honest, I've never made an open source pull request before, but I might make this my first one.

EDIT: Realised the last solution I proposed wouldn't work since we're checking for different stuff in the two methods. Fixed the first solution as well

点赞 评论 复制链接分享
• weixin_39590472 2020-12-28 17:38

So I've done some tinkering on my own fork, and I realised that there's some other important fields like the InitialDelay. Having these for each key would require reworking the entire class, something I'm not willing to do.

I'll probably have to use something else than the listener, as my game doesn't control right when you can't hold multiple buttons.

点赞 评论 复制链接分享
• weixin_39682560 2020-12-28 17:38

So when I'm moving a camera about using WASD, I can't hold both W, and D (up, and right), as the camera will only go up, or right, and not both.

You're really overthinking this. The KeyboardListener is not really made for this purpose. If you want to move a camera when two keys are held down you just need to keep it simple. Something like this.

var mouseState = Mouse.GetState();

if(mouseState.IsKeyDown(Keys.W))
Camera.Position += new Vector2(0, 100);

if(mouseState.IsKeyDown(Keys.D))
Camera.Position += new Vector2(100, 0);


There's really nothing more to it than that. Simply put, there's already a good way to do this in MonoGame. There's really no need to replace this in Extended with something else.

点赞 评论 复制链接分享