Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented control remapping #19

Merged
merged 2 commits into from Sep 4, 2021
Merged

Conversation

kroltan
Copy link
Contributor

@kroltan kroltan commented Sep 3, 2021

Closes #16.

Changes

To do this, I added a new section to the Config, which can take an array of input bindings for each command in the game.

Since the convenient way to write this down in configuration is not strikingly efficient for runtime querying, I created a new resource type DirectionalControls that simplifies runtime access.

Refactored the snake_movement_input system to use this new resource, and cleaned up a bit of its code too, by breaking up the nesting in iteration. While it technically runs faster when the player presses multiple keys in one frame, it was unlikely to be a problem, so this was mainly a readability change. This way it is also a bit easier to add different event-reading loops later.

Usage

Players can change their control configuration like this (likewise for down, left, right):

[controls]
up = [ { device = "keyboard", code = 72 } ]

Sadly, Bevy does not provide conversions from named keys to string and vice-versa, so I had to use their scan codes instead. Good part is that it's keyboard-layout dependent, bad part is that it is rather obscure to set up (I found them by putting a print on key presses and taking note of the codes for each key).

Extensibility

When time comes for #17, the following changes will be needed:

  1. Add a new variant to the config::Binding enum with appropriate data;
  2. Consume those variants when constructing DirectionalControls (the compiler will yell the location at you);
  3. Add a new method to the impl DirectionalControls to read the gamepad event;
  4. Call that method in the input system within the processing loop for gamepads.

@ElnuDev ElnuDev added the enhancement New feature or request label Sep 3, 2021
@ElnuDev
Copy link
Owner

ElnuDev commented Sep 3, 2021

Sadly, Bevy does not provide conversions from named keys to string and vice-versa

Is this worth potentially opening a feature-request issue on Bevy for? I feel like it's a common enough problem

@kroltan
Copy link
Contributor Author

kroltan commented Sep 3, 2021

Yes, I think it would be very welcome. Ideally implemented through TryFrom/Into or such.

@ElnuDev
Copy link
Owner

ElnuDev commented Sep 4, 2021

Just tried it out for myself, and the arrow keys are broken. Are those key codes not universal? I was a bit surprised how high they were numerically compared to everything else.

@ElnuDev
Copy link
Owner

ElnuDev commented Sep 4, 2021

Just tried debugging the scan codes for my arrow keys, and they were 103 for up, 108 for down, 105 for left, and 106 for right.

@kroltan
Copy link
Contributor Author

kroltan commented Sep 4, 2021

Huh that is weird. I'm not sure why those were the numbers I got. I'm on windows, and allegedly the arrow keys should be in the range 37~40. This doesn't fit with your observation nor mine, lol. I'm not sure where Bevy gets those from.

@ElnuDev
Copy link
Owner

ElnuDev commented Sep 4, 2021

