godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.15k stars 97 forks source link

Add a way to differentiate Left and Right Shift, Alt, and Control keys #1387

Closed krscott closed 8 months ago

krscott commented 4 years ago

Describe the project you are working on: A pinball-style game with left and right flippers.

Describe the problem or limitation you are having in your project: I would like the option of using the left and right Shift keys as left and right paddles for users with tenkeyless or shorter keyboards, however, the Input Map treats these keys both as "Shift", and the InputEventKey scancode is 16777237 for both keys.

Describe the feature / enhancement and how it helps to overcome the problem or limitation: If there was a way to differentiate left and right Shift keys, it would be possible to use these keys for separate functions.

Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams: I can imagine two ways to solve this issue:

  1. Add KEY_RIGHT_SHIFT, KEY_RIGHT_ALT, KEY_RIGHT_CONTROL to the KeyList enum.
func _input(ev):
  if ev is InputEventKey:
    match ev.scancode:
      KEY_SHIFT:
        print("left shift")
      KEY_RIGHT_SHIFT:
        print("right shift")
  1. Add a location field to InputEventKey with a new enum for left/right. This would preserve the current functionality of KEY_SHIFT, etc., but probably would require more changes to get working with the Input Map menu.
    func _input(ev):
    if ev is InputEventKey and ev.scancode == KEY_SHIFT:
    match ev.location:
      MULTIKEY_LOCATION_LEFT:
        print("left shift")
      MULTIKEY_LOCATION_RIGHT:
        print("right shift")

If this enhancement will not be used often, can it be worked around with a few lines of script?: I'm not aware of any possible way to work around this issue in GDScript.

Is there a reason why this should be core and not an add-on in the asset library?: This feature would require adding to the GlobalScope KeyList enum or adding an enum to InputEventKey.

KoBeWi commented 4 years ago

The first solution is better and 4.0 is a good chance to add it. Someone already made an attempt to implement this: https://github.com/godotengine/godot/pull/27991

bojidar-bg commented 4 years ago

Note: As implementing (1) will definitely break compatibility, there is no point in leaving a constant named KEY_SHIFT, instead both constant names should include the location, as in KEY_LEFT_SHIFT and KEY_RIGHT_SHIFT.

TheDuriel commented 4 years ago

There should be all three, KEY_SHIFT, left, and right. Otherwise you are asking people to do redundant work when they want to use shift, and not a specific side.

(Thus would mean that pressing shift emitts two events, not just one. But that should be fine.)

Also, if any of this is done for shift. It needs to be done for CTL, ALT and mac/win keys as well.

krscott commented 4 years ago

@TheDuriel This would require more work for other cases, though. For instance, an in-game menu that asks a user for a keybinding would need to handle every possible case of double-events, whereas now it only needs to save the scancode. I think that most use cases where the code doesn't care which modifier key is for handling combos (e.g. Ctrl+S), but this would still be possible by reading the modifier value in InputEventWithModifiers.

Maybe these new behaviors could be configurable in the project settings and just let the author decide if they want separate LEFT/RIGHT scancodes or not.

TheDuriel commented 4 years ago

I don't see how this would require more work. Right now the proposal is to split them anyways, and make treating them generally impossible.

What I'm proposing that we let BOTH happen. Pressing a modifier sends the modifer key, and the left or right variant. One press, two events. No compatibility problems.

Sauermann commented 1 year ago

This is also discussed in https://github.com/godotengine/godot/issues/3347

romlok commented 1 year ago

Is there even any workaround for this right now?

For all of Shift, Ctrl, Alt and Meta ("windows"), all the functions and properties of an InputEventKey make the physical keys indistinguishable as far as I can tell?

I would much rather see a partial solution where it becomes possible to distinguish between the keys - even with a hack - than to wait for someone to implement a satisfactory complete solution, which would have to wait until a next major version anyway.

So absent anything like this already existing that I've missed, I'd like to reiterate and push for something more like the OP's second suggestion as an interim solution:

func _input(ev):
  if ev is InputEventKey and ev.keycode == KEY_SHIFT:
    match ev.location:
      MULTIKEY_LOCATION_LEFT:
        print("left shift")
      MULTIKEY_LOCATION_RIGHT:
        print("right shift")

AFAICT it should be far simpler and easier to implement (and backport), and could be released as part of a minor version, rather than waiting for the next compatibility-breaking release.