Closed JeanMertz closed 4 years ago
Here's an example output:
Window(Focused) at SystemTime { tv_sec: 1589730587, tv_nsec: 523265000 }
Keyboard(Input { state: Pressed, key_code: A }) at SystemTime { tv_sec: 1589730588, tv_nsec: 837026000 }
Keyboard(TextEntered { character: 'a' }) at SystemTime { tv_sec: 1589730588, tv_nsec: 837055000 }
Keyboard(Input { state: Pressed, key_code: A }) at SystemTime { tv_sec: 1589730589, tv_nsec: 79325000 }
Keyboard(TextEntered { character: 'a' }) at SystemTime { tv_sec: 1589730589, tv_nsec: 79345000 }
Keyboard(Input { state: Pressed, key_code: A }) at SystemTime { tv_sec: 1589730589, tv_nsec: 129870000 }
Keyboard(TextEntered { character: 'a' }) at SystemTime { tv_sec: 1589730589, tv_nsec: 129894000 }
Keyboard(Input { state: Pressed, key_code: A }) at SystemTime { tv_sec: 1589730589, tv_nsec: 163413000 }
Keyboard(TextEntered { character: 'a' }) at SystemTime { tv_sec: 1589730589, tv_nsec: 163438000 }
Using the following Input
type:
struct Test;
impl Input for Test {
fn update(&mut self, event: input::Event) {
println!("{:?} at {:?}", event, SystemTime::now());
}
fn new() -> Self { Self }
fn clear(&mut self) {}
}
You can see the first Input
at sec 1589730588
and nsec 837026000
, then, the next input 242 milliseconds later, and then about every 50 milliseconds.
I guess one approach to solve this problem is to do custom tracking of keyboard state.
It would probably be something like:
fn interact
and keep those events aroundfn update
, see what "key" events are active, and act on thosefn interact
, remove them from the event storefn update
won't see that key as "down" any moreBut I wonder if this should "just" be handled by the engine instead, similar to what ggez is doing?
Another problem I noticed with this (which would be solved by my above suggestion of keeping state around), is that holding down two keys simultaneously does not trigger the repeat event for one of those keys (which, my guess would be, is the one that was pressed first):
Keyboard(Input { state: Pressed, key_code: D })
Keyboard(Input { state: Pressed, key_code: S })
Keyboard(Input { state: Pressed, key_code: S })
Keyboard(Input { state: Pressed, key_code: S })
Keyboard(Input { state: Pressed, key_code: S })
Keyboard(Input { state: Released, key_code: S })
Keyboard(Input { state: Released, key_code: D })
I removed the TextEntered
events here, but what can be observed is that I pressed D
and S
simultaneously, with D
being pressed just a bit faster. Because S
was pressed last, repeated events are triggered for that key, whereas only the Released
event is triggered for D
once I release that one, but no repeast Pressed
events are triggered.
Alright, I should have checked the Keyboard
implementation more closely. It's already doing exactly what I described above, I just didn't copy it correctly in my implementation.
The reason why I forked the implementation though, is because I wanted to have access to the pressed_keys
hash set.
I'll create a PR to see if you are okay exposing those details in the public API.
I have a small example that moves a circle across the screen based on
WASD
input.From experimenting on macOS, it appears that Coffee respects macOS's key repeat preferences:
On the one hand, this is obviously a nice thing to have, as it gives the player control over the behaviour. On the other hand, this is unexpected behaviour for games.
Specifically, even with my preferences set to fast/short, there is still a noticeable delay from the "Delay Until Repeat" option. This means that if I press and hold
A
to move the circle to the left, it will move to the left once on press down, it will then stop moving for a moment even though A is still held down, and then start moving again as soon as the "repeat" kicks in, until I release the A key.I've experimented with ggez as well, and that game engine behaves as "expected" on macOS (quotations here because the game behaviour differs from default operating system behaviour, but I believe ggez' behaviour is what people expect in a game).
Given that both engines use
winit
as a dependency, but ggez is still using0.19
and Coffee uses0.22
, I suspect it's actually a change in behaviour between winit versions, and I would also suspect that change in behaviour is considered to be a fix, since regular macOS windows are expected to behave this way, but I don't think this is expected for games.Alternatively, Coffee shouldn't treat key input as "text input". There's some investigation for Piston I found here: https://github.com/PistonDevelopers/piston/issues/1220#issuecomment-569185277.
Another reference is to a long-standing issue for Winit to discuss a better input model, see: https://github.com/rust-windowing/winit/issues/753
And finally, looking at ggez, it appears that they've implemented this behavior themselves by tracking
is_key_repeated
.Although I'm not quite sure (yet) how that works, as that still doesn't explain why ggez doesn't have a delay between the first key and the repeat, whereas Coffee does.