Simplify read of Control, Alt Shift key and equivalents
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 22h
- Merged PRs (30d)
- 161
Description
## What problem does this solve or what need does it fill?
When checking for special key combinaison using control, alt and/or shift key there is no way to check for either left or right variant indistinguishably. It results a pretty verbose code (see below).
```rust
fn system(keyboard: Res>) {
if (keyboard.pressed(KeyCode::LControl) || keyboard.pressed(KeyCode::RControl))
&& (keyboard.pressed(KeyCode::LAlt) || keyboard.pressed(KeyCode::RAlt))
&& keyboard.just_pressed(KeyCode::P)
{
/* ... */
}
}
```
## What solution would you like?
### Solution 1 : special impl for `Input`
Pros:
- easy to use
Cons:
- cannot be used for `Input` due to the orphan rule
```rust
impl Input {
pub fn just_pressed_control(&self) -> bool {
self.just_pressed(KeyCode::LControl) || self.just_pressed(KeyCode::RControl)
}
pub fn pressed_control(&self) -> bool { /* ... */ }
pub fn released_control(&self) -> bool { /* ... */ }
/* ... */
}
```
### Solution 2 : specials functions
Same as solution 1 but with functions instead of methods.
Pros:
- the macro can be adapted to be used with `Input`
Cons:
- inconsistency syntax when reading a single input and special inputs.
```rs
macro_rules! keycode_function {
(
$($name:ident {
$first_code:expr,
$($code:expr),*
$(,)?
})+
) => {
$(pub mod $name {
use bevy::input::{keyboard::KeyCode, Input};
pub fn pressed(inputs: &Input) -> bool {
inputs.pressed($first_code) $(|| inputs.pressed($code))*
}
pub fn just_pressed(inputs: &Input) -> bool {
inputs.just_pressed($first_code) $(|| inputs.just_pressed($code))*
}
pub fn just_released(inputs: &Input) -> bool {
inputs.just_released($first_code) $(|| inputs.just_released($code))*
}
})+
};
}
keycode_function!(
control {
KeyCode::LControl,
KeyCode::RControl,
}
shift {
KeyCode::LShift,
KeyCode::RShift,
}
alt {
KeyCode::LAlt,
KeyCode::RAlt,
}
);
```
**Usage**
```rs
if special_keycode::control::pressed(&keyboard) && keyboard.just_pressed(KeyCode::P) {
/* ... */
}
```
### Solution 3 : Using a special trait
Pros:
- can call `pressed`, `just_pressed` and `just_released` for either a single input or a special input
- user can create it's own `InputGroup`
Cons:
- Add a level of indirection
- Probably breaking change (i'm not 100% sure)
```rust
pub trait InputGroup {
fn pressed(&self, input: &Input) -> bool;
fn just_pressed(&self, input: &Input) -> bool;
fn just_released(&self, input: &Input) -> bool;
}
impl Intput {
// rename pressed, just_pressed and just_release into input_*
pub fn input_pressed(&self, input: T) -> bool { /* ... */ }
pub fn input_just_pressed(&self, input: T) -> bool { /* ... */ }
pub fn input_just_released(&self, input: T) -> bool { /* ... */ }
pub fn pressed(&self, input: impl InputGroup) -> bool {
input.pressed(self);
}
pub fn just_pressed(&self, input: impl InputGroup) -> bool {
input.just_pressed(self);
}
pub fn just_released(&self, input: impl InputGroup) -> bool {
input.just_released(self);
}
}
// allow keyboard.pressed(KeyCode::A) with introducing breaking change (i'm not 100% sure of this)
impl InputGroup for T {
fn pressed(&self, input: &Input) -> bool {
input.input_pressed(self)
}
/* ... */
}
struct Control; // or maybe use an enum for special keys ?
struct Alt;
struct Shift;
impl InputGroup for Control {
fn pressed(&self, input: &Input) -> bool {
input.input_pressed(KeyCode::LControl) || input.input_pressed(KeyCode::RControl)
}
/* ... */
}
/* ... */
```
**Usage**
```rs
if keyboard.pressed(Control) && keyboard.just_pressed(KeyCode::P) {
/* ... */
}
```
Contributor guide
Assessment
This issue has not been assessed yet.