bevyengine / bevyengine/bevy

Simplify read of Control, Alt Shift key and equivalents

Open
#4,568 0 comments 1 reaction 0 assignees View on GitHub
A-Input C-Feature
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.