I think I'm not going to merge this PR until we figure out how to reliably get keys, I'll ask on the Bevy Discord tomorrow. (I am on Linux though, I'll switch over to my Windows install tomorrow and try the same thing and see what key codes I get.)

@kroltan
Copy link
Contributor Author

kroltan commented Sep 4, 2021

I clicked around the source and reached the winit crate.

Also, checking the key codes for the arrows, they all start with 0xE0 when in hex.

And here I find something fun:
winit src/platform_impl/windows/event.rs lines 345 and 346 on commit 1ecc6299db9ec823

So I think it's not very trivial, would indeed be better asking someone more knowledgeable of WIndows internals. Might be a winit bug, too. Fun!

From the link:

In addition to the obvious contenders for problematic keys, there are a few others which will cause problems if we only deal with virtual key codes. The following is a list I assembled while implementing Molecule’s keyboard handling:

  • Left-hand / right-hand “Shift”, “Control” and “Alt” keys – for obvious reasons.
  • “Enter” / “Numpad Enter” – for obvious reasons.
  • “Insert”, “Delete”, “Home”, “End”, “Prior”, “Next”, Arrow keys / corresponding keys on the numpad – the virtual key codes of the latter depend on the state of “Numlock”.
    [...]

(emphasis mine)

@kroltan
Copy link
Contributor Author

kroltan commented Sep 4, 2021

I think I'm not going to merge this PR until we figure out how to reliably get keys,

Yeah I think that's fair.

Is this worth potentially opening a feature-request issue on Bevy for? I feel like it's a common enough problem

Do you want to do that? If not I could do it. Either way, then on the next Bevy version we might not even need to deal with the disastrous keycodes at all!

@ElnuDev
Copy link
Owner

ElnuDev commented Sep 4, 2021

the virtual key codes of the latter depend on the state of “Numlock”.

I want to guess that you had number lock on when you got those suspiciously high key codes? What do you get with it off?

Do you want to do that? If not I could do it. Either way, then on the next Bevy version we might not even need to deal with the disastrous keycodes at all!

I was going to make an issue in the morning, but feel free to do one now if you like! The earlier the better I guess. It would be super cool if it we didn't have to worry about this in Bevy 0.6, whenever that gets released

@kroltan
Copy link
Contributor Author

kroltan commented Sep 4, 2021

I want to guess that you had number lock on when you got those suspiciously high key codes? What do you get with it off?

Yes, but I think that quote refers to the arrows on the numpad, e.g the buttons 2,4,6,8. The arrow keys themselves don't seem to change regardless of the Num Lock, but the numpad-buttons do change their keycodes but not their scancodes! How puzzling. Below is an excerpt log:

KeyboardInput { scan_code: 57421, key_code: Some(Right), state: Pressed }     
KeyboardInput { scan_code: 57424, key_code: Some(Down), state: Pressed }      
KeyboardInput { scan_code: 57421, key_code: Some(Right), state: Pressed }     
KeyboardInput { scan_code: 57416, key_code: Some(Up), state: Pressed }        
KeyboardInput { scan_code: 57424, key_code: Some(Down), state: Pressed }      
KeyboardInput { scan_code: 57421, key_code: Some(Right), state: Pressed }     
KeyboardInput { scan_code: 57416, key_code: Some(Up), state: Pressed }        
KeyboardInput { scan_code: 57416, key_code: Some(Up), state: Pressed }        
KeyboardInput { scan_code: 57416, key_code: Some(Up), state: Pressed }        
KeyboardInput { scan_code: 57416, key_code: Some(Up), state: Pressed }        
KeyboardInput { scan_code: 72, key_code: Some(Numpad8), state: Pressed }      
KeyboardInput { scan_code: 57413, key_code: Some(Numlock), state: Pressed }   
KeyboardInput { scan_code: 72, key_code: Some(Up), state: Pressed }           
KeyboardInput { scan_code: 72, key_code: Some(Up), state: Pressed }           
KeyboardInput { scan_code: 72, key_code: Some(Up), state: Pressed }           
KeyboardInput { scan_code: 75, key_code: Some(Left), state: Pressed }         
KeyboardInput { scan_code: 80, key_code: Some(Down), state: Pressed }         
KeyboardInput { scan_code: 77, key_code: Some(Right), state: Pressed }        
KeyboardInput { scan_code: 72, key_code: Some(Up), state: Pressed }           
KeyboardInput { scan_code: 57413, key_code: Some(Numlock), state: Pressed }   
KeyboardInput { scan_code: 75, key_code: Some(Numpad4), state: Pressed }      
KeyboardInput { scan_code: 72, key_code: Some(Numpad8), state: Pressed }      
KeyboardInput { scan_code: 75, key_code: Some(Numpad4), state: Pressed }      
KeyboardInput { scan_code: 80, key_code: Some(Numpad2), state: Pressed }      
KeyboardInput { scan_code: 77, key_code: Some(Numpad6), state: Pressed }      
KeyboardInput { scan_code: 72, key_code: Some(Numpad8), state: Pressed }      
KeyboardInput { scan_code: 75, key_code: Some(Numpad4), state: Pressed }      
KeyboardInput { scan_code: 80, key_code: Some(Numpad2), state: Pressed }      
KeyboardInput { scan_code: 77, key_code: Some(Numpad6), state: Pressed }      
KeyboardInput { scan_code: 71, key_code: Some(Numpad7), state: Pressed }      
KeyboardInput { scan_code: 72, key_code: Some(Numpad8), state: Pressed }      
KeyboardInput { scan_code: 75, key_code: Some(Numpad4), state: Pressed }

I was going to make an issue in the morning, but feel free to do one now if you like! The earlier the better I guess. It would be super cool if it we didn't have to worry about this in Bevy 0.6, whenever that gets released

I might just go dropkick a pull request on them lol.

@kroltan
Copy link
Contributor Author

kroltan commented Sep 4, 2021

Turns out no PR is necessary! serde support is included with the serialize feature.

Just added that to Cargo.toml and changed the code from u32 to KeyCode accordingly.

Now the binding config looks like:

[controls]
up = [ { device = "keyboard", key = "Up" } ]

To see the full list of possible keys is just a matter of directing people to the Bevy docs.


Note to self: In the future, RTFM.

@kroltan
Copy link
Contributor Author

kroltan commented Sep 4, 2021

Also:

Bevy kind of does some massage to the raw input, like you might have seen in the log I posted above. The numpad arrow keys actually emit KeyCode::Up and similar when numlock is off. This behaviour is the same as what the OS does, so it would be consistent to only accept them in that mode?

For now, to keep parity with the old behaviour I also included the KeyCode::Numpad* values in the default config, but it would be just as valid to just tell people to "use their keyboard properly".

No opinion either way, just a FYI.

@ElnuDev
Copy link
Owner

ElnuDev commented Sep 4, 2021

Just tested it, and it seems to work fine! I'll merge it in. Thanks for the help!

@ElnuDev ElnuDev merged commit f929228 into ElnuDev:main Sep 4, 2021
@kroltan kroltan deleted the input-remapping branch September 4, 2021 19:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add ability to create custom input schemes
2 participants